source: rtems/c/src/lib/libnetworking/rtems/rtems_select.c @ 73f6236

4.104.114.84.95
Last change on this file since 73f6236 was 73f6236, checked in by Joel Sherrill <joel.sherrill@…>, on 03/01/99 at 22:40:08

Patch from Eric Norum <eric@…> to eliminate external
IO handlers scheme that was implemented originally just to support
sockets. The file system IO switch is more general and works fine.

  • Property mode set to 100644
File size: 3.8 KB
RevLine 
[94b3ee13]1/*
2 *  $Id$
3 */
4
5#include <string.h>
6#include <stdarg.h>
7#include <stdlib.h>
8#include <stdio.h>
9
10#include <rtems.h>
11#include <rtems/libio.h>
12#include <rtems/error.h>
13#include <rtems/rtems_bsdnet.h>
14
15#include <sys/errno.h>
16#include <sys/fcntl.h>
17#include <sys/types.h>
18#include <sys/param.h>
19#include <sys/mbuf.h>
20#include <sys/socket.h>
21#include <sys/socketvar.h>
22#include <sys/protosw.h>
23#include <sys/proc.h>
24#include <sys/filio.h>
25
26#include <net/if.h>
27#include <net/route.h>
28
29/*
30 *********************************************************************
31 *            RTEMS implementation of select() system call           *
32 *********************************************************************
33 */
34
35/*
36 * This implementation is quite restricted:
37 *      Works on sockets only -- no support for other devices!
38 *      A given socket can be in a read-select or a read/recv* by only
39 *              one task at a time.
40 *      A given socket can be in a write-select or a write/send* by only
41 *              one task at a time.
42 *
43 * NOTE - select() is a very expensive system call.  It should be avoided
44 *        if at all possible.  In many cases, rewriting the application
45 *        to use multiple tasks (one per socket) is a better solution.
46 */
47
48static __inline int imin(int a, int b) { return (a < b ? a : b); }
[73f6236]49struct socket *rtems_bsdnet_fdToSocket(int fd);
[94b3ee13]50
51static int
52socket_select (struct socket *so, int which, rtems_id tid)
53{
54        switch (which) {
55
56        case FREAD:
57                if (soreadable(so))
58                        return (1);
59                so->so_rcv.sb_sel.si_pid = tid;
60                break;
61
62        case FWRITE:
63                if (sowriteable(so))
64                        return (1);
65                so->so_snd.sb_sel.si_pid = tid;
66                break;
67
68        case 0:
69                if (so->so_oobmark || (so->so_state & SS_RCVATMARK))
70                        return (1);
71                so->so_rcv.sb_sel.si_pid = tid;
72                break;
73        }
74        return (0);
75}
76
77static int
78selscan (rtems_id tid, fd_mask **ibits, fd_mask **obits, int nfd, int *retval)
79{
80        struct socket *so;
81        int msk, i, fd;
82        fd_mask bits, bit;
83        int n = 0;
84        static int flag[3] = { FREAD, FWRITE, 0 };
85
86        for (msk = 0; msk < 3; msk++) {
87                if (ibits[msk] == NULL)
88                        continue;
89                for (i = 0; i < nfd; i += NFDBITS) {
90                        bits = ibits[msk][i/NFDBITS];
91                        for (fd = i, bit = 1 ; bits && (fd < nfd) ; fd++, bit <<= 1) {
92                                if ((bits & bit) == 0)
93                                        continue;
94                                bits &= ~bit;
95                                so = rtems_bsdnet_fdToSocket (fd);
96                                if (so == NULL)
97                                        return (EBADF);
98                                if (socket_select (so, flag[msk], tid)) {
99                                        obits[msk][fd/NFDBITS] |=
100                                                        (1 << (fd % NFDBITS));
101                                        n++;
102                                }
103                        }
104                }
105        }
106        *retval = n;
107        return (0);
108}
109
110int
111select (int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, struct timeval *tv)
112{
113        fd_mask *ibits[3], *obits[3];
114        fd_set ob[3];
115        int error, timo;
116        int retval;
117        rtems_id tid;
118        rtems_interval then, now;
119        rtems_event_set events;
120
121        if (nfds < 0)
122                return (EINVAL);
123        if (tv) {
124                timo = tv->tv_sec * hz + tv->tv_usec / tick;
125                if (timo == 0)
126                        timo = 1;
127                rtems_clock_get (RTEMS_CLOCK_GET_TICKS_SINCE_BOOT, &then);
128        }
129        else {
130                timo = 0;
131        }
132
133#define getbits(name,i) if (name) { \
134                ibits[i] = &name->fds_bits[0]; \
135                obits[i] = &ob[i].fds_bits[0]; \
136                FD_ZERO(&ob[i]); \
137        } \
138        else ibits[i] = NULL
139        getbits (readfds, 0);
140        getbits (writefds, 1);
141        getbits (exceptfds, 2);
142#undef getbits
143
144        rtems_task_ident (RTEMS_SELF, 0, &tid);
145        rtems_event_receive (SBWAIT_EVENT, RTEMS_EVENT_ANY | RTEMS_NO_WAIT, RTEMS_NO_TIMEOUT, &events);
146        for (;;) {
147                rtems_bsdnet_semaphore_obtain ();
148                error = selscan(tid, ibits, obits, nfds, &retval);
149                rtems_bsdnet_semaphore_release ();
150                if (error || retval)
151                        break;
152                if (timo) {
153                        rtems_clock_get (RTEMS_CLOCK_GET_TICKS_SINCE_BOOT, &now);
154                        timo -= now - then;
155                        if (timo <= 0)
156                                break;
157                        then = now;
158                }
159                rtems_event_receive (SBWAIT_EVENT, RTEMS_EVENT_ANY | RTEMS_WAIT, timo, &events);
160        }
161
162#define putbits(name,i) if (name) *name = ob[i]
163        putbits (readfds, 0);
164        putbits (writefds, 1);
165        putbits (exceptfds, 2);
166#undef putbits
167        if (error) {
168                errno = error;
169                retval = -1;
170        }
171        return (retval);
172}
Note: See TracBrowser for help on using the repository browser.