Imported Upstream version 2.64.5
[platform/upstream/glib.git] / glib / gpoll.c
1 /* GLIB - Library of useful routines for C programming
2  * Copyright (C) 1995-1997  Peter Mattis, Spencer Kimball and Josh MacDonald
3  *
4  * gpoll.c: poll(2) abstraction
5  * Copyright 1998 Owen Taylor
6  * Copyright 2008 Red Hat, Inc.
7  *
8  * This library is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU Lesser General Public
10  * License as published by the Free Software Foundation; either
11  * version 2.1 of the License, or (at your option) any later version.
12  *
13  * This library 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 GNU
16  * Lesser General Public License for more details.
17  *
18  * You should have received a copy of the GNU Lesser General Public
19  * License along with this library; if not, see <http://www.gnu.org/licenses/>.
20  */
21
22 /*
23  * Modified by the GLib Team and others 1997-2000.  See the AUTHORS
24  * file for a list of people on the GLib Team.  See the ChangeLog
25  * files for a list of changes.  These files are distributed with
26  * GLib at ftp://ftp.gtk.org/pub/gtk/.
27  */
28
29 /*
30  * MT safe
31  */
32
33 #include "config.h"
34 #include "glibconfig.h"
35 #include "giochannel.h"
36
37 /* Uncomment the next line (and the corresponding line in gmain.c) to
38  * enable debugging printouts if the environment variable
39  * G_MAIN_POLL_DEBUG is set to some value.
40  */
41 /* #define G_MAIN_POLL_DEBUG */
42
43 #ifdef _WIN32
44 /* Always enable debugging printout on Windows, as it is more often
45  * needed there...
46  */
47 #define G_MAIN_POLL_DEBUG
48 #endif
49
50 #include <sys/types.h>
51 #include <time.h>
52 #include <stdlib.h>
53 #ifdef HAVE_SYS_TIME_H
54 #include <sys/time.h>
55 #endif /* HAVE_SYS_TIME_H */
56 #ifdef HAVE_POLL
57 #  include <poll.h>
58
59 /* The poll() emulation on OS/X doesn't handle fds=NULL, nfds=0,
60  * so we prefer our own poll emulation.
61  */
62 #if defined(_POLL_EMUL_H_) || defined(BROKEN_POLL)
63 #undef HAVE_POLL
64 #endif
65
66 #endif /* GLIB_HAVE_SYS_POLL_H */
67 #ifdef G_OS_UNIX
68 #include <unistd.h>
69 #endif /* G_OS_UNIX */
70 #include <errno.h>
71
72 #ifdef G_OS_WIN32
73 #define STRICT
74 #include <windows.h>
75 #include <process.h>
76 #endif /* G_OS_WIN32 */
77
78 #include "gpoll.h"
79
80 #ifdef G_OS_WIN32
81 #include "gprintf.h"
82 #endif
83
84 #ifdef G_MAIN_POLL_DEBUG
85 extern gboolean _g_main_poll_debug;
86 #endif
87
88 #ifdef HAVE_POLL
89
90 /**
91  * g_poll:
92  * @fds: file descriptors to poll
93  * @nfds: the number of file descriptors in @fds
94  * @timeout: amount of time to wait, in milliseconds, or -1 to wait forever
95  *
96  * Polls @fds, as with the poll() system call, but portably. (On
97  * systems that don't have poll(), it is emulated using select().)
98  * This is used internally by #GMainContext, but it can be called
99  * directly if you need to block until a file descriptor is ready, but
100  * don't want to run the full main loop.
101  *
102  * Each element of @fds is a #GPollFD describing a single file
103  * descriptor to poll. The @fd field indicates the file descriptor,
104  * and the @events field indicates the events to poll for. On return,
105  * the @revents fields will be filled with the events that actually
106  * occurred.
107  *
108  * On POSIX systems, the file descriptors in @fds can be any sort of
109  * file descriptor, but the situation is much more complicated on
110  * Windows. If you need to use g_poll() in code that has to run on
111  * Windows, the easiest solution is to construct all of your
112  * #GPollFDs with g_io_channel_win32_make_pollfd().
113  *
114  * Returns: the number of entries in @fds whose @revents fields
115  * were filled in, or 0 if the operation timed out, or -1 on error or
116  * if the call was interrupted.
117  *
118  * Since: 2.20
119  **/
120 gint
121 g_poll (GPollFD *fds,
122         guint    nfds,
123         gint     timeout)
124 {
125   return poll ((struct pollfd *)fds, nfds, timeout);
126 }
127
128 #else   /* !HAVE_POLL */
129
130 #ifdef G_OS_WIN32
131
132 static int
133 poll_rest (GPollFD *msg_fd,
134            GPollFD *stop_fd,
135            HANDLE  *handles,
136            GPollFD *handle_to_fd[],
137            gint     nhandles,
138            gint     timeout_ms)
139 {
140   DWORD ready;
141   GPollFD *f;
142   int recursed_result;
143
144   if (msg_fd != NULL)
145     {
146       /* Wait for either messages or handles
147        * -> Use MsgWaitForMultipleObjectsEx
148        */
149       if (_g_main_poll_debug)
150         g_print ("  MsgWaitForMultipleObjectsEx(%d, %d)\n", nhandles, timeout_ms);
151
152       ready = MsgWaitForMultipleObjectsEx (nhandles, handles, timeout_ms,
153                                            QS_ALLINPUT, MWMO_ALERTABLE);
154
155       if (ready == WAIT_FAILED)
156         {
157           gchar *emsg = g_win32_error_message (GetLastError ());
158           g_warning ("MsgWaitForMultipleObjectsEx failed: %s", emsg);
159           g_free (emsg);
160         }
161     }
162   else if (nhandles == 0)
163     {
164       /* No handles to wait for, just the timeout */
165       if (timeout_ms == INFINITE)
166         ready = WAIT_FAILED;
167       else
168         {
169           /* Wait for the current process to die, more efficient than SleepEx(). */
170           WaitForSingleObjectEx (GetCurrentProcess (), timeout_ms, TRUE);
171           ready = WAIT_TIMEOUT;
172         }
173     }
174   else
175     {
176       /* Wait for just handles
177        * -> Use WaitForMultipleObjectsEx
178        */
179       if (_g_main_poll_debug)
180         g_print ("  WaitForMultipleObjectsEx(%d, %d)\n", nhandles, timeout_ms);
181
182       ready = WaitForMultipleObjectsEx (nhandles, handles, FALSE, timeout_ms, TRUE);
183       if (ready == WAIT_FAILED)
184         {
185           gchar *emsg = g_win32_error_message (GetLastError ());
186           g_warning ("WaitForMultipleObjectsEx failed: %s", emsg);
187           g_free (emsg);
188         }
189     }
190
191   if (_g_main_poll_debug)
192     g_print ("  wait returns %ld%s\n",
193              ready,
194              (ready == WAIT_FAILED ? " (WAIT_FAILED)" :
195               (ready == WAIT_TIMEOUT ? " (WAIT_TIMEOUT)" :
196                (msg_fd != NULL && ready == WAIT_OBJECT_0 + nhandles ? " (msg)" : ""))));
197
198   if (ready == WAIT_FAILED)
199     return -1;
200   else if (ready == WAIT_TIMEOUT ||
201            ready == WAIT_IO_COMPLETION)
202     return 0;
203   else if (msg_fd != NULL && ready == WAIT_OBJECT_0 + nhandles)
204     {
205       msg_fd->revents |= G_IO_IN;
206
207       /* If we have a timeout, or no handles to poll, be satisfied
208        * with just noticing we have messages waiting.
209        */
210       if (timeout_ms != 0 || nhandles == 0)
211         return 1;
212
213       /* If no timeout and handles to poll, recurse to poll them,
214        * too.
215        */
216       recursed_result = poll_rest (NULL, stop_fd, handles, handle_to_fd, nhandles, 0);
217       return (recursed_result == -1) ? -1 : 1 + recursed_result;
218     }
219   else if (ready >= WAIT_OBJECT_0 && ready < WAIT_OBJECT_0 + nhandles)
220     {
221       int retval;
222
223       f = handle_to_fd[ready - WAIT_OBJECT_0];
224       f->revents = f->events;
225       if (_g_main_poll_debug)
226         g_print ("  got event %p\n", (HANDLE) f->fd);
227
228       /* Do not count the stop_fd */
229       retval = (f != stop_fd) ? 1 : 0;
230
231       /* If no timeout and polling several handles, recurse to poll
232        * the rest of them.
233        */
234       if (timeout_ms == 0 && nhandles > 1)
235         {
236           /* Poll the handles with index > ready */
237           HANDLE *shorter_handles;
238           GPollFD **shorter_handle_to_fd;
239           gint shorter_nhandles;
240
241           shorter_handles = &handles[ready - WAIT_OBJECT_0 + 1];
242           shorter_handle_to_fd = &handle_to_fd[ready - WAIT_OBJECT_0 + 1];
243           shorter_nhandles = nhandles - (ready - WAIT_OBJECT_0 + 1);
244
245           recursed_result = poll_rest (NULL, stop_fd, shorter_handles, shorter_handle_to_fd, shorter_nhandles, 0);
246           return (recursed_result == -1) ? -1 : retval + recursed_result;
247         }
248       return retval;
249     }
250
251   return 0;
252 }
253
254 typedef struct
255 {
256   HANDLE handles[MAXIMUM_WAIT_OBJECTS];
257   GPollFD *handle_to_fd[MAXIMUM_WAIT_OBJECTS];
258   GPollFD *msg_fd;
259   GPollFD *stop_fd;
260   gint nhandles;
261   gint timeout_ms;
262 } GWin32PollThreadData;
263
264 static gint
265 poll_single_thread (GWin32PollThreadData *data)
266 {
267   int retval;
268
269   /* Polling for several things? */
270   if (data->nhandles > 1 || (data->nhandles > 0 && data->msg_fd != NULL))
271     {
272       /* First check if one or several of them are immediately
273        * available
274        */
275       retval = poll_rest (data->msg_fd, data->stop_fd, data->handles, data->handle_to_fd, data->nhandles, 0);
276
277       /* If not, and we have a significant timeout, poll again with
278        * timeout then. Note that this will return indication for only
279        * one event, or only for messages.
280        */
281       if (retval == 0 && (data->timeout_ms == INFINITE || data->timeout_ms > 0))
282         retval = poll_rest (data->msg_fd, data->stop_fd, data->handles, data->handle_to_fd, data->nhandles, data->timeout_ms);
283     }
284   else
285     {
286       /* Just polling for one thing, so no need to check first if
287        * available immediately
288        */
289       retval = poll_rest (data->msg_fd, data->stop_fd, data->handles, data->handle_to_fd, data->nhandles, data->timeout_ms);
290     }
291
292   return retval;
293 }
294
295 static void
296 fill_poll_thread_data (GPollFD              *fds,
297                        guint                 nfds,
298                        gint                  timeout_ms,
299                        GPollFD              *stop_fd,
300                        GWin32PollThreadData *data)
301 {
302   GPollFD *f;
303
304   data->timeout_ms = timeout_ms;
305
306   if (stop_fd != NULL)
307     {
308       if (_g_main_poll_debug)
309         g_print (" Stop FD: %p", (HANDLE) stop_fd->fd);
310
311       g_assert (data->nhandles < MAXIMUM_WAIT_OBJECTS);
312
313       data->stop_fd = stop_fd;
314       data->handle_to_fd[data->nhandles] = stop_fd;
315       data->handles[data->nhandles++] = (HANDLE) stop_fd->fd;
316     }
317
318   for (f = fds; f < &fds[nfds]; ++f)
319     {
320       if ((data->nhandles == MAXIMUM_WAIT_OBJECTS) ||
321           (data->msg_fd != NULL && (data->nhandles == MAXIMUM_WAIT_OBJECTS - 1)))
322         {
323           g_warning ("Too many handles to wait for!");
324           break;
325         }
326
327       if (f->fd == G_WIN32_MSG_HANDLE && (f->events & G_IO_IN))
328         {
329           if (_g_main_poll_debug && data->msg_fd == NULL)
330             g_print (" MSG");
331           data->msg_fd = f;
332         }
333       else if (f->fd > 0)
334         {
335           if (_g_main_poll_debug)
336             g_print (" %p", (HANDLE) f->fd);
337           data->handle_to_fd[data->nhandles] = f;
338           data->handles[data->nhandles++] = (HANDLE) f->fd;
339         }
340
341       f->revents = 0;
342     }
343 }
344
345 static guint __stdcall
346 poll_thread_run (gpointer user_data)
347 {
348   GWin32PollThreadData *data = user_data;
349
350   /* Docs say that it is safer to call _endthreadex by our own:
351    * https://docs.microsoft.com/en-us/cpp/c-runtime-library/reference/endthread-endthreadex
352    */
353   _endthreadex (poll_single_thread (data));
354
355   g_assert_not_reached ();
356
357   return 0;
358 }
359
360 /* One slot for a possible msg object or the stop event */
361 #define MAXIMUM_WAIT_OBJECTS_PER_THREAD (MAXIMUM_WAIT_OBJECTS - 1)
362
363 gint
364 g_poll (GPollFD *fds,
365         guint    nfds,
366         gint     timeout)
367 {
368   guint nthreads, threads_remain;
369   HANDLE thread_handles[MAXIMUM_WAIT_OBJECTS];
370   GWin32PollThreadData *threads_data;
371   GPollFD stop_event = { 0, };
372   GPollFD *f;
373   guint i, fds_idx = 0;
374   DWORD ready;
375   DWORD thread_retval;
376   int retval;
377   GPollFD *msg_fd = NULL;
378
379   if (timeout == -1)
380     timeout = INFINITE;
381
382   /* Simple case without extra threads */
383   if (nfds <= MAXIMUM_WAIT_OBJECTS)
384     {
385       GWin32PollThreadData data = { 0, };
386
387       if (_g_main_poll_debug)
388         g_print ("g_poll: waiting for");
389
390       fill_poll_thread_data (fds, nfds, timeout, NULL, &data);
391
392       if (_g_main_poll_debug)
393         g_print ("\n");
394
395       retval = poll_single_thread (&data);
396       if (retval == -1)
397         for (f = fds; f < &fds[nfds]; ++f)
398           f->revents = 0;
399
400       return retval;
401     }
402
403   if (_g_main_poll_debug)
404     g_print ("g_poll: polling with threads\n");
405
406   nthreads = nfds / MAXIMUM_WAIT_OBJECTS_PER_THREAD;
407   threads_remain = nfds % MAXIMUM_WAIT_OBJECTS_PER_THREAD;
408   if (threads_remain > 0)
409     nthreads++;
410
411   if (nthreads > MAXIMUM_WAIT_OBJECTS_PER_THREAD)
412     {
413       g_warning ("Too many handles to wait for in threads!");
414       nthreads = MAXIMUM_WAIT_OBJECTS_PER_THREAD;
415     }
416
417 #if GLIB_SIZEOF_VOID_P == 8
418   stop_event.fd = (gint64)CreateEventW (NULL, TRUE, FALSE, NULL);
419 #else
420   stop_event.fd = (gint)CreateEventW (NULL, TRUE, FALSE, NULL);
421 #endif
422   stop_event.events = G_IO_IN;
423
424   threads_data = g_new0 (GWin32PollThreadData, nthreads);
425   for (i = 0; i < nthreads; i++)
426     {
427       guint thread_fds;
428       guint ignore;
429
430       if (i == (nthreads - 1) && threads_remain > 0)
431         thread_fds = threads_remain;
432       else
433         thread_fds = MAXIMUM_WAIT_OBJECTS_PER_THREAD;
434
435       fill_poll_thread_data (fds + fds_idx, thread_fds, timeout, &stop_event, &threads_data[i]);
436       fds_idx += thread_fds;
437
438       /* We must poll for messages from the same thread, so poll it along with the threads */
439       if (threads_data[i].msg_fd != NULL)
440         {
441           msg_fd = threads_data[i].msg_fd;
442           threads_data[i].msg_fd = NULL;
443         }
444
445       thread_handles[i] = (HANDLE) _beginthreadex (NULL, 0, poll_thread_run, &threads_data[i], 0, &ignore);
446     }
447
448   /* Wait for at least one thread to return */
449   if (msg_fd != NULL)
450     ready = MsgWaitForMultipleObjectsEx (nthreads, thread_handles, timeout,
451                                          QS_ALLINPUT, MWMO_ALERTABLE);
452   else
453     ready = WaitForMultipleObjects (nthreads, thread_handles, FALSE, timeout);
454
455   /* Signal the stop in case any of the threads did not stop yet */
456   if (!SetEvent ((HANDLE)stop_event.fd))
457     {
458       gchar *emsg = g_win32_error_message (GetLastError ());
459       g_warning ("gpoll: failed to signal the stop event: %s", emsg);
460       g_free (emsg);
461     }
462
463   /* Wait for the rest of the threads to finish */
464   WaitForMultipleObjects (nthreads, thread_handles, TRUE, INFINITE);
465
466   /* The return value of all the threads give us all the fds that changed state */
467   retval = 0;
468   if (msg_fd != NULL && ready == WAIT_OBJECT_0 + nthreads)
469     {
470       msg_fd->revents |= G_IO_IN;
471       retval = 1;
472     }
473
474   for (i = 0; i < nthreads; i++)
475     {
476       if (GetExitCodeThread (thread_handles[i], &thread_retval))
477         retval = retval == -1 ? -1 : thread_retval == -1 ? -1 : retval + thread_retval;
478
479       CloseHandle (thread_handles[i]);
480     }
481
482   if (retval == -1)
483     for (f = fds; f < &fds[nfds]; ++f)
484       f->revents = 0;
485
486   g_free (threads_data);
487   CloseHandle ((HANDLE)stop_event.fd);
488
489   return retval;
490 }
491
492 #else  /* !G_OS_WIN32 */
493
494 /* The following implementation of poll() comes from the GNU C Library.
495  * Copyright (C) 1994, 1996, 1997 Free Software Foundation, Inc.
496  */
497
498 #include <string.h> /* for bzero on BSD systems */
499
500 #ifdef HAVE_SYS_SELECT_H
501 #include <sys/select.h>
502 #endif /* HAVE_SYS_SELECT_H */
503
504 gint
505 g_poll (GPollFD *fds,
506         guint    nfds,
507         gint     timeout)
508 {
509   struct timeval tv;
510   fd_set rset, wset, xset;
511   GPollFD *f;
512   int ready;
513   int maxfd = 0;
514
515   FD_ZERO (&rset);
516   FD_ZERO (&wset);
517   FD_ZERO (&xset);
518
519   for (f = fds; f < &fds[nfds]; ++f)
520     if (f->fd >= 0)
521       {
522         if (f->events & G_IO_IN)
523           FD_SET (f->fd, &rset);
524         if (f->events & G_IO_OUT)
525           FD_SET (f->fd, &wset);
526         if (f->events & G_IO_PRI)
527           FD_SET (f->fd, &xset);
528         if (f->fd > maxfd && (f->events & (G_IO_IN|G_IO_OUT|G_IO_PRI)))
529           maxfd = f->fd;
530       }
531
532   tv.tv_sec = timeout / 1000;
533   tv.tv_usec = (timeout % 1000) * 1000;
534
535   ready = select (maxfd + 1, &rset, &wset, &xset,
536                   timeout == -1 ? NULL : &tv);
537   if (ready > 0)
538     for (f = fds; f < &fds[nfds]; ++f)
539       {
540         f->revents = 0;
541         if (f->fd >= 0)
542           {
543             if (FD_ISSET (f->fd, &rset))
544               f->revents |= G_IO_IN;
545             if (FD_ISSET (f->fd, &wset))
546               f->revents |= G_IO_OUT;
547             if (FD_ISSET (f->fd, &xset))
548               f->revents |= G_IO_PRI;
549           }
550       }
551
552   return ready;
553 }
554
555 #endif /* !G_OS_WIN32 */
556
557 #endif  /* !HAVE_POLL */