source: rtems/cpukit/libnetworking/rtems/rtems_select.c @ 26e90fb1

4.11
Last change on this file since 26e90fb1 was 26e90fb1, checked in by Sebastian Huber <sebastian.huber@…>, on Oct 30, 2012 at 4:42:17 PM

libnetworking: Use system events

Add reserved system events RTEMS_EVENT_SYSTEM_NETWORK_SBWAIT and
RTEMS_EVENT_SYSTEM_NETWORK_SOSLEEP.

Add and use rtems_bsdnet_event_send().

  • Property mode set to 100644
File size: 3.9 KB
Line 
1#if HAVE_CONFIG_H
2#include "config.h"
3#endif
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 <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); }
49struct socket *rtems_bsdnet_fdToSocket(int fd);
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_flags |= SB_WAIT;
60                so->so_rcv.sb_sel.si_pid = tid;
61                break;
62
63        case FWRITE:
64                if (sowriteable(so))
65                        return (1);
66                so->so_snd.sb_flags |= SB_WAIT;
67                so->so_snd.sb_sel.si_pid = tid;
68                break;
69
70        case 0:
71                if (so->so_oobmark || (so->so_state & SS_RCVATMARK))
72                        return (1);
73                so->so_rcv.sb_sel.si_pid = tid;
74                break;
75        }
76        return (0);
77}
78
79static int
80selscan (rtems_id tid, fd_mask **ibits, fd_mask **obits, int nfd, int *retval)
81{
82        struct socket *so;
83        int msk, i, fd;
84        fd_mask bits, bit;
85        int n = 0;
86        static int flag[3] = { FREAD, FWRITE, 0 };
87
88        for (msk = 0; msk < 3; msk++) {
89                if (ibits[msk] == NULL)
90                        continue;
91                for (i = 0; i < nfd; i += NFDBITS) {
92                        bits = ibits[msk][i/NFDBITS];
93                        for (fd = i, bit = 1 ; bits && (fd < nfd) ; fd++, bit <<= 1) {
94                                if ((bits & bit) == 0)
95                                        continue;
96                                bits &= ~bit;
97                                so = rtems_bsdnet_fdToSocket (fd);
98                                if (so == NULL)
99                                        return (EBADF);
100                                if (socket_select (so, flag[msk], tid)) {
101                                        obits[msk][fd/NFDBITS] |=
102                                                        (1 << (fd % NFDBITS));
103                                        n++;
104                                }
105                        }
106                }
107        }
108        *retval = n;
109        return (0);
110}
111
112int
113select (int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, struct timeval *tv)
114{
115        fd_mask *ibits[3], *obits[3];
116        fd_set ob[3];
117        int error, timo;
118        int retval = 0;
119        rtems_id tid;
120        rtems_interval then = 0, now;
121        rtems_event_set events;
122
123        if (nfds < 0)
124                return (EINVAL);
125        if (tv) {
126                timo = tv->tv_sec * hz + tv->tv_usec / tick;
127                if (timo == 0)
128                        timo = 1;
129                then = rtems_clock_get_ticks_since_boot();
130        }
131        else {
132                timo = 0;
133        }
134
135#define getbits(name,i) if (name) { \
136                ibits[i] = &name->fds_bits[0]; \
137                obits[i] = &ob[i].fds_bits[0]; \
138                FD_ZERO(&ob[i]); \
139        } \
140        else ibits[i] = NULL
141        getbits (readfds, 0);
142        getbits (writefds, 1);
143        getbits (exceptfds, 2);
144#undef getbits
145
146        rtems_task_ident (RTEMS_SELF, 0, &tid);
147        rtems_event_system_receive (SBWAIT_EVENT, RTEMS_EVENT_ANY | RTEMS_NO_WAIT, RTEMS_NO_TIMEOUT, &events);
148        for (;;) {
149                rtems_bsdnet_semaphore_obtain ();
150                error = selscan(tid, ibits, obits, nfds, &retval);
151                rtems_bsdnet_semaphore_release ();
152                if (error || retval)
153                        break;
154                if (timo) {
155                        now = rtems_clock_get_ticks_since_boot();
156                        timo -= now - then;
157                        if (timo <= 0)
158                                break;
159                        then = now;
160                }
161                rtems_event_system_receive (SBWAIT_EVENT, RTEMS_EVENT_ANY | RTEMS_WAIT, timo, &events);
162        }
163
164#define putbits(name,i) if (name) *name = ob[i]
165        putbits (readfds, 0);
166        putbits (writefds, 1);
167        putbits (exceptfds, 2);
168#undef putbits
169        if (error) {
170                errno = error;
171                retval = -1;
172        }
173        return (retval);
174}
Note: See TracBrowser for help on using the repository browser.