summaryrefslogtreecommitdiff
path: root/config/os/macosx/poll.h
blob: d7445c7591a14f40e4561b7b7bce83089fab48d3 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165

// fakepoll.h
// poll using select
// Warning: a call to this poll() takes about 4K of stack space.

// Greg Parker     gparker-web@sealiesoftware.com     December 2000
// This code is in the public domain and may be copied or modified without
// permission.

// Updated May 2002:
// * fix crash when an fd is less than 0
// * set errno=EINVAL if an fd is greater or equal to FD_SETSIZE
// * don't set POLLIN or POLLOUT in revents if it wasn't requested
//   in events (only happens when an fd is in the poll set twice)

#ifndef _FAKE_POLL_H
#define _FAKE_POLL_H

#include <limits.h>
#include <sys/types.h>
#include <sys/time.h>
#include <unistd.h>
#include <stdlib.h>
#include <errno.h>

typedef struct pollfd {
	int fd;                         /* file desc to poll */
	short events;                   /* events of interest on fd */
	short revents;                  /* events that occurred on fd */
} pollfd_t;


// poll flags
#define POLLIN  0x0001
#define POLLOUT 0x0004
#define POLLERR 0x0008

// synonyms
#define POLLNORM POLLIN
#define POLLPRI POLLIN
#define POLLRDNORM POLLIN
#define POLLRDBAND POLLIN
#define POLLWRNORM POLLOUT
#define POLLWRBAND POLLOUT

// ignored
#define POLLHUP 0x0010
#define POLLNVAL 0x0020

static inline int
poll (struct pollfd *pollSet, int pollCount, int pollTimeout)
{
	struct timeval tv;
	struct timeval *tvp;
	fd_set readFDs, writeFDs, exceptFDs;
	fd_set *readp, *writep, *exceptp;
	struct pollfd *pollEnd, *p;
	int selected;
	int result;
	int maxFD;

	if (!pollSet) {
		pollEnd = NULL;
		readp = NULL;
		writep = NULL;
		exceptp = NULL;
		maxFD = 0;
	} else {
		pollEnd = pollSet + pollCount;
		readp = &readFDs;
		writep = &writeFDs;
		exceptp = &exceptFDs;

		FD_ZERO (readp);
		FD_ZERO (writep);
		FD_ZERO (exceptp);

		// Find the biggest fd in the poll set
		maxFD = 0;
		for (p = pollSet; p < pollEnd; p++)
			if (p->fd > maxFD) {
				maxFD = p->fd;
			}

		if (maxFD >= FD_SETSIZE) {
			// At least one fd is too big
			errno = EINVAL;
			return -1;
		}

		// Transcribe flags from the poll set to the fd sets
		for (p = pollSet; p < pollEnd; p++) {
			if (p->fd < 0) {
				// Negative fd checks nothing and always reports zero
			} else {
				if (p->events & POLLIN) {
					FD_SET (p->fd, readp);
				}
				if (p->events & POLLOUT) {
					FD_SET (p->fd, writep);
				}
				if (p->events != 0) {
					FD_SET (p->fd, exceptp);
				}
				// POLLERR is never set coming in; poll() always reports errors
				// But don't report if we're not listening to anything at all.
			}
		}
	}

	// poll timeout is in milliseconds. Convert to struct timeval.
	// poll timeout == -1 : wait forever : select timeout of NULL
	// poll timeout == 0  : return immediately : select timeout of zero
	if (pollTimeout >= 0) {
		tv.tv_sec = pollTimeout / 1000;
		tv.tv_usec = (pollTimeout % 1000) * 1000;
		tvp = &tv;
	} else {
		tvp = NULL;
	}

	selected = select (maxFD + 1, readp, writep, exceptp, tvp);

	if (selected < 0) {
		// Error during select
		result = -1;
	} else if (selected > 0) {
		// Select found something
		// Transcribe result from fd sets to poll set.
		// Also count the number of selected fds. poll returns the
		// number of ready fds; select returns the number of bits set.
		int polled = 0;
		for (p = pollSet; p < pollEnd; p++) {
			p->revents = 0;
			if (p->fd < 0) {
				// Negative fd always reports zero
			} else {
				if ((p->events & POLLIN)  &&  FD_ISSET (p->fd, readp)) {
					p->revents |= POLLIN;
				}
				if ((p->events & POLLOUT)  &&  FD_ISSET (p->fd, writep)) {
					p->revents |= POLLOUT;
				}
				if ((p->events != 0)  &&  FD_ISSET (p->fd, exceptp)) {
					p->revents |= POLLERR;
				}

				if (p->revents) {
					polled++;
				}
			}
		}
		result = polled;
	} else {
		// selected == 0, select timed out before anything happened
		// Clear all result bits and return zero.
		for (p = pollSet; p < pollEnd; p++)
			p->revents = 0;
		result = 0;
	}

	return result;
}

#endif