SuperTinyKernel™ RTOS 1.05.3
Lightweight, high-performance, deterministic, bare-metal C++ RTOS for resource-constrained embedded systems. MIT Open Source License.
Loading...
Searching...
No Matches
stk::sync::Pipe< T, N > Class Template Reference

Thread-safe FIFO communication pipe for inter-task data passing. More...

#include <stk_sync_pipe.h>

Inheritance diagram for stk::sync::Pipe< T, N >:
Collaboration diagram for stk::sync::Pipe< T, N >:

Public Member Functions

 Pipe ()
 Constructor.
bool Write (const T &data, Timeout timeout=WAIT_INFINITE)
 Write data to the pipe.
bool TryWrite (const T &data)
 Attempt to write data to the pipe.
size_t WriteBulk (const T *src, size_t count, Timeout timeout=WAIT_INFINITE)
 Write multiple elements to the pipe.
size_t TryWriteBulk (const T *src, size_t count)
 Attempt to write multiple elements to the pipe.
bool Read (T &data, Timeout timeout=WAIT_INFINITE)
 Read data from the pipe.
bool TryRead (T &data)
 Attempt to read data from the pipe.
size_t ReadBulk (T *dst, size_t count, Timeout timeout=WAIT_INFINITE)
 Read multiple elements from the pipe.
size_t TryReadBulk (T *dst, size_t count)
 Attempt to read multiple elements from the pipe.
size_t GetSize () const
 Get the current number of elements in the pipe.
bool IsEmpty () const
 Check if queue is currently empty.

Private Member Functions

 STK_NONCOPYABLE_CLASS (Pipe)

Private Attributes

m_buffer [N]
 static storage for FIFO elements
size_t m_head
 index of the next slot to be written (producer)
size_t m_tail
 index of the next slot to be read (consumer)
size_t m_count
 current number of elements stored in the pipe
ConditionVariable m_cv_empty
 condition variable signaled when the pipe is no longer empty
ConditionVariable m_cv_full
 condition variable signaled when the pipe is no longer full

Detailed Description

template<typename T, size_t N>
class stk::sync::Pipe< T, N >

Thread-safe FIFO communication pipe for inter-task data passing.

Template Parameters
TData type of elements.
NCapacity of the pipe (number of elements).

Pipe provides a synchronized ring-buffer mechanism that allows tasks to exchange data safely. It implements blocking semantics:

  • Write() blocks if the pipe is full until space becomes available.
  • Read() blocks if the pipe is empty until data is produced.
// Example: Producer-Consumer pattern
void Task_Producer() {
uint32_t value = 42;
// blocks if pipe is full
g_DataPipe.Write(value);
}
void Task_Consumer() {
uint32_t received;
// blocks until data is available, with a 1s timeout
if (g_DataPipe.Read(received, 1000)) {
// ... process received value ...
}
}
Thread-safe FIFO communication pipe for inter-task data passing.
bool Write(const T &data, Timeout timeout=WAIT_INFINITE)
Write data to the pipe.
bool Read(T &data, Timeout timeout=WAIT_INFINITE)
Read data from the pipe.
See also
Mutex, ConditionVariable
Note
Only available when kernel is compiled with KERNEL_SYNC mode enabled.

Definition at line 58 of file stk_sync_pipe.h.

Constructor & Destructor Documentation

◆ Pipe()

template<typename T, size_t N>
stk::sync::Pipe< T, N >::Pipe ( )
inlineexplicit

Constructor.

Definition at line 63 of file stk_sync_pipe.h.

64 {}
ConditionVariable m_cv_full
condition variable signaled when the pipe is no longer full
size_t m_tail
index of the next slot to be read (consumer)
ConditionVariable m_cv_empty
condition variable signaled when the pipe is no longer empty
size_t m_head
index of the next slot to be written (producer)
size_t m_count
current number of elements stored in the pipe
T m_buffer[N]
static storage for FIFO elements

Member Function Documentation

◆ GetSize()

template<typename T, size_t N>
size_t stk::sync::Pipe< T, N >::GetSize ( ) const
inline

Get the current number of elements in the pipe.

Returns
The number of elements currently stored in the FIFO buffer.
Note
The returned value is a point-in-time snapshot. In a multi-tasking environment, queue size may change immediately after function returns if a producer or consumer is active in another task.

Definition at line 337 of file stk_sync_pipe.h.

