thr_select.c revision 49439
113546Sjulian/*
235509Sjb * Copyright (c) 1995-1998 John Birrell <jb@cimlogic.com.au>
313546Sjulian * All rights reserved.
413546Sjulian *
513546Sjulian * Redistribution and use in source and binary forms, with or without
613546Sjulian * modification, are permitted provided that the following conditions
713546Sjulian * are met:
813546Sjulian * 1. Redistributions of source code must retain the above copyright
913546Sjulian *    notice, this list of conditions and the following disclaimer.
1013546Sjulian * 2. Redistributions in binary form must reproduce the above copyright
1113546Sjulian *    notice, this list of conditions and the following disclaimer in the
1213546Sjulian *    documentation and/or other materials provided with the distribution.
1313546Sjulian * 3. All advertising materials mentioning features or use of this software
1413546Sjulian *    must display the following acknowledgement:
1513546Sjulian *	This product includes software developed by John Birrell.
1613546Sjulian * 4. Neither the name of the author nor the names of any co-contributors
1713546Sjulian *    may be used to endorse or promote products derived from this software
1813546Sjulian *    without specific prior written permission.
1913546Sjulian *
2013546Sjulian * THIS SOFTWARE IS PROVIDED BY JOHN BIRRELL AND CONTRIBUTORS ``AS IS'' AND
2113546Sjulian * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2213546Sjulian * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2349439Sdeischen * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
2413546Sjulian * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2513546Sjulian * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2613546Sjulian * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2713546Sjulian * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2813546Sjulian * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2913546Sjulian * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
3013546Sjulian * SUCH DAMAGE.
3113546Sjulian *
3249439Sdeischen * $Id: uthread_select.c,v 1.8 1999/06/23 15:01:22 dt Exp $
3313546Sjulian */
3413546Sjulian#include <unistd.h>
3513546Sjulian#include <errno.h>
3648046Sjb#include <poll.h>
3748140Sdt#include <stdlib.h>
3813546Sjulian#include <string.h>
3948046Sjb#include <sys/param.h>
4013546Sjulian#include <sys/types.h>
4113546Sjulian#include <sys/time.h>
4244963Sjb#include <sys/fcntl.h>
4313546Sjulian#ifdef _THREAD_SAFE
4413546Sjulian#include <pthread.h>
4513546Sjulian#include "pthread_private.h"
4613546Sjulian
4713546Sjulianint
4813546Sjulianselect(int numfds, fd_set * readfds, fd_set * writefds,
4913546Sjulian       fd_set * exceptfds, struct timeval * timeout)
5013546Sjulian{
5113546Sjulian	struct timespec ts;
5248046Sjb	int             i, ret = 0, f_wait = 1;
5348046Sjb	int		pfd_index, got_one = 0, fd_count = 0;
5448046Sjb	struct pthread_poll_data data;
5513546Sjulian
5613546Sjulian	if (numfds > _thread_dtablesize) {
5713546Sjulian		numfds = _thread_dtablesize;
5813546Sjulian	}
5913546Sjulian	/* Check if a timeout was specified: */
6013546Sjulian	if (timeout) {
6113546Sjulian		/* Convert the timeval to a timespec: */
6213546Sjulian		TIMEVAL_TO_TIMESPEC(timeout, &ts);
6313546Sjulian
6413546Sjulian		/* Set the wake up time: */
6513546Sjulian		_thread_kern_set_timeout(&ts);
6644963Sjb		if (ts.tv_sec == 0 && ts.tv_nsec == 0)
6744963Sjb			f_wait = 0;
6813546Sjulian	} else {
6913546Sjulian		/* Wait for ever: */
7013546Sjulian		_thread_kern_set_timeout(NULL);
7113546Sjulian	}
7213546Sjulian
7348046Sjb	/* Count the number of file descriptors to be polled: */
7413546Sjulian	if (readfds || writefds || exceptfds) {
7513546Sjulian		for (i = 0; i < numfds; i++) {
7648046Sjb			if ((readfds && FD_ISSET(i, readfds)) ||
7748046Sjb			    (exceptfds && FD_ISSET(i, exceptfds)) ||
7848046Sjb			    (writefds && FD_ISSET(i, writefds))) {
7948046Sjb				fd_count++;
8013546Sjulian			}
8113546Sjulian		}
8213546Sjulian	}
8348046Sjb
8448046Sjb	/*
8548046Sjb	 * Allocate memory for poll data if it hasn't already been
8648046Sjb	 * allocated or if previously allocated memory is insufficient.
8748046Sjb	 */
8848046Sjb	if ((_thread_run->poll_data.fds == NULL) ||
8948046Sjb	    (_thread_run->poll_data.nfds < fd_count)) {
9048046Sjb		data.fds = (struct pollfd *) realloc(_thread_run->poll_data.fds,
9148046Sjb		    sizeof(struct pollfd) * MAX(128, fd_count));
9248046Sjb		if (data.fds == NULL) {
9348046Sjb			errno = ENOMEM;
9448046Sjb			ret = -1;
9513546Sjulian		}
9648046Sjb		else {
9748046Sjb			/*
9848046Sjb			 * Note that the threads poll data always
9948046Sjb			 * indicates what is allocated, not what is
10048046Sjb			 * currently being polled.
10148046Sjb			 */
10248046Sjb			_thread_run->poll_data.fds = data.fds;
10348046Sjb			_thread_run->poll_data.nfds = MAX(128, fd_count);
10413546Sjulian		}
10548046Sjb	}
10648046Sjb	if (ret == 0) {
10748046Sjb		/* Setup the wait data. */
10848046Sjb		data.fds = _thread_run->poll_data.fds;
10948046Sjb		data.nfds = fd_count;
11048046Sjb
11148046Sjb		/*
11248046Sjb		 * Setup the array of pollfds.  Optimize this by
11348046Sjb		 * running the loop in reverse and stopping when
11448046Sjb		 * the number of selected file descriptors is reached.
11548046Sjb		 */
11648046Sjb		for (i = numfds - 1, pfd_index = fd_count - 1;
11748046Sjb		    (i >= 0) && (pfd_index >= 0); i--) {
11848046Sjb			data.fds[pfd_index].events = 0;
11948046Sjb			if (readfds && FD_ISSET(i, readfds)) {
12048046Sjb				data.fds[pfd_index].events = POLLRDNORM;
12113546Sjulian			}
12248046Sjb			if (exceptfds && FD_ISSET(i, exceptfds)) {
12348046Sjb				data.fds[pfd_index].events |= POLLRDBAND;
12413546Sjulian			}
12548046Sjb			if (writefds && FD_ISSET(i, writefds)) {
12648046Sjb				data.fds[pfd_index].events |= POLLWRNORM;
12713546Sjulian			}
12848046Sjb			if (data.fds[pfd_index].events != 0) {
12948046Sjb				/*
13048046Sjb				 * Set the file descriptor to be polled and
13148046Sjb				 * clear revents in case of a timeout which
13248046Sjb				 * leaves fds unchanged:
13348046Sjb				 */
13448046Sjb				data.fds[pfd_index].fd = i;
13548046Sjb				data.fds[pfd_index].revents = 0;
13648046Sjb				pfd_index--;
13748046Sjb			}
13848046Sjb		}
13948046Sjb		if (((ret = _thread_sys_poll(data.fds, data.nfds, 0)) == 0) &&
14048046Sjb		   (f_wait != 0)) {
14148046Sjb			_thread_run->data.poll_data = &data;
14235509Sjb			_thread_run->interrupted = 0;
14313546Sjulian			_thread_kern_sched_state(PS_SELECT_WAIT, __FILE__, __LINE__);
14435509Sjb			if (_thread_run->interrupted) {
14535509Sjb				errno = EINTR;
14648046Sjb				data.nfds = 0;
14735509Sjb				ret = -1;
14835509Sjb			} else
14935509Sjb				ret = data.nfds;
15013546Sjulian		}
15113546Sjulian	}
15213546Sjulian
15336904Sjb	if (ret >= 0) {
15448046Sjb		numfds = 0;
15548046Sjb		for (i = 0; i < fd_count; i++) {
15648046Sjb			/*
15748046Sjb			 * Check the results of the poll and clear
15848046Sjb			 * this file descriptor from the fdset if
15948046Sjb			 * the requested event wasn't ready.
16048046Sjb			 */
16148046Sjb			got_one = 0;
16248046Sjb			if (readfds != NULL) {
16348046Sjb				if (FD_ISSET(data.fds[i].fd, readfds)) {
16448046Sjb					if (data.fds[i].revents & (POLLIN |
16548046Sjb					    POLLRDNORM))
16648046Sjb						got_one = 1;
16748046Sjb					else
16848046Sjb						FD_CLR(data.fds[i].fd, readfds);
16913546Sjulian				}
17013546Sjulian			}
17148046Sjb			if (writefds != NULL) {
17248046Sjb				if (FD_ISSET(data.fds[i].fd, writefds)) {
17348046Sjb					if (data.fds[i].revents & (POLLOUT |
17448046Sjb					    POLLWRNORM | POLLWRBAND))
17548046Sjb						got_one = 1;
17648046Sjb					else
17748046Sjb						FD_CLR(data.fds[i].fd,
17848046Sjb						    writefds);
17913546Sjulian				}
18013546Sjulian			}
18148046Sjb			if (exceptfds != NULL) {
18248046Sjb				if (FD_ISSET(data.fds[i].fd, exceptfds)) {
18348046Sjb					if (data.fds[i].revents & (POLLRDBAND |
18448046Sjb					    POLLPRI | POLLHUP | POLLERR |
18548046Sjb					    POLLNVAL))
18648046Sjb						got_one = 1;
18748046Sjb					else
18848046Sjb						FD_CLR(data.fds[i].fd,
18948046Sjb						    exceptfds);
19013546Sjulian				}
19113546Sjulian			}
19248046Sjb			if (got_one)
19348046Sjb				numfds++;
19413546Sjulian		}
19548046Sjb		ret = numfds;
19613546Sjulian	}
19713546Sjulian
19813546Sjulian	return (ret);
19913546Sjulian}
20013546Sjulian#endif
201