1263970Sdes/* $Id: bsd-poll.c,v 1.6 2014/02/05 23:44:13 dtucker Exp $ */
2180744Sdes
3180744Sdes/*
4180744Sdes * Copyright (c) 2004, 2005, 2007 Darren Tucker (dtucker at zip com au).
5180744Sdes *
6180744Sdes * Permission to use, copy, modify, and distribute this software for any
7180744Sdes * purpose with or without fee is hereby granted, provided that the above
8180744Sdes * copyright notice and this permission notice appear in all copies.
9180744Sdes *
10180744Sdes * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11180744Sdes * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12180744Sdes * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13180744Sdes * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14180744Sdes * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15180744Sdes * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16180744Sdes * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17180744Sdes */
18180744Sdes
19180744Sdes#include "includes.h"
20180746Sdes#if !defined(HAVE_POLL)
21180744Sdes
22263970Sdes#include <sys/types.h>
23263970Sdes#include <sys/time.h>
24180744Sdes#ifdef HAVE_SYS_SELECT_H
25180744Sdes# include <sys/select.h>
26180744Sdes#endif
27180744Sdes
28263970Sdes#include <errno.h>
29180750Sdes#include <stdlib.h>
30263970Sdes#include <unistd.h>
31180744Sdes#include "bsd-poll.h"
32180744Sdes
33180744Sdes/*
34180744Sdes * A minimal implementation of poll(2), built on top of select(2).
35180744Sdes *
36180744Sdes * Only supports POLLIN and POLLOUT flags in pfd.events, and POLLIN, POLLOUT
37180744Sdes * and POLLERR flags in revents.
38180744Sdes *
39180744Sdes * Supports pfd.fd = -1 meaning "unused" although it's not standard.
40180744Sdes */
41180744Sdes
42180744Sdesint
43180744Sdespoll(struct pollfd *fds, nfds_t nfds, int timeout)
44180744Sdes{
45180744Sdes	nfds_t i;
46180744Sdes	int saved_errno, ret, fd, maxfd = 0;
47180744Sdes	fd_set *readfds = NULL, *writefds = NULL, *exceptfds = NULL;
48180744Sdes	size_t nmemb;
49180744Sdes	struct timeval tv, *tvp = NULL;
50180744Sdes
51180744Sdes	for (i = 0; i < nfds; i++) {
52192595Sdes		fd = fds[i].fd;
53180744Sdes		if (fd >= FD_SETSIZE) {
54180744Sdes			errno = EINVAL;
55180744Sdes			return -1;
56180744Sdes		}
57192595Sdes		maxfd = MAX(maxfd, fd);
58180744Sdes	}
59180744Sdes
60180744Sdes	nmemb = howmany(maxfd + 1 , NFDBITS);
61180744Sdes	if ((readfds = calloc(nmemb, sizeof(fd_mask))) == NULL ||
62180744Sdes	    (writefds = calloc(nmemb, sizeof(fd_mask))) == NULL ||
63180744Sdes	    (exceptfds = calloc(nmemb, sizeof(fd_mask))) == NULL) {
64180744Sdes		saved_errno = ENOMEM;
65180744Sdes		ret = -1;
66180744Sdes		goto out;
67180744Sdes	}
68180744Sdes
69180744Sdes	/* populate event bit vectors for the events we're interested in */
70180744Sdes	for (i = 0; i < nfds; i++) {
71180744Sdes		fd = fds[i].fd;
72180744Sdes		if (fd == -1)
73180744Sdes			continue;
74180744Sdes		if (fds[i].events & POLLIN) {
75180744Sdes			FD_SET(fd, readfds);
76180744Sdes			FD_SET(fd, exceptfds);
77180744Sdes		}
78180744Sdes		if (fds[i].events & POLLOUT) {
79180744Sdes			FD_SET(fd, writefds);
80180744Sdes			FD_SET(fd, exceptfds);
81180744Sdes		}
82180744Sdes	}
83180744Sdes
84180744Sdes	/* poll timeout is msec, select is timeval (sec + usec) */
85180744Sdes	if (timeout >= 0) {
86180744Sdes		tv.tv_sec = timeout / 1000;
87180744Sdes		tv.tv_usec = (timeout % 1000) * 1000;
88180744Sdes		tvp = &tv;
89180744Sdes	}
90180744Sdes
91180744Sdes	ret = select(maxfd + 1, readfds, writefds, exceptfds, tvp);
92180744Sdes	saved_errno = errno;
93180744Sdes
94180744Sdes	/* scan through select results and set poll() flags */
95180744Sdes	for (i = 0; i < nfds; i++) {
96180744Sdes		fd = fds[i].fd;
97180744Sdes		fds[i].revents = 0;
98180744Sdes		if (fd == -1)
99180744Sdes			continue;
100180744Sdes		if (FD_ISSET(fd, readfds)) {
101180744Sdes			fds[i].revents |= POLLIN;
102180744Sdes		}
103180744Sdes		if (FD_ISSET(fd, writefds)) {
104180744Sdes			fds[i].revents |= POLLOUT;
105180744Sdes		}
106180744Sdes		if (FD_ISSET(fd, exceptfds)) {
107180744Sdes			fds[i].revents |= POLLERR;
108180744Sdes		}
109180744Sdes	}
110180744Sdes
111180744Sdesout:
112263970Sdes	free(readfds);
113263970Sdes	free(writefds);
114263970Sdes	free(exceptfds);
115180744Sdes	if (ret == -1)
116180744Sdes		errno = saved_errno;
117180744Sdes	return ret;
118180744Sdes}
119180744Sdes#endif
120