337{ return m_count; }

Referenced by stk::sync::Pipe< Timer *, 32 >::IsEmpty(), and stk_pipe_get_size().

Here is the caller graph for this function:

◆ IsEmpty()

template<typename T, size_t N>
bool stk::sync::Pipe< T, N >::IsEmpty ( ) const
inline

Check if queue is currently empty.

Returns
True if empty, otherwise false.
Note
The returned value is a point-in-time snapshot. In a multi-tasking environment, queue size may change immediately after function returns if a producer or consumer is active in another task.

Definition at line 346 of file stk_sync_pipe.h.

346{ return (GetSize() == 0); }
size_t GetSize() const
Get the current number of elements in the pipe.

◆ Read()

template<typename T, size_t N>
bool stk::sync::Pipe< T, N >::Read ( T & data,
Timeout timeout = WAIT_INFINITE )
inline

Read data from the pipe.

Attempts to retrieve an element from the FIFO queue. If pipe is empty, the calling task will be suspended until data is provided by a producer or the timeout expires.

Parameters
[out]dataReference to the variable where the retrieved data will be stored.
[in]timeoutMaximum time to wait for data (ticks). Default: WAIT_INFINITE.
Warning
ISR-safe only with timeout=NO_WAIT, ISR-unsafe otherwise.
Returns
true if data was successfully read, false if timeout expired before any data became available.

Definition at line 207 of file stk_sync_pipe.h.

208 {
210
211 while (m_count == 0U)
212 {
213 if (!m_cv_empty.Wait(cs_, timeout))
214 return false;
215 }
216
218 m_tail = (m_tail + 1U) % N;
219 m_count -= 1U;
220
221 // notify producer that space is available
222 m_cv_full.NotifyOne();
223
224 return true;
225 }

Referenced by stk_pipe_read(), and stk::sync::Pipe< Timer *, 32 >::TryRead().

Here is the caller graph for this function:

◆ ReadBulk()

template<typename T, size_t N>
size_t stk::sync::Pipe< T, N >::ReadBulk ( T * dst,
size_t count,
Timeout timeout = WAIT_INFINITE )
inline

Read multiple elements from the pipe.

Attempts to retrieve a block of data from the FIFO. If pipe does not contain enough elements to satisfy the requested count, it will block until the full amount is read or the timeout expires.

Parameters
[out]dstPointer to the destination array.
[in]countNumber of elements to read.
[in]timeoutMaximum time to wait for data (ticks). Default: WAIT_INFINITE.
Warning
ISR-safe only with timeout=NO_WAIT, ISR-unsafe otherwise.
Returns
Number of elements actually read. This will be equal to count unless a timeout occurred.
// Example:
Sample frame[64];
// read the whole block
size_t result = g_Pipe.ReadBulk(frame, 64, 500);
if (result == 64) {
// handle data processing
} else {
// handle partial data due to underrun/timeout
}

Definition at line 260 of file stk_sync_pipe.h.

261 {
262 if ((dst == nullptr) || (count == 0U))
263 return 0U;
264
265 size_t read_count = 0U;
266
268
269 while (read_count < count)
270 {
271 // wait until there is at least 1 element available
272 while (m_count == 0U)
273 {
274 if (!m_cv_empty.Wait(cs_, timeout))
275 return read_count; // return partial count on timeout
276 }
277
278 // determine how many we can pull in this stretch
279 size_t to_read = (count - read_count) < m_count ? (count - read_count) : m_count;
280
281 // copy to destination
282 // note: if value type is not scalar or queue is small we copy with a for loop,
283 // otherwise using faster memcpy version for large scalar arrays
284 if (!std::is_scalar<T>::value || (N < 8))
285 {
286 for (size_t i = 0U; i < to_read; ++i)
287 {
289 m_tail = (m_tail + 1) % N;
290 m_count -= 1U;
291 }
292 }
293 else
294 {
295 size_t first_part = N - m_tail;
296 if (to_read <= first_part)
297 {
298 memcpy(&dst[read_count], &m_buffer[m_tail], (to_read * sizeof(T)));
299 }
300 else
301 {
302 memcpy(&dst[read_count], &m_buffer[m_tail], (first_part * sizeof(T)));
303 memcpy(&dst[read_count + first_part], &m_buffer[0], ((to_read - first_part) * sizeof(T)));
304 }
306 m_tail = (m_tail + to_read) % N;
307 m_count -= to_read;
308 }
309
310 // notify producers that space is now available
311 m_cv_full.NotifyAll();
312 }
313
314 return read_count;
315 }

