git

Форк
0
/
poll.c 
608 строк · 14.5 Кб
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, see <http://www.gnu.org/licenses/>.  */
20

21
/* To bump the minimum Windows version to Windows Vista */
22
#include "git-compat-util.h"
23

24
/* Tell gcc not to warn about the (nfd < 0) tests, below.  */
25
#if (__GNUC__ == 4 && 3 <= __GNUC_MINOR__) || 4 < __GNUC__
26
# pragma GCC diagnostic ignored "-Wtype-limits"
27
#endif
28

29
#if defined(WIN32)
30
# include <malloc.h>
31
#endif
32

33
#include <sys/types.h>
34

35
#include <errno.h>
36
#include <limits.h>
37
#include <assert.h>
38

39
#if (defined _WIN32 || defined __WIN32__) && ! defined __CYGWIN__
40
# define WIN32_NATIVE
41
# if defined (_MSC_VER) && !defined(_WIN32_WINNT)
42
#  define _WIN32_WINNT 0x0502
43
# endif
44
# include <winsock2.h>
45
# include <windows.h>
46
# include <io.h>
47
# include <stdio.h>
48
# include <conio.h>
49
#else
50
# include <sys/time.h>
51
# include <sys/socket.h>
52
# ifndef NO_SYS_SELECT_H
53
#  include <sys/select.h>
54
# endif
55
# include <unistd.h>
56
#endif
57

58
/* Specification.  */
59
#include "poll.h"
60

61
#ifdef HAVE_SYS_IOCTL_H
62
# include <sys/ioctl.h>
63
#endif
64
#ifdef HAVE_SYS_FILIO_H
65
# include <sys/filio.h>
66
#endif
67

68
#include <time.h>
69

70
#ifndef INFTIM
71
# define INFTIM (-1)
72
#endif
73

74
/* BeOS does not have MSG_PEEK.  */
75
#ifndef MSG_PEEK
76
# define MSG_PEEK 0
77
#endif
78

79
#ifdef WIN32_NATIVE
80

81
#define IsConsoleHandle(h) (((long) (intptr_t) (h) & 3) == 3)
82

83
static BOOL
84
IsSocketHandle (HANDLE h)
85
{
86
  WSANETWORKEVENTS ev;
87

88
  if (IsConsoleHandle (h))
89
    return FALSE;
90

91
  /* Under Wine, it seems that getsockopt returns 0 for pipes too.
92
     WSAEnumNetworkEvents instead distinguishes the two correctly.  */
93
  ev.lNetworkEvents = 0xDEADBEEF;
94
  WSAEnumNetworkEvents ((SOCKET) h, NULL, &ev);
95
  return ev.lNetworkEvents != 0xDEADBEEF;
96
}
97

98
/* Declare data structures for ntdll functions.  */
99
typedef struct _FILE_PIPE_LOCAL_INFORMATION {
100
  ULONG NamedPipeType;
101
  ULONG NamedPipeConfiguration;
102
  ULONG MaximumInstances;
103
  ULONG CurrentInstances;
104
  ULONG InboundQuota;
105
  ULONG ReadDataAvailable;
106
  ULONG OutboundQuota;
107
  ULONG WriteQuotaAvailable;
108
  ULONG NamedPipeState;
109
  ULONG NamedPipeEnd;
110
} FILE_PIPE_LOCAL_INFORMATION, *PFILE_PIPE_LOCAL_INFORMATION;
111

112
typedef struct _IO_STATUS_BLOCK
113
{
114
  union {
115
    DWORD Status;
116
    PVOID Pointer;
117
  } u;
118
  ULONG_PTR Information;
119
} IO_STATUS_BLOCK, *PIO_STATUS_BLOCK;
120

121
typedef enum _FILE_INFORMATION_CLASS {
122
  FilePipeLocalInformation = 24
123
} FILE_INFORMATION_CLASS, *PFILE_INFORMATION_CLASS;
124

125
typedef DWORD (WINAPI *PNtQueryInformationFile)
126
	 (HANDLE, IO_STATUS_BLOCK *, VOID *, ULONG, FILE_INFORMATION_CLASS);
127

128
# ifndef PIPE_BUF
129
#  define PIPE_BUF      512
130
# endif
131

132
/* Compute revents values for file handle H.  If some events cannot happen
133
   for the handle, eliminate them from *P_SOUGHT.  */
134

