From ac68024ec1a476871111522e5ce48945b18ce9f7 Mon Sep 17 00:00:00 2001 From: Dan Winship Date: Tue, 23 Sep 2008 16:32:30 +0000 Subject: [PATCH] Move this out of gmain.c and make it part of the public API. (Part of Bug * glib/gpoll.c (g_poll): Move this out of gmain.c and make it part of the public API. (Part of Bug 505361 - gunixinputstream.c assumes poll() available.) svn path=/trunk/; revision=7535 --- docs/reference/glib/glib-sections.txt | 2 + docs/reference/glib/tmpl/main.sgml | 11 + glib/Makefile.am | 2 + glib/giowin32.c | 6 +- glib/glib.symbols | 6 + glib/gmain.c | 347 +-------------------------- glib/gmain.h | 43 +--- glib/gpoll.c | 430 ++++++++++++++++++++++++++++++++++ glib/gpoll.h | 93 ++++++++ 9 files changed, 551 insertions(+), 389 deletions(-) create mode 100644 glib/gpoll.c create mode 100644 glib/gpoll.h diff --git a/docs/reference/glib/glib-sections.txt b/docs/reference/glib/glib-sections.txt index d311664..8b3415a 100644 --- a/docs/reference/glib/glib-sections.txt +++ b/docs/reference/glib/glib-sections.txt @@ -468,8 +468,10 @@ GChildWatchFunc g_child_watch_source_new g_child_watch_add g_child_watch_add_full + GPollFD +g_poll GSource diff --git a/docs/reference/glib/tmpl/main.sgml b/docs/reference/glib/tmpl/main.sgml index 185202c..d711c09 100644 --- a/docs/reference/glib/tmpl/main.sgml +++ b/docs/reference/glib/tmpl/main.sgml @@ -725,6 +725,17 @@ you would use %G_IO_IN | %G_IO_HUP | %G_IO_ERR, and for writing you would use @events: @revents: + + + + + +@fds: +@nfds: +@timeout: +@Returns: + + The GSource struct is an opaque data type representing diff --git a/glib/Makefile.am b/glib/Makefile.am index 81a9656..94556b6 100644 --- a/glib/Makefile.am +++ b/glib/Makefile.am @@ -129,6 +129,7 @@ libglib_2_0_la_SOURCES = \ gnode.c \ goption.c \ gpattern.c \ + gpoll.c \ gprimes.c \ gqsort.c \ gqueue.c \ @@ -212,6 +213,7 @@ glibsubinclude_HEADERS = \ gnode.h \ goption.h \ gpattern.h \ + gpoll.h \ gprimes.h \ gqsort.h \ gquark.h \ diff --git a/glib/giowin32.c b/glib/giowin32.c index c31aa8e..7f39547 100644 --- a/glib/giowin32.c +++ b/glib/giowin32.c @@ -2121,13 +2121,9 @@ g_io_channel_win32_poll (GPollFD *fds, gint n_fds, gint timeout) { - int result; - g_return_val_if_fail (n_fds >= 0, 0); - result = (*g_main_context_get_poll_func (NULL)) (fds, n_fds, timeout); - - return result; + return g_poll (fds, n_fds, timeout); } void diff --git a/glib/glib.symbols b/glib/glib.symbols index 06e6ea2..5ca5fec 100644 --- a/glib/glib.symbols +++ b/glib/glib.symbols @@ -845,6 +845,12 @@ g_pattern_spec_new #endif #endif +#if IN_HEADER(__G_POLL_H__) +#if IN_FILE(__G_POLL_C__) +g_poll +#endif +#endif + #if IN_HEADER(__G_PRIMES_H__) #if IN_FILE(__G_PRIMES_C__) g_spaced_primes_closest G_GNUC_CONST diff --git a/glib/gmain.c b/glib/gmain.c index 6b444bd..0b30c5b 100644 --- a/glib/gmain.c +++ b/glib/gmain.c @@ -33,8 +33,9 @@ #include "config.h" -/* Uncomment the next line to enable debugging printouts if the - * environment variable G_MAIN_POLL_DEBUG is set to some value. +/* Uncomment the next line (and the corresponding line in gpoll.c) to + * enable debugging printouts if the environment variable + * G_MAIN_POLL_DEBUG is set to some value. */ /* #define G_MAIN_POLL_DEBUG */ @@ -54,19 +55,6 @@ #ifdef HAVE_SYS_TIME_H #include #endif /* HAVE_SYS_TIME_H */ -#ifdef GLIB_HAVE_SYS_POLL_H -# include -# undef events /* AIX 4.1.5 & 4.3.2 define this for SVR3,4 compatibility */ -# undef revents /* AIX 4.1.5 & 4.3.2 define this for SVR3,4 compatibility */ - -/* The poll() emulation on OS/X doesn't handle fds=NULL, nfds=0, - * so we prefer our own poll emulation. - */ -#if defined(_POLL_EMUL_H_) || defined(BROKEN_POLL) -#undef HAVE_POLL -#endif - -#endif /* GLIB_HAVE_SYS_POLL_H */ #ifdef HAVE_UNISTD_H #include #endif /* HAVE_UNISTD_H */ @@ -89,16 +77,6 @@ #include "galias.h" -#ifdef G_OS_WIN32 -#ifdef _WIN64 -#define GPOLLFD_FORMAT "%#I64x" -#else -#define GPOLLFD_FORMAT "%#x" -#endif -#else -#define GPOLLFD_FORMAT "%d" -#endif - /* Types */ typedef struct _GTimeoutSource GTimeoutSource; @@ -332,311 +310,6 @@ GSourceFuncs g_idle_funcs = NULL }; -#ifdef HAVE_POLL -/* SunOS has poll, but doesn't provide a prototype. */ -# if defined (sun) && !defined (__SVR4) -extern gint poll (GPollFD *ufds, guint nfsd, gint timeout); -# endif /* !sun */ -#else /* !HAVE_POLL */ - -#ifdef G_OS_WIN32 - -static int -poll_rest (gboolean poll_msgs, - HANDLE *handles, - gint nhandles, - GPollFD *fds, - guint nfds, - gint timeout) -{ - DWORD ready; - GPollFD *f; - int recursed_result; - - if (poll_msgs) - { - /* Wait for either messages or handles - * -> Use MsgWaitForMultipleObjectsEx - */ - if (g_main_poll_debug) - g_print (" MsgWaitForMultipleObjectsEx(%d, %d)\n", nhandles, timeout); - - ready = MsgWaitForMultipleObjectsEx (nhandles, handles, timeout, - QS_ALLINPUT, MWMO_ALERTABLE); - - if (ready == WAIT_FAILED) - { - gchar *emsg = g_win32_error_message (GetLastError ()); - g_warning ("MsgWaitForMultipleObjectsEx failed: %s", emsg); - g_free (emsg); - } - } - else if (nhandles == 0) - { - /* No handles to wait for, just the timeout */ - if (timeout == INFINITE) - ready = WAIT_FAILED; - else - { - SleepEx (timeout, TRUE); - ready = WAIT_TIMEOUT; - } - } - else - { - /* Wait for just handles - * -> Use WaitForMultipleObjectsEx - */ - if (g_main_poll_debug) - g_print (" WaitForMultipleObjectsEx(%d, %d)\n", nhandles, timeout); - - ready = WaitForMultipleObjectsEx (nhandles, handles, FALSE, timeout, TRUE); - if (ready == WAIT_FAILED) - { - gchar *emsg = g_win32_error_message (GetLastError ()); - g_warning ("WaitForMultipleObjectsEx failed: %s", emsg); - g_free (emsg); - } - } - - if (g_main_poll_debug) - g_print (" wait returns %ld%s\n", - ready, - (ready == WAIT_FAILED ? " (WAIT_FAILED)" : - (ready == WAIT_TIMEOUT ? " (WAIT_TIMEOUT)" : - (poll_msgs && ready == WAIT_OBJECT_0 + nhandles ? " (msg)" : "")))); - - if (ready == WAIT_FAILED) - return -1; - else if (ready == WAIT_TIMEOUT || - ready == WAIT_IO_COMPLETION) - return 0; - else if (poll_msgs && ready == WAIT_OBJECT_0 + nhandles) - { - for (f = fds; f < &fds[nfds]; ++f) - if (f->fd == G_WIN32_MSG_HANDLE && f->events & G_IO_IN) - f->revents |= G_IO_IN; - - /* If we have a timeout, or no handles to poll, be satisfied - * with just noticing we have messages waiting. - */ - if (timeout != 0 || nhandles == 0) - return 1; - - /* If no timeout and handles to poll, recurse to poll them, - * too. - */ - recursed_result = poll_rest (FALSE, handles, nhandles, fds, nfds, 0); - return (recursed_result == -1) ? -1 : 1 + recursed_result; - } - else if (ready >= WAIT_OBJECT_0 && ready < WAIT_OBJECT_0 + nhandles) - { - for (f = fds; f < &fds[nfds]; ++f) - { - if ((HANDLE) f->fd == handles[ready - WAIT_OBJECT_0]) - { - f->revents = f->events; - if (g_main_poll_debug) - g_print (" got event %p\n", (HANDLE) f->fd); - } - } - - /* If no timeout and polling several handles, recurse to poll - * the rest of them. - */ - if (timeout == 0 && nhandles > 1) - { - /* Remove the handle that fired */ - int i; - if (ready < nhandles - 1) - for (i = ready - WAIT_OBJECT_0 + 1; i < nhandles; i++) - handles[i-1] = handles[i]; - nhandles--; - recursed_result = poll_rest (FALSE, handles, nhandles, fds, nfds, 0); - return (recursed_result == -1) ? -1 : 1 + recursed_result; - } - return 1; - } - - return 0; -} - - -static gint -g_poll (GPollFD *fds, - guint nfds, - gint timeout) -{ - HANDLE handles[MAXIMUM_WAIT_OBJECTS]; - gboolean poll_msgs = FALSE; - GPollFD *f; - gint nhandles = 0; - int retval; - - if (g_main_poll_debug) - g_print ("g_poll: waiting for"); - - for (f = fds; f < &fds[nfds]; ++f) - if (f->fd == G_WIN32_MSG_HANDLE && (f->events & G_IO_IN)) - { - if (g_main_poll_debug && !poll_msgs) - g_print (" MSG"); - poll_msgs = TRUE; - } - else if (f->fd > 0) - { - /* Don't add the same handle several times into the array, as - * docs say that is not allowed, even if it actually does seem - * to work. - */ - gint i; - - for (i = 0; i < nhandles; i++) - if (handles[i] == (HANDLE) f->fd) - break; - - if (i == nhandles) - { - if (nhandles == MAXIMUM_WAIT_OBJECTS) - { - g_warning ("Too many handles to wait for!\n"); - break; - } - else - { - if (g_main_poll_debug) - g_print (" %p", (HANDLE) f->fd); - handles[nhandles++] = (HANDLE) f->fd; - } - } - } - - if (g_main_poll_debug) - g_print ("\n"); - - for (f = fds; f < &fds[nfds]; ++f) - f->revents = 0; - - if (timeout == -1) - timeout = INFINITE; - - /* Polling for several things? */ - if (nhandles > 1 || (nhandles > 0 && poll_msgs)) - { - /* First check if one or several of them are immediately - * available - */ - retval = poll_rest (poll_msgs, handles, nhandles, fds, nfds, 0); - - /* If not, and we have a significant timeout, poll again with - * timeout then. Note that this will return indication for only - * one event, or only for messages. We ignore timeouts less than - * ten milliseconds as they are mostly pointless on Windows, the - * MsgWaitForMultipleObjectsEx() call will timeout right away - * anyway. - */ - if (retval == 0 && (timeout == INFINITE || timeout >= 10)) - retval = poll_rest (poll_msgs, handles, nhandles, fds, nfds, timeout); - } - else - { - /* Just polling for one thing, so no need to check first if - * available immediately - */ - retval = poll_rest (poll_msgs, handles, nhandles, fds, nfds, timeout); - } - - if (retval == -1) - for (f = fds; f < &fds[nfds]; ++f) - f->revents = 0; - - return retval; -} - -#else /* !G_OS_WIN32 */ - -/* The following implementation of poll() comes from the GNU C Library. - * Copyright (C) 1994, 1996, 1997 Free Software Foundation, Inc. - */ - -#include /* for bzero on BSD systems */ - -#ifdef HAVE_SYS_SELECT_H -#include -#endif /* HAVE_SYS_SELECT_H */ - -#ifdef G_OS_BEOS -#undef NO_FD_SET -#endif /* G_OS_BEOS */ - -#ifndef NO_FD_SET -# define SELECT_MASK fd_set -#else /* !NO_FD_SET */ -# ifndef _AIX -typedef long fd_mask; -# endif /* _AIX */ -# ifdef _IBMR2 -# define SELECT_MASK void -# else /* !_IBMR2 */ -# define SELECT_MASK int -# endif /* !_IBMR2 */ -#endif /* !NO_FD_SET */ - -static gint -g_poll (GPollFD *fds, - guint nfds, - gint timeout) -{ - struct timeval tv; - SELECT_MASK rset, wset, xset; - GPollFD *f; - int ready; - int maxfd = 0; - - FD_ZERO (&rset); - FD_ZERO (&wset); - FD_ZERO (&xset); - - for (f = fds; f < &fds[nfds]; ++f) - if (f->fd >= 0) - { - if (f->events & G_IO_IN) - FD_SET (f->fd, &rset); - if (f->events & G_IO_OUT) - FD_SET (f->fd, &wset); - if (f->events & G_IO_PRI) - FD_SET (f->fd, &xset); - if (f->fd > maxfd && (f->events & (G_IO_IN|G_IO_OUT|G_IO_PRI))) - maxfd = f->fd; - } - - tv.tv_sec = timeout / 1000; - tv.tv_usec = (timeout % 1000) * 1000; - - ready = select (maxfd + 1, &rset, &wset, &xset, - timeout == -1 ? NULL : &tv); - if (ready > 0) - for (f = fds; f < &fds[nfds]; ++f) - { - f->revents = 0; - if (f->fd >= 0) - { - if (FD_ISSET (f->fd, &rset)) - f->revents |= G_IO_IN; - if (FD_ISSET (f->fd, &wset)) - f->revents |= G_IO_OUT; - if (FD_ISSET (f->fd, &xset)) - f->revents |= G_IO_PRI; - } - } - - return ready; -} - -#endif /* !G_OS_WIN32 */ - -#endif /* !HAVE_POLL */ - /** * g_main_context_ref: * @context: a #GMainContext @@ -813,11 +486,7 @@ g_main_context_new (void) context->source_list = NULL; -#if HAVE_POLL - context->poll_func = (GPollFunc)poll; -#else context->poll_func = g_poll; -#endif context->cached_poll_array = NULL; context->cached_poll_array_size = 0; @@ -3119,7 +2788,7 @@ g_main_context_poll (GMainContext *context, pollrec->fd->events && fds[i].revents) { - g_print (" [" GPOLLFD_FORMAT " :", fds[i].fd); + g_print (" [" G_POLLFD_FORMAT " :", fds[i].fd); if (fds[i].revents & G_IO_IN) g_print ("i"); if (fds[i].revents & G_IO_OUT) @@ -3333,13 +3002,7 @@ g_main_context_set_poll_func (GMainContext *context, if (func) context->poll_func = func; else - { -#ifdef HAVE_POLL - context->poll_func = (GPollFunc) poll; -#else - context->poll_func = (GPollFunc) g_poll; -#endif - } + context->poll_func = g_poll; UNLOCK_CONTEXT (context); } diff --git a/glib/gmain.h b/glib/gmain.h index db20e68..3f0e9cd 100644 --- a/glib/gmain.h +++ b/glib/gmain.h @@ -24,6 +24,7 @@ #ifndef __G_MAIN_H__ #define __G_MAIN_H__ +#include #include #include @@ -90,48 +91,6 @@ struct _GSourceFuncs GSourceDummyMarshal closure_marshal; /* Really is of type GClosureMarshal */ }; -/* Any definitions using GPollFD or GPollFunc are primarily - * for Unix and not guaranteed to be the compatible on all - * operating systems on which GLib runs. Right now, the - * GLib does use these functions on Win32 as well, but interprets - * them in a fairly different way than on Unix. If you use - * these definitions, you are should be prepared to recode - * for different operating systems. - * - * - * On Win32, the fd in a GPollFD should be Win32 HANDLE (*not* a file - * descriptor as provided by the C runtime) that can be used by - * MsgWaitForMultipleObjects. This does *not* include file handles - * from CreateFile, SOCKETs, nor pipe handles. (But you can use - * WSAEventSelect to signal events when a SOCKET is readable). - * - * On Win32, fd can also be the special value G_WIN32_MSG_HANDLE to - * indicate polling for messages. - * - * But note that G_WIN32_MSG_HANDLE GPollFDs should not be used by GDK - * (GTK) programs, as GDK itself wants to read messages and convert them - * to GDK events. - * - * So, unless you really know what you are doing, it's best not to try - * to use the main loop polling stuff for your own needs on - * Windows. - */ -typedef struct _GPollFD GPollFD; -typedef gint (*GPollFunc) (GPollFD *ufds, - guint nfsd, - gint timeout_); - -struct _GPollFD -{ -#if defined (G_OS_WIN32) && GLIB_SIZEOF_VOID_P == 8 - gint64 fd; -#else - gint fd; -#endif - gushort events; - gushort revents; -}; - /* Standard priorities */ #define G_PRIORITY_HIGH -100 diff --git a/glib/gpoll.c b/glib/gpoll.c new file mode 100644 index 0000000..d26cf2f --- /dev/null +++ b/glib/gpoll.c @@ -0,0 +1,430 @@ +/* GLIB - Library of useful routines for C programming + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * + * gpoll.c: poll(2) abstraction + * Copyright 1998 Owen Taylor + * Copyright 2008 Red Hat, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +/* + * Modified by the GLib Team and others 1997-2000. See the AUTHORS + * file for a list of people on the GLib Team. See the ChangeLog + * files for a list of changes. These files are distributed with + * GLib at ftp://ftp.gtk.org/pub/gtk/. + */ + +/* + * MT safe + */ + +#include "config.h" + +/* Uncomment the next line (and the corresponding line in gmain.c) to + * enable debugging printouts if the environment variable + * G_MAIN_POLL_DEBUG is set to some value. + */ +/* #define G_MAIN_POLL_DEBUG */ + +#ifdef _WIN32 +/* Always enable debugging printout on Windows, as it is more often + * needed there... + */ +#define G_MAIN_POLL_DEBUG +#endif + +#include "glib.h" +#include +#include +#include +#ifdef HAVE_SYS_TIME_H +#include +#endif /* HAVE_SYS_TIME_H */ +#ifdef GLIB_HAVE_SYS_POLL_H +# include +# undef events /* AIX 4.1.5 & 4.3.2 define this for SVR3,4 compatibility */ +# undef revents /* AIX 4.1.5 & 4.3.2 define this for SVR3,4 compatibility */ + +/* The poll() emulation on OS/X doesn't handle fds=NULL, nfds=0, + * so we prefer our own poll emulation. + */ +#if defined(_POLL_EMUL_H_) || defined(BROKEN_POLL) +#undef HAVE_POLL +#endif + +#endif /* GLIB_HAVE_SYS_POLL_H */ +#ifdef HAVE_UNISTD_H +#include +#endif /* HAVE_UNISTD_H */ +#include + +#ifdef G_OS_WIN32 +#define STRICT +#include +#endif /* G_OS_WIN32 */ + +#include "galias.h" + +#ifdef G_MAIN_POLL_DEBUG +extern gboolean g_main_poll_debug; +#endif + +#ifdef HAVE_POLL +/* SunOS has poll, but doesn't provide a prototype. */ +# if defined (sun) && !defined (__SVR4) +extern gint poll (struct pollfd *fds, guint nfsd, gint timeout); +# endif /* !sun */ + +/** + * g_poll: + * @fds: file descriptors to poll + * @nfds: the number of file descriptors in @fds + * @timeout: amount of time to wait, in milliseconds, or -1 to wait forever + * + * Polls @fds, as with the poll() system call, but portably. (On + * systems that don't have poll(), it is emulated using select().) + * This is used internally by #GMainContext, but it can be called + * directly if you need to block until a file descriptor is ready, but + * don't want to run the full main loop. + * + * Each element of @fds is a #GPollFD describing a single file + * descriptor to poll. The %fd field indicates the file descriptor, + * and the %events field indicates the events to poll for. On return, + * the %revents fields will be filled with the events that actually + * occurred. + * + * On POSIX systems, the file descriptors in @fds can be any sort of + * file descriptor, but the situation is much more complicated on + * Windows. If you need to use g_poll() in code that has to run on + * Windows, the easiest solution is to construct all of your + * #GPollFDs with g_io_channel_win32_make_pollfd(). + * + * Return value: the number of entries in @fds whose %revents fields + * were filled in, or 0 if the operation timed out, or -1 on error or + * if the call was interrupted. + * + * Since: 2.20 + **/ +gint +g_poll (GPollFD *fds, + guint nfds, + gint timeout) +{ + return poll ((struct pollfd *)fds, nfds, timeout); +} + +#else /* !HAVE_POLL */ + +#ifdef G_OS_WIN32 + +static int +poll_rest (gboolean poll_msgs, + HANDLE *handles, + gint nhandles, + GPollFD *fds, + guint nfds, + gint timeout) +{ + DWORD ready; + GPollFD *f; + int recursed_result; + + if (poll_msgs) + { + /* Wait for either messages or handles + * -> Use MsgWaitForMultipleObjectsEx + */ + if (g_main_poll_debug) + g_print (" MsgWaitForMultipleObjectsEx(%d, %d)\n", nhandles, timeout); + + ready = MsgWaitForMultipleObjectsEx (nhandles, handles, timeout, + QS_ALLINPUT, MWMO_ALERTABLE); + + if (ready == WAIT_FAILED) + { + gchar *emsg = g_win32_error_message (GetLastError ()); + g_warning ("MsgWaitForMultipleObjectsEx failed: %s", emsg); + g_free (emsg); + } + } + else if (nhandles == 0) + { + /* No handles to wait for, just the timeout */ + if (timeout == INFINITE) + ready = WAIT_FAILED; + else + { + SleepEx (timeout, TRUE); + ready = WAIT_TIMEOUT; + } + } + else + { + /* Wait for just handles + * -> Use WaitForMultipleObjectsEx + */ + if (g_main_poll_debug) + g_print (" WaitForMultipleObjectsEx(%d, %d)\n", nhandles, timeout); + + ready = WaitForMultipleObjectsEx (nhandles, handles, FALSE, timeout, TRUE); + if (ready == WAIT_FAILED) + { + gchar *emsg = g_win32_error_message (GetLastError ()); + g_warning ("WaitForMultipleObjectsEx failed: %s", emsg); + g_free (emsg); + } + } + + if (g_main_poll_debug) + g_print (" wait returns %ld%s\n", + ready, + (ready == WAIT_FAILED ? " (WAIT_FAILED)" : + (ready == WAIT_TIMEOUT ? " (WAIT_TIMEOUT)" : + (poll_msgs && ready == WAIT_OBJECT_0 + nhandles ? " (msg)" : "")))); + + if (ready == WAIT_FAILED) + return -1; + else if (ready == WAIT_TIMEOUT || + ready == WAIT_IO_COMPLETION) + return 0; + else if (poll_msgs && ready == WAIT_OBJECT_0 + nhandles) + { + for (f = fds; f < &fds[nfds]; ++f) + if (f->fd == G_WIN32_MSG_HANDLE && f->events & G_IO_IN) + f->revents |= G_IO_IN; + + /* If we have a timeout, or no handles to poll, be satisfied + * with just noticing we have messages waiting. + */ + if (timeout != 0 || nhandles == 0) + return 1; + + /* If no timeout and handles to poll, recurse to poll them, + * too. + */ + recursed_result = poll_rest (FALSE, handles, nhandles, fds, nfds, 0); + return (recursed_result == -1) ? -1 : 1 + recursed_result; + } + else if (ready >= WAIT_OBJECT_0 && ready < WAIT_OBJECT_0 + nhandles) + { + for (f = fds; f < &fds[nfds]; ++f) + { + if ((HANDLE) f->fd == handles[ready - WAIT_OBJECT_0]) + { + f->revents = f->events; + if (g_main_poll_debug) + g_print (" got event %p\n", (HANDLE) f->fd); + } + } + + /* If no timeout and polling several handles, recurse to poll + * the rest of them. + */ + if (timeout == 0 && nhandles > 1) + { + /* Remove the handle that fired */ + if (ready < nhandles - 1) + for (i = ready - WAIT_OBJECT_0 + 1; i < nhandles; i++) + handles[i-1] = handles[i]; + nhandles--; + recursed_result = poll_rest (FALSE, handles, nhandles, fds, nfds, 0); + return (recursed_result == -1) ? -1 : 1 + recursed_result; + } + return 1; + } + + return 0; +} + + +static gint +g_poll (GPollFD *fds, + guint nfds, + gint timeout) +{ + HANDLE handles[MAXIMUM_WAIT_OBJECTS]; + gboolean poll_msgs = FALSE; + GPollFD *f; + gint nhandles = 0; + int retval; + + if (g_main_poll_debug) + g_print ("g_poll: waiting for"); + + for (f = fds; f < &fds[nfds]; ++f) + if (f->fd == G_WIN32_MSG_HANDLE && (f->events & G_IO_IN)) + { + if (g_main_poll_debug && !poll_msgs) + g_print (" MSG"); + poll_msgs = TRUE; + } + else if (f->fd > 0) + { + /* Don't add the same handle several times into the array, as + * docs say that is not allowed, even if it actually does seem + * to work. + */ + gint i; + + for (i = 0; i < nhandles; i++) + if (handles[i] == (HANDLE) f->fd) + break; + + if (i == nhandles) + { + if (nhandles == MAXIMUM_WAIT_OBJECTS) + { + g_warning ("Too many handles to wait for!\n"); + break; + } + else + { + if (g_main_poll_debug) + g_print (" %p", (HANDLE) f->fd); + handles[nhandles++] = (HANDLE) f->fd; + } + } + } + + if (g_main_poll_debug) + g_print ("\n"); + + for (f = fds; f < &fds[nfds]; ++f) + f->revents = 0; + + if (timeout == -1) + timeout = INFINITE; + + /* Polling for several things? */ + if (nhandles > 1 || (nhandles > 0 && poll_msgs)) + { + /* First check if one or several of them are immediately + * available + */ + retval = poll_rest (poll_msgs, handles, nhandles, fds, nfds, 0); + + /* If not, and we have a significant timeout, poll again with + * timeout then. Note that this will return indication for only + * one event, or only for messages. We ignore timeouts less than + * ten milliseconds as they are mostly pointless on Windows, the + * MsgWaitForMultipleObjectsEx() call will timeout right away + * anyway. + */ + if (retval == 0 && (timeout == INFINITE || timeout >= 10)) + retval = poll_rest (poll_msgs, handles, nhandles, fds, nfds, timeout); + } + else + { + /* Just polling for one thing, so no need to check first if + * available immediately + */ + retval = poll_rest (poll_msgs, handles, nhandles, fds, nfds, timeout); + } + + if (retval == -1) + for (f = fds; f < &fds[nfds]; ++f) + f->revents = 0; + + return retval; +} + +#else /* !G_OS_WIN32 */ + +/* The following implementation of poll() comes from the GNU C Library. + * Copyright (C) 1994, 1996, 1997 Free Software Foundation, Inc. + */ + +#include /* for bzero on BSD systems */ + +#ifdef HAVE_SYS_SELECT_H +#include +#endif /* HAVE_SYS_SELECT_H */ + +#ifdef G_OS_BEOS +#undef NO_FD_SET +#endif /* G_OS_BEOS */ + +#ifndef NO_FD_SET +# define SELECT_MASK fd_set +#else /* !NO_FD_SET */ +# ifndef _AIX +typedef long fd_mask; +# endif /* _AIX */ +# ifdef _IBMR2 +# define SELECT_MASK void +# else /* !_IBMR2 */ +# define SELECT_MASK int +# endif /* !_IBMR2 */ +#endif /* !NO_FD_SET */ + +gint +g_poll (GPollFD *fds, + guint nfds, + gint timeout) +{ + struct timeval tv; + SELECT_MASK rset, wset, xset; + GPollFD *f; + int ready; + int maxfd = 0; + + FD_ZERO (&rset); + FD_ZERO (&wset); + FD_ZERO (&xset); + + for (f = fds; f < &fds[nfds]; ++f) + if (f->fd >= 0) + { + if (f->events & G_IO_IN) + FD_SET (f->fd, &rset); + if (f->events & G_IO_OUT) + FD_SET (f->fd, &wset); + if (f->events & G_IO_PRI) + FD_SET (f->fd, &xset); + if (f->fd > maxfd && (f->events & (G_IO_IN|G_IO_OUT|G_IO_PRI))) + maxfd = f->fd; + } + + tv.tv_sec = timeout / 1000; + tv.tv_usec = (timeout % 1000) * 1000; + + ready = select (maxfd + 1, &rset, &wset, &xset, + timeout == -1 ? NULL : &tv); + if (ready > 0) + for (f = fds; f < &fds[nfds]; ++f) + { + f->revents = 0; + if (f->fd >= 0) + { + if (FD_ISSET (f->fd, &rset)) + f->revents |= G_IO_IN; + if (FD_ISSET (f->fd, &wset)) + f->revents |= G_IO_OUT; + if (FD_ISSET (f->fd, &xset)) + f->revents |= G_IO_PRI; + } + } + + return ready; +} + +#endif /* !G_OS_WIN32 */ + +#endif /* !HAVE_POLL */ + +#define __G_POLL_C__ +#include "galiasdef.c" diff --git a/glib/gpoll.h b/glib/gpoll.h new file mode 100644 index 0000000..dccd832 --- /dev/null +++ b/glib/gpoll.h @@ -0,0 +1,93 @@ +/* gpoll.h - poll(2) support + * Copyright (C) 2008 Red Hat, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#if defined(G_DISABLE_SINGLE_INCLUDES) && !defined (__GLIB_H_INSIDE__) && !defined (GLIB_COMPILATION) +#error "Only can be included directly." +#endif + +#ifndef __G_POLL_H__ +#define __G_POLL_H__ + +#include + +G_BEGIN_DECLS + +/* Any definitions using GPollFD or GPollFunc are primarily + * for Unix and not guaranteed to be the compatible on all + * operating systems on which GLib runs. Right now, the + * GLib does use these functions on Win32 as well, but interprets + * them in a fairly different way than on Unix. If you use + * these definitions, you are should be prepared to recode + * for different operating systems. + * + * Note that on systems with a working poll(2), that function is used + * in place of g_poll(). Thus g_poll() must have the same signature as + * poll(), meaning GPollFD must have the same layout as struct pollfd. + * + * + * On Win32, the fd in a GPollFD should be Win32 HANDLE (*not* a file + * descriptor as provided by the C runtime) that can be used by + * MsgWaitForMultipleObjects. This does *not* include file handles + * from CreateFile, SOCKETs, nor pipe handles. (But you can use + * WSAEventSelect to signal events when a SOCKET is readable). + * + * On Win32, fd can also be the special value G_WIN32_MSG_HANDLE to + * indicate polling for messages. + * + * But note that G_WIN32_MSG_HANDLE GPollFDs should not be used by GDK + * (GTK) programs, as GDK itself wants to read messages and convert them + * to GDK events. + * + * So, unless you really know what you are doing, it's best not to try + * to use the main loop polling stuff for your own needs on + * Windows. + */ +typedef struct _GPollFD GPollFD; +typedef gint (*GPollFunc) (GPollFD *ufds, + guint nfsd, + gint timeout_); + +struct _GPollFD +{ +#if defined (G_OS_WIN32) && GLIB_SIZEOF_VOID_P == 8 + gint64 fd; +#else + gint fd; +#endif + gushort events; + gushort revents; +}; + +#ifdef G_OS_WIN32 +#if GLIB_SIZEOF_VOID_P == 8 +#define G_POLLFD_FORMAT "%#I64x" +#else +#define G_POLLFD_FORMAT "%#x" +#endif +#else +#define G_POLLFD_FORMAT "%d" +#endif + +gint g_poll (GPollFD *fds, + guint nfds, + gint timeout); + +G_END_DECLS + +#endif /* __G_POLL_H__ */ -- 2.7.4