source: rtems-libbsd/freebsd/lib/libc/isc/ev_streams.c @ f41a394

55-freebsd-126-freebsd-12freebsd-9.3
Last change on this file since f41a394 was 3d1e767, checked in by Sebastian Huber <sebastian.huber@…>, on Apr 27, 2016 at 8:25:22 AM

Directly use <sys/types.h> provided by Newlib

  • Property mode set to 100644
File size: 7.6 KB
Line 
1#include <machine/rtems-bsd-user-space.h>
2
3/*
4 * Copyright (c) 2004 by Internet Systems Consortium, Inc. ("ISC")
5 * Copyright (c) 1996-1999 by Internet Software Consortium
6 *
7 * Permission to use, copy, modify, and distribute this software for any
8 * purpose with or without fee is hereby granted, provided that the above
9 * copyright notice and this permission notice appear in all copies.
10 *
11 * THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES
12 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
13 * MERCHANTABILITY AND FITNESS.  IN NO EVENT SHALL ISC BE LIABLE FOR
14 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
15 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
16 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
17 * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
18 */
19
20/* ev_streams.c - implement asynch stream file IO for the eventlib
21 * vix 04mar96 [initial]
22 */
23
24#if !defined(LINT) && !defined(CODECENTER)
25static const char rcsid[] = "$Id: ev_streams.c,v 1.5 2005/04/27 04:56:36 sra Exp $";
26#endif
27#include <sys/cdefs.h>
28__FBSDID("$FreeBSD$");
29
30#include "port_before.h"
31#ifndef _LIBC
32#include "fd_setsize.h"
33#endif
34
35#include <sys/types.h>
36#include <sys/uio.h>
37
38#include <errno.h>
39
40#include <isc/eventlib.h>
41#ifndef _LIBC
42#include <isc/assertions.h>
43#endif
44#include "eventlib_p.h"
45
46#include "port_after.h"
47
48#ifndef _LIBC
49static int      copyvec(evStream *str, const struct iovec *iov, int iocnt);
50static void     consume(evStream *str, size_t bytes);
51static void     done(evContext opaqueCtx, evStream *str);
52static void     writable(evContext opaqueCtx, void *uap, int fd, int evmask);
53static void     readable(evContext opaqueCtx, void *uap, int fd, int evmask);
54#endif
55
56struct iovec
57evConsIovec(void *buf, size_t cnt) {
58        struct iovec ret;
59
60        memset(&ret, 0xf5, sizeof ret);
61        ret.iov_base = buf;
62        ret.iov_len = cnt;
63        return (ret);
64}
65
66#ifndef _LIBC
67int
68evWrite(evContext opaqueCtx, int fd, const struct iovec *iov, int iocnt,
69        evStreamFunc func, void *uap, evStreamID *id)
70{
71        evContext_p *ctx = opaqueCtx.opaque;
72        evStream *new;
73        int save;
74
75        OKNEW(new);
76        new->func = func;
77        new->uap = uap;
78        new->fd = fd;
79        new->flags = 0;
80        if (evSelectFD(opaqueCtx, fd, EV_WRITE, writable, new, &new->file) < 0)
81                goto free;
82        if (copyvec(new, iov, iocnt) < 0)
83                goto free;
84        new->prevDone = NULL;
85        new->nextDone = NULL;
86        if (ctx->streams != NULL)
87                ctx->streams->prev = new;
88        new->prev = NULL;
89        new->next = ctx->streams;
90        ctx->streams = new;
91        if (id != NULL)
92                id->opaque = new;
93        return (0);
94 free:
95        save = errno;
96        FREE(new);
97        errno = save;
98        return (-1);
99}
100
101int
102evRead(evContext opaqueCtx, int fd, const struct iovec *iov, int iocnt,
103       evStreamFunc func, void *uap, evStreamID *id)
104{
105        evContext_p *ctx = opaqueCtx.opaque;
106        evStream *new;
107        int save;
108
109        OKNEW(new);
110        new->func = func;
111        new->uap = uap;
112        new->fd = fd;
113        new->flags = 0;
114        if (evSelectFD(opaqueCtx, fd, EV_READ, readable, new, &new->file) < 0)
115                goto free;
116        if (copyvec(new, iov, iocnt) < 0)
117                goto free;
118        new->prevDone = NULL;
119        new->nextDone = NULL;
120        if (ctx->streams != NULL)
121                ctx->streams->prev = new;
122        new->prev = NULL;
123        new->next = ctx->streams;
124        ctx->streams = new;
125        if (id)
126                id->opaque = new;
127        return (0);
128 free:
129        save = errno;
130        FREE(new);
131        errno = save;
132        return (-1);
133}
134
135int
136evTimeRW(evContext opaqueCtx, evStreamID id, evTimerID timer) /*ARGSUSED*/ {
137        evStream *str = id.opaque;
138
139        UNUSED(opaqueCtx);
140
141        str->timer = timer;
142        str->flags |= EV_STR_TIMEROK;
143        return (0);
144}
145
146int
147evUntimeRW(evContext opaqueCtx, evStreamID id) /*ARGSUSED*/ {
148        evStream *str = id.opaque;
149
150        UNUSED(opaqueCtx);
151
152        str->flags &= ~EV_STR_TIMEROK;
153        return (0);
154}
155
156int
157evCancelRW(evContext opaqueCtx, evStreamID id) {
158        evContext_p *ctx = opaqueCtx.opaque;
159        evStream *old = id.opaque;
160
161        /*
162         * The streams list is doubly threaded.  First, there's ctx->streams
163         * that's used by evDestroy() to find and cancel all streams.  Second,
164         * there's ctx->strDone (head) and ctx->strLast (tail) which thread
165         * through the potentially smaller number of "IO completed" streams,
166         * used in evGetNext() to avoid scanning the entire list.
167         */
168
169        /* Unlink from ctx->streams. */
170        if (old->prev != NULL)
171                old->prev->next = old->next;
172        else
173                ctx->streams = old->next;
174        if (old->next != NULL)
175                old->next->prev = old->prev;
176
177        /*
178         * If 'old' is on the ctx->strDone list, remove it.  Update
179         * ctx->strLast if necessary.
180         */
181        if (old->prevDone == NULL && old->nextDone == NULL) {
182                /*
183                 * Either 'old' is the only item on the done list, or it's
184                 * not on the done list.  If the former, then we unlink it
185                 * from the list.  If the latter, we leave the list alone.
186                 */
187                if (ctx->strDone == old) {
188                        ctx->strDone = NULL;
189                        ctx->strLast = NULL;
190                }
191        } else {
192                if (old->prevDone != NULL)
193                        old->prevDone->nextDone = old->nextDone;
194                else
195                        ctx->strDone = old->nextDone;
196                if (old->nextDone != NULL)
197                        old->nextDone->prevDone = old->prevDone;
198                else
199                        ctx->strLast = old->prevDone;
200        }
201
202        /* Deallocate the stream. */
203        if (old->file.opaque)
204                evDeselectFD(opaqueCtx, old->file);
205        memput(old->iovOrig, sizeof (struct iovec) * old->iovOrigCount);
206        FREE(old);
207        return (0);
208}
209
210/* Copy a scatter/gather vector and initialize a stream handler's IO. */
211static int
212copyvec(evStream *str, const struct iovec *iov, int iocnt) {
213        int i;
214
215        str->iovOrig = (struct iovec *)memget(sizeof(struct iovec) * iocnt);
216        if (str->iovOrig == NULL) {
217                errno = ENOMEM;
218                return (-1);
219        }
220        str->ioTotal = 0;
221        for (i = 0; i < iocnt; i++) {
222                str->iovOrig[i] = iov[i];
223                str->ioTotal += iov[i].iov_len;
224        }
225        str->iovOrigCount = iocnt;
226        str->iovCur = str->iovOrig;
227        str->iovCurCount = str->iovOrigCount;
228        str->ioDone = 0;
229        return (0);
230}
231
232/* Pull off or truncate lead iovec(s). */
233static void
234consume(evStream *str, size_t bytes) {
235        while (bytes > 0U) {
236                if (bytes < (size_t)str->iovCur->iov_len) {
237                        str->iovCur->iov_len -= bytes;
238                        str->iovCur->iov_base = (void *)
239                                ((u_char *)str->iovCur->iov_base + bytes);
240                        str->ioDone += bytes;
241                        bytes = 0;
242                } else {
243                        bytes -= str->iovCur->iov_len;
244                        str->ioDone += str->iovCur->iov_len;
245                        str->iovCur++;
246                        str->iovCurCount--;
247                }
248        }
249}
250
251/* Add a stream to Done list and deselect the FD. */
252static void
253done(evContext opaqueCtx, evStream *str) {
254        evContext_p *ctx = opaqueCtx.opaque;
255
256        if (ctx->strLast != NULL) {
257                str->prevDone = ctx->strLast;
258                ctx->strLast->nextDone = str;
259                ctx->strLast = str;
260        } else {
261                INSIST(ctx->strDone == NULL);
262                ctx->strDone = ctx->strLast = str;
263        }
264        evDeselectFD(opaqueCtx, str->file);
265        str->file.opaque = NULL;
266        /* evDrop() will call evCancelRW() on us. */
267}
268
269/* Dribble out some bytes on the stream.  (Called by evDispatch().) */
270static void
271writable(evContext opaqueCtx, void *uap, int fd, int evmask) {
272        evStream *str = uap;
273        int bytes;
274
275        UNUSED(evmask);
276
277        bytes = writev(fd, str->iovCur, str->iovCurCount);
278        if (bytes > 0) {
279                if ((str->flags & EV_STR_TIMEROK) != 0)
280                        evTouchIdleTimer(opaqueCtx, str->timer);
281                consume(str, bytes);
282        } else {
283                if (bytes < 0 && errno != EINTR) {
284                        str->ioDone = -1;
285                        str->ioErrno = errno;
286                }
287        }
288        if (str->ioDone == -1 || str->ioDone == str->ioTotal)
289                done(opaqueCtx, str);
290}
291
292/* Scoop up some bytes from the stream.  (Called by evDispatch().) */
293static void
294readable(evContext opaqueCtx, void *uap, int fd, int evmask) {
295        evStream *str = uap;
296        int bytes;
297
298        UNUSED(evmask);
299
300        bytes = readv(fd, str->iovCur, str->iovCurCount);
301        if (bytes > 0) {
302                if ((str->flags & EV_STR_TIMEROK) != 0)
303                        evTouchIdleTimer(opaqueCtx, str->timer);
304                consume(str, bytes);
305        } else {
306                if (bytes == 0)
307                        str->ioDone = 0;
308                else {
309                        if (errno != EINTR) {
310                                str->ioDone = -1;
311                                str->ioErrno = errno;
312                        }
313                }
314        }
315        if (str->ioDone <= 0 || str->ioDone == str->ioTotal)
316                done(opaqueCtx, str);
317}
318#endif
319
320/*! \file */
Note: See TracBrowser for help on using the repository browser.