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