Referenced by stk_pipe_read_bulk(), and stk::sync::Pipe< Timer *, 32 >::TryReadBulk().

Here is the caller graph for this function:

◆ STK_NONCOPYABLE_CLASS()

template<typename T, size_t N>
stk::sync::Pipe< T, N >::STK_NONCOPYABLE_CLASS ( Pipe< T, N > )
private

◆ TryRead()

template<typename T, size_t N>
bool stk::sync::Pipe< T, N >::TryRead ( T & data)
inline

Attempt to read data from the pipe.

Checks if an element is available in the FIFO and retrieves it immediately without blocking. If the pipe is empty, returns false without yielding the CPU or touching the kernel wait list.

Parameters
[out]dataReference to the variable where the retrieved data will be stored.
Warning
ISR-safe.
Returns
true if data was successfully read, false if the pipe was empty.

Definition at line 235 of file stk_sync_pipe.h.

235{ return Read(data, NO_WAIT); }

◆ TryReadBulk()

template<typename T, size_t N>
size_t stk::sync::Pipe< T, N >::TryReadBulk ( T * dst,
size_t count )
inline

Attempt to read multiple elements from the pipe.

Reads as many elements as are currently available in the FIFO without blocking. If fewer elements than requested are available, only the available elements are read.

Parameters
[out]dstPointer to the destination array.
[in]countNumber of elements to read.
Warning
ISR-safe.
Returns
Number of elements actually read. This will be equal to count if all requested elements were available, or less if the pipe was empty or became empty before all elements could be read.

Definition at line 328 of file stk_sync_pipe.h.

328{ return ReadBulk(dst, count, NO_WAIT); }
size_t ReadBulk(T *dst, size_t count, Timeout timeout=WAIT_INFINITE)
Read multiple elements from the pipe.

◆ TryWrite()

template<typename T, size_t N>
bool stk::sync::Pipe< T, N >::TryWrite ( const T & data)
inline

Attempt to write data to the pipe.

Attempts to push an element into the FIFO queue. If pipe is full, a false will be returned without waiting for a free space.

Parameters
[in]dataReference to the data element to be copied into the pipe.
Warning
ISR-safe.
Returns
true if data was successfully written, false if no space is available.

Definition at line 103 of file stk_sync_pipe.h.

103{ return Write(data, NO_WAIT); }

◆ TryWriteBulk()

template<typename T, size_t N>
size_t stk::sync::Pipe< T, N >::TryWriteBulk ( const T * src,
size_t count )
inline

Attempt to write multiple elements to the pipe.

Copies as many elements as possible into the FIFO without blocking. If the pipe does not have enough space for the entire block, only the elements that fit are written and the rest are discarded.

Parameters
[in]srcPointer to the source array.
[in]countNumber of elements to write.
Warning
ISR-safe.
Returns
Number of elements actually written. This will be equal to count if all elements were written successfully, or less if the pipe was full or became full before all elements could be written.

Definition at line 195 of file stk_sync_pipe.h.

195{ return WriteBulk(src, count, NO_WAIT); }
size_t WriteBulk(const T *src, size_t count, Timeout timeout=WAIT_INFINITE)
Write multiple elements to the pipe.

◆ Write()

template<typename T, size_t N>
bool stk::sync::Pipe< T, N >::Write ( const T & data,
Timeout timeout = WAIT_INFINITE )
inline

Write data to the pipe.

Attempts to push an element into the FIFO queue. If pipe is full, the calling task will be suspended until space is made available by a consumer or the timeout expires.

Parameters
[in]dataReference to the data element to be copied into the pipe.
[in]timeoutMaximum time to wait for space (ticks). Default: WAIT_INFINITE.
Warning
ISR-safe only with timeout=NO_WAIT, ISR-unsafe otherwise.
Returns
true if data was successfully written, false if timeout expired before space became available.

Definition at line 76 of file stk_sync_pipe.h.

77 {
79
80 while (m_count == N)
81 {
82 if (!m_cv_full.Wait(cs_, timeout))
83 return false;
84 }
85
87 m_head = (m_head + 1U) % N;
88 m_count += 1U;
89
90 // notify consumer that data is available
91 m_cv_empty.NotifyOne();
92
93 return true;
94 }

