diff options
author | Ron Yorston <rmy@pobox.com> | 2012-03-30 12:28:32 +0100 |
---|---|---|
committer | Ron Yorston <rmy@pobox.com> | 2012-03-30 12:28:32 +0100 |
commit | d1efee49c1a0f7d1ad7eabd9065dc3098a3d4b1d (patch) | |
tree | af2c57383a49dc620920482500d2f8120e376f0a | |
parent | 800c3f176fb21e30fbaa81ef68f50e601ea2f78b (diff) | |
download | busybox-w32-d1efee49c1a0f7d1ad7eabd9065dc3098a3d4b1d.tar.gz busybox-w32-d1efee49c1a0f7d1ad7eabd9065dc3098a3d4b1d.tar.bz2 busybox-w32-d1efee49c1a0f7d1ad7eabd9065dc3098a3d4b1d.zip |
Use gnulib poll, importing the version from git
-rw-r--r-- | include/mingw.h | 14 | ||||
-rw-r--r-- | win32/Kbuild | 1 | ||||
-rw-r--r-- | win32/mingw.c | 69 | ||||
-rw-r--r-- | win32/poll.c | 606 | ||||
-rw-r--r-- | win32/sys/poll.h | 53 |
5 files changed, 660 insertions, 83 deletions
diff --git a/include/mingw.h b/include/mingw.h index 69bf05574..33f83e3ab 100644 --- a/include/mingw.h +++ b/include/mingw.h | |||
@@ -64,20 +64,6 @@ struct sockaddr_un { | |||
64 | }; | 64 | }; |
65 | 65 | ||
66 | /* | 66 | /* |
67 | * poll.h | ||
68 | */ | ||
69 | struct pollfd { | ||
70 | int fd; /* file descriptor */ | ||
71 | short events; /* requested events */ | ||
72 | short revents; /* returned events */ | ||
73 | }; | ||
74 | typedef unsigned long nfds_t; | ||
75 | #define POLLIN 1 | ||
76 | #define POLLHUP 2 | ||
77 | |||
78 | int poll(struct pollfd *ufds, unsigned int nfds, int timeout); | ||
79 | |||
80 | /* | ||
81 | * pwd.h | 67 | * pwd.h |
82 | */ | 68 | */ |
83 | struct passwd { | 69 | struct passwd { |
diff --git a/win32/Kbuild b/win32/Kbuild index ef3af7458..3b06e83a7 100644 --- a/win32/Kbuild +++ b/win32/Kbuild | |||
@@ -10,6 +10,7 @@ lib-$(CONFIG_PLATFORM_MINGW32) += mingw.o | |||
10 | lib-$(CONFIG_PLATFORM_MINGW32) += process.o | 10 | lib-$(CONFIG_PLATFORM_MINGW32) += process.o |
11 | lib-$(CONFIG_PLATFORM_MINGW32) += regex.o | 11 | lib-$(CONFIG_PLATFORM_MINGW32) += regex.o |
12 | lib-$(CONFIG_WIN32_NET) += net.o | 12 | lib-$(CONFIG_WIN32_NET) += net.o |
13 | lib-$(CONFIG_PLATFORM_MINGW32) += poll.o | ||
13 | lib-$(CONFIG_PLATFORM_MINGW32) += termios.o | 14 | lib-$(CONFIG_PLATFORM_MINGW32) += termios.o |
14 | lib-$(CONFIG_PLATFORM_MINGW32) += uname.o | 15 | lib-$(CONFIG_PLATFORM_MINGW32) += uname.o |
15 | lib-$(CONFIG_PLATFORM_MINGW32) += winansi.o | 16 | lib-$(CONFIG_PLATFORM_MINGW32) += winansi.o |
diff --git a/win32/mingw.c b/win32/mingw.c index 0a7345374..df413d18e 100644 --- a/win32/mingw.c +++ b/win32/mingw.c | |||
@@ -421,75 +421,6 @@ int pipe(int filedes[2]) | |||
421 | return 0; | 421 | return 0; |
422 | } | 422 | } |
423 | 423 | ||
424 | int poll(struct pollfd *ufds, unsigned int nfds, int timeout) | ||
425 | { | ||
426 | int i, pending; | ||
427 | |||
428 | if (timeout >= 0) { | ||
429 | if (nfds == 0) { | ||
430 | Sleep(timeout); | ||
431 | return 0; | ||
432 | } | ||
433 | errno = EINVAL; | ||
434 | return -1; | ||
435 | } | ||
436 | |||
437 | /* When there is only one fd to wait for, then we pretend that | ||
438 | * input is available and let the actual wait happen when the | ||
439 | * caller invokes read(). | ||
440 | */ | ||
441 | if (nfds == 1) { | ||
442 | if (!(ufds[0].events & POLLIN)) { | ||
443 | errno = EINVAL; | ||
444 | return -1; | ||
445 | } | ||
446 | ufds[0].revents = POLLIN; | ||
447 | return 0; | ||
448 | } | ||
449 | |||
450 | repeat: | ||
451 | pending = 0; | ||
452 | for (i = 0; i < nfds; i++) { | ||
453 | DWORD avail = 0; | ||
454 | HANDLE h = (HANDLE) _get_osfhandle(ufds[i].fd); | ||
455 | if (h == INVALID_HANDLE_VALUE) | ||
456 | return -1; /* errno was set */ | ||
457 | |||
458 | if (!(ufds[i].events & POLLIN)) { | ||
459 | errno = EINVAL; | ||
460 | return -1; | ||
461 | } | ||
462 | |||
463 | /* this emulation works only for pipes */ | ||
464 | if (!PeekNamedPipe(h, NULL, 0, NULL, &avail, NULL)) { | ||
465 | int err = GetLastError(); | ||
466 | if (err == ERROR_BROKEN_PIPE) { | ||
467 | ufds[i].revents = POLLHUP; | ||
468 | pending++; | ||
469 | } else { | ||
470 | errno = EINVAL; | ||
471 | return -1; | ||
472 | } | ||
473 | } else if (avail) { | ||
474 | ufds[i].revents = POLLIN; | ||
475 | pending++; | ||
476 | } else | ||
477 | ufds[i].revents = 0; | ||
478 | } | ||
479 | if (!pending) { | ||
480 | /* The only times that we spin here is when the process | ||
481 | * that is connected through the pipes is waiting for | ||
482 | * its own input data to become available. But since | ||
483 | * the process (pack-objects) is itself CPU intensive, | ||
484 | * it will happily pick up the time slice that we are | ||
485 | * relinguishing here. | ||
486 | */ | ||
487 | Sleep(0); | ||
488 | goto repeat; | ||
489 | } | ||
490 | return 0; | ||
491 | } | ||
492 | |||
493 | struct tm *gmtime_r(const time_t *timep, struct tm *result) | 424 | struct tm *gmtime_r(const time_t *timep, struct tm *result) |
494 | { | 425 | { |
495 | /* gmtime() in MSVCRT.DLL is thread-safe, but not reentrant */ | 426 | /* gmtime() in MSVCRT.DLL is thread-safe, but not reentrant */ |
diff --git a/win32/poll.c b/win32/poll.c new file mode 100644 index 000000000..4438305ce --- /dev/null +++ b/win32/poll.c | |||
@@ -0,0 +1,606 @@ | |||
1 | /* Emulation for poll(2) | ||
2 | Contributed by Paolo Bonzini. | ||
3 | |||
4 | Copyright 2001-2003, 2006-2011 Free Software Foundation, Inc. | ||
5 | |||
6 | This file is part of gnulib. | ||
7 | |||
8 | This program is free software; you can redistribute it and/or modify | ||
9 | it under the terms of the GNU General Public License as published by | ||
10 | the Free Software Foundation; either version 2, or (at your option) | ||
11 | any later version. | ||
12 | |||
13 | This program is distributed in the hope that it will be useful, | ||
14 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
15 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
16 | GNU General Public License for more details. | ||
17 | |||
18 | You should have received a copy of the GNU General Public License along | ||
19 | with this program; if not, write to the Free Software Foundation, | ||
20 | Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ | ||
21 | |||
22 | /* Tell gcc not to warn about the (nfd < 0) tests, below. */ | ||
23 | #if (__GNUC__ == 4 && 3 <= __GNUC_MINOR__) || 4 < __GNUC__ | ||
24 | # pragma GCC diagnostic ignored "-Wtype-limits" | ||
25 | #endif | ||
26 | |||
27 | #include <malloc.h> | ||
28 | |||
29 | #include <sys/types.h> | ||
30 | |||
31 | /* Specification. */ | ||
32 | #include <sys/poll.h> | ||
33 | |||
34 | #include <errno.h> | ||
35 | #include <limits.h> | ||
36 | #include <assert.h> | ||
37 | |||
38 | #if (defined _WIN32 || defined __WIN32__) && ! defined __CYGWIN__ | ||
39 | # define WIN32_NATIVE | ||
40 | # if defined (_MSC_VER) | ||
41 | # define _WIN32_WINNT 0x0502 | ||
42 | # endif | ||
43 | # include <winsock2.h> | ||
44 | # include <windows.h> | ||
45 | # include <io.h> | ||
46 | # include <stdio.h> | ||
47 | # include <conio.h> | ||
48 | #else | ||
49 | # include <sys/time.h> | ||
50 | # include <sys/socket.h> | ||
51 | # include <sys/select.h> | ||
52 | # include <unistd.h> | ||
53 | #endif | ||
54 | |||
55 | #ifdef HAVE_SYS_IOCTL_H | ||
56 | # include <sys/ioctl.h> | ||
57 | #endif | ||
58 | #ifdef HAVE_SYS_FILIO_H | ||
59 | # include <sys/filio.h> | ||
60 | #endif | ||
61 | |||
62 | #include <time.h> | ||
63 | |||
64 | #ifndef INFTIM | ||
65 | # define INFTIM (-1) | ||
66 | #endif | ||
67 | |||
68 | /* BeOS does not have MSG_PEEK. */ | ||
69 | #ifndef MSG_PEEK | ||
70 | # define MSG_PEEK 0 | ||
71 | #endif | ||
72 | |||
73 | #ifdef WIN32_NATIVE | ||
74 | |||
75 | #define IsConsoleHandle(h) (((long) (h) & 3) == 3) | ||
76 | |||
77 | static BOOL | ||
78 | IsSocketHandle (HANDLE h) | ||
79 | { | ||
80 | WSANETWORKEVENTS ev; | ||
81 | |||
82 | if (IsConsoleHandle (h)) | ||
83 | return FALSE; | ||
84 | |||
85 | /* Under Wine, it seems that getsockopt returns 0 for pipes too. | ||
86 | WSAEnumNetworkEvents instead distinguishes the two correctly. */ | ||
87 | ev.lNetworkEvents = 0xDEADBEEF; | ||
88 | WSAEnumNetworkEvents ((SOCKET) h, NULL, &ev); | ||
89 | return ev.lNetworkEvents != 0xDEADBEEF; | ||
90 | } | ||
91 | |||
92 | /* Declare data structures for ntdll functions. */ | ||
93 | typedef struct _FILE_PIPE_LOCAL_INFORMATION { | ||
94 | ULONG NamedPipeType; | ||
95 | ULONG NamedPipeConfiguration; | ||
96 | ULONG MaximumInstances; | ||
97 | ULONG CurrentInstances; | ||
98 | ULONG InboundQuota; | ||
99 | ULONG ReadDataAvailable; | ||
100 | ULONG OutboundQuota; | ||
101 | ULONG WriteQuotaAvailable; | ||
102 | ULONG NamedPipeState; | ||
103 | ULONG NamedPipeEnd; | ||
104 | } FILE_PIPE_LOCAL_INFORMATION, *PFILE_PIPE_LOCAL_INFORMATION; | ||
105 | |||
106 | typedef struct _IO_STATUS_BLOCK | ||
107 | { | ||
108 | union { | ||
109 | DWORD Status; | ||
110 | PVOID Pointer; | ||
111 | } u; | ||
112 | ULONG_PTR Information; | ||
113 | } IO_STATUS_BLOCK, *PIO_STATUS_BLOCK; | ||
114 | |||
115 | typedef enum _FILE_INFORMATION_CLASS { | ||
116 | FilePipeLocalInformation = 24 | ||
117 | } FILE_INFORMATION_CLASS, *PFILE_INFORMATION_CLASS; | ||
118 | |||
119 | typedef DWORD (WINAPI *PNtQueryInformationFile) | ||
120 | (HANDLE, IO_STATUS_BLOCK *, VOID *, ULONG, FILE_INFORMATION_CLASS); | ||
121 | |||
122 | # ifndef PIPE_BUF | ||
123 | # define PIPE_BUF 512 | ||
124 | # endif | ||
125 | |||
126 | /* Compute revents values for file handle H. If some events cannot happen | ||
127 | for the handle, eliminate them from *P_SOUGHT. */ | ||
128 | |||
129 | static int | ||
130 | win32_compute_revents (HANDLE h, int *p_sought) | ||
131 | { | ||
132 | int i, ret, happened; | ||
133 | INPUT_RECORD *irbuffer; | ||
134 | DWORD avail, nbuffer; | ||
135 | BOOL bRet; | ||
136 | IO_STATUS_BLOCK iosb; | ||
137 | FILE_PIPE_LOCAL_INFORMATION fpli; | ||
138 | static PNtQueryInformationFile NtQueryInformationFile; | ||
139 | static BOOL once_only; | ||
140 | |||
141 | switch (GetFileType (h)) | ||
142 | { | ||
143 | case FILE_TYPE_PIPE: | ||
144 | if (!once_only) | ||
145 | { | ||
146 | NtQueryInformationFile = (PNtQueryInformationFile) | ||
147 | GetProcAddress (GetModuleHandle ("ntdll.dll"), | ||
148 | "NtQueryInformationFile"); | ||
149 | once_only = TRUE; | ||
150 | } | ||
151 | |||
152 | happened = 0; | ||
153 | if (PeekNamedPipe (h, NULL, 0, NULL, &avail, NULL) != 0) | ||
154 | { | ||
155 | if (avail) | ||
156 | happened |= *p_sought & (POLLIN | POLLRDNORM); | ||
157 | } | ||
158 | else if (GetLastError () == ERROR_BROKEN_PIPE) | ||
159 | happened |= POLLHUP; | ||
160 | |||
161 | else | ||
162 | { | ||
163 | /* It was the write-end of the pipe. Check if it is writable. | ||
164 | If NtQueryInformationFile fails, optimistically assume the pipe is | ||
165 | writable. This could happen on Win9x, where NtQueryInformationFile | ||
166 | is not available, or if we inherit a pipe that doesn't permit | ||
167 | FILE_READ_ATTRIBUTES access on the write end (I think this should | ||
168 | not happen since WinXP SP2; WINE seems fine too). Otherwise, | ||
169 | ensure that enough space is available for atomic writes. */ | ||
170 | memset (&iosb, 0, sizeof (iosb)); | ||
171 | memset (&fpli, 0, sizeof (fpli)); | ||
172 | |||
173 | if (!NtQueryInformationFile | ||
174 | || NtQueryInformationFile (h, &iosb, &fpli, sizeof (fpli), | ||
175 | FilePipeLocalInformation) | ||
176 | || fpli.WriteQuotaAvailable >= PIPE_BUF | ||
177 | || (fpli.OutboundQuota < PIPE_BUF && | ||
178 | fpli.WriteQuotaAvailable == fpli.OutboundQuota)) | ||
179 | happened |= *p_sought & (POLLOUT | POLLWRNORM | POLLWRBAND); | ||
180 | } | ||
181 | return happened; | ||
182 | |||
183 | case FILE_TYPE_CHAR: | ||
184 | ret = WaitForSingleObject (h, 0); | ||
185 | if (!IsConsoleHandle (h)) | ||
186 | return ret == WAIT_OBJECT_0 ? *p_sought & ~(POLLPRI | POLLRDBAND) : 0; | ||
187 | |||
188 | nbuffer = avail = 0; | ||
189 | bRet = GetNumberOfConsoleInputEvents (h, &nbuffer); | ||
190 | if (bRet) | ||
191 | { | ||
192 | /* Input buffer. */ | ||
193 | *p_sought &= POLLIN | POLLRDNORM; | ||
194 | if (nbuffer == 0) | ||
195 | return POLLHUP; | ||
196 | if (!*p_sought) | ||
197 | return 0; | ||
198 | |||
199 | irbuffer = (INPUT_RECORD *) alloca (nbuffer * sizeof (INPUT_RECORD)); | ||
200 | bRet = PeekConsoleInput (h, irbuffer, nbuffer, &avail); | ||
201 | if (!bRet || avail == 0) | ||
202 | return POLLHUP; | ||
203 | |||
204 | for (i = 0; i < avail; i++) | ||
205 | if (irbuffer[i].EventType == KEY_EVENT) | ||
206 | return *p_sought; | ||
207 | return 0; | ||
208 | } | ||
209 | else | ||
210 | { | ||
211 | /* Screen buffer. */ | ||
212 | *p_sought &= POLLOUT | POLLWRNORM | POLLWRBAND; | ||
213 | return *p_sought; | ||
214 | } | ||
215 | |||
216 | default: | ||
217 | ret = WaitForSingleObject (h, 0); | ||
218 | if (ret == WAIT_OBJECT_0) | ||
219 | return *p_sought & ~(POLLPRI | POLLRDBAND); | ||
220 | |||
221 | return *p_sought & (POLLOUT | POLLWRNORM | POLLWRBAND); | ||
222 | } | ||
223 | } | ||
224 | |||
225 | /* Convert fd_sets returned by select into revents values. */ | ||
226 | |||
227 | static int | ||
228 | win32_compute_revents_socket (SOCKET h, int sought, long lNetworkEvents) | ||
229 | { | ||
230 | int happened = 0; | ||
231 | |||
232 | if ((lNetworkEvents & (FD_READ | FD_ACCEPT | FD_CLOSE)) == FD_ACCEPT) | ||
233 | happened |= (POLLIN | POLLRDNORM) & sought; | ||
234 | |||
235 | else if (lNetworkEvents & (FD_READ | FD_ACCEPT | FD_CLOSE)) | ||
236 | { | ||
237 | int r, error; | ||
238 | |||
239 | char data[64]; | ||
240 | WSASetLastError (0); | ||
241 | r = recv (h, data, sizeof (data), MSG_PEEK); | ||
242 | error = WSAGetLastError (); | ||
243 | WSASetLastError (0); | ||
244 | |||
245 | if (r > 0 || error == WSAENOTCONN) | ||
246 | happened |= (POLLIN | POLLRDNORM) & sought; | ||
247 | |||
248 | /* Distinguish hung-up sockets from other errors. */ | ||
249 | else if (r == 0 || error == WSAESHUTDOWN || error == WSAECONNRESET | ||
250 | || error == WSAECONNABORTED || error == WSAENETRESET) | ||
251 | happened |= POLLHUP; | ||
252 | |||
253 | else | ||
254 | happened |= POLLERR; | ||
255 | } | ||
256 | |||
257 | if (lNetworkEvents & (FD_WRITE | FD_CONNECT)) | ||
258 | happened |= (POLLOUT | POLLWRNORM | POLLWRBAND) & sought; | ||
259 | |||
260 | if (lNetworkEvents & FD_OOB) | ||
261 | happened |= (POLLPRI | POLLRDBAND) & sought; | ||
262 | |||
263 | return happened; | ||
264 | } | ||
265 | |||
266 | #else /* !MinGW */ | ||
267 | |||
268 | /* Convert select(2) returned fd_sets into poll(2) revents values. */ | ||
269 | static int | ||
270 | compute_revents (int fd, int sought, fd_set *rfds, fd_set *wfds, fd_set *efds) | ||
271 | { | ||
272 | int happened = 0; | ||
273 | if (FD_ISSET (fd, rfds)) | ||
274 | { | ||
275 | int r; | ||
276 | int socket_errno; | ||
277 | |||
278 | # if defined __MACH__ && defined __APPLE__ | ||
279 | /* There is a bug in Mac OS X that causes it to ignore MSG_PEEK | ||
280 | for some kinds of descriptors. Detect if this descriptor is a | ||
281 | connected socket, a server socket, or something else using a | ||
282 | 0-byte recv, and use ioctl(2) to detect POLLHUP. */ | ||
283 | r = recv (fd, NULL, 0, MSG_PEEK); | ||
284 | socket_errno = (r < 0) ? errno : 0; | ||
285 | if (r == 0 || socket_errno == ENOTSOCK) | ||
286 | ioctl (fd, FIONREAD, &r); | ||
287 | # else | ||
288 | char data[64]; | ||
289 | r = recv (fd, data, sizeof (data), MSG_PEEK); | ||
290 | socket_errno = (r < 0) ? errno : 0; | ||
291 | # endif | ||
292 | if (r == 0) | ||
293 | happened |= POLLHUP; | ||
294 | |||
295 | /* If the event happened on an unconnected server socket, | ||
296 | that's fine. */ | ||
297 | else if (r > 0 || ( /* (r == -1) && */ socket_errno == ENOTCONN)) | ||
298 | happened |= (POLLIN | POLLRDNORM) & sought; | ||
299 | |||
300 | /* Distinguish hung-up sockets from other errors. */ | ||
301 | else if (socket_errno == ESHUTDOWN || socket_errno == ECONNRESET | ||
302 | || socket_errno == ECONNABORTED || socket_errno == ENETRESET) | ||
303 | happened |= POLLHUP; | ||
304 | |||
305 | else | ||
306 | happened |= POLLERR; | ||
307 | } | ||
308 | |||
309 | if (FD_ISSET (fd, wfds)) | ||
310 | happened |= (POLLOUT | POLLWRNORM | POLLWRBAND) & sought; | ||
311 | |||
312 | if (FD_ISSET (fd, efds)) | ||
313 | happened |= (POLLPRI | POLLRDBAND) & sought; | ||
314 | |||
315 | return happened; | ||
316 | } | ||
317 | #endif /* !MinGW */ | ||
318 | |||
319 | int | ||
320 | poll (struct pollfd *pfd, nfds_t nfd, int timeout) | ||
321 | { | ||
322 | #ifndef WIN32_NATIVE | ||
323 | fd_set rfds, wfds, efds; | ||
324 | struct timeval tv; | ||
325 | struct timeval *ptv; | ||
326 | int maxfd, rc; | ||
327 | nfds_t i; | ||
328 | |||
329 | # ifdef _SC_OPEN_MAX | ||
330 | static int sc_open_max = -1; | ||
331 | |||
332 | if (nfd < 0 | ||
333 | || (nfd > sc_open_max | ||
334 | && (sc_open_max != -1 | ||
335 | || nfd > (sc_open_max = sysconf (_SC_OPEN_MAX))))) | ||
336 | { | ||
337 | errno = EINVAL; | ||
338 | return -1; | ||
339 | } | ||
340 | # else /* !_SC_OPEN_MAX */ | ||
341 | # ifdef OPEN_MAX | ||
342 | if (nfd < 0 || nfd > OPEN_MAX) | ||
343 | { | ||
344 | errno = EINVAL; | ||
345 | return -1; | ||
346 | } | ||
347 | # endif /* OPEN_MAX -- else, no check is needed */ | ||
348 | # endif /* !_SC_OPEN_MAX */ | ||
349 | |||
350 | /* EFAULT is not necessary to implement, but let's do it in the | ||
351 | simplest case. */ | ||
352 | if (!pfd) | ||
353 | { | ||
354 | errno = EFAULT; | ||
355 | return -1; | ||
356 | } | ||
357 | |||
358 | /* convert timeout number into a timeval structure */ | ||
359 | if (timeout == 0) | ||
360 | { | ||
361 | ptv = &tv; | ||
362 | ptv->tv_sec = 0; | ||
363 | ptv->tv_usec = 0; | ||
364 | } | ||
365 | else if (timeout > 0) | ||
366 | { | ||
367 | ptv = &tv; | ||
368 | ptv->tv_sec = timeout / 1000; | ||
369 | ptv->tv_usec = (timeout % 1000) * 1000; | ||
370 | } | ||
371 | else if (timeout == INFTIM) | ||
372 | /* wait forever */ | ||
373 | ptv = NULL; | ||
374 | else | ||
375 | { | ||
376 | errno = EINVAL; | ||
377 | return -1; | ||
378 | } | ||
379 | |||
380 | /* create fd sets and determine max fd */ | ||
381 | maxfd = -1; | ||
382 | FD_ZERO (&rfds); | ||
383 | FD_ZERO (&wfds); | ||
384 | FD_ZERO (&efds); | ||
385 | for (i = 0; i < nfd; i++) | ||
386 | { | ||
387 | if (pfd[i].fd < 0) | ||
388 | continue; | ||
389 | |||
390 | if (pfd[i].events & (POLLIN | POLLRDNORM)) | ||
391 | FD_SET (pfd[i].fd, &rfds); | ||
392 | |||
393 | /* see select(2): "the only exceptional condition detectable | ||
394 | is out-of-band data received on a socket", hence we push | ||
395 | POLLWRBAND events onto wfds instead of efds. */ | ||
396 | if (pfd[i].events & (POLLOUT | POLLWRNORM | POLLWRBAND)) | ||
397 | FD_SET (pfd[i].fd, &wfds); | ||
398 | if (pfd[i].events & (POLLPRI | POLLRDBAND)) | ||
399 | FD_SET (pfd[i].fd, &efds); | ||
400 | if (pfd[i].fd >= maxfd | ||
401 | && (pfd[i].events & (POLLIN | POLLOUT | POLLPRI | ||
402 | | POLLRDNORM | POLLRDBAND | ||
403 | | POLLWRNORM | POLLWRBAND))) | ||
404 | { | ||
405 | maxfd = pfd[i].fd; | ||
406 | if (maxfd > FD_SETSIZE) | ||
407 | { | ||
408 | errno = EOVERFLOW; | ||
409 | return -1; | ||
410 | } | ||
411 | } | ||
412 | } | ||
413 | |||
414 | /* examine fd sets */ | ||
415 | rc = select (maxfd + 1, &rfds, &wfds, &efds, ptv); | ||
416 | if (rc < 0) | ||
417 | return rc; | ||
418 | |||
419 | /* establish results */ | ||
420 | rc = 0; | ||
421 | for (i = 0; i < nfd; i++) | ||
422 | if (pfd[i].fd < 0) | ||
423 | pfd[i].revents = 0; | ||
424 | else | ||
425 | { | ||
426 | int happened = compute_revents (pfd[i].fd, pfd[i].events, | ||
427 | &rfds, &wfds, &efds); | ||
428 | if (happened) | ||
429 | { | ||
430 | pfd[i].revents = happened; | ||
431 | rc++; | ||
432 | } | ||
433 | } | ||
434 | |||
435 | return rc; | ||
436 | #else | ||
437 | static struct timeval tv0; | ||
438 | static HANDLE hEvent; | ||
439 | WSANETWORKEVENTS ev; | ||
440 | HANDLE h, handle_array[FD_SETSIZE + 2]; | ||
441 | DWORD ret, wait_timeout, nhandles; | ||
442 | fd_set rfds, wfds, xfds; | ||
443 | BOOL poll_again; | ||
444 | MSG msg; | ||
445 | int rc = 0; | ||
446 | nfds_t i; | ||
447 | |||
448 | if (nfd < 0 || timeout < -1) | ||
449 | { | ||
450 | errno = EINVAL; | ||
451 | return -1; | ||
452 | } | ||
453 | |||
454 | if (!hEvent) | ||
455 | hEvent = CreateEvent (NULL, FALSE, FALSE, NULL); | ||
456 | |||
457 | restart: | ||
458 | handle_array[0] = hEvent; | ||
459 | nhandles = 1; | ||
460 | FD_ZERO (&rfds); | ||
461 | FD_ZERO (&wfds); | ||
462 | FD_ZERO (&xfds); | ||
463 | |||
464 | /* Classify socket handles and create fd sets. */ | ||
465 | for (i = 0; i < nfd; i++) | ||
466 | { | ||
467 | int sought = pfd[i].events; | ||
468 | pfd[i].revents = 0; | ||
469 | if (pfd[i].fd < 0) | ||
470 | continue; | ||
471 | if (!(sought & (POLLIN | POLLRDNORM | POLLOUT | POLLWRNORM | POLLWRBAND | ||
472 | | POLLPRI | POLLRDBAND))) | ||
473 | continue; | ||
474 | |||
475 | h = (HANDLE) _get_osfhandle (pfd[i].fd); | ||
476 | assert (h != NULL); | ||
477 | if (IsSocketHandle (h)) | ||
478 | { | ||
479 | int requested = FD_CLOSE; | ||
480 | |||
481 | /* see above; socket handles are mapped onto select. */ | ||
482 | if (sought & (POLLIN | POLLRDNORM)) | ||
483 | { | ||
484 | requested |= FD_READ | FD_ACCEPT; | ||
485 | FD_SET ((SOCKET) h, &rfds); | ||
486 | } | ||
487 | if (sought & (POLLOUT | POLLWRNORM | POLLWRBAND)) | ||
488 | { | ||
489 | requested |= FD_WRITE | FD_CONNECT; | ||
490 | FD_SET ((SOCKET) h, &wfds); | ||
491 | } | ||
492 | if (sought & (POLLPRI | POLLRDBAND)) | ||
493 | { | ||
494 | requested |= FD_OOB; | ||
495 | FD_SET ((SOCKET) h, &xfds); | ||
496 | } | ||
497 | |||
498 | if (requested) | ||
499 | WSAEventSelect ((SOCKET) h, hEvent, requested); | ||
500 | } | ||
501 | else | ||
502 | { | ||
503 | /* Poll now. If we get an event, do not poll again. Also, | ||
504 | screen buffer handles are waitable, and they'll block until | ||
505 | a character is available. win32_compute_revents eliminates | ||
506 | bits for the "wrong" direction. */ | ||
507 | pfd[i].revents = win32_compute_revents (h, &sought); | ||
508 | if (sought) | ||
509 | handle_array[nhandles++] = h; | ||
510 | if (pfd[i].revents) | ||
511 | timeout = 0; | ||
512 | } | ||
513 | } | ||
514 | |||
515 | if (select (0, &rfds, &wfds, &xfds, &tv0) > 0) | ||
516 | { | ||
517 | /* Do MsgWaitForMultipleObjects anyway to dispatch messages, but | ||
518 | no need to call select again. */ | ||
519 | poll_again = FALSE; | ||
520 | wait_timeout = 0; | ||
521 | } | ||
522 | else | ||
523 | { | ||
524 | poll_again = TRUE; | ||
525 | if (timeout == INFTIM) | ||
526 | wait_timeout = INFINITE; | ||
527 | else | ||
528 | wait_timeout = timeout; | ||
529 | } | ||
530 | |||
531 | for (;;) | ||
532 | { | ||
533 | ret = MsgWaitForMultipleObjects (nhandles, handle_array, FALSE, | ||
534 | wait_timeout, QS_ALLINPUT); | ||
535 | |||
536 | if (ret == WAIT_OBJECT_0 + nhandles) | ||
537 | { | ||
538 | /* new input of some other kind */ | ||
539 | BOOL bRet; | ||
540 | while ((bRet = PeekMessage (&msg, NULL, 0, 0, PM_REMOVE)) != 0) | ||
541 | { | ||
542 | TranslateMessage (&msg); | ||
543 | DispatchMessage (&msg); | ||
544 | } | ||
545 | } | ||
546 | else | ||
547 | break; | ||
548 | } | ||
549 | |||
550 | if (poll_again) | ||
551 | select (0, &rfds, &wfds, &xfds, &tv0); | ||
552 | |||
553 | /* Place a sentinel at the end of the array. */ | ||
554 | handle_array[nhandles] = NULL; | ||
555 | nhandles = 1; | ||
556 | for (i = 0; i < nfd; i++) | ||
557 | { | ||
558 | int happened; | ||
559 | |||
560 | if (pfd[i].fd < 0) | ||
561 | continue; | ||
562 | if (!(pfd[i].events & (POLLIN | POLLRDNORM | | ||
563 | POLLOUT | POLLWRNORM | POLLWRBAND))) | ||
564 | continue; | ||
565 | |||
566 | h = (HANDLE) _get_osfhandle (pfd[i].fd); | ||
567 | if (h != handle_array[nhandles]) | ||
568 | { | ||
569 | /* It's a socket. */ | ||
570 | WSAEnumNetworkEvents ((SOCKET) h, NULL, &ev); | ||
571 | WSAEventSelect ((SOCKET) h, 0, 0); | ||
572 | |||
573 | /* If we're lucky, WSAEnumNetworkEvents already provided a way | ||
574 | to distinguish FD_READ and FD_ACCEPT; this saves a recv later. */ | ||
575 | if (FD_ISSET ((SOCKET) h, &rfds) | ||
576 | && !(ev.lNetworkEvents & (FD_READ | FD_ACCEPT))) | ||
577 | ev.lNetworkEvents |= FD_READ | FD_ACCEPT; | ||
578 | if (FD_ISSET ((SOCKET) h, &wfds)) | ||
579 | ev.lNetworkEvents |= FD_WRITE | FD_CONNECT; | ||
580 | if (FD_ISSET ((SOCKET) h, &xfds)) | ||
581 | ev.lNetworkEvents |= FD_OOB; | ||
582 | |||
583 | happened = win32_compute_revents_socket ((SOCKET) h, pfd[i].events, | ||
584 | ev.lNetworkEvents); | ||
585 | } | ||
586 | else | ||
587 | { | ||
588 | /* Not a socket. */ | ||
589 | int sought = pfd[i].events; | ||
590 | happened = win32_compute_revents (h, &sought); | ||
591 | nhandles++; | ||
592 | } | ||
593 | |||
594 | if ((pfd[i].revents |= happened) != 0) | ||
595 | rc++; | ||
596 | } | ||
597 | |||
598 | if (!rc && timeout == INFTIM) | ||
599 | { | ||
600 | SwitchToThread(); | ||
601 | goto restart; | ||
602 | } | ||
603 | |||
604 | return rc; | ||
605 | #endif | ||
606 | } | ||
diff --git a/win32/sys/poll.h b/win32/sys/poll.h index e69de29bb..b7aa59d97 100644 --- a/win32/sys/poll.h +++ b/win32/sys/poll.h | |||
@@ -0,0 +1,53 @@ | |||
1 | /* Header for poll(2) emulation | ||
2 | Contributed by Paolo Bonzini. | ||
3 | |||
4 | Copyright 2001, 2002, 2003, 2007, 2009, 2010 Free Software Foundation, Inc. | ||
5 | |||
6 | This file is part of gnulib. | ||
7 | |||
8 | This program is free software; you can redistribute it and/or modify | ||
9 | it under the terms of the GNU General Public License as published by | ||
10 | the Free Software Foundation; either version 2, or (at your option) | ||
11 | any later version. | ||
12 | |||
13 | This program is distributed in the hope that it will be useful, | ||
14 | but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
15 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
16 | GNU General Public License for more details. | ||
17 | |||
18 | You should have received a copy of the GNU General Public License along | ||
19 | with this program; if not, write to the Free Software Foundation, | ||
20 | Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ | ||
21 | |||
22 | #ifndef _GL_POLL_H | ||
23 | #define _GL_POLL_H | ||
24 | |||
25 | /* fake a poll(2) environment */ | ||
26 | #define POLLIN 0x0001 /* any readable data available */ | ||
27 | #define POLLPRI 0x0002 /* OOB/Urgent readable data */ | ||
28 | #define POLLOUT 0x0004 /* file descriptor is writeable */ | ||
29 | #define POLLERR 0x0008 /* some poll error occurred */ | ||
30 | #define POLLHUP 0x0010 /* file descriptor was "hung up" */ | ||
31 | #define POLLNVAL 0x0020 /* requested events "invalid" */ | ||
32 | #define POLLRDNORM 0x0040 | ||
33 | #define POLLRDBAND 0x0080 | ||
34 | #define POLLWRNORM 0x0100 | ||
35 | #define POLLWRBAND 0x0200 | ||
36 | |||
37 | struct pollfd | ||
38 | { | ||
39 | int fd; /* which file descriptor to poll */ | ||
40 | short events; /* events we are interested in */ | ||
41 | short revents; /* events found on return */ | ||
42 | }; | ||
43 | |||
44 | typedef unsigned long nfds_t; | ||
45 | |||
46 | extern int poll (struct pollfd *pfd, nfds_t nfd, int timeout); | ||
47 | |||
48 | /* Define INFTIM only if doing so conforms to POSIX. */ | ||
49 | #if !defined (_POSIX_C_SOURCE) && !defined (_XOPEN_SOURCE) | ||
50 | #define INFTIM (-1) | ||
51 | #endif | ||
52 | |||
53 | #endif /* _GL_POLL_H */ | ||