1 /* GLIB - Library of useful routines for C programming
2 * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
4 * gpoll.c: poll(2) abstraction
5 * Copyright 1998 Owen Taylor
6 * Copyright 2008 Red Hat, Inc.
8 * SPDX-License-Identifier: LGPL-2.1-or-later
10 * This library is free software; you can redistribute it and/or
11 * modify it under the terms of the GNU Lesser General Public
12 * License as published by the Free Software Foundation; either
13 * version 2.1 of the License, or (at your option) any later version.
15 * This library is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18 * Lesser General Public License for more details.
20 * You should have received a copy of the GNU Lesser General Public
21 * License along with this library; if not, see <http://www.gnu.org/licenses/>.
25 * Modified by the GLib Team and others 1997-2000. See the AUTHORS
26 * file for a list of people on the GLib Team. See the ChangeLog
27 * files for a list of changes. These files are distributed with
28 * GLib at ftp://ftp.gtk.org/pub/gtk/.
36 #include "glibconfig.h"
37 #include "giochannel.h"
39 /* Uncomment the next line (and the corresponding line in gmain.c) to
40 * enable debugging printouts if the environment variable
41 * G_MAIN_POLL_DEBUG is set to some value.
43 /* #define G_MAIN_POLL_DEBUG */
46 /* Always enable debugging printout on Windows, as it is more often
49 #define G_MAIN_POLL_DEBUG
52 #include <sys/types.h>
55 #ifdef HAVE_SYS_TIME_H
57 #endif /* HAVE_SYS_TIME_H */
61 /* The poll() emulation on OS/X doesn't handle fds=NULL, nfds=0,
62 * so we prefer our own poll emulation.
64 #if defined(_POLL_EMUL_H_) || defined(BROKEN_POLL)
68 #endif /* GLIB_HAVE_SYS_POLL_H */
71 #endif /* G_OS_UNIX */
78 #endif /* G_OS_WIN32 */
86 #ifdef G_MAIN_POLL_DEBUG
87 extern gboolean _g_main_poll_debug;
94 * @fds: file descriptors to poll
95 * @nfds: the number of file descriptors in @fds
96 * @timeout: amount of time to wait, in milliseconds, or -1 to wait forever
98 * Polls @fds, as with the poll() system call, but portably. (On
99 * systems that don't have poll(), it is emulated using select().)
100 * This is used internally by #GMainContext, but it can be called
101 * directly if you need to block until a file descriptor is ready, but
102 * don't want to run the full main loop.
104 * Each element of @fds is a #GPollFD describing a single file
105 * descriptor to poll. The @fd field indicates the file descriptor,
106 * and the @events field indicates the events to poll for. On return,
107 * the @revents fields will be filled with the events that actually
110 * On POSIX systems, the file descriptors in @fds can be any sort of
111 * file descriptor, but the situation is much more complicated on
112 * Windows. If you need to use g_poll() in code that has to run on
113 * Windows, the easiest solution is to construct all of your
114 * #GPollFDs with g_io_channel_win32_make_pollfd().
116 * Returns: the number of entries in @fds whose @revents fields
117 * were filled in, or 0 if the operation timed out, or -1 on error or
118 * if the call was interrupted.
123 g_poll (GPollFD *fds,
127 return poll ((struct pollfd *)fds, nfds, timeout);
130 #else /* !HAVE_POLL */
135 poll_rest (GPollFD *msg_fd,
138 GPollFD *handle_to_fd[],
148 /* Wait for either messages or handles
149 * -> Use MsgWaitForMultipleObjectsEx
151 if (_g_main_poll_debug)
152 g_print (" MsgWaitForMultipleObjectsEx(%d, %lu)\n", nhandles, timeout_ms);
154 ready = MsgWaitForMultipleObjectsEx (nhandles, handles, timeout_ms,
155 QS_ALLINPUT, MWMO_ALERTABLE);
157 if (ready == WAIT_FAILED)
159 gchar *emsg = g_win32_error_message (GetLastError ());
160 g_warning ("MsgWaitForMultipleObjectsEx failed: %s", emsg);
164 else if (nhandles == 0)
166 /* No handles to wait for, just the timeout */
167 if (timeout_ms == INFINITE)
171 /* Wait for the current process to die, more efficient than SleepEx(). */
172 WaitForSingleObjectEx (GetCurrentProcess (), timeout_ms, TRUE);
173 ready = WAIT_TIMEOUT;
178 /* Wait for just handles
179 * -> Use WaitForMultipleObjectsEx
181 if (_g_main_poll_debug)
182 g_print (" WaitForMultipleObjectsEx(%d, %lu)\n", nhandles, timeout_ms);
184 ready = WaitForMultipleObjectsEx (nhandles, handles, FALSE, timeout_ms, TRUE);
185 if (ready == WAIT_FAILED)
187 gchar *emsg = g_win32_error_message (GetLastError ());
188 g_warning ("WaitForMultipleObjectsEx failed: %s", emsg);
193 if (_g_main_poll_debug)
194 g_print (" wait returns %ld%s\n",
196 (ready == WAIT_FAILED ? " (WAIT_FAILED)" :
197 (ready == WAIT_TIMEOUT ? " (WAIT_TIMEOUT)" :
198 (msg_fd != NULL && ready == WAIT_OBJECT_0 + nhandles ? " (msg)" : ""))));
200 if (ready == WAIT_FAILED)
202 else if (ready == WAIT_TIMEOUT ||
203 ready == WAIT_IO_COMPLETION)
205 else if (msg_fd != NULL && ready == WAIT_OBJECT_0 + nhandles)
207 msg_fd->revents |= G_IO_IN;
209 /* If we have a timeout, or no handles to poll, be satisfied
210 * with just noticing we have messages waiting.
212 if (timeout_ms != 0 || nhandles == 0)
215 /* If no timeout and handles to poll, recurse to poll them,
218 recursed_result = poll_rest (NULL, stop_fd, handles, handle_to_fd, nhandles, 0);
219 return (recursed_result == -1) ? -1 : 1 + recursed_result;
221 else if (ready < WAIT_OBJECT_0 + nhandles)
225 f = handle_to_fd[ready - WAIT_OBJECT_0];
226 f->revents = f->events;
227 if (_g_main_poll_debug)
228 g_print (" got event %p\n", (HANDLE) f->fd);
230 /* Do not count the stop_fd */
231 retval = (f != stop_fd) ? 1 : 0;
233 /* If no timeout and polling several handles, recurse to poll
236 if (timeout_ms == 0 && nhandles > 1)
238 /* Poll the handles with index > ready */
239 HANDLE *shorter_handles;
240 GPollFD **shorter_handle_to_fd;
241 gint shorter_nhandles;
243 shorter_handles = &handles[ready - WAIT_OBJECT_0 + 1];
244 shorter_handle_to_fd = &handle_to_fd[ready - WAIT_OBJECT_0 + 1];
245 shorter_nhandles = nhandles - (ready - WAIT_OBJECT_0 + 1);
247 recursed_result = poll_rest (NULL, stop_fd, shorter_handles, shorter_handle_to_fd, shorter_nhandles, 0);
248 return (recursed_result == -1) ? -1 : retval + recursed_result;
258 HANDLE handles[MAXIMUM_WAIT_OBJECTS];
259 GPollFD *handle_to_fd[MAXIMUM_WAIT_OBJECTS];
264 } GWin32PollThreadData;
267 poll_single_thread (GWin32PollThreadData *data)
271 /* Polling for several things? */
272 if (data->nhandles > 1 || (data->nhandles > 0 && data->msg_fd != NULL))
274 /* First check if one or several of them are immediately
277 retval = poll_rest (data->msg_fd, data->stop_fd, data->handles, data->handle_to_fd, data->nhandles, 0);
279 /* If not, and we have a significant timeout, poll again with
280 * timeout then. Note that this will return indication for only
281 * one event, or only for messages.
283 if (retval == 0 && (data->timeout_ms == INFINITE || data->timeout_ms > 0))
284 retval = poll_rest (data->msg_fd, data->stop_fd, data->handles, data->handle_to_fd, data->nhandles, data->timeout_ms);
288 /* Just polling for one thing, so no need to check first if
289 * available immediately
291 retval = poll_rest (data->msg_fd, data->stop_fd, data->handles, data->handle_to_fd, data->nhandles, data->timeout_ms);
298 fill_poll_thread_data (GPollFD *fds,
302 GWin32PollThreadData *data)
306 data->timeout_ms = timeout_ms;
310 if (_g_main_poll_debug)
311 g_print (" Stop FD: %p", (HANDLE) stop_fd->fd);
313 g_assert (data->nhandles < MAXIMUM_WAIT_OBJECTS);
315 data->stop_fd = stop_fd;
316 data->handle_to_fd[data->nhandles] = stop_fd;
317 data->handles[data->nhandles++] = (HANDLE) stop_fd->fd;
320 for (f = fds; f < &fds[nfds]; ++f)
322 if ((data->nhandles == MAXIMUM_WAIT_OBJECTS) ||
323 (data->msg_fd != NULL && (data->nhandles == MAXIMUM_WAIT_OBJECTS - 1)))
325 g_warning ("Too many handles to wait for!");
329 if (f->fd == G_WIN32_MSG_HANDLE && (f->events & G_IO_IN))
331 if (_g_main_poll_debug && data->msg_fd == NULL)
337 if (_g_main_poll_debug)
338 g_print (" %p", (HANDLE) f->fd);
339 data->handle_to_fd[data->nhandles] = f;
340 data->handles[data->nhandles++] = (HANDLE) f->fd;
347 static guint __stdcall
348 poll_thread_run (gpointer user_data)
350 GWin32PollThreadData *data = user_data;
352 /* Docs say that it is safer to call _endthreadex by our own:
353 * https://docs.microsoft.com/en-us/cpp/c-runtime-library/reference/endthread-endthreadex
355 _endthreadex (poll_single_thread (data));
357 g_assert_not_reached ();
362 /* One slot for a possible msg object or the stop event */
363 #define MAXIMUM_WAIT_OBJECTS_PER_THREAD (MAXIMUM_WAIT_OBJECTS - 1)
366 g_poll (GPollFD *fds,
370 guint nthreads, threads_remain;
371 HANDLE thread_handles[MAXIMUM_WAIT_OBJECTS];
372 GWin32PollThreadData *threads_data;
373 GPollFD stop_event = { 0, };
375 guint i, fds_idx = 0;
379 GPollFD *msg_fd = NULL;
384 /* Simple case without extra threads */
385 if (nfds <= MAXIMUM_WAIT_OBJECTS)
387 GWin32PollThreadData data = { 0, };
389 if (_g_main_poll_debug)
390 g_print ("g_poll: waiting for");
392 fill_poll_thread_data (fds, nfds, timeout, NULL, &data);
394 if (_g_main_poll_debug)
397 retval = poll_single_thread (&data);
399 for (f = fds; f < &fds[nfds]; ++f)
405 if (_g_main_poll_debug)
406 g_print ("g_poll: polling with threads\n");
408 nthreads = nfds / MAXIMUM_WAIT_OBJECTS_PER_THREAD;
409 threads_remain = nfds % MAXIMUM_WAIT_OBJECTS_PER_THREAD;
410 if (threads_remain > 0)
413 if (nthreads > MAXIMUM_WAIT_OBJECTS_PER_THREAD)
415 g_warning ("Too many handles to wait for in threads!");
416 nthreads = MAXIMUM_WAIT_OBJECTS_PER_THREAD;
419 #if GLIB_SIZEOF_VOID_P == 8
420 stop_event.fd = (gint64)CreateEventW (NULL, TRUE, FALSE, NULL);
422 stop_event.fd = (gint)CreateEventW (NULL, TRUE, FALSE, NULL);
424 stop_event.events = G_IO_IN;
426 threads_data = g_new0 (GWin32PollThreadData, nthreads);
427 for (i = 0; i < nthreads; i++)
432 if (i == (nthreads - 1) && threads_remain > 0)
433 thread_fds = threads_remain;
435 thread_fds = MAXIMUM_WAIT_OBJECTS_PER_THREAD;
437 fill_poll_thread_data (fds + fds_idx, thread_fds, timeout, &stop_event, &threads_data[i]);
438 fds_idx += thread_fds;
440 /* We must poll for messages from the same thread, so poll it along with the threads */
441 if (threads_data[i].msg_fd != NULL)
443 msg_fd = threads_data[i].msg_fd;
444 threads_data[i].msg_fd = NULL;
447 thread_handles[i] = (HANDLE) _beginthreadex (NULL, 0, poll_thread_run, &threads_data[i], 0, &ignore);
450 /* Wait for at least one thread to return */
452 ready = MsgWaitForMultipleObjectsEx (nthreads, thread_handles, timeout,
453 QS_ALLINPUT, MWMO_ALERTABLE);
455 ready = WaitForMultipleObjects (nthreads, thread_handles, FALSE, timeout);
457 /* Signal the stop in case any of the threads did not stop yet */
458 if (!SetEvent ((HANDLE)stop_event.fd))
460 gchar *emsg = g_win32_error_message (GetLastError ());
461 g_warning ("gpoll: failed to signal the stop event: %s", emsg);
465 /* Wait for the rest of the threads to finish */
466 WaitForMultipleObjects (nthreads, thread_handles, TRUE, INFINITE);
468 /* The return value of all the threads give us all the fds that changed state */
470 if (msg_fd != NULL && ready == WAIT_OBJECT_0 + nthreads)
472 msg_fd->revents |= G_IO_IN;
476 for (i = 0; i < nthreads; i++)
478 if (GetExitCodeThread (thread_handles[i], &thread_retval))
479 retval = (retval == -1) ? -1 : ((thread_retval == (DWORD) -1) ? -1 : (int) (retval + thread_retval));
481 CloseHandle (thread_handles[i]);
485 for (f = fds; f < &fds[nfds]; ++f)
488 g_free (threads_data);
489 CloseHandle ((HANDLE)stop_event.fd);
494 #else /* !G_OS_WIN32 */
496 /* The following implementation of poll() comes from the GNU C Library.
497 * Copyright (C) 1994, 1996, 1997 Free Software Foundation, Inc.
500 #include <string.h> /* for bzero on BSD systems */
502 #ifdef HAVE_SYS_SELECT_H
503 #include <sys/select.h>
504 #endif /* HAVE_SYS_SELECT_H */
507 g_poll (GPollFD *fds,
512 fd_set rset, wset, xset;
521 for (f = fds; f < &fds[nfds]; ++f)
524 if (f->events & G_IO_IN)
525 FD_SET (f->fd, &rset);
526 if (f->events & G_IO_OUT)
527 FD_SET (f->fd, &wset);
528 if (f->events & G_IO_PRI)
529 FD_SET (f->fd, &xset);
530 if (f->fd > maxfd && (f->events & (G_IO_IN|G_IO_OUT|G_IO_PRI)))
534 tv.tv_sec = timeout / 1000;
535 tv.tv_usec = (timeout % 1000) * 1000;
537 ready = select (maxfd + 1, &rset, &wset, &xset,
538 timeout == -1 ? NULL : &tv);
540 for (f = fds; f < &fds[nfds]; ++f)
545 if (FD_ISSET (f->fd, &rset))
546 f->revents |= G_IO_IN;
547 if (FD_ISSET (f->fd, &wset))
548 f->revents |= G_IO_OUT;
549 if (FD_ISSET (f->fd, &xset))
550 f->revents |= G_IO_PRI;
557 #endif /* !G_OS_WIN32 */
559 #endif /* !HAVE_POLL */