135
static int
136
win32_compute_revents (HANDLE h, int *p_sought)
137
{
138
  int i, ret, happened;
139
  INPUT_RECORD *irbuffer;
140
  DWORD avail, nbuffer;
141
  BOOL bRet;
142

143
  switch (GetFileType (h))
144
    {
145
    case FILE_TYPE_PIPE:
146
      happened = 0;
147
      if (PeekNamedPipe (h, NULL, 0, NULL, &avail, NULL) != 0)
148
	{
149
	  if (avail)
150
	    happened |= *p_sought & (POLLIN | POLLRDNORM);
151
	}
152
      else if (GetLastError () == ERROR_BROKEN_PIPE)
153
	happened |= POLLHUP;
154

155
      else
156
	{
157
	  /* It was the write-end of the pipe. Unfortunately there is no
158
	     reliable way of knowing if it can be written without blocking.
159
	     Just say that it's all good. */
160
	    happened |= *p_sought & (POLLOUT | POLLWRNORM | POLLWRBAND);
161
	}
162
      return happened;
163

164
    case FILE_TYPE_CHAR:
165
      ret = WaitForSingleObject (h, 0);
166
      if (!IsConsoleHandle (h))
167
	return ret == WAIT_OBJECT_0 ? *p_sought & ~(POLLPRI | POLLRDBAND) : 0;
168

169
      nbuffer = avail = 0;
170
      bRet = GetNumberOfConsoleInputEvents (h, &nbuffer);
171
      if (bRet)
172
	{
173
	  /* Input buffer.  */
174
	  *p_sought &= POLLIN | POLLRDNORM;
175
	  if (nbuffer == 0)
176
	    return POLLHUP;
177
	  if (!*p_sought)
178
	    return 0;
179

180
	  irbuffer = (INPUT_RECORD *) alloca (nbuffer * sizeof (INPUT_RECORD));
181
	  bRet = PeekConsoleInput (h, irbuffer, nbuffer, &avail);
182
	  if (!bRet || avail == 0)
183
	    return POLLHUP;
184

185
	  for (i = 0; i < avail; i++)
186
	    if (irbuffer[i].EventType == KEY_EVENT)
187
	      return *p_sought;
188
	  return 0;
189
	}
190
      else
191
	{
192
	  /* Screen buffer.  */
193
	  *p_sought &= POLLOUT | POLLWRNORM | POLLWRBAND;
194
	  return *p_sought;
195
	}
196

197
    default:
198
      ret = WaitForSingleObject (h, 0);
199
      if (ret == WAIT_OBJECT_0)
200
	return *p_sought & ~(POLLPRI | POLLRDBAND);
201

202
      return *p_sought & (POLLOUT | POLLWRNORM | POLLWRBAND);
203
    }
204
}
205

206
/* Convert fd_sets returned by select into revents values.  */
207

208
static int
209
win32_compute_revents_socket (SOCKET h, int sought, long lNetworkEvents)
210
{
211
  int happened = 0;
212

213
  if ((lNetworkEvents & (FD_READ | FD_ACCEPT | FD_CLOSE)) == FD_ACCEPT)
214
    happened |= (POLLIN | POLLRDNORM) & sought;
215

216
  else if (lNetworkEvents & (FD_READ | FD_ACCEPT | FD_CLOSE))
217
    {
218
      int r, error;
219

220
      char data[64];
221
      WSASetLastError (0);
222
      r = recv (h, data, sizeof (data), MSG_PEEK);
223
      error = WSAGetLastError ();
224
      WSASetLastError (0);
225

226
      if (r > 0 || error == WSAENOTCONN)
227
	happened |= (POLLIN | POLLRDNORM) & sought;
228

229
      /* Distinguish hung-up sockets from other errors.  */
230
      else if (r == 0 || error == WSAESHUTDOWN || error == WSAECONNRESET
231
	       || error == WSAECONNABORTED || error == WSAENETRESET)
232
	happened |= POLLHUP;
233

234
      else
235
	happened |= POLLERR;
236
    }
237

238
  if (lNetworkEvents & (FD_WRITE | FD_CONNECT))
239
    happened |= (POLLOUT | POLLWRNORM | POLLWRBAND) & sought;
240

241
  if (lNetworkEvents & FD_OOB)
242
    happened |= (POLLPRI | POLLRDBAND) & sought;
243

244
  return happened;
245
}
246

247
#else /* !MinGW */
248

