]> CyberLeo.Net >> Repos - FreeBSD/releng/8.1.git/blob - lib/libc_r/uthread/uthread_select.c
Copy stable/8 to releng/8.1 in preparation for 8.1-RC1.
[FreeBSD/releng/8.1.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. Neither the name of the author nor the names of any co-contributors
14  *    may be used to endorse or promote products derived from this software
15  *    without specific prior written permission.
16  *
17  * THIS SOFTWARE IS PROVIDED BY JOHN BIRRELL AND CONTRIBUTORS ``AS IS'' AND
18  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
21  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27  * SUCH DAMAGE.
28  *
29  * $FreeBSD$
30  */
31 #include <unistd.h>
32 #include <errno.h>
33 #include <poll.h>
34 #include <stdlib.h>
35 #include <string.h>
36 #include <sys/param.h>
37 #include <sys/types.h>
38 #include <sys/time.h>
39 #include <sys/fcntl.h>
40 #include <pthread.h>
41 #include "pthread_private.h"
42
43 __weak_reference(__select, select);
44
45 int 
46 _select(int numfds, fd_set * readfds, fd_set * writefds, fd_set * exceptfds,
47     struct timeval * timeout)
48 {
49         struct pthread  *curthread = _get_curthread();
50         struct timespec ts;
51         int             i, ret = 0, f_wait = 1;
52         int             pfd_index, got_events = 0, fd_count = 0;
53         struct pthread_poll_data data;
54
55         if (numfds > _thread_dtablesize) {
56                 numfds = _thread_dtablesize;
57         }
58         /* Count the number of file descriptors to be polled: */
59         if (readfds || writefds || exceptfds) {
60                 for (i = 0; i < numfds; i++) {
61                         if ((readfds && FD_ISSET(i, readfds)) ||
62                             (exceptfds && FD_ISSET(i, exceptfds)) ||
63                             (writefds && FD_ISSET(i, writefds))) {
64                                 fd_count++;
65                         }
66                 }
67         }
68
69         /*
70          * Allocate memory for poll data if it hasn't already been
71          * allocated or if previously allocated memory is insufficient.
72          */
73         if ((curthread->poll_data.fds == NULL) ||
74             (curthread->poll_data.nfds < fd_count)) {
75                 data.fds = (struct pollfd *) realloc(curthread->poll_data.fds,
76                     sizeof(struct pollfd) * MAX(128, fd_count));
77                 if (data.fds == NULL) {
78                         errno = ENOMEM;
79                         ret = -1;
80                 }
81                 else {
82                         /*
83                          * Note that the threads poll data always
84                          * indicates what is allocated, not what is
85                          * currently being polled.
86                          */
87                         curthread->poll_data.fds = data.fds;
88                         curthread->poll_data.nfds = MAX(128, fd_count);
89                 }
90         }
91         /* Check if a timeout was specified: */
92         if (timeout) {
93                 if (timeout->tv_sec < 0 ||
94                         timeout->tv_usec < 0 || timeout->tv_usec >= 1000000) {
95                         errno = EINVAL;
96                         return (-1);
97                 }
98
99                 /* Convert the timeval to a timespec: */
100                 TIMEVAL_TO_TIMESPEC(timeout, &ts);
101
102                 /* Set the wake up time: */
103                 _thread_kern_set_timeout(&ts);
104                 if (ts.tv_sec == 0 && ts.tv_nsec == 0)
105                         f_wait = 0;
106         } else {
107                 /* Wait for ever: */
108                 _thread_kern_set_timeout(NULL);
109         }
110
111         if (ret == 0) {
112                 /* Setup the wait data. */
113                 data.fds = curthread->poll_data.fds;
114                 data.nfds = fd_count;
115
116                 /*
117                  * Setup the array of pollfds.  Optimize this by
118                  * running the loop in reverse and stopping when
119                  * the number of selected file descriptors is reached.
120                  */
121                 for (i = numfds - 1, pfd_index = fd_count - 1;
122                     (i >= 0) && (pfd_index >= 0); i--) {
123                         data.fds[pfd_index].events = 0;
124                         if (readfds && FD_ISSET(i, readfds)) {
125                                 data.fds[pfd_index].events = POLLRDNORM;
126                         }
127                         if (exceptfds && FD_ISSET(i, exceptfds)) {
128                                 data.fds[pfd_index].events |= POLLRDBAND;
129                         }
130                         if (writefds && FD_ISSET(i, writefds)) {
131                                 data.fds[pfd_index].events |= POLLWRNORM;
132                         }
133                         if (data.fds[pfd_index].events != 0) {
134                                 /*
135                                  * Set the file descriptor to be polled and
136                                  * clear revents in case of a timeout which
137                                  * leaves fds unchanged:
138                                  */
139                                 data.fds[pfd_index].fd = i;
140                                 data.fds[pfd_index].revents = 0;
141                                 pfd_index--;
142                         }
143                 }
144                 if (((ret = __sys_poll(data.fds, data.nfds, 0)) == 0) &&
145                    (f_wait != 0)) {
146                         curthread->data.poll_data = &data;
147                         curthread->interrupted = 0;
148                         _thread_kern_sched_state(PS_SELECT_WAIT, __FILE__, __LINE__);
149                         if (curthread->interrupted) {
150                                 errno = EINTR;
151                                 data.nfds = 0;
152                                 ret = -1;
153                         } else
154                                 ret = data.nfds;
155                 }
156         }
157
158         if (ret >= 0) {
159                 numfds = 0;
160                 for (i = 0; i < fd_count; i++) {
161                         /*
162                          * Check the results of the poll and clear
163                          * this file descriptor from the fdset if
164                          * the requested event wasn't ready.
165                          */
166
167                         /*
168                          * First check for invalid descriptor.
169                          * If found, set errno and return -1.
170                          */
171                         if (data.fds[i].revents & POLLNVAL) {
172                                 errno = EBADF;
173                                 return -1;
174                         }
175
176                         got_events = 0;
177                         if (readfds != NULL) {
178                                 if (FD_ISSET(data.fds[i].fd, readfds)) {
179                                         if ((data.fds[i].revents & (POLLIN
180                                             | POLLRDNORM | POLLERR
181                                             | POLLHUP | POLLNVAL)) != 0)
182                                                 got_events++;
183                                         else
184                                                 FD_CLR(data.fds[i].fd, readfds);
185                                 }
186                         }
187                         if (writefds != NULL) {
188                                 if (FD_ISSET(data.fds[i].fd, writefds)) {
189                                         if ((data.fds[i].revents & (POLLOUT
190                                             | POLLWRNORM | POLLWRBAND | POLLERR
191                                             | POLLHUP | POLLNVAL)) != 0)
192                                                 got_events++;
193                                         else
194                                                 FD_CLR(data.fds[i].fd,
195                                                     writefds);
196                                 }
197                         }
198                         if (exceptfds != NULL) {
199                                 if (FD_ISSET(data.fds[i].fd, exceptfds)) {
200                                         if (data.fds[i].revents & (POLLRDBAND |
201                                             POLLPRI))
202                                                 got_events++;
203                                         else
204                                                 FD_CLR(data.fds[i].fd,
205                                                     exceptfds);
206                                 }
207                         }
208                         if (got_events != 0)
209                                 numfds+=got_events;
210                 }
211                 ret = numfds;
212         }
213
214         return (ret);
215 }
216
217 int 
218 __select(int numfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds,
219         struct timeval *timeout)
220 {
221         int ret;
222
223         _thread_enter_cancellation_point();
224         ret = _select(numfds, readfds, writefds, exceptfds, timeout);
225         _thread_leave_cancellation_point();
226
227         return ret;
228 }