Code

Windows: A rudimentary poll() emulation.
authorJohannes Sixt <johannes.sixt@telecom.at>
Sat, 1 Dec 2007 21:00:56 +0000 (22:00 +0100)
committerJohannes Sixt <johannes.sixt@telecom.at>
Thu, 26 Jun 2008 06:45:07 +0000 (08:45 +0200)
This emulation of poll() is by far not general. It assumes that the
fds that are to be waited for are connected to pipes. The pipes are
polled in a loop until data becomes available in at least one of them.
If only a single fd is waited for, the implementation actually does
not wait at all, but assumes that a subsequent read() will block.

In order not to needlessly burn CPU time, the CPU is yielded to other
processes before the next round in the poll loop using Sleep(0). Note that
any sleep timeout greater than zero will reduce the efficiency by a
magnitude.

Signed-off-by: Johannes Sixt <johannes.sixt@telecom.at>
compat/mingw.c

index 7f89a6cb87e4457c8ff017b25d4736732455aaa1..2677e78626f9a618d2b17b112c6b58ca1f5f0394 100644 (file)
@@ -101,7 +101,62 @@ int pipe(int filedes[2])
 
 int poll(struct pollfd *ufds, unsigned int nfds, int timeout)
 {
-       return -1;
+       int i, pending;
+
+       if (timeout != -1)
+               return errno = EINVAL, error("poll timeout not supported");
+
+       /* When there is only one fd to wait for, then we pretend that
+        * input is available and let the actual wait happen when the
+        * caller invokes read().
+        */
+       if (nfds == 1) {
+               if (!(ufds[0].events & POLLIN))
+                       return errno = EINVAL, error("POLLIN not set");
+               ufds[0].revents = POLLIN;
+               return 0;
+       }
+
+repeat:
+       pending = 0;
+       for (i = 0; i < nfds; i++) {
+               DWORD avail = 0;
+               HANDLE h = (HANDLE) _get_osfhandle(ufds[i].fd);
+               if (h == INVALID_HANDLE_VALUE)
+                       return -1;      /* errno was set */
+
+               if (!(ufds[i].events & POLLIN))
+                       return errno = EINVAL, error("POLLIN not set");
+
+               /* this emulation works only for pipes */
+               if (!PeekNamedPipe(h, NULL, 0, NULL, &avail, NULL)) {
+                       int err = GetLastError();
+                       if (err == ERROR_BROKEN_PIPE) {
+                               ufds[i].revents = POLLHUP;
+                               pending++;
+                       } else {
+                               errno = EINVAL;
+                               return error("PeekNamedPipe failed,"
+                                       " GetLastError: %u", err);
+                       }
+               } else if (avail) {
+                       ufds[i].revents = POLLIN;
+                       pending++;
+               } else
+                       ufds[i].revents = 0;
+       }
+       if (!pending) {
+               /* The only times that we spin here is when the process
+                * that is connected through the pipes is waiting for
+                * its own input data to become available. But since
+                * the process (pack-objects) is itself CPU intensive,
+                * it will happily pick up the time slice that we are
+                * relinguishing here.
+                */
+               Sleep(0);
+               goto repeat;
+       }
+       return 0;
 }
 
 struct tm *gmtime_r(const time_t *timep, struct tm *result)