249
/* Convert select(2) returned fd_sets into poll(2) revents values.  */
250
static int
251
compute_revents (int fd, int sought, fd_set *rfds, fd_set *wfds, fd_set *efds)
252
{
253
  int happened = 0;
254
  if (FD_ISSET (fd, rfds))
255
    {
256
      int r;
257
      int socket_errno;
258

259
# if defined __MACH__ && defined __APPLE__
260
      /* There is a bug in Mac OS X that causes it to ignore MSG_PEEK
261
	 for some kinds of descriptors.  Detect if this descriptor is a
262
	 connected socket, a server socket, or something else using a
263
	 0-byte recv, and use ioctl(2) to detect POLLHUP.  */
264
      r = recv (fd, NULL, 0, MSG_PEEK);
265
      socket_errno = (r < 0) ? errno : 0;
266
      if (r == 0 || socket_errno == ENOTSOCK)
267
	ioctl (fd, FIONREAD, &r);
268
# else
269
      char data[64];
270
      r = recv (fd, data, sizeof (data), MSG_PEEK);
271
      socket_errno = (r < 0) ? errno : 0;
272
# endif
273
      if (r == 0)
274
	happened |= POLLHUP;
275

276
      /* If the event happened on an unconnected server socket,
277
	 that's fine. */
278
      else if (r > 0 || ( /* (r == -1) && */ socket_errno == ENOTCONN))
279
	happened |= (POLLIN | POLLRDNORM) & sought;
280

281
      /* Distinguish hung-up sockets from other errors.  */
282
      else if (socket_errno == ESHUTDOWN || socket_errno == ECONNRESET
283
	       || socket_errno == ECONNABORTED || socket_errno == ENETRESET)
284
	happened |= POLLHUP;
285

286
      /* some systems can't use recv() on non-socket, including HP NonStop */
287
      else if (/* (r == -1) && */ socket_errno == ENOTSOCK)
288
	happened |= (POLLIN | POLLRDNORM) & sought;
289

290
      else
291
	happened |= POLLERR;
292
    }
293

294
  if (FD_ISSET (fd, wfds))
295
    happened |= (POLLOUT | POLLWRNORM | POLLWRBAND) & sought;
296

297
  if (FD_ISSET (fd, efds))
298
    happened |= (POLLPRI | POLLRDBAND) & sought;
299

300
  return happened;
301
}
302
#endif /* !MinGW */
303

