source: rtems/cpukit/libfs/src/pipe/fifo.c @ 11eb818

Last change on this file since 11eb818 was 11eb818, checked in by Joel Sherrill <joel@…>, on Mar 13, 2019 at 3:06:45 PM

fifo.c: Eliminate logically dead code (Coverity 1437635)

  • 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      pipe_unlock();
154      return err;
155    }
156  }
157
158  PIPE_LOCK(pipe);
159
160  *pipep = pipe;
161
162out:
163  pipe_unlock();
164  return err;
165}
166
167void pipe_release(
168  pipe_control_t **pipep,
169  rtems_libio_t *iop
170)
171{
172  pipe_control_t *pipe = *pipep;
173  uint32_t mode;
174
175  pipe_lock();
176  PIPE_LOCK(pipe);
177
178  mode = LIBIO_ACCMODE(iop);
179  if (mode & LIBIO_FLAGS_READ)
180     pipe->Readers --;
181  if (mode & LIBIO_FLAGS_WRITE)
182     pipe->Writers --;
183
184  PIPE_UNLOCK(pipe);
185
186  if (pipe->Readers == 0 && pipe->Writers == 0) {
187#if 0
188    /* To delete an anonymous pipe file when all users closed it */
189    if (pipe->Anonymous)
190      delfile = TRUE;
191#endif
192    pipe_free(pipe);
193    *pipep = NULL;
194  }
195  else if (pipe->Readers == 0 && mode != LIBIO_FLAGS_WRITE)
196    /* Notify waiting Writers that all their partners left */
197    PIPE_WAKEUPWRITERS(pipe);
198  else if (pipe->Writers == 0 && mode != LIBIO_FLAGS_READ)
199    PIPE_WAKEUPREADERS(pipe);
200
201  pipe_unlock();
202
203#if 0
204  if (! delfile)
205    return;
206  if (iop->pathinfo.ops->unlink_h == NULL)
207    return;
208
209  /* This is safe for IMFS, but how about other FSes? */
210  rtems_libio_iop_flags_clear( iop, LIBIO_FLAGS_OPEN );
211  if(iop->pathinfo.ops->unlink_h(&iop->pathinfo))
212    return;
213#endif
214
215}
216
217int fifo_open(
218  pipe_control_t **pipep,
219  rtems_libio_t *iop
220)
221{
222  pipe_control_t *pipe;
223  unsigned int prevCounter;
224  int err;
225
226  err = pipe_new(pipep);
227  if (err)
228    return err;
229  pipe = *pipep;
230
231  switch (LIBIO_ACCMODE(iop)) {
232    case LIBIO_FLAGS_READ:
233      pipe->readerCounter ++;
234      if (pipe->Readers ++ == 0)
235        PIPE_WAKEUPWRITERS(pipe);
236
237      if (pipe->Writers == 0) {
238        /* Not an error */
239        if (LIBIO_NODELAY(iop))
240          break;
241
242        prevCounter = pipe->writerCounter;
243        err = -EINTR;
244        /* Wait until a writer opens the pipe */
245        do {
246          PIPE_UNLOCK(pipe);
247          if (! PIPE_READWAIT(pipe))
248            goto out_error;
249          PIPE_LOCK(pipe);
250        } while (prevCounter == pipe->writerCounter);
251      }
252      break;
253
254    case LIBIO_FLAGS_WRITE:
255      pipe->writerCounter ++;
256
257      if (pipe->Writers ++ == 0)
258        PIPE_WAKEUPREADERS(pipe);
259
260      if (pipe->Readers == 0 && LIBIO_NODELAY(iop)) {
261        PIPE_UNLOCK(pipe);
262        err = -ENXIO;
263        goto out_error;
264      }
265
266      if (pipe->Readers == 0) {
267        prevCounter = pipe->readerCounter;
268        err = -EINTR;
269        do {
270          PIPE_UNLOCK(pipe);
271          if (! PIPE_WRITEWAIT(pipe))
272            goto out_error;
273          PIPE_LOCK(pipe);
274        } while (prevCounter == pipe->readerCounter);
275      }
276      break;
277
278    case LIBIO_FLAGS_READ_WRITE:
279      pipe->readerCounter ++;
280      if (pipe->Readers ++ == 0)
281        PIPE_WAKEUPWRITERS(pipe);
282      pipe->writerCounter ++;
283      if (pipe->Writers ++ == 0)
284        PIPE_WAKEUPREADERS(pipe);
285      break;
286  }
287
288  PIPE_UNLOCK(pipe);
289  return 0;
290
291out_error:
292  pipe_release(pipep, iop);
293  return err;
294}
295
296ssize_t pipe_read(
297  pipe_control_t *pipe,
298  void           *buffer,
299  size_t          count,
300  rtems_libio_t  *iop
301)
302{
303  int chunk, chunk1, read = 0, ret = 0;
304
305  PIPE_LOCK(pipe);
306
307  while (PIPE_EMPTY(pipe)) {
308    /* Not an error */
309    if (pipe->Writers == 0)
310      goto out_locked;
311
312    if (LIBIO_NODELAY(iop)) {
313      ret = -EAGAIN;
314      goto out_locked;
315    }
316
317    /* Wait until pipe is no more empty or no writer exists */
318    pipe->waitingReaders ++;
319    PIPE_UNLOCK(pipe);
320    if (! PIPE_READWAIT(pipe))
321      ret = -EINTR;
322    PIPE_LOCK(pipe);
323    pipe->waitingReaders --;
324    if (ret != 0)
325      goto out_locked;
326  }
327
328  /* Read chunk bytes */
329  chunk = MIN(count - read,  pipe->Length);
330  chunk1 = pipe->Size - pipe->Start;
331  if (chunk > chunk1) {
332    memcpy(buffer + read, pipe->Buffer + pipe->Start, chunk1);
333    memcpy(buffer + read + chunk1, pipe->Buffer, chunk - chunk1);
334  }
335  else
336    memcpy(buffer + read, pipe->Buffer + pipe->Start, chunk);
337
338  pipe->Start += chunk;
339  pipe->Start %= pipe->Size;
340  pipe->Length -= chunk;
341  /* For buffering optimization */
342  if (PIPE_EMPTY(pipe))
343    pipe->Start = 0;
344
345  if (pipe->waitingWriters > 0)
346    PIPE_WAKEUPWRITERS(pipe);
347  read += chunk;
348
349out_locked:
350  PIPE_UNLOCK(pipe);
351
352  if (read > 0)
353    return read;
354  return ret;
355}
356
357ssize_t pipe_write(
358  pipe_control_t *pipe,
359  const void     *buffer,
360  size_t          count,
361  rtems_libio_t  *iop
362)
363{
364  int chunk, chunk1, written = 0, ret = 0;
365
366  /* Write nothing */
367  if (count == 0)
368    return 0;
369
370  PIPE_LOCK(pipe);
371
372  if (pipe->Readers == 0) {
373    ret = -EPIPE;
374    goto out_locked;
375  }
376
377  /* Write of PIPE_BUF bytes or less shall not be interleaved */
378  chunk = count <= pipe->Size ? count : 1;
379
380  while (written < count) {
381    while (PIPE_SPACE(pipe) < chunk) {
382      if (LIBIO_NODELAY(iop)) {
383        ret = -EAGAIN;
384        goto out_locked;
385      }
386
387      /* Wait until there is chunk bytes space or no reader exists */
388      pipe->waitingWriters ++;
389      PIPE_UNLOCK(pipe);
390      if (! PIPE_WRITEWAIT(pipe))
391        ret = -EINTR;
392      PIPE_LOCK(pipe);
393      pipe->waitingWriters --;
394      if (ret != 0)
395        goto out_locked;
396
397      if (pipe->Readers == 0) {
398        ret = -EPIPE;
399        goto out_locked;
400      }
401    }
402
403    chunk = MIN(count - written, PIPE_SPACE(pipe));
404    chunk1 = pipe->Size - PIPE_WSTART(pipe);
405    if (chunk > chunk1) {
406      memcpy(pipe->Buffer + PIPE_WSTART(pipe), buffer + written, chunk1);
407      memcpy(pipe->Buffer, buffer + written + chunk1, chunk - chunk1);
408    }
409    else
410      memcpy(pipe->Buffer + PIPE_WSTART(pipe), buffer + written, chunk);
411
412    pipe->Length += chunk;
413    if (pipe->waitingReaders > 0)
414      PIPE_WAKEUPREADERS(pipe);
415    written += chunk;
416    /* Write of more than PIPE_BUF bytes can be interleaved */
417    chunk = 1;
418  }
419
420out_locked:
421  PIPE_UNLOCK(pipe);
422
423#ifdef RTEMS_POSIX_API
424  /* Signal SIGPIPE */
425  if (ret == -EPIPE)
426    kill(getpid(), SIGPIPE);
427#endif
428
429  if (written > 0)
430    return written;
431  return ret;
432}
433
434int pipe_ioctl(
435  pipe_control_t  *pipe,
436  ioctl_command_t  cmd,
437  void            *buffer,
438  rtems_libio_t   *iop
439)
440{
441  if (cmd == FIONREAD) {
442    if (buffer == NULL)
443      return -EFAULT;
444
445    PIPE_LOCK(pipe);
446
447    /* Return length of pipe */
448    *(unsigned int *)buffer = pipe->Length;
449    PIPE_UNLOCK(pipe);
450    return 0;
451  }
452
453  return -EINVAL;
454}
Note: See TracBrowser for help on using the repository browser.