~drizzle-trunk/drizzle/development

« back to all changes in this revision

Viewing changes to win32/poll.c

  • Committer: Monty Taylor
  • Date: 2011-02-12 19:46:19 UTC
  • mto: (2165.1.1 build)
  • mto: This revision was merged to the branch mainline in revision 2166.
  • Revision ID: mordred@inaugust.com-20110212194619-bpk3oxfno3of3tdj
Merged in various amounts of win32 fixes. Now is quite happy in vs10.

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
 
}