304
int
305
poll (struct pollfd *pfd, nfds_t nfd, int timeout)
306
{
307
#ifndef WIN32_NATIVE
308
  fd_set rfds, wfds, efds;
309
  struct timeval tv;
310
  struct timeval *ptv;
311
  int maxfd, rc;
312
  nfds_t i;
313

314
# ifdef _SC_OPEN_MAX
315
  static int sc_open_max = -1;
316

317
  if (nfd < 0
318
      || (nfd > sc_open_max
319
	  && (sc_open_max != -1
320
	      || nfd > (sc_open_max = sysconf (_SC_OPEN_MAX)))))
321
    {
322
      errno = EINVAL;
323
      return -1;
324
    }
325
# else /* !_SC_OPEN_MAX */
326
#  ifdef OPEN_MAX
327
  if (nfd < 0 || nfd > OPEN_MAX)
328
    {
329
      errno = EINVAL;
330
      return -1;
331
    }
332
#  endif /* OPEN_MAX -- else, no check is needed */
333
# endif /* !_SC_OPEN_MAX */
334

335
  /* EFAULT is not necessary to implement, but let's do it in the
336
     simplest case. */
337
  if (!pfd && nfd)
338
    {
339
      errno = EFAULT;
340
      return -1;
341
    }
342

343
  /* convert timeout number into a timeval structure */
344
  if (timeout == 0)
345
    {
346
      ptv = &tv;
347
      ptv->tv_sec = 0;
348
      ptv->tv_usec = 0;
349
    }
350
  else if (timeout > 0)
351
    {
352
      ptv = &tv;
353
      ptv->tv_sec = timeout / 1000;
354
      ptv->tv_usec = (timeout % 1000) * 1000;
355
    }
356
  else if (timeout == INFTIM)
357
    /* wait forever */
358
    ptv = NULL;
359
  else
360
    {
361
      errno = EINVAL;
362
      return -1;
363
    }
364

365
  /* create fd sets and determine max fd */
366
  maxfd = -1;
367
  FD_ZERO (&rfds);
368
  FD_ZERO (&wfds);
369
  FD_ZERO (&efds);
370
  for (i = 0; i < nfd; i++)
371
    {
372
      if (pfd[i].fd < 0)
373
	continue;
374

375
      if (pfd[i].events & (POLLIN | POLLRDNORM))
376
	FD_SET (pfd[i].fd, &rfds);
377

378
      /* see select(2): "the only exceptional condition detectable
379
	 is out-of-band data received on a socket", hence we push
380
	 POLLWRBAND events onto wfds instead of efds. */
381
      if (pfd[i].events & (POLLOUT | POLLWRNORM | POLLWRBAND))
382
	FD_SET (pfd[i].fd, &wfds);
383
      if (pfd[i].events & (POLLPRI | POLLRDBAND))
384
	FD_SET (pfd[i].fd, &efds);
385
      if (pfd[i].fd >= maxfd
386
	  && (pfd[i].events & (POLLIN | POLLOUT | POLLPRI
387
			       | POLLRDNORM | POLLRDBAND
388
			       | POLLWRNORM | POLLWRBAND)))
389
	{
390
	  maxfd = pfd[i].fd;
391
	  if (maxfd > FD_SETSIZE)
392
	    {
393
	      errno = EOVERFLOW;
394
	      return -1;
395
	    }
396
	}
397
    }
398

399
  /* examine fd sets */
400
  rc = select (maxfd + 1, &rfds, &wfds, &efds, ptv);
401
  if (rc < 0)
402
    return rc;
403

404
  /* establish results */
405
  rc = 0;
406
  for (i = 0; i < nfd; i++)
407
    if (pfd[i].fd < 0)
408
      pfd[i].revents = 0;
409
    else
410
      {
411
	int happened = compute_revents (pfd[i].fd, pfd[i].events,
412
					&rfds, &wfds, &efds);
413
	if (happened)
414
	  {
415
	    pfd[i].revents = happened;
416
	    rc++;
417
	  }
418
	else
419
	  {
420
	    pfd[i].revents = 0;
421
	  }
422
      }
423

424
  return rc;
425
#else
426
  static struct timeval tv0;
427
  static HANDLE hEvent;
428
  WSANETWORKEVENTS ev;
429
  HANDLE h, handle_array[FD_SETSIZE + 2];
430
  DWORD ret, wait_timeout, nhandles, orig_timeout = 0;
431
  ULONGLONG start = 0;
432
  fd_set rfds, wfds, xfds;
433
  BOOL poll_again;
434
  MSG msg;
435
  int rc = 0;
436
  nfds_t i;
437

438
  if (nfd < 0 || timeout < -1)
439
    {
440
      errno = EINVAL;
441
      return -1;
442
    }
443

444
  if (timeout != INFTIM)
445
    {
446
      orig_timeout = timeout;
447
      start = GetTickCount64();
448
    }
449

450
  if (!hEvent)
451
    hEvent = CreateEvent (NULL, FALSE, FALSE, NULL);
452

453
restart:
454
  handle_array[0] = hEvent;
455
  nhandles = 1;
456
  FD_ZERO (&rfds);
457
  FD_ZERO (&wfds);
458
  FD_ZERO (&xfds);
459

460
  /* Classify socket handles and create fd sets. */
461
  for (i = 0; i < nfd; i++)
462
    {
463
      int sought = pfd[i].events;
464
      pfd[i].revents = 0;
465
      if (pfd[i].fd < 0)
466
	continue;
467
      if (!(sought & (POLLIN | POLLRDNORM | POLLOUT | POLLWRNORM | POLLWRBAND
468
		      | POLLPRI | POLLRDBAND)))
469
	continue;
470

471
      h = (HANDLE) _get_osfhandle (pfd[i].fd);
472
      assert (h != NULL);
473
      if (IsSocketHandle (h))
474
	{
475
	  int requested = FD_CLOSE;
476

477
	  /* see above; socket handles are mapped onto select.  */
478
	  if (sought & (POLLIN | POLLRDNORM))
479
	    {
480
	      requested |= FD_READ | FD_ACCEPT;
481
	      FD_SET ((SOCKET) h, &rfds);
482
	    }
483
	  if (sought & (POLLOUT | POLLWRNORM | POLLWRBAND))
484
	    {
485
	      requested |= FD_WRITE | FD_CONNECT;
486
	      FD_SET ((SOCKET) h, &wfds);
487
	    }
488
	  if (sought & (POLLPRI | POLLRDBAND))
489
	    {
490
	      requested |= FD_OOB;
491
	      FD_SET ((SOCKET) h, &xfds);
492
	    }
493

494
	  if (requested)
495
	    WSAEventSelect ((SOCKET) h, hEvent, requested);
496
	}
497
      else
498
	{
499
	  /* Poll now.  If we get an event, do not poll again.  Also,
500
	     screen buffer handles are waitable, and they'll block until
501
	     a character is available.  win32_compute_revents eliminates
502
	     bits for the "wrong" direction. */
503
	  pfd[i].revents = win32_compute_revents (h, &sought);
504
	  if (sought)
505
	    handle_array[nhandles++] = h;
506
	  if (pfd[i].revents)
507
	    timeout = 0;
508
	}
509
    }
510

511
  if (select (0, &rfds, &wfds, &xfds, &tv0) > 0)
512
    {
513
      /* Do MsgWaitForMultipleObjects anyway to dispatch messages, but
514
	 no need to call select again.  */
515
      poll_again = FALSE;
516
      wait_timeout = 0;
517
    }
518
  else
519
    {
520
      poll_again = TRUE;
521
      if (timeout == INFTIM)
522
	wait_timeout = INFINITE;
523
      else
524
	wait_timeout = timeout;
525
    }
526

527
  for (;;)
528
    {
529
      ret = MsgWaitForMultipleObjects (nhandles, handle_array, FALSE,
530
				       wait_timeout, QS_ALLINPUT);
531

532
      if (ret == WAIT_OBJECT_0 + nhandles)
533
	{
534
	  /* new input of some other kind */
535
	  BOOL bRet;
536
	  while ((bRet = PeekMessage (&msg, NULL, 0, 0, PM_REMOVE)) != 0)
537
	    {
538
	      TranslateMessage (&msg);
539
	      DispatchMessage (&msg);
540
	    }
541
	}
542
      else
543
	break;
544
    }
545

546
  if (poll_again)
547
    select (0, &rfds, &wfds, &xfds, &tv0);
548

549
  /* Place a sentinel at the end of the array.  */
550
  handle_array[nhandles] = NULL;
551
  nhandles = 1;
552
  for (i = 0; i < nfd; i++)
553
    {
554
      int happened;
555

556
      if (pfd[i].fd < 0)
557
	continue;
558
      if (!(pfd[i].events & (POLLIN | POLLRDNORM |
559
			     POLLOUT | POLLWRNORM | POLLWRBAND)))
560
	continue;
561

562
      h = (HANDLE) _get_osfhandle (pfd[i].fd);
563
      if (h != handle_array[nhandles])
564
	{
565
	  /* It's a socket.  */
566
	  WSAEnumNetworkEvents ((SOCKET) h, NULL, &ev);
567
	  WSAEventSelect ((SOCKET) h, NULL, 0);
568

569
	  /* If we're lucky, WSAEnumNetworkEvents already provided a way
570
	     to distinguish FD_READ and FD_ACCEPT; this saves a recv later.  */
571
	  if (FD_ISSET ((SOCKET) h, &rfds)
572
	      && !(ev.lNetworkEvents & (FD_READ | FD_ACCEPT)))
573
	    ev.lNetworkEvents |= FD_READ | FD_ACCEPT;
574
	  if (FD_ISSET ((SOCKET) h, &wfds))
575
	    ev.lNetworkEvents |= FD_WRITE | FD_CONNECT;
576
	  if (FD_ISSET ((SOCKET) h, &xfds))
577
	    ev.lNetworkEvents |= FD_OOB;
578

579
	  happened = win32_compute_revents_socket ((SOCKET) h, pfd[i].events,
580
						   ev.lNetworkEvents);
581
	}
582
      else
583
	{
584
	  /* Not a socket.  */
585
	  int sought = pfd[i].events;
586
	  happened = win32_compute_revents (h, &sought);
587
	  nhandles++;
588
	}
589

590
       if ((pfd[i].revents |= happened) != 0)
591
	rc++;
592
    }
593

594
  if (!rc && orig_timeout && timeout != INFTIM)
595
    {
596
      ULONGLONG elapsed = GetTickCount64() - start;
597
      timeout = elapsed >= orig_timeout ? 0 : (int)(orig_timeout - elapsed);
598
    }
599

600
  if (!rc && timeout)
601
    {
602
      SleepEx (1, TRUE);
603
      goto restart;
604
    }
605

606
  return rc;
607
#endif
608
}
609

Использование cookies

Мы используем файлы cookie в соответствии с Политикой конфиденциальности и Политикой использования cookies.

Нажимая кнопку «Принимаю», Вы даете АО «СберТех» согласие на обработку Ваших персональных данных в целях совершенствования нашего веб-сайта и Сервиса GitVerse, а также повышения удобства их использования.

Запретить использование cookies Вы можете самостоятельно в настройках Вашего браузера.