source: rtems/cpukit/libmisc/redirector/stdio-redirect.c @ a1626726

5
Last change on this file since a1626726 was a1626726, checked in by Sebastian Huber <sebastian.huber@…>, on 12/13/17 at 07:28:46

redirector: Include <rtems/stdio-redirect.h>

Prepare for header file move to common include directory.

Update #3254.

  • Property mode set to 100644
File size: 7.6 KB
Line 
1/*
2 * Copyright (C) 2014 Chris Johns (chrisj@rtems.org)
3 *
4 * The license and distribution terms for this file may be
5 * found in the file LICENSE in this distribution.
6 *
7 * This software with is provided ``as is'' and with NO WARRANTY.
8 */
9
10/*
11 * RTEMS std redirector.
12 */
13
14#include <errno.h>
15#include <stdio.h>
16#include <stdlib.h>
17#include <string.h>
18#include <strings.h>
19#include <sys/types.h>
20#include <unistd.h>
21
22#include <rtems.h>
23#include <rtems/error.h>
24#include <rtems/stdio-redirect.h>
25
26#define RTEMS_STDIO_REDIRECT_LOCK_ATTRIBS                             \
27  (RTEMS_PRIORITY | RTEMS_BINARY_SEMAPHORE |                          \
28   RTEMS_INHERIT_PRIORITY | RTEMS_NO_PRIORITY_CEILING | RTEMS_LOCAL)
29
30#define RTEMS_STDIO_REDIRECT_RUNNING  (1 << 0)
31#define RTEMS_STDIO_REDIRECT_FINISHED (1 << 1)
32
33static bool
34rtems_stdio_redirect_lock(rtems_stdio_redirect* sr)
35{
36  rtems_status_code sc = rtems_semaphore_obtain (sr->lock,
37                                                 RTEMS_WAIT,
38                                                 RTEMS_NO_TIMEOUT);
39  if (sc != RTEMS_SUCCESSFUL)
40  {
41    fprintf(stderr, "error: stdio-redirect: lock failed: %s\n", rtems_status_text(sc));
42    return false;
43  }
44  return true;
45}
46
47static bool
48rtems_stdio_redirect_unlock(rtems_stdio_redirect* sr)
49{
50  rtems_status_code sc = rtems_semaphore_release (sr->lock);
51  if (sc != RTEMS_SUCCESSFUL)
52  {
53    fprintf(stderr, "error: stdio-redirect: unlock failed: %s\n", rtems_status_text(sc));
54    return false;
55  }
56  return true;
57}
58
59static bool
60rtems_stdio_redirect_write (rtems_stdio_redirect* sr, const char* buf, ssize_t len)
61{
62  if (!rtems_stdio_redirect_lock(sr))
63    return false;
64
65  if (sr->buffer)
66  {
67    if (len >= sr->buffer_size)
68    {
69      ssize_t offset = len - sr->buffer_size;
70      memcpy (sr->buffer, buf + offset, sr->buffer_size);
71      sr->in  = 0;
72      sr->full = true;
73    }
74    else
75    {
76      if ((sr->in + len) > sr->buffer_size)
77      {
78        ssize_t bytes = sr->buffer_size - sr->in;
79        memcpy (sr->buffer + sr->in, buf, bytes);
80        buf += bytes;
81        len -= bytes;
82        sr->in = 0;
83        sr->full = true;
84      }
85      else
86      {
87        memcpy (sr->buffer + sr->in, buf, len);
88        sr->in += len;
89      }
90    }
91  }
92
93  if (sr->handler)
94    sr->handler(buf, len);
95
96  return rtems_stdio_redirect_unlock(sr);
97}
98
99static rtems_task
100rtems_stdio_redirect_reader(rtems_task_argument arg)
101{
102  rtems_stdio_redirect* sr = (rtems_stdio_redirect*) arg;
103
104  while (sr->state & RTEMS_STDIO_REDIRECT_RUNNING)
105  {
106    ssize_t r = read (sr->pipe[0], sr->input, sr->input_size);
107
108    if (r <= 0)
109      break;
110
111    if (sr->echo)
112      write (sr->fd_dup, sr->input, r);
113
114    if (!rtems_stdio_redirect_write (sr, sr->input, r))
115      break;
116  }
117
118  sr->state |= RTEMS_STDIO_REDIRECT_FINISHED;
119
120  rtems_task_delete(RTEMS_SELF);
121}
122
123rtems_stdio_redirect*
124rtems_stdio_redirect_open(int                          fd,
125                          rtems_task_priority          priority,
126                          size_t                       stack_size,
127                          ssize_t                      input_size,
128                          ssize_t                      buffer_size,
129                          bool                         echo,
130                          rtems_stdio_redirect_handler handler)
131{
132  rtems_stdio_redirect* sr;
133  rtems_name            name;
134  rtems_status_code     sc;
135
136  sr = malloc(sizeof(*sr));
137  if (!sr)
138  {
139    fprintf(stderr, "error: stdio-redirect: no memory\n");
140    return NULL;
141  }
142
143  memset(sr, 0, sizeof(*sr));
144
145  sr->input_size = input_size;
146  sr->input = malloc(input_size);
147  if (!sr->input)
148  {
149    fprintf(stderr, "error: stdio-redirect: no memory for input\n");
150    free(sr);
151    return NULL;
152  }
153
154  if (buffer_size)
155  {
156    sr->buffer_size = buffer_size;
157    sr->buffer = malloc(buffer_size);
158    if (!sr->buffer)
159    {
160      fprintf(stderr, "error: stdio-redirect: no memory for buffer\n");
161      free(sr->input);
162      free(sr);
163      return NULL;
164    }
165  }
166
167  sr->fd = fd;
168
169  sr->fd_dup = dup(fd);
170  if (sr->fd_dup < 0)
171  {
172    fprintf(stderr, "error: stdio-redirect: dup: %s\n", strerror(errno));
173    free(sr->buffer);
174    free(sr->input);
175    free(sr);
176    return NULL;
177  }
178
179  if (pipe(sr->pipe) < 0)
180  {
181    fprintf(stderr, "error: stdio-redirect: pipe create: %s\n", strerror(errno));
182    free(sr->buffer);
183    free(sr->input);
184    free(sr);
185    return NULL;
186
187  }
188
189  sr->echo = echo;
190  sr->handler = handler;
191
192  sc = rtems_semaphore_create (rtems_build_name ('R', 'S', 'R', 'l'),
193                               1, RTEMS_STDIO_REDIRECT_LOCK_ATTRIBS, 0,
194                               &sr->lock);
195  if (sc != RTEMS_SUCCESSFUL)
196  {
197    fprintf(stderr, "error: stdio-redirect: lock create: %s\n", rtems_status_text(sc));
198    free(sr->buffer);
199    free(sr->input);
200    free(sr);
201    return NULL;
202  }
203
204  name = rtems_build_name ('S', 'R', '0' + (fd / 10), '0' + (fd % 10));
205  sc = rtems_task_create (name,
206                          priority,
207                          stack_size,
208                          RTEMS_PREEMPT | RTEMS_NO_TIMESLICE | RTEMS_NO_ASR,
209                          RTEMS_LOCAL | RTEMS_NO_FLOATING_POINT,
210                          &sr->reader);
211  if (sc != RTEMS_SUCCESSFUL)
212  {
213    fprintf(stderr, "error: stdio-redirect: reader create: %s\n", rtems_status_text(sc));
214    rtems_semaphore_delete(sr->lock);
215    free(sr->buffer);
216    free(sr->input);
217    free(sr);
218    return NULL;
219  }
220
221  sr->state |= RTEMS_STDIO_REDIRECT_RUNNING;
222
223  if (dup2 (sr->pipe[1], fd) < 0)
224  {
225    fprintf(stderr, "error: stdio-redirect: dup2: %s\n", strerror(errno));
226    free(sr->buffer);
227    free(sr->input);
228    free(sr);
229    return NULL;
230  }
231
232  sc = rtems_task_start (sr->reader,
233                         rtems_stdio_redirect_reader,
234                         (rtems_task_argument) sr);
235
236  if (sc != RTEMS_SUCCESSFUL)
237  {
238    fprintf(stderr, "error: stdio-redirect: reader start: %s\n", rtems_status_text(sc));
239    rtems_task_delete(sr->reader);
240    rtems_semaphore_delete(sr->lock);
241    free(sr->buffer);
242    free(sr->input);
243    free(sr);
244    return NULL;
245  }
246
247  return sr;
248}
249
250void
251rtems_stdio_redirect_close(rtems_stdio_redirect* sr)
252{
253  if (rtems_stdio_redirect_lock(sr))
254  {
255    sr->state &= ~RTEMS_STDIO_REDIRECT_RUNNING;
256    close(sr->pipe[0]);
257
258    rtems_stdio_redirect_unlock(sr);
259
260    while (sr->state & RTEMS_STDIO_REDIRECT_FINISHED)
261    {
262      usleep(250UL * 1000000UL);
263    }
264
265    rtems_stdio_redirect_lock(sr);
266
267    dup2(sr->fd, sr->fd_dup);
268
269    free(sr->buffer);
270    free(sr->input);
271
272    rtems_stdio_redirect_unlock(sr);
273
274    rtems_semaphore_delete(sr->lock);
275
276    free(sr);
277  }
278}
279
280ssize_t
281rtems_stdio_redirect_read(rtems_stdio_redirect* sr,
282                          char*                 buffer,
283                          ssize_t               length)
284{
285  ssize_t written = 0;
286
287  if (!rtems_stdio_redirect_lock(sr))
288    return written;
289
290  if (sr->buffer)
291  {
292    ssize_t rem = 0;
293
294    if (sr->full)
295    {
296      if (length < sr->buffer_size)
297      {
298        if (length > sr->in)
299        {
300          rem = length - sr->in;
301          memcpy (buffer, sr->buffer + sr->buffer_size - rem, rem);
302        }
303
304        memcpy (buffer + rem, sr->buffer, sr->in);
305        written = length;
306      }
307      else
308      {
309        rem = sr->buffer_size - sr->in;
310        memcpy (buffer, sr->buffer + sr->in, rem);
311        memcpy (buffer + rem, sr->buffer, sr->in);
312        written = sr->buffer_size;
313      }
314
315      sr->full = false;
316    }
317    else if (length < sr->in)
318    {
319      rem = sr->in - length;
320      memcpy (buffer, sr->buffer + rem, length);
321      written = length;
322    }
323    else
324    {
325      memcpy (buffer, sr->buffer, sr->in);
326      written = sr->in;
327    }
328  }
329
330  rtems_stdio_redirect_unlock(sr);
331
332  return written;
333}
Note: See TracBrowser for help on using the repository browser.