ChibiOS 21.11.5
chpipes.c
Go to the documentation of this file.
1/*
2 ChibiOS - Copyright (C) 2006-2026 Giovanni Di Sirio.
3
4 This file is part of ChibiOS.
5
6 ChibiOS is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation version 3 of the License.
9
10 ChibiOS is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with this program. If not, see <http://www.gnu.org/licenses/>.
17*/
18
19/**
20 * @file oslib/src/chpipes.c
21 * @brief Pipes code.
22 * @details Byte pipes.
23 * <h2>Operation mode</h2>
24 * A pipe is an asynchronous communication mechanism.<br>
25 * Operations defined for mailboxes:
26 * - <b>Write</b>: Writes a buffer of data in the pipe in FIFO order.
27 * - <b>Read</b>: A buffer of data is read from the read and removed.
28 * - <b>Reset</b>: The pipe is emptied and all the stored data
29 * is lost.
30 * .
31 * @pre In order to use the pipes APIs the @p CH_CFG_USE_PIPES
32 * option must be enabled in @p chconf.h.
33 * @note Compatible with RT and NIL.
34 *
35 * @addtogroup oslib_pipes
36 * @{
37 */
38
39#include <string.h>
40
41#include "ch.h"
42
43#if (CH_CFG_USE_PIPES == TRUE) || defined(__DOXYGEN__)
44
45/*===========================================================================*/
46/* Module local definitions. */
47/*===========================================================================*/
48
49/*
50 * Defaults on the best synchronization mechanism available.
51 */
52#if (CH_CFG_USE_MUTEXES == TRUE) || defined(__DOXYGEN__)
53#define PC_INIT(p) chMtxObjectInit(&(p)->cmtx)
54#define PC_LOCK(p) chMtxLock(&(p)->cmtx)
55#define PC_UNLOCK(p) chMtxUnlock(&(p)->cmtx)
56#define PW_INIT(p) chMtxObjectInit(&(p)->wmtx)
57#define PW_LOCK(p) chMtxLock(&(p)->wmtx)
58#define PW_UNLOCK(p) chMtxUnlock(&(p)->wmtx)
59#define PR_INIT(p) chMtxObjectInit(&(p)->rmtx)
60#define PR_LOCK(p) chMtxLock(&(p)->rmtx)
61#define PR_UNLOCK(p) chMtxUnlock(&(p)->rmtx)
62#else
63#define PC_INIT(p) chSemObjectInit(&(p)->csem, (cnt_t)1)
64#define PC_LOCK(p) (void) chSemWait(&(p)->csem)
65#define PC_UNLOCK(p) chSemSignal(&(p)->csem)
66#define PW_INIT(p) chSemObjectInit(&(p)->wsem, (cnt_t)1)
67#define PW_LOCK(p) (void) chSemWait(&(p)->wsem)
68#define PW_UNLOCK(p) chSemSignal(&(p)->wsem)
69#define PR_INIT(p) chSemObjectInit(&(p)->rsem, (cnt_t)1)
70#define PR_LOCK(p) (void) chSemWait(&(p)->rsem)
71#define PR_UNLOCK(p) chSemSignal(&(p)->rsem)
72#endif
73
74/*===========================================================================*/
75/* Module exported variables. */
76/*===========================================================================*/
77
78/*===========================================================================*/
79/* Module local types. */
80/*===========================================================================*/
81
82/*===========================================================================*/
83/* Module local variables. */
84/*===========================================================================*/
85
86/*===========================================================================*/
87/* Module local functions. */
88/*===========================================================================*/
89
90/**
91 * @brief Non-blocking pipe write.
92 * @details The function writes data from a buffer to a pipe. The
93 * operation completes when the specified amount of data has been
94 * transferred or when the pipe buffer has been filled.
95 *
96 * @param[in] pp the pointer to an initialized @p pipe_t object
97 * @param[in] bp pointer to the data buffer
98 * @param[in] n the maximum amount of data to be transferred, the
99 * value 0 is reserved
100 * @return The number of bytes effectively transferred.
101 *
102 * @notapi
103 */
104static size_t pipe_write(pipe_t *pp, const uint8_t *bp, size_t n) {
105 size_t s1, s2;
106
107 PC_LOCK(pp);
108
109 /* Number of bytes that can be written in a single atomic operation.*/
110 if (n > chPipeGetFreeCount(pp)) {
111 n = chPipeGetFreeCount(pp);
112 }
113 pp->cnt += n;
114
115 /* Number of bytes before buffer limit.*/
116 /*lint -save -e9033 [10.8] Checked to be safe.*/
117 s1 = (size_t)(pp->top - pp->wrptr);
118 /*lint -restore*/
119
120 if (n < s1) {
121 memcpy((void *)pp->wrptr, (const void *)bp, n);
122 pp->wrptr += n;
123 }
124 else if (n > s1) {
125 memcpy((void *)pp->wrptr, (const void *)bp, s1);
126 bp += s1;
127 s2 = n - s1;
128 memcpy((void *)pp->buffer, (const void *)bp, s2);
129 pp->wrptr = pp->buffer + s2;
130 }
131 else {
132 memcpy((void *)pp->wrptr, (const void *)bp, n);
133 pp->wrptr = pp->buffer;
134 }
135
136 PC_UNLOCK(pp);
137
138 return n;
139}
140
141/**
142 * @brief Non-blocking pipe read.
143 * @details The function reads data from a pipe into a buffer. The
144 * operation completes when the specified amount of data has been
145 * transferred or when the pipe buffer has been emptied.
146 *
147 * @param[in] pp the pointer to an initialized @p pipe_t object
148 * @param[out] bp pointer to the data buffer
149 * @param[in] n the maximum amount of data to be transferred, the
150 * value 0 is reserved
151 * @return The number of bytes effectively transferred.
152 *
153 * @notapi
154 */
155static size_t pipe_read(pipe_t *pp, uint8_t *bp, size_t n) {
156 size_t s1, s2;
157
158 PC_LOCK(pp);
159
160 /* Number of bytes that can be read in a single atomic operation.*/
161 if (n > chPipeGetUsedCount(pp)) {
162 n = chPipeGetUsedCount(pp);
163 }
164 pp->cnt -= n;
165
166 /* Number of bytes before buffer limit.*/
167 /*lint -save -e9033 [10.8] Checked to be safe.*/
168 s1 = (size_t)(pp->top - pp->rdptr);
169 /*lint -restore*/
170
171 if (n < s1) {
172 memcpy((void *)bp, (void *)pp->rdptr, n);
173 pp->rdptr += n;
174 }
175 else if (n > s1) {
176 memcpy((void *)bp, (void *)pp->rdptr, s1);
177 bp += s1;
178 s2 = n - s1;
179 memcpy((void *)bp, (void *)pp->buffer, s2);
180 pp->rdptr = pp->buffer + s2;
181 }
182 else {
183 memcpy((void *)bp, (void *)pp->rdptr, n);
184 pp->rdptr = pp->buffer;
185 }
186
187 PC_UNLOCK(pp);
188
189 return n;
190}
191
192/*===========================================================================*/
193/* Module exported functions. */
194/*===========================================================================*/
195
196/**
197 * @brief Initializes a @p mailbox_t object.
198 *
199 * @param[out] pp the pointer to the @p pipe_t structure to be
200 * initialized
201 * @param[in] buf pointer to the pipe buffer as an array of @p uint8_t
202 * @param[in] n number of elements in the buffer array
203 *
204 * @init
205 */
206void chPipeObjectInit(pipe_t *pp, uint8_t *buf, size_t n) {
207
208 chDbgCheck((pp != NULL) && (buf != NULL) && (n > (size_t)0));
209
210 pp->buffer = buf;
211 pp->rdptr = buf;
212 pp->wrptr = buf;
213 pp->top = &buf[n];
214 pp->cnt = (size_t)0;
215 pp->reset = false;
216 pp->wtr = NULL;
217 pp->rtr = NULL;
218 PC_INIT(pp);
219 PW_INIT(pp);
220 PR_INIT(pp);
221}
222
223/**
224 * @brief Resets a @p pipe_t object.
225 * @details All the waiting threads are resumed with status @p MSG_RESET and
226 * the queued data is lost.
227 * @post The pipe is in reset state, all operations will fail and
228 * return @p MSG_RESET until the mailbox is enabled again using
229 * @p chPipeResumeX().
230 *
231 * @param[in] pp the pointer to an initialized @p pipe_t object
232 *
233 * @api
234 */
236
237 chDbgCheck(pp != NULL);
238
239 PC_LOCK(pp);
240
241 pp->wrptr = pp->buffer;
242 pp->rdptr = pp->buffer;
243 pp->cnt = (size_t)0;
244 pp->reset = true;
245
246 chSysLock();
250 chSysUnlock();
251
252 PC_UNLOCK(pp);
253}
254
255/**
256 * @brief Pipe write with timeout.
257 * @details The function writes data from a buffer to a pipe. The
258 * operation completes when the specified amount of data has been
259 * transferred or after the specified timeout or if the pipe has
260 * been reset.
261 *
262 * @param[in] pp the pointer to an initialized @p pipe_t object
263 * @param[in] bp pointer to the data buffer
264 * @param[in] n the number of bytes to be written, the value 0 is
265 * reserved
266 * @param[in] timeout the number of ticks before the operation timeouts,
267 * the following special values are allowed:
268 * - @a TIME_IMMEDIATE immediate timeout.
269 * - @a TIME_INFINITE no timeout.
270 * .
271 * @return The number of bytes effectively transferred. A number
272 * lower than @p n means that a timeout occurred or the
273 * pipe went in reset state.
274 *
275 * @api
276 */
277size_t chPipeWriteTimeout(pipe_t *pp, const uint8_t *bp,
278 size_t n, sysinterval_t timeout) {
279 size_t max = n;
280
281 chDbgCheck(n > 0U);
282
283 /* If the pipe is in reset state then returns immediately.*/
284 if (pp->reset) {
285 return (size_t)0;
286 }
287
288 PW_LOCK(pp);
289
290 while (n > 0U) {
291 size_t done;
292
293 done = pipe_write(pp, bp, n);
294 if (done == (size_t)0) {
295 msg_t msg;
296
297 chSysLock();
298 msg = chThdSuspendTimeoutS(&pp->wtr, timeout);
299 chSysUnlock();
300
301 /* Anything except MSG_OK causes the operation to stop.*/
302 if (msg != MSG_OK) {
303 break;
304 }
305 }
306 else {
307 n -= done;
308 bp += done;
309
310 /* Resuming the reader, if present.*/
311 chThdResume(&pp->rtr, MSG_OK);
312 }
313 }
314
315 PW_UNLOCK(pp);
316
317 return max - n;
318}
319
320/**
321 * @brief Pipe read with timeout.
322 * @details The function reads data from a pipe into a buffer. The
323 * operation completes when the specified amount of data has been
324 * transferred or after the specified timeout or if the pipe has
325 * been reset.
326 *
327 * @param[in] pp the pointer to an initialized @p pipe_t object
328 * @param[out] bp pointer to the data buffer
329 * @param[in] n the number of bytes to be read, the value 0 is
330 * reserved
331 * @param[in] timeout the number of ticks before the operation timeouts,
332 * the following special values are allowed:
333 * - @a TIME_IMMEDIATE immediate timeout.
334 * - @a TIME_INFINITE no timeout.
335 * .
336 * @return The number of bytes effectively transferred. A number
337 * lower than @p n means that a timeout occurred or the
338 * pipe went in reset state.
339 *
340 * @api
341 */
342size_t chPipeReadTimeout(pipe_t *pp, uint8_t *bp,
343 size_t n, sysinterval_t timeout) {
344 size_t max = n;
345
346 chDbgCheck(n > 0U);
347
348 /* If the pipe is in reset state then returns immediately.*/
349 if (pp->reset) {
350 return (size_t)0;
351 }
352
353 PR_LOCK(pp);
354
355 while (n > 0U) {
356 size_t done;
357
358 done = pipe_read(pp, bp, n);
359 if (done == (size_t)0) {
360 msg_t msg;
361
362 chSysLock();
363 msg = chThdSuspendTimeoutS(&pp->rtr, timeout);
364 chSysUnlock();
365
366 /* Anything except MSG_OK causes the operation to stop.*/
367 if (msg != MSG_OK) {
368 break;
369 }
370 }
371 else {
372 n -= done;
373 bp += done;
374
375 /* Resuming the writer, if present.*/
376 chThdResume(&pp->wtr, MSG_OK);
377 }
378 }
379
380 PR_UNLOCK(pp);
381
382 return max - n;
383}
384
385#endif /* CH_CFG_USE_PIPES == TRUE */
386
387/** @} */
#define chSysUnlock()
Leaves the kernel lock state.
#define chSysLock()
Enters the kernel lock state.
#define chDbgCheck(c)
Function parameters check.
Definition chdebug.h:117
int32_t msg_t
Definition chearly.h:87
static size_t pipe_read(pipe_t *pp, uint8_t *bp, size_t n)
Non-blocking pipe read.
Definition chpipes.c:155
size_t chPipeReadTimeout(pipe_t *pp, uint8_t *bp, size_t n, sysinterval_t timeout)
Pipe read with timeout.
Definition chpipes.c:342
#define PW_LOCK(p)
Definition chpipes.c:57
static size_t pipe_write(pipe_t *pp, const uint8_t *bp, size_t n)
Non-blocking pipe write.
Definition chpipes.c:104
static size_t chPipeGetUsedCount(const pipe_t *pp)
Returns the number of used byte slots into a pipe.
Definition chpipes.h:173
#define PR_INIT(p)
Definition chpipes.c:59
#define PC_INIT(p)
Definition chpipes.c:53
#define PC_LOCK(p)
Definition chpipes.c:54
#define PW_INIT(p)
Definition chpipes.c:56
static size_t chPipeGetFreeCount(const pipe_t *pp)
Returns the number of free byte slots into a pipe.
Definition chpipes.h:186
size_t chPipeWriteTimeout(pipe_t *pp, const uint8_t *bp, size_t n, sysinterval_t timeout)
Pipe write with timeout.
Definition chpipes.c:277
void chPipeObjectInit(pipe_t *pp, uint8_t *buf, size_t n)
Initializes a mailbox_t object.
Definition chpipes.c:206
void chPipeReset(pipe_t *pp)
Resets a pipe_t object.
Definition chpipes.c:235
#define PR_UNLOCK(p)
Definition chpipes.c:61
#define PW_UNLOCK(p)
Definition chpipes.c:58
#define PR_LOCK(p)
Definition chpipes.c:60
#define PC_UNLOCK(p)
Definition chpipes.c:55
void chSchRescheduleS(void)
Performs a reschedule if a higher priority thread is runnable.
Definition chschd.c:457
#define MSG_OK
Normal wakeup message.
Definition chschd.h:38
#define MSG_RESET
Wakeup caused by a reset condition.
Definition chschd.h:41
void chThdResume(thread_reference_t *trp, msg_t msg)
Wakes up a thread waiting on a thread reference object.
Definition chthreads.c:837
msg_t chThdSuspendTimeoutS(thread_reference_t *trp, sysinterval_t timeout)
Sends the current thread sleeping and sets a reference variable.
Definition chthreads.c:767
void chThdResumeI(thread_reference_t *trp, msg_t msg)
Wakes up a thread waiting on a thread reference object.
Definition chthreads.c:792
uint64_t sysinterval_t
Type of time interval.
Definition chtime.h:118
Structure representing a pipe object.
Definition chpipes.h:51
thread_reference_t rtr
Waiting reader.
Definition chpipes.h:61
uint8_t * wrptr
Write pointer.
Definition chpipes.h:56
size_t cnt
Bytes in the pipe.
Definition chpipes.h:58
uint8_t * top
Pointer to the location after the buffer.
Definition chpipes.h:54
uint8_t * buffer
Pointer to the pipe buffer.
Definition chpipes.h:52
bool reset
True if in reset state.
Definition chpipes.h:59
thread_reference_t wtr
Waiting writer.
Definition chpipes.h:60
uint8_t * rdptr
Read pointer.
Definition chpipes.h:57