X-Git-Url: http://review.tizen.org/git/?a=blobdiff_plain;f=glib%2Fgmain.c;h=e20128a47d8cff1b32bc8c36bec51e3ef4a10c8d;hb=13e15733f38a40c6ef6a1baede91cce81c86ebaa;hp=98603f7dfbbcf20e69fcbfd5a5e93de4d88c9ab6;hpb=a919be3d39150328874ff647fb2c2be7af3df996;p=platform%2Fupstream%2Fglib.git diff --git a/glib/gmain.c b/glib/gmain.c index 98603f7..e20128a 100644 --- a/glib/gmain.c +++ b/glib/gmain.c @@ -15,9 +15,7 @@ * 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. + * License along with this library; if not, see . */ /* @@ -62,9 +60,9 @@ #ifdef HAVE_SYS_TIME_H #include #endif /* HAVE_SYS_TIME_H */ -#ifdef HAVE_UNISTD_H +#ifdef G_OS_UNIX #include -#endif /* HAVE_UNISTD_H */ +#endif /* G_OS_UNIX */ #include #include @@ -73,10 +71,11 @@ #include #endif /* G_OS_WIN32 */ -#ifdef G_OS_BEOS -#include -#include -#endif /* G_OS_BEOS */ +#ifdef HAVE_MACH_MACH_TIME_H +#include +#endif + +#include "glib_trace.h" #include "gmain.h" @@ -141,42 +140,46 @@ * GTK+ contains wrappers of some of these functions, e.g. gtk_main(), * gtk_main_quit() and gtk_events_pending(). * - * Creating new source types - * One of the unusual features of the #GMainLoop functionality + * ## Creating new source types + * + * One of the unusual features of the #GMainLoop functionality * is that new types of event source can be created and used in * addition to the builtin type of event source. A new event source * type is used for handling GDK events. A new source type is created - * by deriving from the #GSource structure. - * The derived type of source is represented by a structure that has - * the #GSource structure as a first element, and other elements specific - * to the new source type. To create an instance of the new source type, - * call g_source_new() passing in the size of the derived structure and + * by "deriving" from the #GSource structure. The derived type of + * source is represented by a structure that has the #GSource structure + * as a first element, and other elements specific to the new source + * type. To create an instance of the new source type, call + * g_source_new() passing in the size of the derived structure and * a table of functions. These #GSourceFuncs determine the behavior of - * the new source type. - * New source types basically interact with the main context + * the new source type. + * + * New source types basically interact with the main context * in two ways. Their prepare function in #GSourceFuncs can set a timeout * to determine the maximum amount of time that the main loop will sleep * before checking the source again. In addition, or as well, the source * can add file descriptors to the set that the main context checks using - * g_source_add_poll(). - * - * Customizing the main loop iteration - * Single iterations of a #GMainContext can be run with + * g_source_add_poll(). + * + * ## Customizing the main loop iteration + * + * Single iterations of a #GMainContext can be run with * g_main_context_iteration(). In some cases, more detailed control * of exactly how the details of the main loop work is desired, for * instance, when integrating the #GMainLoop with an external main loop. * In such cases, you can call the component functions of * g_main_context_iteration() directly. These functions are * g_main_context_prepare(), g_main_context_query(), - * g_main_context_check() and g_main_context_dispatch(). - * The operation of these functions can best be seen in terms - * of a state diagram, as shown in . - *
States of a Main Context - * - *
- *
- * - * On Unix, the GLib mainloop is incompatible with fork(). Any program + * g_main_context_check() and g_main_context_dispatch(). + * + * ## State of a Main Context # {#mainloop-states} + * + * The operation of these functions can best be seen in terms + * of a state diagram, as shown in this image. + * + * ![](mainloop-states.gif) + * + * On UNIX, the GLib mainloop is incompatible with fork(). Any program * using the mainloop must either exec() or exit() from the child * without returning to the mainloop. */ @@ -237,15 +240,16 @@ struct _GMainContext gint ref_count; + GHashTable *sources; /* guint -> GSource */ + GPtrArray *pending_dispatches; gint timeout; /* Timeout for current iteration */ guint next_id; - GHashTable *overflow_used_source_ids; /* set */ GList *source_lists; gint in_check_or_prepare; - GPollRec *poll_records, *poll_records_tail; + GPollRec *poll_records; guint n_poll_records; GPollFD *cached_poll_array; guint cached_poll_array_size; @@ -510,6 +514,7 @@ g_main_context_unref (GMainContext *context) GSource *source; GList *sl_iter; GSourceList *list; + guint i; g_return_if_fail (context != NULL); g_return_if_fail (g_atomic_int_get (&context->ref_count) > 0); @@ -521,6 +526,10 @@ g_main_context_unref (GMainContext *context) main_context_list = g_slist_remove (main_context_list, context); G_UNLOCK (main_context_list); + /* Free pending dispatches */ + for (i = 0; i < context->pending_dispatches->len; i++) + g_source_unref_internal (context->pending_dispatches->pdata[i], context, FALSE); + /* g_source_iter_next() assumes the context is locked. */ LOCK_CONTEXT (context); g_source_iter_init (&iter, context, TRUE); @@ -538,8 +547,7 @@ g_main_context_unref (GMainContext *context) } g_list_free (context->source_lists); - if (context->overflow_used_source_ids) - g_hash_table_destroy (context->overflow_used_source_ids); + g_hash_table_destroy (context->sources); g_mutex_clear (&context->mutex); @@ -571,7 +579,7 @@ g_main_context_new_with_next_id (guint next_id) * * Creates a new #GMainContext structure. * - * Return value: the new #GMainContext + * Returns: the new #GMainContext **/ GMainContext * g_main_context_new (void) @@ -594,6 +602,7 @@ g_main_context_new (void) g_mutex_init (&context->mutex); g_cond_init (&context->cond); + context->sources = g_hash_table_new (NULL, NULL); context->owner = NULL; context->waiters = NULL; @@ -637,7 +646,7 @@ g_main_context_new (void) * specified, and corresponds to the "main" main loop. See also * g_main_context_get_thread_default(). * - * Return value: (transfer none): the global default main context. + * Returns: (transfer none): the global default main context. **/ GMainContext * g_main_context_default (void) @@ -684,14 +693,13 @@ static GPrivate thread_context_stack = G_PRIVATE_INIT (free_context_stack); * * Acquires @context and sets it as the thread-default context for the * current thread. This will cause certain asynchronous operations - * (such as most gio-based I/O) which are + * (such as most [gio][gio]-based I/O) which are * started in this thread to run under @context and deliver their * results to its main loop, rather than running under the global * default context in the main thread. Note that calling this function - * changes the context returned by - * g_main_context_get_thread_default(), not the - * one returned by g_main_context_default(), so it does not affect the - * context used by functions like g_idle_add(). + * changes the context returned by g_main_context_get_thread_default(), + * not the one returned by g_main_context_default(), so it does not affect + * the context used by functions like g_idle_add(). * * Normally you would call this function shortly after creating a new * thread, passing it a #GMainContext which will be run by a @@ -773,7 +781,7 @@ g_main_context_pop_thread_default (GMainContext *context) * operations that want to be able to be run in contexts other than * the default one should call this method or * g_main_context_ref_thread_default() to get a #GMainContext to add - * their #GSources to. (Note that even in single-threaded + * their #GSources to. (Note that even in single-threaded * programs applications may sometimes want to temporarily push a * non-default context, so it is not safe to assume that this will * always return %NULL if you are running in the default thread.) @@ -835,13 +843,13 @@ g_main_context_ref_thread_default (void) * Creates a new #GSource structure. The size is specified to * allow creating structures derived from #GSource that contain * additional data. The size passed in must be at least - * sizeof (GSource). + * `sizeof (GSource)`. * * The source will not initially be associated with any #GMainContext * and must be added to one with g_source_attach() before it will be * executed. * - * Return value: the newly-created #GSource. + * Returns: the newly-created #GSource. **/ GSource * g_source_new (GSourceFuncs *source_funcs, @@ -1052,72 +1060,29 @@ source_remove_from_context (GSource *source, context->source_lists = g_list_remove (context->source_lists, source_list); g_slice_free (GSourceList, source_list); } - - if (context->overflow_used_source_ids) - g_hash_table_remove (context->overflow_used_source_ids, - GUINT_TO_POINTER (source->source_id)); - } -static void -assign_source_id_unlocked (GMainContext *context, - GSource *source) +static guint +g_source_attach_unlocked (GSource *source, + GMainContext *context, + gboolean do_wakeup) { + GSList *tmp_list; guint id; - /* Are we about to overflow back to 0? - * See https://bugzilla.gnome.org/show_bug.cgi?id=687098 + /* The counter may have wrapped, so we must ensure that we do not + * reuse the source id of an existing source. */ - if (G_UNLIKELY (context->next_id == G_MAXUINT && - context->overflow_used_source_ids == NULL)) - { - GSourceIter iter; - GSource *source; - - context->overflow_used_source_ids = g_hash_table_new (NULL, NULL); - - g_source_iter_init (&iter, context, FALSE); - while (g_source_iter_next (&iter, &source)) - { - g_hash_table_add (context->overflow_used_source_ids, - GUINT_TO_POINTER (source->source_id)); - } - id = G_MAXUINT; - g_hash_table_add (context->overflow_used_source_ids, GUINT_TO_POINTER (id)); - } - else if (context->overflow_used_source_ids == NULL) - { - id = context->next_id++; - } - else - { - /* - * If we overran G_MAXUINT, we fall back to randomly probing the - * source ids for the current context. This will be slower the more - * sources there are, but we're mainly concerned right now about - * correctness and code size. There's time for a more clever solution - * later. - */ - do - id = g_random_int (); - while (id == 0 || - g_hash_table_contains (context->overflow_used_source_ids, - GUINT_TO_POINTER (id))); - g_hash_table_add (context->overflow_used_source_ids, GUINT_TO_POINTER (id)); - } + do + id = context->next_id++; + while (id == 0 || g_hash_table_contains (context->sources, GUINT_TO_POINTER (id))); + source->context = context; source->source_id = id; -} + source->ref_count++; -static guint -g_source_attach_unlocked (GSource *source, - GMainContext *context) -{ - GSList *tmp_list; + g_hash_table_insert (context->sources, GUINT_TO_POINTER (id), source); - source->context = context; - assign_source_id_unlocked (context, source); - source->ref_count++; source_add_to_context (source, context); if (!SOURCE_BLOCKED (source)) @@ -1136,10 +1101,16 @@ g_source_attach_unlocked (GSource *source, tmp_list = source->priv->child_sources; while (tmp_list) { - g_source_attach_unlocked (tmp_list->data, context); + g_source_attach_unlocked (tmp_list->data, context, FALSE); tmp_list = tmp_list->next; } + /* If another thread has acquired the context, wake it up since it + * might be in poll() right now. + */ + if (do_wakeup && context->owner && context->owner != G_THREAD_SELF) + g_wakeup_signal (context->wakeup); + return source->source_id; } @@ -1151,7 +1122,7 @@ g_source_attach_unlocked (GSource *source, * Adds a #GSource to a @context so that it will be executed within * that context. Remove it by calling g_source_destroy(). * - * Return value: the ID (greater than 0) for the source within the + * Returns: the ID (greater than 0) for the source within the * #GMainContext. **/ guint @@ -1163,18 +1134,14 @@ g_source_attach (GSource *source, g_return_val_if_fail (source->context == NULL, 0); g_return_val_if_fail (!SOURCE_DESTROYED (source), 0); + TRACE (GLIB_MAIN_SOURCE_ATTACH (g_source_get_name (source))); + if (!context) context = g_main_context_default (); LOCK_CONTEXT (context); - result = g_source_attach_unlocked (source, context); - - /* If another thread has acquired the context, wake it up since it - * might be in poll() right now. - */ - if (context->owner && context->owner != G_THREAD_SELF) - g_wakeup_signal (context->wakeup); + result = g_source_attach_unlocked (source, context, TRUE); UNLOCK_CONTEXT (context); @@ -1186,6 +1153,8 @@ g_source_destroy_internal (GSource *source, GMainContext *context, gboolean have_lock) { + TRACE (GLIB_MAIN_SOURCE_DESTROY (g_source_get_name (source))); + if (!have_lock) LOCK_CONTEXT (context); @@ -1242,7 +1211,8 @@ g_source_destroy_internal (GSource *source, * * Removes a source from its #GMainContext, if any, and mark it as * destroyed. The source cannot be subsequently added to another - * context. + * context. It is safe to call this on sources which have already been + * removed from their context. **/ void g_source_destroy (GSource *source) @@ -1268,7 +1238,7 @@ g_source_destroy (GSource *source) * context. The reverse * mapping from ID to source is done by g_main_context_find_source_by_id(). * - * Return value: the ID (greater than 0) for the source + * Returns: the ID (greater than 0) for the source **/ guint g_source_get_id (GSource *source) @@ -1298,7 +1268,7 @@ g_source_get_id (GSource *source) * g_main_current_source(). But calling this function on a source * whose #GMainContext has been destroyed is an error. * - * Return value: (transfer none) (allow-none): the #GMainContext with which the + * Returns: (transfer none) (allow-none): the #GMainContext with which the * source is associated, or %NULL if the context has not * yet been added to a source. **/ @@ -1322,6 +1292,9 @@ g_source_get_context (GSource *source) * the @revents field in the #GPollFD struct and return %TRUE if events need * to be processed. * + * This API is only intended to be used by implementations of #GSource. + * Do not call this API on a #GSource that you did not create. + * * Using this API forces the linear scanning of event sources on each * main loop iteration. Newly-written event sources should try to use * g_source_add_unix_fd() instead of this API. @@ -1358,6 +1331,9 @@ g_source_add_poll (GSource *source, * * Removes a file descriptor from the set of file descriptors polled for * this source. + * + * This API is only intended to be used by implementations of #GSource. + * Do not call this API on a #GSource that you did not create. **/ void g_source_remove_poll (GSource *source, @@ -1404,6 +1380,9 @@ g_source_remove_poll (GSource *source, * @source will hold a reference on @child_source while @child_source * is attached to it. * + * This API is only intended to be used by implementations of #GSource. + * Do not call this API on a #GSource that you did not create. + * * Since: 2.28 **/ void @@ -1433,8 +1412,8 @@ g_source_add_child_source (GSource *source, if (context) { + g_source_attach_unlocked (child_source, context, TRUE); UNLOCK_CONTEXT (context); - g_source_attach (child_source, context); } } @@ -1460,6 +1439,9 @@ g_child_source_remove_internal (GSource *child_source, * * Detaches @child_source from @source and destroys it. * + * This API is only intended to be used by implementations of #GSource. + * Do not call this API on a #GSource that you did not create. + * * Since: 2.28 **/ void @@ -1693,6 +1675,10 @@ g_source_set_priority_unlocked (GSource *source, * source will be dispatched if it is ready to be dispatched and no * sources at a higher (numerically smaller) priority are ready to be * dispatched. + * + * A child source always has the same priority as its parent. It is not + * permitted to change the priority of a source once it has been added + * as a child of another source. **/ void g_source_set_priority (GSource *source, @@ -1701,6 +1687,7 @@ g_source_set_priority (GSource *source, GMainContext *context; g_return_if_fail (source != NULL); + g_return_if_fail (source->priv->parent_source == NULL); context = source->context; @@ -1717,7 +1704,7 @@ g_source_set_priority (GSource *source, * * Gets the priority of a source. * - * Return value: the priority of the source + * Returns: the priority of the source **/ gint g_source_get_priority (GSource *source) @@ -1750,6 +1737,9 @@ g_source_get_priority (GSource *source) * for both sources is reached during the same main context iteration * then the order of dispatch is undefined. * + * This API is only intended to be used by implementations of #GSource. + * Do not call this API on a #GSource that you did not create. + * * Since: 2.36 **/ void @@ -1839,7 +1829,7 @@ g_source_set_can_recurse (GSource *source, * Checks whether a source is allowed to be called recursively. * see g_source_set_can_recurse(). * - * Return value: whether recursion is allowed. + * Returns: whether recursion is allowed. **/ gboolean g_source_get_can_recurse (GSource *source) @@ -1864,17 +1854,29 @@ g_source_get_can_recurse (GSource *source) * * It is permitted to call this function multiple times, but is not * recommended due to the potential performance impact. For example, - * one could change the name in the "check" function of a #GSourceFuncs + * one could change the name in the "check" function of a #GSourceFuncs * to include details like the event type in the source name. * + * Use caution if changing the name while another thread may be + * accessing it with g_source_get_name(); that function does not copy + * the value, and changing the value will free it while the other thread + * may be attempting to use it. + * * Since: 2.26 **/ void g_source_set_name (GSource *source, const char *name) { + GMainContext *context; + g_return_if_fail (source != NULL); + context = source->context; + + if (context) + LOCK_CONTEXT (context); + /* setting back to NULL is allowed, just because it's * weird if get_name can return NULL but you can't * set that. @@ -1882,17 +1884,20 @@ g_source_set_name (GSource *source, g_free (source->name); source->name = g_strdup (name); + + if (context) + UNLOCK_CONTEXT (context); } /** * g_source_get_name: * @source: a #GSource * - * Gets a name for the source, used in debugging and profiling. - * The name may be #NULL if it has never been set with - * g_source_set_name(). + * Gets a name for the source, used in debugging and profiling. The + * name may be #NULL if it has never been set with g_source_set_name(). + * + * Returns: the name of the source * - * Return value: the name of the source * Since: 2.26 **/ const char * @@ -1913,6 +1918,18 @@ g_source_get_name (GSource *source) * This is a convenience utility to set source names from the return * value of g_idle_add(), g_timeout_add(), etc. * + * It is a programmer error to attempt to set the name of a non-existent + * source. + * + * More specifically: source IDs can be reissued after a source has been + * destroyed and therefore it is never valid to use this function with a + * source ID which may have already been removed. An example is when + * scheduling an idle to run in another thread with g_idle_add(): the + * idle may already have run and been removed by the time this function + * is called on its (now invalid) source ID. This source ID may have + * been reissued, leading to the operation being performed against the + * wrong source. + * * Since: 2.26 **/ void @@ -1937,7 +1954,7 @@ g_source_set_name_by_id (guint tag, * * Increases the reference count on a source by one. * - * Return value: @source + * Returns: @source **/ GSource * g_source_ref (GSource *source) @@ -1988,6 +2005,8 @@ g_source_unref_internal (GSource *source, if (!SOURCE_DESTROYED (source)) g_warning (G_STRLOC ": ref_count == 0, but source was still attached to a context!"); source_remove_from_context (source, context); + + g_hash_table_remove (context->sources, GUINT_TO_POINTER (source->source_id)); } if (source->source_funcs->finalize) @@ -2007,6 +2026,17 @@ g_source_unref_internal (GSource *source, g_slist_free_full (source->priv->fds, g_free); + while (source->priv->child_sources) + { + GSource *child_source = source->priv->child_sources->data; + + source->priv->child_sources = + g_slist_remove (source->priv->child_sources, child_source); + child_source->priv->parent_source = NULL; + + g_source_unref_internal (child_source, context, have_lock); + } + g_slice_free (GSourcePrivate, source->priv); source->priv = NULL; @@ -2047,37 +2077,41 @@ g_source_unref (GSource *source) /** * g_main_context_find_source_by_id: * @context: (allow-none): a #GMainContext (if %NULL, the default context will be used) - * @source_id: the source ID, as returned by g_source_get_id(). - * + * @source_id: the source ID, as returned by g_source_get_id(). + * * Finds a #GSource given a pair of context and ID. - * - * Return value: (transfer none): the #GSource if found, otherwise, %NULL + * + * It is a programmer error to attempt to lookup a non-existent source. + * + * More specifically: source IDs can be reissued after a source has been + * destroyed and therefore it is never valid to use this function with a + * source ID which may have already been removed. An example is when + * scheduling an idle to run in another thread with g_idle_add(): the + * idle may already have run and been removed by the time this function + * is called on its (now invalid) source ID. This source ID may have + * been reissued, leading to the operation being performed against the + * wrong source. + * + * Returns: (transfer none): the #GSource **/ GSource * g_main_context_find_source_by_id (GMainContext *context, - guint source_id) + guint source_id) { - GSourceIter iter; GSource *source; - + g_return_val_if_fail (source_id > 0, NULL); if (context == NULL) context = g_main_context_default (); - - LOCK_CONTEXT (context); - - g_source_iter_init (&iter, context, FALSE); - while (g_source_iter_next (&iter, &source)) - { - if (!SOURCE_DESTROYED (source) && - source->source_id == source_id) - break; - } - g_source_iter_clear (&iter); + LOCK_CONTEXT (context); + source = g_hash_table_lookup (context->sources, GUINT_TO_POINTER (source_id)); UNLOCK_CONTEXT (context); + if (source && SOURCE_DESTROYED (source)) + source = NULL; + return source; } @@ -2091,7 +2125,7 @@ g_main_context_find_source_by_id (GMainContext *context, * multiple sources exist with the same source function and user data, * the first one found will be returned. * - * Return value: (transfer none): the source, if one was found, otherwise %NULL + * Returns: (transfer none): the source, if one was found, otherwise %NULL **/ GSource * g_main_context_find_source_by_funcs_user_data (GMainContext *context, @@ -2140,7 +2174,7 @@ g_main_context_find_source_by_funcs_user_data (GMainContext *context, * multiple sources exist with the same user data, the first * one found will be returned. * - * Return value: (transfer none): the source, if one was found, otherwise %NULL + * Returns: (transfer none): the source, if one was found, otherwise %NULL **/ GSource * g_main_context_find_source_by_user_data (GMainContext *context, @@ -2193,7 +2227,16 @@ g_main_context_find_source_by_user_data (GMainContext *context, * * It is a programmer error to attempt to remove a non-existent source. * - * Return value: For historical reasons, this function always returns %TRUE + * More specifically: source IDs can be reissued after a source has been + * destroyed and therefore it is never valid to use this function with a + * source ID which may have already been removed. An example is when + * scheduling an idle to run in another thread with g_idle_add(): the + * idle may already have run and been removed by the time this function + * is called on its (now invalid) source ID. This source ID may have + * been reissued, leading to the operation being performed against the + * wrong source. + * + * Returns: For historical reasons, this function always returns %TRUE **/ gboolean g_source_remove (guint tag) @@ -2219,7 +2262,7 @@ g_source_remove (guint tag) * data for the callback. If multiple sources exist with the same user * data, only one will be destroyed. * - * Return value: %TRUE if a source was found and removed. + * Returns: %TRUE if a source was found and removed. **/ gboolean g_source_remove_by_user_data (gpointer user_data) @@ -2245,7 +2288,7 @@ g_source_remove_by_user_data (gpointer user_data) * source functions and user data. If multiple sources exist with the * same source functions and user data, only one will be destroyed. * - * Return value: %TRUE if a source was found and removed. + * Returns: %TRUE if a source was found and removed. **/ gboolean g_source_remove_by_funcs_user_data (GSourceFuncs *funcs, @@ -2281,6 +2324,9 @@ g_source_remove_by_funcs_user_data (GSourceFuncs *funcs, * It is not necessary to remove the fd before destroying the source; it * will be cleaned up automatically. * + * This API is only intended to be used by implementations of #GSource. + * Do not call this API on a #GSource that you did not create. + * * As the name suggests, this function is not available on Windows. * * Returns: an opaque tag @@ -2333,6 +2379,9 @@ g_source_add_unix_fd (GSource *source, * If you want to remove a fd, don't set its event mask to zero. * Instead, call g_source_remove_unix_fd(). * + * This API is only intended to be used by implementations of #GSource. + * Do not call this API on a #GSource that you did not create. + * * As the name suggests, this function is not available on Windows. * * Since: 2.36 @@ -2368,6 +2417,9 @@ g_source_modify_unix_fd (GSource *source, * watched while keeping the same source around. In the normal case you * will just want to destroy the source. * + * This API is only intended to be used by implementations of #GSource. + * Do not call this API on a #GSource that you did not create. + * * As the name suggests, this function is not available on Windows. * * Since: 2.36 @@ -2412,6 +2464,9 @@ g_source_remove_unix_fd (GSource *source, * The return value of this function is only defined when the function * is called from the check or dispatch functions for @source. * + * This API is only intended to be used by implementations of #GSource. + * Do not call this API on a #GSource that you did not create. + * * As the name suggests, this function is not available on Windows. * * Returns: the conditions reported on the fd @@ -2501,7 +2556,25 @@ g_get_real_time (void) return (((gint64) tv.tv_sec) * 1000000) + tv.tv_usec; } -#ifdef G_OS_WIN32 +/** + * g_get_monotonic_time: + * + * Queries the system monotonic time. + * + * The monotonic clock will always increase and doesn't suffer + * discontinuities when the user (or NTP) changes the system time. It + * may or may not continue to tick during times where the machine is + * suspended. + * + * We try to use the clock that corresponds as closely as possible to + * the passage of time as measured by system calls such as poll() but it + * may not always be possible to do this. + * + * Returns: the monotonic time, in microseconds + * + * Since: 2.28 + **/ +#if defined (G_OS_WIN32) static ULONGLONG (*g_GetTickCount64) (void) = NULL; static guint32 g_win32_tick_epoch = 0; @@ -2516,70 +2589,10 @@ g_clock_win32_init (void) g_GetTickCount64 = (void *) GetProcAddress (kernel32, "GetTickCount64"); g_win32_tick_epoch = ((guint32)GetTickCount()) >> 31; } -#endif -/** - * g_get_monotonic_time: - * - * Queries the system monotonic time, if available. - * - * On POSIX systems with clock_gettime() and CLOCK_MONOTONIC this call - * is a very shallow wrapper for that. Otherwise, we make a best effort - * that probably involves returning the wall clock time (with at least - * microsecond accuracy, subject to the limitations of the OS kernel). - * - * It's important to note that POSIX CLOCK_MONOTONIC does - * not count time spent while the machine is suspended. - * - * On Windows, "limitations of the OS kernel" is a rather substantial - * statement. Depending on the configuration of the system, the wall - * clock time is updated as infrequently as 64 times a second (which - * is approximately every 16ms). Also, on XP (but not on Vista or later) - * the monotonic clock is locally monotonic, but may differ in exact - * value between processes due to timer wrap handling. - * - * Returns: the monotonic time, in microseconds - * - * Since: 2.28 - **/ gint64 g_get_monotonic_time (void) { -#ifdef HAVE_CLOCK_GETTIME - /* librt clock_gettime() is our first choice */ - struct timespec ts; - -#ifdef CLOCK_MONOTONIC - clock_gettime (CLOCK_MONOTONIC, &ts); -#else - clock_gettime (CLOCK_REALTIME, &ts); -#endif - - /* In theory monotonic time can have any epoch. - * - * glib presently assumes the following: - * - * 1) The epoch comes some time after the birth of Jesus of Nazareth, but - * not more than 10000 years later. - * - * 2) The current time also falls sometime within this range. - * - * These two reasonable assumptions leave us with a maximum deviation from - * the epoch of 10000 years, or 315569520000000000 seconds. - * - * If we restrict ourselves to this range then the number of microseconds - * will always fit well inside the constraints of a int64 (by a factor of - * about 29). - * - * If you actually hit the following assertion, probably you should file a - * bug against your operating system for being excessively silly. - **/ - g_assert (G_GINT64_CONSTANT (-315569520000000000) < ts.tv_sec && - ts.tv_sec < G_GINT64_CONSTANT (315569520000000000)); - - return (((gint64) ts.tv_sec) * 1000000) + (ts.tv_nsec / 1000); - -#elif defined (G_OS_WIN32) guint64 ticks; guint32 ticks32; @@ -2613,7 +2626,7 @@ g_get_monotonic_time (void) * is to use it to interpolate the lower precision clocks. Firefox does something like * this: * https://bugzilla.mozilla.org/show_bug.cgi?id=363258 - * + * * However this seems quite complicated, so we're not doing this right now. * * The approach we take instead is to use the TGT timer, extending it to 64bit @@ -2624,7 +2637,7 @@ g_get_monotonic_time (void) * This means that: * - We have a globally consistent monotonic clock on Vista and later * - We have a locally monotonic clock on XP - * - Apps that need higher precision in timeouts and clock reads can call + * - Apps that need higher precision in timeouts and clock reads can call * timeBeginPeriod() to increase it as much as they want */ @@ -2635,10 +2648,10 @@ g_get_monotonic_time (void) ticks = g_GetTickCount64 (); ticks32 = timeGetTime(); - /* GTC64 and TGT are sampled at different times, however they - * have the same base and source (msecs since system boot). + /* GTC64 and TGT are sampled at different times, however they + * have the same base and source (msecs since system boot). * They can differ by as much as -16 to +16 msecs. - * We can't just inject the low bits into the 64bit counter + * We can't just inject the low bits into the 64bit counter * as one of the counters can have wrapped in 32bit space and * the other not. Instead we calculate the signed difference * in 32bit space and apply that difference to the 64bit counter. @@ -2647,9 +2660,9 @@ g_get_monotonic_time (void) /* We could do some 2's complement hack, but we play it safe */ if (ticks32 - ticks_as_32bit <= G_MAXINT32) - ticks += ticks32 - ticks_as_32bit; + ticks += ticks32 - ticks_as_32bit; else - ticks -= ticks_as_32bit - ticks32; + ticks -= ticks_as_32bit - ticks32; } else { @@ -2677,26 +2690,78 @@ g_get_monotonic_time (void) * processes. */ if ((ticks32 >> 31) != (epoch & 1)) - { - epoch++; - g_atomic_int_set (&g_win32_tick_epoch, epoch); - } + { + epoch++; + g_atomic_int_set (&g_win32_tick_epoch, epoch); + } ticks = (guint64)ticks32 | ((guint64)epoch) << 31; } return ticks * 1000; +} +#elif defined(HAVE_MACH_MACH_TIME_H) /* Mac OS */ +gint64 +g_get_monotonic_time (void) +{ + static mach_timebase_info_data_t timebase_info; -#else /* !HAVE_CLOCK_GETTIME && ! G_OS_WIN32*/ + if (timebase_info.denom == 0) + { + /* This is a fraction that we must use to scale + * mach_absolute_time() by in order to reach nanoseconds. + * + * We've only ever observed this to be 1/1, but maybe it could be + * 1000/1 if mach time is microseconds already, or 1/1000 if + * picoseconds. Try to deal nicely with that. + */ + mach_timebase_info (&timebase_info); - GTimeVal tv; + /* We actually want microseconds... */ + if (timebase_info.numer % 1000 == 0) + timebase_info.numer /= 1000; + else + timebase_info.denom *= 1000; - g_get_current_time (&tv); + /* We want to make the numer 1 to avoid having to multiply... */ + if (timebase_info.denom % timebase_info.numer == 0) + { + timebase_info.denom /= timebase_info.numer; + timebase_info.numer = 1; + } + else + { + /* We could just multiply by timebase_info.numer below, but why + * bother for a case that may never actually exist... + * + * Plus -- performing the multiplication would risk integer + * overflow. If we ever actually end up in this situation, we + * should more carefully evaluate the correct course of action. + */ + mach_timebase_info (&timebase_info); /* Get a fresh copy for a better message */ + g_error ("Got weird mach timebase info of %d/%d. Please file a bug against GLib.", + timebase_info.numer, timebase_info.denom); + } + } - return (((gint64) tv.tv_sec) * 1000000) + tv.tv_usec; -#endif + return mach_absolute_time () / timebase_info.denom; } +#else +gint64 +g_get_monotonic_time (void) +{ + struct timespec ts; + gint result; + + result = clock_gettime (CLOCK_MONOTONIC, &ts); + + if G_UNLIKELY (result != 0) + g_error ("GLib requires working CLOCK_MONOTONIC"); + + return (((gint64) ts.tv_sec) * 1000000) + (ts.tv_nsec / 1000); +} +#endif static void g_main_dispatch_free (gpointer dispatch) @@ -2737,7 +2802,7 @@ get_dispatch (void) * This function is useful in a situation like the following: * Imagine an extremely simple "garbage collected" system. * - * |[ + * |[ * static GList *free_list; * * gpointer @@ -2774,7 +2839,7 @@ get_dispatch (void) * doesn't work, since the idle function could be called from a * recursive callback. This can be fixed by using g_main_depth() * - * |[ + * |[ * gpointer * allocate_memory (gsize size) * { @@ -2819,26 +2884,17 @@ get_dispatch (void) * many things that the user could do. Instead, you can use the * following techniques: * - * - * - * - * Use gtk_widget_set_sensitive() or modal dialogs to prevent - * the user from interacting with elements while the main - * loop is recursing. - * - * - * - * - * Avoid main loop recursion in situations where you can't handle - * arbitrary callbacks. Instead, structure your code so that you - * simply return to the main loop and then get called again when - * there is more work to do. - * - * - * + * 1. Use gtk_widget_set_sensitive() or modal dialogs to prevent + * the user from interacting with elements while the main + * loop is recursing. * - * Return value: The main loop recursion level in the current thread - **/ + * 2. Avoid main loop recursion in situations where you can't handle + * arbitrary callbacks. Instead, structure your code so that you + * simply return to the main loop and then get called again when + * there is more work to do. + * + * Returns: The main loop recursion level in the current thread + */ int g_main_depth (void) { @@ -2851,7 +2907,7 @@ g_main_depth (void) * * Returns the currently firing source for this thread. * - * Return value: (transfer none): The currently firing source or %NULL. + * Returns: (transfer none): The currently firing source or %NULL. * * Since: 2.12 */ @@ -2872,16 +2928,16 @@ g_main_current_source (void) * from within idle handlers, but may have freed the object * before the dispatch of your idle handler. * - * |[ + * |[ * static gboolean * idle_callback (gpointer data) * { * SomeWidget *self = data; * - * GDK_THREADS_ENTER (); - * /* do stuff with self */ + * GDK_THREADS_ENTER (); + * // do stuff with self * self->idle_id = 0; - * GDK_THREADS_LEAVE (); + * GDK_THREADS_LEAVE (); * * return G_SOURCE_REMOVE; * } @@ -2910,7 +2966,7 @@ g_main_current_source (void) * this particular problem, is to check to if the source * has already been destroy within the callback. * - * |[ + * |[ * static gboolean * idle_callback (gpointer data) * { @@ -2919,7 +2975,7 @@ g_main_current_source (void) * GDK_THREADS_ENTER (); * if (!g_source_is_destroyed (g_main_current_source ())) * { - * /* do stuff with self */ + * // do stuff with self * } * GDK_THREADS_LEAVE (); * @@ -2927,7 +2983,7 @@ g_main_current_source (void) * } * ]| * - * Return value: %TRUE if the source has been destroyed + * Returns: %TRUE if the source has been destroyed * * Since: 2.12 */ @@ -3062,7 +3118,9 @@ g_main_dispatch (GMainContext *context) current->source = source; current->depth++; + TRACE( GLIB_MAIN_BEFORE_DISPATCH (g_source_get_name (source))); need_destroy = !(* dispatch) (source, callback, user_data); + TRACE( GLIB_MAIN_AFTER_DISPATCH (g_source_get_name (source))); current->source = prev_source; current->depth--; @@ -3109,7 +3167,7 @@ g_main_dispatch (GMainContext *context) * can call g_main_context_prepare(), g_main_context_query(), * g_main_context_check(), g_main_context_dispatch(). * - * Return value: %TRUE if the operation succeeded, and + * Returns: %TRUE if the operation succeeded, and * this thread is now the owner of @context. **/ gboolean @@ -3193,7 +3251,7 @@ g_main_context_release (GMainContext *context) * that owner releases ownership or until @cond is signaled, then * try again (once) to become the owner. * - * Return value: %TRUE if the operation succeeded, and + * Returns: %TRUE if the operation succeeded, and * this thread is now the owner of @context. **/ gboolean @@ -3208,6 +3266,18 @@ g_main_context_wait (GMainContext *context, if (context == NULL) context = g_main_context_default (); + if G_UNLIKELY (cond != &context->cond || mutex != &context->mutex) + { + static gboolean warned; + + if (!warned) + { + g_critical ("WARNING!! g_main_context_wait() will be removed in a future release. " + "If you see this message, please file a bug immediately."); + warned = TRUE; + } + } + loop_internal_waiter = (mutex == &context->mutex); if (!loop_internal_waiter) @@ -3254,18 +3324,21 @@ g_main_context_wait (GMainContext *context, * @context: a #GMainContext * @priority: location to store priority of highest priority * source already ready. - * + * * Prepares to poll sources within a main loop. The resulting information * for polling is determined by calling g_main_context_query (). - * - * Return value: %TRUE if some source is ready to be dispatched + * + * You must have successfully acquired the context with + * g_main_context_acquire() before you may call this function. + * + * Returns: %TRUE if some source is ready to be dispatched * prior to polling. **/ gboolean g_main_context_prepare (GMainContext *context, gint *priority) { - gint i; + guint i; gint n_ready = 0; gint current_priority = G_MAXINT; GSource *source; @@ -3415,10 +3488,13 @@ g_main_context_prepare (GMainContext *context, * @fds: (out caller-allocates) (array length=n_fds): location to * store #GPollFD records that need to be polled. * @n_fds: length of @fds. - * + * * Determines information necessary to poll this main loop. - * - * Return value: the number of records actually stored in @fds, + * + * You must have successfully acquired the context with + * g_main_context_acquire() before you may call this function. + * + * Returns: the number of records actually stored in @fds, * or, if more than @n_fds records need to be stored, the number * of records that need to be stored. **/ @@ -3430,33 +3506,43 @@ g_main_context_query (GMainContext *context, gint n_fds) { gint n_poll; - GPollRec *pollrec; + GPollRec *pollrec, *lastpollrec; + gushort events; LOCK_CONTEXT (context); - pollrec = context->poll_records; n_poll = 0; - while (pollrec && max_priority >= pollrec->priority) + lastpollrec = NULL; + for (pollrec = context->poll_records; pollrec; pollrec = pollrec->next) { - /* We need to include entries with fd->events == 0 in the array because - * otherwise if the application changes fd->events behind our back and - * makes it non-zero, we'll be out of sync when we check the fds[] array. - * (Changing fd->events after adding an FD wasn't an anticipated use of - * this API, but it occurs in practice.) */ - if (n_poll < n_fds) - { - fds[n_poll].fd = pollrec->fd->fd; - /* In direct contradiction to the Unix98 spec, IRIX runs into - * difficulty if you pass in POLLERR, POLLHUP or POLLNVAL - * flags in the events field of the pollfd while it should - * just ignoring them. So we mask them out here. - */ - fds[n_poll].events = pollrec->fd->events & ~(G_IO_ERR|G_IO_HUP|G_IO_NVAL); - fds[n_poll].revents = 0; - } + if (pollrec->priority > max_priority) + continue; + + /* In direct contradiction to the Unix98 spec, IRIX runs into + * difficulty if you pass in POLLERR, POLLHUP or POLLNVAL + * flags in the events field of the pollfd while it should + * just ignoring them. So we mask them out here. + */ + events = pollrec->fd->events & ~(G_IO_ERR|G_IO_HUP|G_IO_NVAL); - pollrec = pollrec->next; - n_poll++; + if (lastpollrec && pollrec->fd->fd == lastpollrec->fd->fd) + { + if (n_poll - 1 < n_fds) + fds[n_poll - 1].events |= events; + } + else + { + if (n_poll < n_fds) + { + fds[n_poll].fd = pollrec->fd->fd; + fds[n_poll].events = events; + fds[n_poll].revents = 0; + } + + n_poll++; + } + + lastpollrec = pollrec; } context->poll_changed = FALSE; @@ -3480,10 +3566,13 @@ g_main_context_query (GMainContext *context, * @fds: (array length=n_fds): array of #GPollFD's that was passed to * the last call to g_main_context_query() * @n_fds: return value of g_main_context_query() - * + * * Passes the results of polling back to the main loop. - * - * Return value: %TRUE if some sources are ready to be dispatched. + * + * You must have successfully acquired the context with + * g_main_context_acquire() before you may call this function. + * + * Returns: %TRUE if some sources are ready to be dispatched. **/ gboolean g_main_context_check (GMainContext *context, @@ -3518,15 +3607,21 @@ g_main_context_check (GMainContext *context, UNLOCK_CONTEXT (context); return FALSE; } - + pollrec = context->poll_records; i = 0; - while (i < n_fds) + while (pollrec && i < n_fds) { - if (pollrec->fd->events) - pollrec->fd->revents = fds[i].revents; + while (pollrec && pollrec->fd->fd == fds[i].fd) + { + if (pollrec->priority <= max_priority) + { + pollrec->fd->revents = + fds[i].revents & (pollrec->fd->events | G_IO_ERR | G_IO_HUP | G_IO_NVAL); + } + pollrec = pollrec->next; + } - pollrec = pollrec->next; i++; } @@ -3626,8 +3721,11 @@ g_main_context_check (GMainContext *context, /** * g_main_context_dispatch: * @context: a #GMainContext - * + * * Dispatches all pending sources. + * + * You must have successfully acquired the context with + * g_main_context_acquire() before you may call this function. **/ void g_main_context_dispatch (GMainContext *context) @@ -3722,7 +3820,7 @@ g_main_context_iterate (GMainContext *context, * * Checks if any sources have pending events for the given context. * - * Return value: %TRUE if events are pending. + * Returns: %TRUE if events are pending. **/ gboolean g_main_context_pending (GMainContext *context) @@ -3757,7 +3855,7 @@ g_main_context_pending (GMainContext *context) * g_main_context_iteration() to return %FALSE, since the wait may * be interrupted for other reasons than an event source becoming ready. * - * Return value: %TRUE if events were dispatched. + * Returns: %TRUE if events were dispatched. **/ gboolean g_main_context_iteration (GMainContext *context, gboolean may_block) @@ -3783,7 +3881,7 @@ g_main_context_iteration (GMainContext *context, gboolean may_block) * * Creates a new #GMainLoop structure. * - * Return value: a new #GMainLoop. + * Returns: a new #GMainLoop. **/ GMainLoop * g_main_loop_new (GMainContext *context, @@ -3810,7 +3908,7 @@ g_main_loop_new (GMainContext *context, * * Increases the reference count on a #GMainLoop object by one. * - * Return value: @loop + * Returns: @loop **/ GMainLoop * g_main_loop_ref (GMainLoop *loop) @@ -3941,7 +4039,7 @@ g_main_loop_quit (GMainLoop *loop) * * Checks to see if the main loop is currently being run via g_main_loop_run(). * - * Return value: %TRUE if the mainloop is currently being run. + * Returns: %TRUE if the mainloop is currently being run. **/ gboolean g_main_loop_is_running (GMainLoop *loop) @@ -3958,7 +4056,7 @@ g_main_loop_is_running (GMainLoop *loop) * * Returns the #GMainContext of @loop. * - * Return value: (transfer none): the #GMainContext of @loop + * Returns: (transfer none): the #GMainContext of @loop **/ GMainContext * g_main_loop_get_context (GMainLoop *loop) @@ -3988,6 +4086,7 @@ g_main_context_poll (GMainContext *context, if (n_fds || timeout != 0) { #ifdef G_MAIN_POLL_DEBUG + poll_timer = NULL; if (_g_main_poll_debug) { g_print ("polling context=%p n=%d timeout=%d\n", @@ -4102,12 +4201,14 @@ g_main_context_add_poll_unlocked (GMainContext *context, newrec->fd = fd; newrec->priority = priority; - prevrec = context->poll_records_tail; - nextrec = NULL; - while (prevrec && priority < prevrec->priority) + prevrec = NULL; + nextrec = context->poll_records; + while (nextrec) { - nextrec = prevrec; - prevrec = prevrec->prev; + if (nextrec->fd->fd > fd->fd) + break; + prevrec = nextrec; + nextrec = nextrec->next; } if (prevrec) @@ -4120,8 +4221,6 @@ g_main_context_add_poll_unlocked (GMainContext *context, if (nextrec) nextrec->prev = newrec; - else - context->poll_records_tail = newrec; context->n_poll_records++; @@ -4175,8 +4274,6 @@ g_main_context_remove_poll_unlocked (GMainContext *context, if (nextrec != NULL) nextrec->prev = prevrec; - else - context->poll_records_tail = prevrec; g_slice_free (GPollRec, pollrec); @@ -4289,7 +4386,7 @@ g_main_context_set_poll_func (GMainContext *context, * * Gets the poll function set by g_main_context_set_poll_func(). * - * Return value: the poll function + * Returns: the poll function **/ GPollFunc g_main_context_get_poll_func (GMainContext *context) @@ -4324,7 +4421,7 @@ g_main_context_get_poll_func (GMainContext *context) * Another related use for this function is when implementing a main * loop with a termination condition, computed from multiple threads: * - * |[ + * |[ * #define NUM_TASKS 10 * static volatile gint tasks_remaining = NUM_TASKS; * ... @@ -4334,7 +4431,7 @@ g_main_context_get_poll_func (GMainContext *context) * ]| * * Then in a thread: - * |[ + * |[ * perform_work(); * * if (g_atomic_int_dec_and_test (&tasks_remaining)) @@ -4466,7 +4563,7 @@ g_timeout_dispatch (GSource *source, * The interval given is in terms of monotonic time, not wall clock * time. See g_get_monotonic_time(). * - * Return value: the newly-created timeout source + * Returns: the newly-created timeout source **/ GSource * g_timeout_source_new (guint interval) @@ -4496,7 +4593,7 @@ g_timeout_source_new (guint interval) * The interval given in terms of monotonic time, not wall clock time. * See g_get_monotonic_time(). * - * Return value: the newly-created timeout source + * Returns: the newly-created timeout source * * Since: 2.14 **/ @@ -4545,7 +4642,7 @@ g_timeout_source_new_seconds (guint interval) * The interval given in terms of monotonic time, not wall clock time. * See g_get_monotonic_time(). * - * Return value: the ID (greater than 0) of the event source. + * Returns: the ID (greater than 0) of the event source. * Rename to: g_timeout_add **/ guint @@ -4603,7 +4700,7 @@ g_timeout_add_full (gint priority, * The interval given is in terms of monotonic time, not wall clock * time. See g_get_monotonic_time(). * - * Return value: the ID (greater than 0) of the event source. + * Returns: the ID (greater than 0) of the event source. **/ guint g_timeout_add (guint32 interval, @@ -4657,7 +4754,7 @@ g_timeout_add (guint32 interval, * The interval given is in terms of monotonic time, not wall clock * time. See g_get_monotonic_time(). * - * Return value: the ID (greater than 0) of the event source. + * Returns: the ID (greater than 0) of the event source. * * Rename to: g_timeout_add_seconds * Since: 2.14 @@ -4709,7 +4806,7 @@ g_timeout_add_seconds_full (gint priority, * The interval given is in terms of monotonic time, not wall clock * time. See g_get_monotonic_time(). * - * Return value: the ID (greater than 0) of the event source. + * Returns: the ID (greater than 0) of the event source. * * Since: 2.14 **/ @@ -4815,17 +4912,39 @@ wake_source (GSource *source) } static void -dispatch_unix_signals (void) +dispatch_unix_signals_unlocked (void) { + gboolean pending[NSIG]; GSList *node; + gint i; /* clear this first incase another one arrives while we're processing */ any_unix_signal_pending = FALSE; - G_LOCK(unix_signal_lock); + /* We atomically test/clear the bit from the global array in case + * other signals arrive while we are dispatching. + * + * We then can safely use our own array below without worrying about + * races. + */ + for (i = 0; i < NSIG; i++) + { + /* Be very careful with (the volatile) unix_signal_pending. + * + * We must ensure that it's not possible that we clear it without + * handling the signal. We therefore must ensure that our pending + * array has a field set (ie: we will do something about the + * signal) before we clear the item in unix_signal_pending. + * + * Note specifically: we must check _our_ array. + */ + pending[i] = unix_signal_pending[i]; + if (pending[i]) + unix_signal_pending[i] = FALSE; + } /* handle GChildWatchSource instances */ - if (unix_signal_pending[SIGCHLD]) + if (pending[SIGCHLD]) { /* The only way we can do this is to scan all of the children. * @@ -4844,6 +4963,8 @@ dispatch_unix_signals (void) pid_t pid; do { + g_assert (source->pid > 0); + pid = waitpid (source->pid, &source->child_status, WNOHANG); if (pid > 0) { @@ -4870,7 +4991,7 @@ dispatch_unix_signals (void) if (!source->pending) { - if (unix_signal_pending[source->signum]) + if (pending[source->signum]) { source->pending = TRUE; @@ -4879,8 +5000,13 @@ dispatch_unix_signals (void) } } - memset ((void*)unix_signal_pending, 0, sizeof (unix_signal_pending)); +} +static void +dispatch_unix_signals (void) +{ + G_LOCK(unix_signal_lock); + dispatch_unix_signals_unlocked (); G_UNLOCK(unix_signal_lock); } @@ -4977,6 +5103,7 @@ unref_unix_signal_handler_unlocked (int signum) if (unix_signal_refcount[signum] == 0) { struct sigaction action; + memset (&action, 0, sizeof (action)); action.sa_handler = SIG_DFL; sigemptyset (&action.sa_mask); sigaction (signum, &action, NULL); @@ -4998,8 +5125,7 @@ _g_main_create_unix_signal_watch (int signum) G_LOCK (unix_signal_lock); ref_unix_signal_handler_unlocked (signum); unix_signal_watches = g_slist_prepend (unix_signal_watches, unix_signal_source); - if (unix_signal_pending[signum]) - unix_signal_source->pending = TRUE; + dispatch_unix_signals_unlocked (); G_UNLOCK (unix_signal_lock); return source; @@ -5067,7 +5193,7 @@ g_unix_signal_handler (int signum) /** * g_child_watch_source_new: - * @pid: process to watch. On POSIX the pid of a child process. On + * @pid: process to watch. On POSIX the positive pid of a child process. On * Windows a handle for a process (which doesn't have to be a child). * * Creates a new child_watch source. @@ -5077,8 +5203,7 @@ g_unix_signal_handler (int signum) * executed. * * Note that child watch sources can only be used in conjunction with - * g_spawn... when the %G_SPAWN_DO_NOT_REAP_CHILD - * flag is used. + * `g_spawn...` when the %G_SPAWN_DO_NOT_REAP_CHILD flag is used. * * Note that on platforms where #GPid must be explicitly closed * (see g_spawn_close_pid()) @pid must not be closed while the @@ -5086,19 +5211,30 @@ g_unix_signal_handler (int signum) * g_spawn_close_pid() in the callback function for the source. * * Note further that using g_child_watch_source_new() is not - * compatible with calling waitpid with a - * nonpositive first argument in the application. Calling waitpid() - * for individual pids will still work fine. - * - * Return value: the newly-created child watch source + * compatible with calling `waitpid` with a nonpositive first + * argument in the application. Calling waitpid() for individual + * pids will still work fine. + * + * Similarly, on POSIX platforms, the @pid passed to this function must + * be greater than 0 (i.e. this function must wait for a specific child, + * and cannot wait for one of many children by using a nonpositive argument). + * + * Returns: the newly-created child watch source * * Since: 2.4 **/ GSource * g_child_watch_source_new (GPid pid) { - GSource *source = g_source_new (&g_child_watch_funcs, sizeof (GChildWatchSource)); - GChildWatchSource *child_watch_source = (GChildWatchSource *)source; + GSource *source; + GChildWatchSource *child_watch_source; + +#ifndef G_OS_WIN32 + g_return_val_if_fail (pid > 0, NULL); +#endif + + source = g_source_new (&g_child_watch_funcs, sizeof (GChildWatchSource)); + child_watch_source = (GChildWatchSource *)source; child_watch_source->pid = pid; @@ -5123,7 +5259,7 @@ g_child_watch_source_new (GPid pid) * g_child_watch_add_full: * @priority: the priority of the idle source. Typically this will be in the * range between #G_PRIORITY_DEFAULT_IDLE and #G_PRIORITY_HIGH_IDLE. - * @pid: process to watch. On POSIX the pid of a child process. On + * @pid: process to watch. On POSIX the positive pid of a child process. On * Windows a handle for a process (which doesn't have to be a child). * @function: function to call * @data: data to pass to @function @@ -5152,7 +5288,7 @@ g_child_watch_source_new (GPid pid) * using g_source_attach(). You can do these steps manually if you * need greater control. * - * Return value: the ID (greater than 0) of the event source. + * Returns: the ID (greater than 0) of the event source. * * Rename to: g_child_watch_add * Since: 2.4 @@ -5168,6 +5304,9 @@ g_child_watch_add_full (gint priority, guint id; g_return_val_if_fail (function != NULL, 0); +#ifndef G_OS_WIN32 + g_return_val_if_fail (pid > 0, 0); +#endif source = g_child_watch_source_new (pid); @@ -5183,8 +5322,9 @@ g_child_watch_add_full (gint priority, /** * g_child_watch_add: - * @pid: process id to watch. On POSIX the pid of a child process. On - * Windows a handle for a process (which doesn't have to be a child). + * @pid: process id to watch. On POSIX the positive pid of a child + * process. On Windows a handle for a process (which doesn't have to be + * a child). * @function: function to call * @data: data to pass to @function * @@ -5207,7 +5347,7 @@ g_child_watch_add_full (gint priority, * using g_source_attach(). You can do these steps manually if you * need greater control. * - * Return value: the ID (greater than 0) of the event source. + * Returns: the ID (greater than 0) of the event source. * * Since: 2.4 **/ @@ -5263,7 +5403,7 @@ g_idle_dispatch (GSource *source, * %G_PRIORITY_DEFAULT_IDLE, as compared to other sources which * have a default priority of %G_PRIORITY_DEFAULT. * - * Return value: the newly-created idle source + * Returns: the newly-created idle source **/ GSource * g_idle_source_new (void) @@ -5292,7 +5432,7 @@ g_idle_source_new (void) * and attaches it to the main loop context using g_source_attach(). * You can do these steps manually if you need greater control. * - * Return value: the ID (greater than 0) of the event source. + * Returns: the ID (greater than 0) of the event source. * Rename to: g_idle_add **/ guint @@ -5333,7 +5473,7 @@ g_idle_add_full (gint priority, * and attaches it to the main loop context using g_source_attach(). * You can do these steps manually if you need greater control. * - * Return value: the ID (greater than 0) of the event source. + * Returns: the ID (greater than 0) of the event source. **/ guint g_idle_add (GSourceFunc function, @@ -5348,7 +5488,7 @@ g_idle_add (GSourceFunc function, * * Removes the idle function with the given data. * - * Return value: %TRUE if an idle source was found and removed. + * Returns: %TRUE if an idle source was found and removed. **/ gboolean g_idle_remove_by_data (gpointer data)