ChibiOS/RT  6.0.3
chpipes.c
Go to the documentation of this file.
1 /*
2  ChibiOS - Copyright (C) 2006..2018 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; either version 3 of the License, or
9  (at your option) any later version.
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 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  */
105 static 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 { /* n == s1 */
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  */
156 static 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 { /* n == s1 */
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  */
207 void 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  */
236 void chPipeReset(pipe_t *pp) {
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();
248  chThdResumeI(&pp->wtr, MSG_RESET);
249  chThdResumeI(&pp->rtr, MSG_RESET);
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  */
278 size_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  */
343 size_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_MAILBOXES == TRUE */
387 
388 /** @} */
bool reset
True if in reset state.
Definition: chpipes.h:60
uint64_t sysinterval_t
Type of time interval.
Definition: chtime.h:119
msg_t chThdSuspendTimeoutS(thread_reference_t *trp, sysinterval_t timeout)
Sends the current thread sleeping and sets a reference variable.
Definition: chthreads.c:764
uint8_t * rdptr
Read pointer.
Definition: chpipes.h:58
static void chSysLock(void)
Enters the kernel lock state.
Definition: chsys.h:353
size_t chPipeReadTimeout(pipe_t *pp, uint8_t *bp, size_t n, sysinterval_t timeout)
Pipe read with timeout.
Definition: chpipes.c:343
static void chSysUnlock(void)
Leaves the kernel lock state.
Definition: chsys.h:365
static size_t chPipeGetFreeCount(const pipe_t *pp)
Returns the number of free byte slots into a pipe.
Definition: chpipes.h:187
uint8_t * top
Pointer to the location after the buffer.
Definition: chpipes.h:55
size_t cnt
Bytes in the pipe.
Definition: chpipes.h:59
Structure representing a pipe object.
Definition: chpipes.h:52
thread_reference_t rtr
Waiting reader.
Definition: chpipes.h:62
static size_t chPipeGetUsedCount(const pipe_t *pp)
Returns the number of used byte slots into a pipe.
Definition: chpipes.h:174
static size_t pipe_write(pipe_t *pp, const uint8_t *bp, size_t n)
Non-blocking pipe write.
Definition: chpipes.c:105
void chSchRescheduleS(void)
Performs a reschedule if a higher priority thread is runnable.
Definition: chschd.c:456
#define chDbgCheck(c)
Function parameters check.
Definition: chdebug.h:101
size_t chPipeWriteTimeout(pipe_t *pp, const uint8_t *bp, size_t n, sysinterval_t timeout)
Pipe write with timeout.
Definition: chpipes.c:278
uint8_t * buffer
Pointer to the pipe buffer.
Definition: chpipes.h:53
void chThdResumeI(thread_reference_t *trp, msg_t msg)
Wakes up a thread waiting on a thread reference object.
Definition: chthreads.c:789
#define MSG_OK
Normal wakeup message.
Definition: chschd.h:39
uint8_t * wrptr
Write pointer.
Definition: chpipes.h:57
void chPipeReset(pipe_t *pp)
Resets a pipe_t object.
Definition: chpipes.c:236
thread_reference_t wtr
Waiting writer.
Definition: chpipes.h:61
void chThdResume(thread_reference_t *trp, msg_t msg)
Wakes up a thread waiting on a thread reference object.
Definition: chthreads.c:834
static size_t pipe_read(pipe_t *pp, uint8_t *bp, size_t n)
Non-blocking pipe read.
Definition: chpipes.c:156
void chPipeObjectInit(pipe_t *pp, uint8_t *buf, size_t n)
Initializes a mailbox_t object.
Definition: chpipes.c:207
ChibiOS/RT main include file.
#define MSG_RESET
Wakeup caused by a reset condition.
Definition: chschd.h:43