source: rtems/cpukit/libfs/src/pipe/fifo.c @ 90232bc

5
Last change on this file since 90232bc was 9dfb9a98, checked in by Joel Sherrill <joel@…>, on 11/22/18 at 00:46:35

pipe/fifo.c: Remove dead code (CID 1437649)

Closes #3581.

  • Property mode set to 100644
File size: 9.5 KB
Line 
1/**
2 * @file
3 *
4 * @brief FIFO/Pipe Support
5 * @ingroup FIFO_PIPE
6 */
7
8/*
9 * Author: Wei Shen <cquark@gmail.com>
10 *
11 * The license and distribution terms for this file may be
12 * found in the file LICENSE in this distribution or at
13 * http://www.rtems.org/license/LICENSE.
14 */
15
16
17#if HAVE_CONFIG_H
18#include "config.h"
19#endif
20
21#include <sys/param.h>
22#include <sys/filio.h>
23#include <errno.h>
24#include <stdlib.h>
25#include <string.h>
26
27#include <rtems.h>
28#include <rtems/libio_.h>
29#include <rtems/pipe.h>
30#include <rtems/rtems/barrierimpl.h>
31#include <rtems/score/statesimpl.h>
32
33#define LIBIO_ACCMODE(_iop) (rtems_libio_iop_flags(_iop) & LIBIO_FLAGS_READ_WRITE)
34#define LIBIO_NODELAY(_iop) rtems_libio_iop_is_no_delay(_iop)
35
36static rtems_mutex pipe_mutex = RTEMS_MUTEX_INITIALIZER("Pipes");
37
38
39#define PIPE_EMPTY(_pipe) (_pipe->Length == 0)
40#define PIPE_FULL(_pipe)  (_pipe->Length == _pipe->Size)
41#define PIPE_SPACE(_pipe) (_pipe->Size - _pipe->Length)
42#define PIPE_WSTART(_pipe) ((_pipe->Start + _pipe->Length) % _pipe->Size)
43
44#define PIPE_LOCK(_pipe) rtems_mutex_lock(&(_pipe)->Mutex)
45
46#define PIPE_UNLOCK(_pipe) rtems_mutex_unlock(&(_pipe)->Mutex)
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 * Alloc pipe control structure, buffer, and resources.
64 * Called with pipe_semaphore held.
65 */
66static int pipe_alloc(
67  pipe_control_t **pipep
68)
69{
70  static char c = 'a';
71  pipe_control_t *pipe;
72  int err = -ENOMEM;
73
74  pipe = malloc(sizeof(pipe_control_t));
75  if (pipe == NULL)
76    return err;
77  memset(pipe, 0, sizeof(pipe_control_t));
78
79  pipe->Size = PIPE_BUF;
80  pipe->Buffer = malloc(pipe->Size);
81  if (! pipe->Buffer)
82    goto err_buf;
83
84  err = -ENOMEM;
85
86  if (rtems_barrier_create(
87        rtems_build_name ('P', 'I', 'r', c),
88        RTEMS_BARRIER_MANUAL_RELEASE, 0,
89        &pipe->readBarrier) != RTEMS_SUCCESSFUL)
90    goto err_rbar;
91  if (rtems_barrier_create(
92        rtems_build_name ('P', 'I', 'w', c),
93        RTEMS_BARRIER_MANUAL_RELEASE, 0,
94        &pipe->writeBarrier) != RTEMS_SUCCESSFUL)
95    goto err_wbar;
96  rtems_mutex_init(&pipe->Mutex, "Pipe");
97
98  *pipep = pipe;
99  if (c ++ == 'z')
100    c = 'a';
101  return 0;
102
103err_wbar:
104  rtems_barrier_delete(pipe->readBarrier);
105err_rbar:
106  free(pipe->Buffer);
107err_buf:
108  free(pipe);
109  return err;
110}
111
112/* Called with pipe_semaphore held. */
113static inline void pipe_free(
114  pipe_control_t *pipe
115)
116{
117  rtems_barrier_delete(pipe->readBarrier);
118  rtems_barrier_delete(pipe->writeBarrier);
119  rtems_mutex_destroy(&pipe->Mutex);
120  free(pipe->Buffer);
121  free(pipe);
122}
123
124static void pipe_lock(void)
125{
126  rtems_mutex_lock(&pipe_mutex);
127}
128
129static void pipe_unlock(void)
130{
131  rtems_mutex_unlock(&pipe_mutex);
132}
133
134/*
135 * If called with *pipep = NULL, pipe_new will call pipe_alloc to allocate a
136 * pipe control structure and set *pipep to its address.
137 * pipe is locked, when pipe_new returns with no error.
138 */
139static int pipe_new(
140  pipe_control_t **pipep
141)
142{
143  pipe_control_t *pipe;
144  int err = 0;
145
146  _Assert( pipep );
147  pipe_lock();
148
149  pipe = *pipep;
150  if (pipe == NULL) {
151    err = pipe_alloc(&pipe);
152    if (err)
153      goto out;
154  }
155
156  PIPE_LOCK(pipe);
157
158  if (*pipep == NULL) {
159    if (err)
160      pipe_free(pipe);
161    else
162      *pipep = pipe;
163  }
164
165out:
166  pipe_unlock();
167  return err;
168}
169
170void pipe_release(
171  pipe_control_t **pipep,
172  rtems_libio_t *iop
173)
174{
175  pipe_control_t *pipe = *pipep;
176  uint32_t mode;
177
178  pipe_lock();
179  PIPE_LOCK(pipe);
180
181  mode = LIBIO_ACCMODE(iop);
182  if (mode & LIBIO_FLAGS_READ)
183     pipe->Readers --;
184  if (mode & LIBIO_FLAGS_WRITE)
185     pipe->Writers --;
186
187  PIPE_UNLOCK(pipe);
188
189  if (pipe->Readers == 0 && pipe->Writers == 0) {
190#if 0
191    /* To delete an anonymous pipe file when all users closed it */
192    if (pipe->Anonymous)
193      delfile = TRUE;
194#endif
195    pipe_free(pipe);
196    *pipep = NULL;
197  }
198  else if (pipe->Readers == 0 && mode != LIBIO_FLAGS_WRITE)
199    /* Notify waiting Writers that all their partners left */
200    PIPE_WAKEUPWRITERS(pipe);
201  else if (pipe->Writers == 0 && mode != LIBIO_FLAGS_READ)
202    PIPE_WAKEUPREADERS(pipe);
203
204  pipe_unlock();
205
206#if 0
207  if (! delfile)
208    return;
209  if (iop->pathinfo.ops->unlink_h == NULL)
210    return;
211
212  /* This is safe for IMFS, but how about other FSes? */
213  rtems_libio_iop_flags_clear( iop, LIBIO_FLAGS_OPEN );
214  if(iop->pathinfo.ops->unlink_h(&iop->pathinfo))
215    return;
216#endif
217
218}
219
220int fifo_open(
221  pipe_control_t **pipep,
222  rtems_libio_t *iop
223)
224{
225  pipe_control_t *pipe;
226  unsigned int prevCounter;
227  int err;
228
229  err = pipe_new(pipep);
230  if (err)
231    return err;
232  pipe = *pipep;
233
234  switch (LIBIO_ACCMODE(iop)) {
235    case LIBIO_FLAGS_READ:
236      pipe->readerCounter ++;
237      if (pipe->Readers ++ == 0)
238        PIPE_WAKEUPWRITERS(pipe);
239
240      if (pipe->Writers == 0) {
241        /* Not an error */
242        if (LIBIO_NODELAY(iop))
243          break;
244
245        prevCounter = pipe->writerCounter;
246        err = -EINTR;
247        /* Wait until a writer opens the pipe */
248        do {
249          PIPE_UNLOCK(pipe);
250          if (! PIPE_READWAIT(pipe))
251            goto out_error;
252          PIPE_LOCK(pipe);
253        } while (prevCounter == pipe->writerCounter);
254      }
255      break;
256
257    case LIBIO_FLAGS_WRITE:
258      pipe->writerCounter ++;
259
260      if (pipe->Writers ++ == 0)
261        PIPE_WAKEUPREADERS(pipe);
262
263      if (pipe->Readers == 0 && LIBIO_NODELAY(iop)) {
264        PIPE_UNLOCK(pipe);
265        err = -ENXIO;
266        goto out_error;
267      }
268
269      if (pipe->Readers == 0) {
270        prevCounter = pipe->readerCounter;
271        err = -EINTR;
272        do {
273          PIPE_UNLOCK(pipe);
274          if (! PIPE_WRITEWAIT(pipe))
275            goto out_error;
276          PIPE_LOCK(pipe);
277        } while (prevCounter == pipe->readerCounter);
278      }
279      break;
280
281    case LIBIO_FLAGS_READ_WRITE:
282      pipe->readerCounter ++;
283      if (pipe->Readers ++ == 0)
284        PIPE_WAKEUPWRITERS(pipe);
285      pipe->writerCounter ++;
286      if (pipe->Writers ++ == 0)
287        PIPE_WAKEUPREADERS(pipe);
288      break;
289  }
290
291  PIPE_UNLOCK(pipe);
292  return 0;
293
294out_error:
295  pipe_release(pipep, iop);
296  return err;
297}
298
299ssize_t pipe_read(
300  pipe_control_t *pipe,
301  void           *buffer,
302  size_t          count,
303  rtems_libio_t  *iop
304)
305{
306  int chunk, chunk1, read = 0, ret = 0;
307
308  PIPE_LOCK(pipe);
309
310  while (PIPE_EMPTY(pipe)) {
311    /* Not an error */
312    if (pipe->Writers == 0)
313      goto out_locked;
314
315    if (LIBIO_NODELAY(iop)) {
316      ret = -EAGAIN;
317      goto out_locked;
318    }
319
320    /* Wait until pipe is no more empty or no writer exists */
321    pipe->waitingReaders ++;
322    PIPE_UNLOCK(pipe);
323    if (! PIPE_READWAIT(pipe))
324      ret = -EINTR;
325    PIPE_LOCK(pipe);
326    pipe->waitingReaders --;
327    if (ret != 0)
328      goto out_locked;
329  }
330
331  /* Read chunk bytes */
332  chunk = MIN(count - read,  pipe->Length);
333  chunk1 = pipe->Size - pipe->Start;
334  if (chunk > chunk1) {
335    memcpy(buffer + read, pipe->Buffer + pipe->Start, chunk1);
336    memcpy(buffer + read + chunk1, pipe->Buffer, chunk - chunk1);
337  }
338  else
339    memcpy(buffer + read, pipe->Buffer + pipe->Start, chunk);
340
341  pipe->Start += chunk;
342  pipe->Start %= pipe->Size;
343  pipe->Length -= chunk;
344  /* For buffering optimization */
345  if (PIPE_EMPTY(pipe))
346    pipe->Start = 0;
347
348  if (pipe->waitingWriters > 0)
349    PIPE_WAKEUPWRITERS(pipe);
350  read += chunk;
351
352out_locked:
353  PIPE_UNLOCK(pipe);
354
355  if (read > 0)
356    return read;
357  return ret;
358}
359
360ssize_t pipe_write(
361  pipe_control_t *pipe,
362  const void     *buffer,
363  size_t          count,
364  rtems_libio_t  *iop
365)
366{
367  int chunk, chunk1, written = 0, ret = 0;
368
369  /* Write nothing */
370  if (count == 0)
371    return 0;
372
373  PIPE_LOCK(pipe);
374
375  if (pipe->Readers == 0) {
376    ret = -EPIPE;
377    goto out_locked;
378  }
379
380  /* Write of PIPE_BUF bytes or less shall not be interleaved */
381  chunk = count <= pipe->Size ? count : 1;
382
383  while (written < count) {
384    while (PIPE_SPACE(pipe) < chunk) {
385      if (LIBIO_NODELAY(iop)) {
386        ret = -EAGAIN;
387        goto out_locked;
388      }
389
390      /* Wait until there is chunk bytes space or no reader exists */
391      pipe->waitingWriters ++;
392      PIPE_UNLOCK(pipe);
393      if (! PIPE_WRITEWAIT(pipe))
394        ret = -EINTR;
395      PIPE_LOCK(pipe);
396      pipe->waitingWriters --;
397      if (ret != 0)
398        goto out_locked;
399
400      if (pipe->Readers == 0) {
401        ret = -EPIPE;
402        goto out_locked;
403      }
404    }
405
406    chunk = MIN(count - written, PIPE_SPACE(pipe));
407    chunk1 = pipe->Size - PIPE_WSTART(pipe);
408    if (chunk > chunk1) {
409      memcpy(pipe->Buffer + PIPE_WSTART(pipe), buffer + written, chunk1);
410      memcpy(pipe->Buffer, buffer + written + chunk1, chunk - chunk1);
411    }
412    else
413      memcpy(pipe->Buffer + PIPE_WSTART(pipe), buffer + written, chunk);
414
415    pipe->Length += chunk;
416    if (pipe->waitingReaders > 0)
417      PIPE_WAKEUPREADERS(pipe);
418    written += chunk;
419    /* Write of more than PIPE_BUF bytes can be interleaved */
420    chunk = 1;
421  }
422
423out_locked:
424  PIPE_UNLOCK(pipe);
425
426#ifdef RTEMS_POSIX_API
427  /* Signal SIGPIPE */
428  if (ret == -EPIPE)
429    kill(getpid(), SIGPIPE);
430#endif
431
432  if (written > 0)
433    return written;
434  return ret;
435}
436
437int pipe_ioctl(
438  pipe_control_t  *pipe,
439  ioctl_command_t  cmd,
440  void            *buffer,
441  rtems_libio_t   *iop
442)
443{
444  if (cmd == FIONREAD) {
445    if (buffer == NULL)
446      return -EFAULT;
447
448    PIPE_LOCK(pipe);
449
450    /* Return length of pipe */
451    *(unsigned int *)buffer = pipe->Length;
452    PIPE_UNLOCK(pipe);
453    return 0;
454  }
455
456  return -EINVAL;
457}
Note: See TracBrowser for help on using the repository browser.