source: rtems/cpukit/libfs/src/pipe/fifo.c @ 9b4422a2

4.115
Last change on this file since 9b4422a2 was 9b4422a2, checked in by Joel Sherrill <joel.sherrill@…>, on 05/03/12 at 15:09:24

Remove All CVS Id Strings Possible Using a Script

Script does what is expected and tries to do it as
smartly as possible.

+ remove occurrences of two blank comment lines

next to each other after Id string line removed.

+ remove entire comment blocks which only exited to

contain CVS Ids

+ If the processing left a blank line at the top of

a file, it was removed.

  • Property mode set to 100644
File size: 12.4 KB
Line 
1/*
2 * fifo.c: POSIX FIFO/pipe for RTEMS
3 *
4 * Author: Wei Shen <cquark@gmail.com>
5 *
6 * The license and distribution terms for this file may be
7 * found in the file LICENSE in this distribution or at
8 * http://www.rtems.com/license/LICENSE.
9 */
10
11
12#if HAVE_CONFIG_H
13#include "config.h"
14#endif
15
16#ifdef RTEMS_POSIX_API
17#define __RTEMS_VIOLATE_KERNEL_VISIBILITY__
18#endif
19
20#include <errno.h>
21#include <stdlib.h>
22
23#include <rtems.h>
24#include <rtems/libio_.h>
25
26#include "pipe.h"
27
28
29#define MIN(a, b) ((a) < (b)? (a): (b))
30
31#define LIBIO_ACCMODE(_iop) ((_iop)->flags & LIBIO_FLAGS_READ_WRITE)
32#define LIBIO_NODELAY(_iop) ((_iop)->flags & LIBIO_FLAGS_NO_DELAY)
33
34static rtems_id pipe_semaphore = RTEMS_ID_NONE;
35
36
37#define PIPE_EMPTY(_pipe) (_pipe->Length == 0)
38#define PIPE_FULL(_pipe)  (_pipe->Length == _pipe->Size)
39#define PIPE_SPACE(_pipe) (_pipe->Size - _pipe->Length)
40#define PIPE_WSTART(_pipe) ((_pipe->Start + _pipe->Length) % _pipe->Size)
41
42#define PIPE_LOCK(_pipe)  \
43  ( rtems_semaphore_obtain(_pipe->Semaphore, RTEMS_WAIT, RTEMS_NO_TIMEOUT)  \
44   == RTEMS_SUCCESSFUL )
45
46#define PIPE_UNLOCK(_pipe)  rtems_semaphore_release(_pipe->Semaphore)
47
48#define PIPE_READWAIT(_pipe)  \
49  ( rtems_barrier_wait(_pipe->readBarrier, RTEMS_NO_TIMEOUT)  \
50   == RTEMS_SUCCESSFUL)
51
52#define PIPE_WRITEWAIT(_pipe)  \
53  ( rtems_barrier_wait(_pipe->writeBarrier, RTEMS_NO_TIMEOUT)  \
54   == RTEMS_SUCCESSFUL)
55
56#define PIPE_WAKEUPREADERS(_pipe) \
57  do {uint32_t n; rtems_barrier_release(_pipe->readBarrier, &n); } while(0)
58
59#define PIPE_WAKEUPWRITERS(_pipe) \
60  do {uint32_t n; rtems_barrier_release(_pipe->writeBarrier, &n); } while(0)
61
62
63#ifdef RTEMS_POSIX_API
64#define __RTEMS_VIOLATE_KERNEL_VISIBILITY__
65
66#include <rtems/rtems/barrier.h>
67#include <rtems/score/thread.h>
68
69/* Set barriers to be interruptible by signals. */
70static void pipe_interruptible(pipe_control_t *pipe)
71{
72  Objects_Locations location;
73
74  _Barrier_Get(pipe->readBarrier, &location)->Barrier.Wait_queue.state
75    |= STATES_INTERRUPTIBLE_BY_SIGNAL;
76  _Thread_Enable_dispatch();
77  _Barrier_Get(pipe->writeBarrier, &location)->Barrier.Wait_queue.state
78    |= STATES_INTERRUPTIBLE_BY_SIGNAL;
79  _Thread_Enable_dispatch();
80}
81#endif
82
83/*
84 * Alloc pipe control structure, buffer, and resources.
85 * Called with pipe_semaphore held.
86 */
87static int pipe_alloc(
88  pipe_control_t **pipep
89)
90{
91  static char c = 'a';
92  pipe_control_t *pipe;
93  int err = -ENOMEM;
94
95  pipe = malloc(sizeof(pipe_control_t));
96  if (pipe == NULL)
97    return err;
98  memset(pipe, 0, sizeof(pipe_control_t));
99
100  pipe->Size = PIPE_BUF;
101  pipe->Buffer = malloc(pipe->Size);
102  if (! pipe->Buffer)
103    goto err_buf;
104
105  err = -ENOMEM;
106
107  if (rtems_barrier_create(
108        rtems_build_name ('P', 'I', 'r', c),
109        RTEMS_BARRIER_MANUAL_RELEASE, 0,
110        &pipe->readBarrier) != RTEMS_SUCCESSFUL)
111    goto err_rbar;
112  if (rtems_barrier_create(
113        rtems_build_name ('P', 'I', 'w', c),
114        RTEMS_BARRIER_MANUAL_RELEASE, 0,
115        &pipe->writeBarrier) != RTEMS_SUCCESSFUL)
116    goto err_wbar;
117  if (rtems_semaphore_create(
118        rtems_build_name ('P', 'I', 's', c), 1,
119        RTEMS_BINARY_SEMAPHORE | RTEMS_FIFO,
120        RTEMS_NO_PRIORITY, &pipe->Semaphore) != RTEMS_SUCCESSFUL)
121    goto err_sem;
122
123#ifdef RTEMS_POSIX_API
124  pipe_interruptible(pipe);
125#endif
126
127  *pipep = pipe;
128  if (c ++ == 'z')
129    c = 'a';
130  return 0;
131
132err_sem:
133  rtems_barrier_delete(pipe->writeBarrier);
134err_wbar:
135  rtems_barrier_delete(pipe->readBarrier);
136err_rbar:
137  free(pipe->Buffer);
138err_buf:
139  free(pipe);
140  return err;
141}
142
143/* Called with pipe_semaphore held. */
144static inline void pipe_free(
145  pipe_control_t *pipe
146)
147{
148  rtems_barrier_delete(pipe->readBarrier);
149  rtems_barrier_delete(pipe->writeBarrier);
150  rtems_semaphore_delete(pipe->Semaphore);
151  free(pipe->Buffer);
152  free(pipe);
153}
154
155static int pipe_lock(void)
156{
157  rtems_status_code sc = RTEMS_SUCCESSFUL;
158
159  if (pipe_semaphore == RTEMS_ID_NONE) {
160    rtems_libio_lock();
161
162    if (pipe_semaphore == RTEMS_ID_NONE) {
163      sc = rtems_semaphore_create(
164        rtems_build_name('P', 'I', 'P', 'E'),
165        1,
166        RTEMS_BINARY_SEMAPHORE | RTEMS_INHERIT_PRIORITY | RTEMS_PRIORITY,
167        RTEMS_NO_PRIORITY,
168        &pipe_semaphore
169      );
170    }
171
172    rtems_libio_unlock();
173  }
174
175  if (sc == RTEMS_SUCCESSFUL) {
176    sc = rtems_semaphore_obtain(pipe_semaphore, RTEMS_WAIT, RTEMS_NO_TIMEOUT);
177  }
178
179  if (sc == RTEMS_SUCCESSFUL) {
180    return 0;
181  } else {
182    return -ENOMEM;
183  }
184}
185
186static void pipe_unlock(void)
187{
188#ifdef RTEMS_DEBUG
189  rtems_status_code sc = RTEMS_SUCCESSFUL;
190
191  sc =
192#endif
193   rtems_semaphore_release(pipe_semaphore);
194  #ifdef RTEMS_DEBUG
195    if (sc != RTEMS_SUCCESSFUL) {
196      rtems_fatal_error_occurred(0xdeadbeef);
197    }
198  #endif
199}
200
201/*
202 * If called with *pipep = NULL, pipe_new will call pipe_alloc to allocate a
203 * pipe control structure and set *pipep to its address.
204 * pipe is locked, when pipe_new returns with no error.
205 */
206static int pipe_new(
207  pipe_control_t **pipep
208)
209{
210  pipe_control_t *pipe;
211  int err = 0;
212
213  err = pipe_lock();
214  if (err)
215    return err;
216
217  pipe = *pipep;
218  if (pipe == NULL) {
219    err = pipe_alloc(&pipe);
220    if (err)
221      goto out;
222  }
223
224  if (! PIPE_LOCK(pipe))
225    err = -EINTR;
226
227  if (*pipep == NULL) {
228    if (err)
229      pipe_free(pipe);
230    else
231      *pipep = pipe;
232  }
233
234out:
235  pipe_unlock();
236  return err;
237}
238
239/*
240 * Interface to file system close.
241 *
242 * *pipep points to pipe control structure. When the last user releases pipe,
243 * it will be set to NULL.
244 */
245void pipe_release(
246  pipe_control_t **pipep,
247  rtems_libio_t *iop
248)
249{
250  pipe_control_t *pipe = *pipep;
251  uint32_t mode;
252
253  #if defined(RTEMS_DEBUG)
254    /* WARN pipe not freed and pipep not set to NULL! */
255    if (pipe_lock())
256      rtems_fatal_error_occurred(0xdeadbeef);
257
258    /* WARN pipe not released! */
259    if (!PIPE_LOCK(pipe))
260      rtems_fatal_error_occurred(0xdeadbeef);
261  #endif
262
263  mode = LIBIO_ACCMODE(iop);
264  if (mode & LIBIO_FLAGS_READ)
265     pipe->Readers --;
266  if (mode & LIBIO_FLAGS_WRITE)
267     pipe->Writers --;
268
269  PIPE_UNLOCK(pipe);
270
271  if (pipe->Readers == 0 && pipe->Writers == 0) {
272#if 0
273    /* To delete an anonymous pipe file when all users closed it */
274    if (pipe->Anonymous)
275      delfile = TRUE;
276#endif
277    pipe_free(pipe);
278    *pipep = NULL;
279  }
280  else if (pipe->Readers == 0 && mode != LIBIO_FLAGS_WRITE)
281    /* Notify waiting Writers that all their partners left */
282    PIPE_WAKEUPWRITERS(pipe);
283  else if (pipe->Writers == 0 && mode != LIBIO_FLAGS_READ)
284    PIPE_WAKEUPREADERS(pipe);
285
286  pipe_unlock();
287
288#if 0
289  if (! delfile)
290    return;
291  if (iop->pathinfo.ops->unlink_h == NULL)
292    return;
293
294  /* This is safe for IMFS, but how about other FSes? */
295  iop->flags &= ~LIBIO_FLAGS_OPEN;
296  if(iop->pathinfo.ops->unlink_h(&iop->pathinfo))
297    return;
298#endif
299
300}
301
302/*
303 * Interface to file system open.
304 *
305 * *pipep points to pipe control structure. If called with *pipep = NULL,
306 * fifo_open will try allocating and initializing a control structure. If the
307 * call succeeds, *pipep will be set to address of new control structure.
308 */
309int fifo_open(
310  pipe_control_t **pipep,
311  rtems_libio_t *iop
312)
313{
314  pipe_control_t *pipe;
315  unsigned int prevCounter;
316  int err;
317
318  err = pipe_new(pipep);
319  if (err)
320    return err;
321  pipe = *pipep;
322
323  switch (LIBIO_ACCMODE(iop)) {
324    case LIBIO_FLAGS_READ:
325      pipe->readerCounter ++;
326      if (pipe->Readers ++ == 0)
327        PIPE_WAKEUPWRITERS(pipe);
328
329      if (pipe->Writers == 0) {
330        /* Not an error */
331        if (LIBIO_NODELAY(iop))
332          break;
333
334        prevCounter = pipe->writerCounter;
335        err = -EINTR;
336        /* Wait until a writer opens the pipe */
337        do {
338          PIPE_UNLOCK(pipe);
339          if (! PIPE_READWAIT(pipe))
340            goto out_error;
341          if (! PIPE_LOCK(pipe))
342            goto out_error;
343        } while (prevCounter == pipe->writerCounter);
344      }
345      break;
346
347    case LIBIO_FLAGS_WRITE:
348      pipe->writerCounter ++;
349
350      if (pipe->Writers ++ == 0)
351        PIPE_WAKEUPREADERS(pipe);
352
353      if (pipe->Readers == 0 && LIBIO_NODELAY(iop)) {
354        PIPE_UNLOCK(pipe);
355        err = -ENXIO;
356        goto out_error;
357      }
358
359      if (pipe->Readers == 0) {
360        prevCounter = pipe->readerCounter;
361        err = -EINTR;
362        do {
363          PIPE_UNLOCK(pipe);
364          if (! PIPE_WRITEWAIT(pipe))
365            goto out_error;
366          if (! PIPE_LOCK(pipe))
367            goto out_error;
368        } while (prevCounter == pipe->readerCounter);
369      }
370      break;
371
372    case LIBIO_FLAGS_READ_WRITE:
373      pipe->readerCounter ++;
374      if (pipe->Readers ++ == 0)
375        PIPE_WAKEUPWRITERS(pipe);
376      pipe->writerCounter ++;
377      if (pipe->Writers ++ == 0)
378        PIPE_WAKEUPREADERS(pipe);
379      break;
380  }
381
382  PIPE_UNLOCK(pipe);
383  return 0;
384
385out_error:
386  pipe_release(pipep, iop);
387  return err;
388}
389
390/*
391 * Interface to file system read.
392 */
393ssize_t pipe_read(
394  pipe_control_t *pipe,
395  void           *buffer,
396  size_t          count,
397  rtems_libio_t  *iop
398)
399{
400  int chunk, chunk1, read = 0, ret = 0;
401
402  if (! PIPE_LOCK(pipe))
403    return -EINTR;
404
405  while (read < count) {
406    while (PIPE_EMPTY(pipe)) {
407      /* Not an error */
408      if (pipe->Writers == 0)
409        goto out_locked;
410
411      if (LIBIO_NODELAY(iop)) {
412        ret = -EAGAIN;
413        goto out_locked;
414      }
415
416      /* Wait until pipe is no more empty or no writer exists */
417      pipe->waitingReaders ++;
418      PIPE_UNLOCK(pipe);
419      if (! PIPE_READWAIT(pipe))
420        ret = -EINTR;
421      if (! PIPE_LOCK(pipe)) {
422        /* WARN waitingReaders not restored! */
423        ret = -EINTR;
424        goto out_nolock;
425      }
426      pipe->waitingReaders --;
427      if (ret != 0)
428        goto out_locked;
429    }
430
431    /* Read chunk bytes */
432    chunk = MIN(count - read,  pipe->Length);
433    chunk1 = pipe->Size - pipe->Start;
434    if (chunk > chunk1) {
435      memcpy(buffer + read, pipe->Buffer + pipe->Start, chunk1);
436      memcpy(buffer + read + chunk1, pipe->Buffer, chunk - chunk1);
437    }
438    else
439      memcpy(buffer + read, pipe->Buffer + pipe->Start, chunk);
440
441    pipe->Start += chunk;
442    pipe->Start %= pipe->Size;
443    pipe->Length -= chunk;
444    /* For buffering optimization */
445    if (PIPE_EMPTY(pipe))
446      pipe->Start = 0;
447
448    if (pipe->waitingWriters > 0)
449      PIPE_WAKEUPWRITERS(pipe);
450    read += chunk;
451  }
452
453out_locked:
454  PIPE_UNLOCK(pipe);
455
456out_nolock:
457  if (read > 0)
458    return read;
459  return ret;
460}
461
462/*
463 * Interface to file system write.
464 */
465ssize_t pipe_write(
466  pipe_control_t *pipe,
467  const void     *buffer,
468  size_t          count,
469  rtems_libio_t  *iop
470)
471{
472  int chunk, chunk1, written = 0, ret = 0;
473
474  /* Write nothing */
475  if (count == 0)
476    return 0;
477
478  if (! PIPE_LOCK(pipe))
479    return -EINTR;
480
481  if (pipe->Readers == 0) {
482    ret = -EPIPE;
483    goto out_locked;
484  }
485
486  /* Write of PIPE_BUF bytes or less shall not be interleaved */
487  chunk = count <= pipe->Size ? count : 1;
488
489  while (written < count) {
490    while (PIPE_SPACE(pipe) < chunk) {
491      if (LIBIO_NODELAY(iop)) {
492        ret = -EAGAIN;
493        goto out_locked;
494      }
495
496      /* Wait until there is chunk bytes space or no reader exists */
497      pipe->waitingWriters ++;
498      PIPE_UNLOCK(pipe);
499      if (! PIPE_WRITEWAIT(pipe))
500        ret = -EINTR;
501      if (! PIPE_LOCK(pipe)) {
502        /* WARN waitingWriters not restored! */
503        ret = -EINTR;
504        goto out_nolock;
505      }
506      pipe->waitingWriters --;
507      if (ret != 0)
508        goto out_locked;
509
510      if (pipe->Readers == 0) {
511        ret = -EPIPE;
512        goto out_locked;
513      }
514    }
515
516    chunk = MIN(count - written, PIPE_SPACE(pipe));
517    chunk1 = pipe->Size - PIPE_WSTART(pipe);
518    if (chunk > chunk1) {
519      memcpy(pipe->Buffer + PIPE_WSTART(pipe), buffer + written, chunk1);
520      memcpy(pipe->Buffer, buffer + written + chunk1, chunk - chunk1);
521    }
522    else
523      memcpy(pipe->Buffer + PIPE_WSTART(pipe), buffer + written, chunk);
524
525    pipe->Length += chunk;
526    if (pipe->waitingReaders > 0)
527      PIPE_WAKEUPREADERS(pipe);
528    written += chunk;
529    /* Write of more than PIPE_BUF bytes can be interleaved */
530    chunk = 1;
531  }
532
533out_locked:
534  PIPE_UNLOCK(pipe);
535
536out_nolock:
537#ifdef RTEMS_POSIX_API
538  /* Signal SIGPIPE */
539  if (ret == -EPIPE)
540    kill(getpid(), SIGPIPE);
541#endif
542
543  if (written > 0)
544    return written;
545  return ret;
546}
547
548/*
549 * Interface to file system ioctl.
550 */
551int pipe_ioctl(
552  pipe_control_t *pipe,
553  uint32_t        cmd,
554  void           *buffer,
555  rtems_libio_t  *iop
556)
557{
558  if (cmd == FIONREAD) {
559    if (buffer == NULL)
560      return -EFAULT;
561
562    if (! PIPE_LOCK(pipe))
563      return -EINTR;
564
565    /* Return length of pipe */
566    *(unsigned int *)buffer = pipe->Length;
567    PIPE_UNLOCK(pipe);
568    return 0;
569  }
570
571  return -EINVAL;
572}
Note: See TracBrowser for help on using the repository browser.