]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - lib/libc_r/uthread/uthread_select.c
unfinished sblive driver, playback/mixer only for now - not enabled in
[FreeBSD/FreeBSD.git] / lib / libc_r / uthread / uthread_select.c
1 /*
2  * Copyright (c) 1995-1998 John Birrell <jb@cimlogic.com.au>
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  * 3. All advertising materials mentioning features or use of this software
14  *    must display the following acknowledgement:
15  *      This product includes software developed by John Birrell.
16  * 4. Neither the name of the author nor the names of any co-contributors
17  *    may be used to endorse or promote products derived from this software
18  *    without specific prior written permission.
19  *
20  * THIS SOFTWARE IS PROVIDED BY JOHN BIRRELL AND CONTRIBUTORS ``AS IS'' AND
21  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
24  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30  * SUCH DAMAGE.
31  *
32  * $FreeBSD$
33  */
34 #include <unistd.h>
35 #include <errno.h>
36 #include <poll.h>
37 #include <stdlib.h>
38 #include <string.h>
39 #include <sys/param.h>
40 #include <sys/types.h>
41 #include <sys/time.h>
42 #include <sys/fcntl.h>
43 #ifdef _THREAD_SAFE
44 #include <pthread.h>
45 #include "pthread_private.h"
46
47 int 
48 _select(int numfds, fd_set * readfds, fd_set * writefds, fd_set * exceptfds,
49     struct timeval * timeout)
50 {
51         struct timespec ts;
52         int             i, ret = 0, f_wait = 1;
53         int             pfd_index, got_one = 0, fd_count = 0;
54         struct pthread_poll_data data;
55
56         if (numfds > _thread_dtablesize) {
57                 numfds = _thread_dtablesize;
58         }
59         /* Check if a timeout was specified: */
60         if (timeout) {
61                 if (timeout->tv_sec < 0 ||
62                         timeout->tv_usec < 0 || timeout->tv_usec >= 1000000) {
63                         errno = EINVAL;
64                         return (-1);
65                 }
66
67                 /* Convert the timeval to a timespec: */
68                 TIMEVAL_TO_TIMESPEC(timeout, &ts);
69
70                 /* Set the wake up time: */
71                 _thread_kern_set_timeout(&ts);
72                 if (ts.tv_sec == 0 && ts.tv_nsec == 0)
73                         f_wait = 0;
74         } else {
75                 /* Wait for ever: */
76                 _thread_kern_set_timeout(NULL);
77         }
78
79         /* Count the number of file descriptors to be polled: */
80         if (readfds || writefds || exceptfds) {
81                 for (i = 0; i < numfds; i++) {
82                         if ((readfds && FD_ISSET(i, readfds)) ||
83                             (exceptfds && FD_ISSET(i, exceptfds)) ||
84                             (writefds && FD_ISSET(i, writefds))) {
85                                 fd_count++;
86                         }
87                 }
88         }
89
90         /*
91          * Allocate memory for poll data if it hasn't already been
92          * allocated or if previously allocated memory is insufficient.
93          */
94         if ((_thread_run->poll_data.fds == NULL) ||
95             (_thread_run->poll_data.nfds < fd_count)) {
96                 data.fds = (struct pollfd *) realloc(_thread_run->poll_data.fds,
97                     sizeof(struct pollfd) * MAX(128, fd_count));
98                 if (data.fds == NULL) {
99                         errno = ENOMEM;
100                         ret = -1;
101                 }
102                 else {
103                         /*
104                          * Note that the threads poll data always
105                          * indicates what is allocated, not what is
106                          * currently being polled.
107                          */
108                         _thread_run->poll_data.fds = data.fds;
109                         _thread_run->poll_data.nfds = MAX(128, fd_count);
110                 }
111         }
112         if (ret == 0) {
113                 /* Setup the wait data. */
114                 data.fds = _thread_run->poll_data.fds;
115                 data.nfds = fd_count;
116
117                 /*
118                  * Setup the array of pollfds.  Optimize this by
119                  * running the loop in reverse and stopping when
120                  * the number of selected file descriptors is reached.
121                  */
122                 for (i = numfds - 1, pfd_index = fd_count - 1;
123                     (i >= 0) && (pfd_index >= 0); i--) {
124                         data.fds[pfd_index].events = 0;
125                         if (readfds && FD_ISSET(i, readfds)) {
126                                 data.fds[pfd_index].events = POLLRDNORM;
127                         }
128                         if (exceptfds && FD_ISSET(i, exceptfds)) {
129                                 data.fds[pfd_index].events |= POLLRDBAND;
130                         }
131                         if (writefds && FD_ISSET(i, writefds)) {
132                                 data.fds[pfd_index].events |= POLLWRNORM;
133                         }
134                         if (data.fds[pfd_index].events != 0) {
135                                 /*
136                                  * Set the file descriptor to be polled and
137                                  * clear revents in case of a timeout which
138                                  * leaves fds unchanged:
139                                  */
140                                 data.fds[pfd_index].fd = i;
141                                 data.fds[pfd_index].revents = 0;
142                                 pfd_index--;
143                         }
144                 }
145                 if (((ret = _thread_sys_poll(data.fds, data.nfds, 0)) == 0) &&
146                    (f_wait != 0)) {
147                         _thread_run->data.poll_data = &data;
148                         _thread_run->interrupted = 0;
149                         _thread_kern_sched_state(PS_SELECT_WAIT, __FILE__, __LINE__);
150                         if (_thread_run->interrupted) {
151                                 errno = EINTR;
152                                 data.nfds = 0;
153                                 ret = -1;
154                         } else
155                                 ret = data.nfds;
156                 }
157         }
158
159         if (ret >= 0) {
160                 numfds = 0;
161                 for (i = 0; i < fd_count; i++) {
162                         /*
163                          * Check the results of the poll and clear
164                          * this file descriptor from the fdset if
165                          * the requested event wasn't ready.
166                          */
167                         got_one = 0;
168                         if (readfds != NULL) {
169                                 if (FD_ISSET(data.fds[i].fd, readfds)) {
170                                         if (data.fds[i].revents & (POLLIN |
171                                             POLLRDNORM))
172                                                 got_one = 1;
173                                         else
174                                                 FD_CLR(data.fds[i].fd, readfds);
175                                 }
176                         }
177                         if (writefds != NULL) {
178                                 if (FD_ISSET(data.fds[i].fd, writefds)) {
179                                         if (data.fds[i].revents & (POLLOUT |
180                                             POLLWRNORM | POLLWRBAND))
181                                                 got_one = 1;
182                                         else
183                                                 FD_CLR(data.fds[i].fd,
184                                                     writefds);
185                                 }
186                         }
187                         if (exceptfds != NULL) {
188                                 if (FD_ISSET(data.fds[i].fd, exceptfds)) {
189                                         if (data.fds[i].revents & (POLLRDBAND |
190                                             POLLPRI | POLLHUP | POLLERR |
191                                             POLLNVAL))
192                                                 got_one = 1;
193                                         else
194                                                 FD_CLR(data.fds[i].fd,
195                                                     exceptfds);
196                                 }
197                         }
198                         if (got_one)
199                                 numfds++;
200                 }
201                 ret = numfds;
202         }
203
204         return (ret);
205 }
206
207 __strong_reference(_select, select);
208 #endif