Referenced by stk_pipe_write(), and stk::sync::Pipe< Timer *, 32 >::TryWrite().

Here is the caller graph for this function:

◆ WriteBulk()

template<typename T, size_t N>
size_t stk::sync::Pipe< T, N >::WriteBulk ( const T * src,
size_t count,
Timeout timeout = WAIT_INFINITE )
inline

Write multiple elements to the pipe.

Copies a block of data into the FIFO. If the pipe does not have enough space for the entire block, it will block until the full amount can be written or the timeout expires.

Parameters
[in]srcPointer to the source array.
[in]countNumber of elements to write.
[in]timeoutMaximum time to wait for sufficient space (ticks).
Warning
ISR-safe only with timeout=NO_WAIT, ISR-unsafe otherwise.
Returns
Number of elements actually written. This will be equal to count unless a timeout occurred.
// Example:
Sample frame[64];
FillFrame(frame); // e.g., from decoder
// move the whole block
size_t result = g_Pipe.WriteBulk(frame, 64, 500);
if (result < 64) {
// handle buffer underrun/timeout
}

Definition at line 127 of file stk_sync_pipe.h.

128 {
129 if ((src == nullptr) || (count == 0U))
130 return 0U;
131
132 size_t written = 0U;
134
135 while (written < count)
136 {
137 // wait until there is at least 1 slot available
138 while (m_count == N)
139 {
140 if (!m_cv_full.Wait(cs_, timeout))
141 return written; // Return partial count on timeout
142 }
143
144 // calculate how many we can copy in this contiguous stretch
145 size_t available = N - m_count;
146 size_t to_write = ((count - written) < available ? (count - written) : available);
147
148 // copy from source
149 // note: if value type is not scalar or queue is small we copy with a for loop,
150 // otherwise using faster memcpy version for large scalar arrays
151 if (!std::is_scalar<T>::value && (N < 8))
152 {
153 for (size_t i = 0; i < to_write; ++i)
154 {
156 m_head = (m_head + 1U) % N;
157 m_count += 1U;
158 }
159 }
160 else
161 {
162 size_t first_part = N - m_head;
163 if (to_write <= first_part)
164 {
165 memcpy(&m_buffer[m_head], &src[written], (to_write * sizeof(T)));
166 }
167 else
168 {
169 memcpy(&m_buffer[m_head], &src[written], (first_part * sizeof(T)));
170 memcpy(&m_buffer[0], &src[written + first_part], ((to_write - first_part) * sizeof(T)));
171 }
172 written += to_write;
173 m_head = (m_head + to_write) % N;
174 m_count += to_write;
175 }
176
177 // notify consumers that data is ready
178 m_cv_empty.NotifyAll();
179 }
180
181 return written;
182 }

Referenced by stk_pipe_write_bulk(), and stk::sync::Pipe< Timer *, 32 >::TryWriteBulk().

Here is the caller graph for this function:

Member Data Documentation

◆ m_buffer

template<typename T, size_t N>
T stk::sync::Pipe< T, N >::m_buffer[N]
private

static storage for FIFO elements

Definition at line 351 of file stk_sync_pipe.h.

◆ m_count

template<typename T, size_t N>
size_t stk::sync::Pipe< T, N >::m_count
private

current number of elements stored in the pipe

Definition at line 354 of file stk_sync_pipe.h.

◆ m_cv_empty

template<typename T, size_t N>
ConditionVariable stk::sync::Pipe< T, N >::m_cv_empty
private

condition variable signaled when the pipe is no longer empty

Definition at line 355 of file stk_sync_pipe.h.

◆ m_cv_full

template<typename T, size_t N>
ConditionVariable stk::sync::Pipe< T, N >::m_cv_full
private

condition variable signaled when the pipe is no longer full

Definition at line 356 of file stk_sync_pipe.h.

◆ m_head

template<typename T, size_t N>
size_t stk::sync::Pipe< T, N >::m_head
private

index of the next slot to be written (producer)

Definition at line 352 of file stk_sync_pipe.h.

◆ m_tail

template<typename T, size_t N>
size_t stk::sync::Pipe< T, N >::m_tail
private

index of the next slot to be read (consumer)

Definition at line 353 of file stk_sync_pipe.h.


The documentation for this class was generated from the following file: