~drizzle-developers/drizzle/elliott-release

« back to all changes in this revision

Viewing changes to win32/poll.c

  • Committer: Patrick Crews
  • Date: 2011-02-01 20:33:06 UTC
  • mfrom: (1845.2.288 drizzle)
  • Revision ID: gleebix@gmail.com-20110201203306-mwq2rk0it81tlwxh
Merged Trunk

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* Emulation for poll(2)
 
2
   Contributed by Paolo Bonzini.
 
3
 
 
4
   Copyright 2001, 2002, 2003, 2006, 2007, 2008 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 Lesser 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 Lesser General Public License for more details.
 
17
 
 
18
   You should have received a copy of the GNU Lesser 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
#include <config.h>
 
23
#include <alloca.h>
 
24
 
 
25
#include <sys/types.h>
 
26
#include "poll.h"
 
27
#include <errno.h>
 
28
#include <limits.h>
 
29
#include <assert.h>
 
30
 
 
31
#if (defined _WIN32 || defined __WIN32__) && ! defined __CYGWIN__
 
32
#define WIN32_NATIVE
 
33
#include <winsock2.h>
 
34
#include <windows.h>
 
35
#include <io.h>
 
36
#include <stdio.h>
 
37
#include <conio.h>
 
38
#else
 
39
#include <sys/time.h>
 
40
#include <sys/socket.h>
 
41
#include <sys/select.h>
 
42
#include <unistd.h>
 
43
#endif
 
44
 
 
45
#ifdef HAVE_SYS_IOCTL_H
 
46
#include <sys/ioctl.h>
 
47
#endif
 
48
#ifdef HAVE_SYS_FILIO_H
 
49
#include <sys/filio.h>
 
50
#endif
 
51
 
 
52
#include <time.h>
 
53
 
 
54
#ifndef INFTIM
 
55
#define INFTIM (-1)
 
56
#endif
 
57
 
 
58
/* BeOS does not have MSG_PEEK.  */
 
59
#ifndef MSG_PEEK
 
60
#define MSG_PEEK 0
 
61
#endif
 
62
 
 
63
#ifdef WIN32_NATIVE
 
64
 
 
65
/* Declare data structures for ntdll functions.  */
 
66
typedef struct _FILE_PIPE_LOCAL_INFORMATION {
 
67
  ULONG NamedPipeType;
 
68
  ULONG NamedPipeConfiguration;
 
69
  ULONG MaximumInstances;
 
70
  ULONG CurrentInstances;
 
71
  ULONG InboundQuota;
 
72
  ULONG ReadDataAvailable;
 
73
  ULONG OutboundQuota;
 
74
  ULONG WriteQuotaAvailable;
 
75
  ULONG NamedPipeState;
 
76
  ULONG NamedPipeEnd;
 
77
} FILE_PIPE_LOCAL_INFORMATION, *PFILE_PIPE_LOCAL_INFORMATION;
 
78
 
 
79
typedef struct _IO_STATUS_BLOCK
 
80
{
 
81
  union {
 
82
    DWORD Status;
 
83
    PVOID Pointer;
 
84
  } u;
 
85
  ULONG_PTR Information;
 
86
} IO_STATUS_BLOCK, *PIO_STATUS_BLOCK;
 
87
 
 
88
typedef enum _FILE_INFORMATION_CLASS {
 
89
  FilePipeLocalInformation = 24
 
90
} FILE_INFORMATION_CLASS, *PFILE_INFORMATION_CLASS;
 
91
 
 
92
typedef DWORD (WINAPI *PNtQueryInformationFile)
 
93
         (HANDLE, IO_STATUS_BLOCK *, VOID *, ULONG, FILE_INFORMATION_CLASS);
 
94
 
 
95
#ifndef PIPE_BUF
 
96
#define PIPE_BUF        512
 
97
#endif
 
98
 
 
99
/* Compute revents values for file handle H.  */
 
100
 
 
101
static int
 
102
win32_compute_revents (HANDLE h, int sought)
 
103
{
 
104
  int ret, happened;
 
105
  unsigned i;
 
106
  INPUT_RECORD *irbuffer;
 
107
  DWORD avail, nbuffer;
 
108
  BOOL bRet;
 
109
  IO_STATUS_BLOCK iosb;
 
110
  FILE_PIPE_LOCAL_INFORMATION fpli;
 
111
  static PNtQueryInformationFile NtQueryInformationFile;
 
112
  static BOOL once_only;
 
113
 
 
114
  switch (GetFileType (h))
 
115
    {
 
116
    case FILE_TYPE_PIPE:
 
117
      if (!once_only)
 
118
        {
 
119
          NtQueryInformationFile = (PNtQueryInformationFile)
 
120
            GetProcAddress (GetModuleHandle ("ntdll.dll"),
 
121
                            "NtQueryInformationFile");
 
122
          once_only = TRUE;
 
123
        }
 
124
 
 
125
      happened = 0;
 
126
      if (PeekNamedPipe (h, NULL, 0, NULL, &avail, NULL) != 0)
 
127
        {
 
128
          if (avail)
 
129
            happened |= sought & (POLLIN | POLLRDNORM);
 
130
        }
 
131
 
 
132
      else
 
133
        {
 
134
          /* It was the write-end of the pipe.  Check if it is writable.
 
135
             If NtQueryInformationFile fails, optimistically assume the pipe is
 
136
             writable.  This could happen on Win9x, where NtQueryInformationFile
 
137
             is not available, or if we inherit a pipe that doesn't permit
 
138
             FILE_READ_ATTRIBUTES access on the write end (I think this should
 
139
             not happen since WinXP SP2; WINE seems fine too).  Otherwise,
 
140
             ensure that enough space is available for atomic writes.  */
 
141
          memset (&iosb, 0, sizeof (iosb));
 
142
          memset (&fpli, 0, sizeof (fpli));
 
143
 
 
144
          if (!NtQueryInformationFile
 
145
              || NtQueryInformationFile (h, &iosb, &fpli, sizeof (fpli),
 
146
                                         FilePipeLocalInformation)
 
147
              || fpli.WriteQuotaAvailable >= PIPE_BUF
 
148
              || (fpli.OutboundQuota < PIPE_BUF &&
 
149
                  fpli.WriteQuotaAvailable == fpli.OutboundQuota))
 
150
            happened |= sought & (POLLOUT | POLLWRNORM | POLLWRBAND);
 
151
        }
 
152
      return happened;
 
153
 
 
154
    case FILE_TYPE_CHAR:
 
155
      ret = WaitForSingleObject (h, 0);
 
156
      if (ret == WAIT_OBJECT_0)
 
157
        {
 
158
          nbuffer = avail = 0;
 
159
          bRet = GetNumberOfConsoleInputEvents (h, &nbuffer);
 
160
          if (!bRet || nbuffer == 0)
 
161
            return POLLHUP;
 
162
 
 
163
          irbuffer = (INPUT_RECORD *) alloca (nbuffer * sizeof (INPUT_RECORD));
 
164
          bRet = PeekConsoleInput (h, irbuffer, nbuffer, &avail);
 
165
          if (!bRet || avail == 0)
 
166
            return POLLHUP;
 
167
 
 
168
          for (i = 0; i < avail; i++)
 
169
            if (irbuffer[i].EventType == KEY_EVENT)
 
170
              return sought & ~(POLLPRI | POLLRDBAND);
 
171
        }
 
172
      break;
 
173
 
 
174
    default:
 
175
      ret = WaitForSingleObject (h, 0);
 
176
      if (ret == WAIT_OBJECT_0)
 
177
        return sought & ~(POLLPRI | POLLRDBAND);
 
178
 
 
179
      break;
 
180
    }
 
181
 
 
182
  return sought & (POLLOUT | POLLWRNORM | POLLWRBAND);
 
183
}
 
184
 
 
185
/* Convert fd_sets returned by select into revents values.  */
 
186
 
 
187
static int
 
188
win32_compute_revents_socket (SOCKET h, int sought, long lNetworkEvents)
 
189
{
 
190
  int happened = 0;
 
191
 
 
192
  if ((lNetworkEvents & (FD_READ | FD_ACCEPT | FD_CLOSE)) == FD_ACCEPT)
 
193
    happened |= (POLLIN | POLLRDNORM) & sought;
 
194
 
 
195
  else if (lNetworkEvents & (FD_READ | FD_ACCEPT | FD_CLOSE))
 
196
    {
 
197
      int r, error;
 
198
 
 
199
      char data[64];
 
200
      WSASetLastError (0);
 
201
      r = recv (h, data, sizeof (data), MSG_PEEK);
 
202
      error = WSAGetLastError ();
 
203
      WSASetLastError (0);
 
204
 
 
205
      if (r > 0 || error == WSAENOTCONN)
 
206
        happened |= (POLLIN | POLLRDNORM) & sought;
 
207
 
 
208
      /* Distinguish hung-up sockets from other errors.  */
 
209
      else if (r == 0 || error == WSAESHUTDOWN || error == WSAECONNRESET
 
210
               || error == WSAECONNABORTED || error == WSAENETRESET)
 
211
        happened |= POLLHUP;
 
212
 
 
213
      else
 
214
        happened |= POLLERR;
 
215
    }
 
216
 
 
217
  if (lNetworkEvents & (FD_WRITE | FD_CONNECT))
 
218
    happened |= (POLLOUT | POLLWRNORM | POLLWRBAND) & sought;
 
219
 
 
220
  if (lNetworkEvents & FD_OOB)
 
221
    happened |= (POLLPRI | POLLRDBAND) & sought;
 
222
 
 
223
  return happened;
 
224
}
 
225
 
 
226
#else /* !MinGW */
 
227
 
 
228
/* Convert select(2) returned fd_sets into poll(2) revents values.  */
 
229
static int
 
230
compute_revents (int fd, int sought, fd_set *rfds, fd_set *wfds, fd_set *efds)
 
231
{
 
232
  int happened = 0;
 
233
  if (FD_ISSET (fd, rfds))
 
234
    {
 
235
      int r;
 
236
      int socket_errno;
 
237
 
 
238
#if defined __MACH__ && defined __APPLE__
 
239
      /* There is a bug in Mac OS X that causes it to ignore MSG_PEEK
 
240
         for some kinds of descriptors.  Detect if this descriptor is a
 
241
         connected socket, a server socket, or something else using a
 
242
         0-byte recv, and use ioctl(2) to detect POLLHUP.  */
 
243
      r = recv (fd, NULL, 0, MSG_PEEK);
 
244
      socket_errno = (r < 0) ? errno : 0;
 
245
      if (r == 0 || socket_errno == ENOTSOCK)
 
246
        ioctl (fd, FIONREAD, &r);
 
247
#else
 
248
      char data[64];
 
249
      r = recv (fd, data, sizeof (data), MSG_PEEK);
 
250
      socket_errno = (r < 0) ? errno : 0;
 
251
#endif
 
252
      if (r == 0)
 
253
        happened |= POLLHUP;
 
254
 
 
255
      /* If the event happened on an unconnected server socket,
 
256
         that's fine. */
 
257
      else if (r > 0 || ( /* (r == -1) && */ socket_errno == ENOTCONN))
 
258
        happened |= (POLLIN | POLLRDNORM) & sought;
 
259
 
 
260
      /* Distinguish hung-up sockets from other errors.  */
 
261
      else if (socket_errno == ESHUTDOWN || socket_errno == ECONNRESET
 
262
               || socket_errno == ECONNABORTED || socket_errno == ENETRESET)
 
263
        happened |= POLLHUP;
 
264
 
 
265
      else
 
266
        happened |= POLLERR;
 
267
    }
 
268
 
 
269
  if (FD_ISSET (fd, wfds))
 
270
    happened |= (POLLOUT | POLLWRNORM | POLLWRBAND) & sought;
 
271
 
 
272
  if (FD_ISSET (fd, efds))
 
273
    happened |= (POLLPRI | POLLRDBAND) & sought;
 
274
 
 
275
  return happened;
 
276
}
 
277
#endif /* !MinGW */
 
278
 
 
279
int
 
280
poll (pfd, nfd, timeout)
 
281
     struct pollfd *pfd;
 
282
     nfds_t nfd;
 
283
     int timeout;
 
284
{
 
285
#ifndef WIN32_NATIVE
 
286
  fd_set rfds, wfds, efds;
 
287
  struct timeval tv;
 
288
  struct timeval *ptv;
 
289
  int maxfd, rc;
 
290
  nfds_t i;
 
291
 
 
292
#ifdef _SC_OPEN_MAX
 
293
  static int sc_open_max = -1;
 
294
 
 
295
  if (nfd < 0
 
296
      || (nfd > sc_open_max
 
297
          && (sc_open_max != -1
 
298
              || nfd > (sc_open_max = sysconf (_SC_OPEN_MAX)))))
 
299
    {
 
300
      errno = EINVAL;
 
301
      return -1;
 
302
    }
 
303
#else /* !_SC_OPEN_MAX */
 
304
#ifdef OPEN_MAX
 
305
  if (nfd < 0 || nfd > OPEN_MAX)
 
306
    {
 
307
      errno = EINVAL;
 
308
      return -1;
 
309
    }
 
310
#endif /* OPEN_MAX -- else, no check is needed */
 
311
#endif /* !_SC_OPEN_MAX */
 
312
 
 
313
  /* EFAULT is not necessary to implement, but let's do it in the
 
314
     simplest case. */
 
315
  if (!pfd)
 
316
    {
 
317
      errno = EFAULT;
 
318
      return -1;
 
319
    }
 
320
 
 
321
  /* convert timeout number into a timeval structure */
 
322
  if (timeout == 0)
 
323
    {
 
324
      ptv = &tv;
 
325
      ptv->tv_sec = 0;
 
326
      ptv->tv_usec = 0;
 
327
    }
 
328
  else if (timeout > 0)
 
329
    {
 
330
      ptv = &tv;
 
331
      ptv->tv_sec = timeout / 1000;
 
332
      ptv->tv_usec = (timeout % 1000) * 1000;
 
333
    }
 
334
  else if (timeout == INFTIM)
 
335
    /* wait forever */
 
336
    ptv = NULL;
 
337
  else
 
338
    {
 
339
      errno = EINVAL;
 
340
      return -1;
 
341
    }
 
342
 
 
343
  /* create fd sets and determine max fd */
 
344
  maxfd = -1;
 
345
  FD_ZERO (&rfds);
 
346
  FD_ZERO (&wfds);
 
347
  FD_ZERO (&efds);
 
348
  for (i = 0; i < nfd; i++)
 
349
    {
 
350
      if (pfd[i].fd < 0)
 
351
        continue;
 
352
 
 
353
      if (pfd[i].events & (POLLIN | POLLRDNORM))
 
354
        FD_SET (pfd[i].fd, &rfds);
 
355
 
 
356
      /* see select(2): "the only exceptional condition detectable
 
357
         is out-of-band data received on a socket", hence we push
 
358
         POLLWRBAND events onto wfds instead of efds. */
 
359
      if (pfd[i].events & (POLLOUT | POLLWRNORM | POLLWRBAND))
 
360
        FD_SET (pfd[i].fd, &wfds);
 
361
      if (pfd[i].events & (POLLPRI | POLLRDBAND))
 
362
        FD_SET (pfd[i].fd, &efds);
 
363
      if (pfd[i].fd >= maxfd
 
364
          && (pfd[i].events & (POLLIN | POLLOUT | POLLPRI
 
365
                               | POLLRDNORM | POLLRDBAND
 
366
                               | POLLWRNORM | POLLWRBAND)))
 
367
        {
 
368
          maxfd = pfd[i].fd;
 
369
          if (maxfd > FD_SETSIZE)
 
370
            {
 
371
              errno = EOVERFLOW;
 
372
              return -1;
 
373
            }
 
374
        }
 
375
    }
 
376
 
 
377
  /* examine fd sets */
 
378
  rc = select (maxfd + 1, &rfds, &wfds, &efds, ptv);
 
379
  if (rc < 0)
 
380
    return rc;
 
381
 
 
382
  /* establish results */
 
383
  rc = 0;
 
384
  for (i = 0; i < nfd; i++)
 
385
    if (pfd[i].fd < 0)
 
386
      pfd[i].revents = 0;
 
387
    else
 
388
      {
 
389
        int happened = compute_revents (pfd[i].fd, pfd[i].events,
 
390
                                        &rfds, &wfds, &efds);
 
391
        if (happened)
 
392
          {
 
393
            pfd[i].revents = happened;
 
394
            rc++;
 
395
          }
 
396
      }
 
397
 
 
398
  return rc;
 
399
#else
 
400
  static struct timeval tv0;
 
401
  static HANDLE hEvent;
 
402
  WSANETWORKEVENTS ev;
 
403
  HANDLE h, handle_array[FD_SETSIZE + 2];
 
404
  DWORD ret, wait_timeout, nhandles;
 
405
  fd_set rfds, wfds, xfds;
 
406
  BOOL poll_again;
 
407
  MSG msg;
 
408
  int rc= 0;
 
409
  nfds_t i;
 
410
 
 
411
  if (timeout < -1)
 
412
    {
 
413
      errno = EINVAL;
 
414
      return -1;
 
415
    }
 
416
 
 
417
  if (!hEvent)
 
418
    hEvent = CreateEvent (NULL, FALSE, FALSE, NULL);
 
419
 
 
420
  handle_array[0] = hEvent;
 
421
  nhandles = 1;
 
422
  FD_ZERO (&rfds);
 
423
  FD_ZERO (&wfds);
 
424
  FD_ZERO (&xfds);
 
425
 
 
426
  /* Classify socket handles and create fd sets. */
 
427
  for (i = 0; i < nfd; i++)
 
428
    {
 
429
      pfd[i].revents = 0;
 
430
      if (pfd[i].fd < 0)
 
431
        continue;
 
432
      if (!(pfd[i].events & (POLLIN | POLLRDNORM |
 
433
                             POLLOUT | POLLWRNORM | POLLWRBAND)))
 
434
        continue;
 
435
 
 
436
      h = (HANDLE) _get_osfhandle (pfd[i].fd);
 
437
      assert (h != NULL);
 
438
 
 
439
      /* Under Wine, it seems that getsockopt returns 0 for pipes too.
 
440
         WSAEnumNetworkEvents instead distinguishes the two correctly.  */
 
441
      ev.lNetworkEvents = 0xDEADBEEF;
 
442
      WSAEnumNetworkEvents ((SOCKET) h, NULL, &ev);
 
443
      if (ev.lNetworkEvents != (long)0xDEADBEEF)
 
444
        {
 
445
          int requested = FD_CLOSE;
 
446
 
 
447
          /* see above; socket handles are mapped onto select.  */
 
448
          if (pfd[i].events & (POLLIN | POLLRDNORM))
 
449
            {
 
450
              requested |= FD_READ | FD_ACCEPT;
 
451
              FD_SET ((SOCKET) h, &rfds);
 
452
            }
 
453
          if (pfd[i].events & (POLLOUT | POLLWRNORM | POLLWRBAND))
 
454
            {
 
455
              requested |= FD_WRITE | FD_CONNECT;
 
456
              FD_SET ((SOCKET) h, &wfds);
 
457
            }
 
458
          if (pfd[i].events & (POLLPRI | POLLRDBAND))
 
459
            {
 
460
              requested |= FD_OOB;
 
461
              FD_SET ((SOCKET) h, &xfds);
 
462
            }
 
463
 
 
464
          if (requested)
 
465
            WSAEventSelect ((SOCKET) h, hEvent, requested);
 
466
        }
 
467
      else
 
468
        {
 
469
          handle_array[nhandles++] = h;
 
470
 
 
471
          /* Poll now.  If we get an event, do not poll again.  */
 
472
          pfd[i].revents = win32_compute_revents (h, pfd[i].events);
 
473
          if (pfd[i].revents)
 
474
            wait_timeout = 0;
 
475
        }
 
476
    }
 
477
 
 
478
  if (select (0, &rfds, &wfds, &xfds, &tv0) > 0)
 
479
    {
 
480
      /* Do MsgWaitForMultipleObjects anyway to dispatch messages, but
 
481
         no need to call select again.  */
 
482
      poll_again = FALSE;
 
483
      wait_timeout = 0;
 
484
    }
 
485
  else
 
486
    {
 
487
      poll_again = TRUE;
 
488
      if (timeout == INFTIM)
 
489
        wait_timeout = INFINITE;
 
490
      else
 
491
        wait_timeout = timeout;
 
492
    }
 
493
 
 
494
  for (;;)
 
495
    {
 
496
      ret = MsgWaitForMultipleObjects (nhandles, handle_array, FALSE,
 
497
                                       wait_timeout, QS_ALLINPUT);
 
498
 
 
499
      if (ret == WAIT_OBJECT_0 + nhandles)
 
500
        {
 
501
          /* new input of some other kind */
 
502
          BOOL bRet;
 
503
          while ((bRet = PeekMessage (&msg, NULL, 0, 0, PM_REMOVE)) != 0)
 
504
            {
 
505
              TranslateMessage (&msg);
 
506
              DispatchMessage (&msg);
 
507
            }
 
508
        }
 
509
      else
 
510
        break;
 
511
    }
 
512
 
 
513
  if (poll_again)
 
514
    select (0, &rfds, &wfds, &xfds, &tv0);
 
515
 
 
516
  /* Place a sentinel at the end of the array.  */
 
517
  handle_array[nhandles] = NULL;
 
518
  nhandles = 1;
 
519
  for (i = 0; i < nfd; i++)
 
520
    {
 
521
      int happened;
 
522
 
 
523
      if (pfd[i].fd < 0)
 
524
        continue;
 
525
      if (!(pfd[i].events & (POLLIN | POLLRDNORM |
 
526
                             POLLOUT | POLLWRNORM | POLLWRBAND)))
 
527
        continue;
 
528
 
 
529
      h = (HANDLE) _get_osfhandle (pfd[i].fd);
 
530
      if (h != handle_array[nhandles])
 
531
        {
 
532
          /* It's a socket.  */
 
533
          WSAEnumNetworkEvents ((SOCKET) h, NULL, &ev);
 
534
          WSAEventSelect ((SOCKET) h, 0, 0);
 
535
 
 
536
          /* If we're lucky, WSAEnumNetworkEvents already provided a way
 
537
             to distinguish FD_READ and FD_ACCEPT; this saves a recv later.  */
 
538
          if (FD_ISSET ((SOCKET) h, &rfds)
 
539
              && !(ev.lNetworkEvents & (FD_READ | FD_ACCEPT)))
 
540
            ev.lNetworkEvents |= FD_READ | FD_ACCEPT;
 
541
          if (FD_ISSET ((SOCKET) h, &wfds))
 
542
            ev.lNetworkEvents |= FD_WRITE | FD_CONNECT;
 
543
          if (FD_ISSET ((SOCKET) h, &xfds))
 
544
            ev.lNetworkEvents |= FD_OOB;
 
545
 
 
546
          happened = win32_compute_revents_socket ((SOCKET) h, pfd[i].events,
 
547
                                                   ev.lNetworkEvents);
 
548
        }
 
549
      else
 
550
        {
 
551
          /* Not a socket.  */
 
552
          nhandles++;
 
553
          happened = win32_compute_revents (h, pfd[i].events);
 
554
        }
 
555
 
 
556
       if ((pfd[i].revents |= happened) != 0)
 
557
        rc++;
 
558
    }
 
559
 
 
560
  return rc;
 
561
#endif
 
562
}