X-Git-Url: http://review.tizen.org/git/?a=blobdiff_plain;f=glib%2Fgmain.c;h=3058b06cd332dadf24adf5633a123f84a0b21e37;hb=42cf80780b4fbbe9063ed3d962bb13f341757b3f;hp=7f1d2b98b2f8cd29ad8642caabd7dc10705e61f8;hpb=8a899265329f6bbbb066991fdc036045d7031b37;p=platform%2Fupstream%2Fglib.git diff --git a/glib/gmain.c b/glib/gmain.c index 7f1d2b9..3058b06 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,7 @@ #include #endif /* G_OS_WIN32 */ -#ifdef G_OS_BEOS -#include -#include -#endif /* G_OS_BEOS */ +#include "glib_trace.h" #include "gmain.h" @@ -217,7 +212,7 @@ typedef struct _GMainDispatch GMainDispatch; struct _GMainDispatch { gint depth; - GSList *dispatching_sources; /* stack of current sources */ + GSource *source; }; #ifdef G_MAIN_POLL_DEBUG @@ -428,6 +423,7 @@ static volatile sig_atomic_t any_unix_signal_pending; static volatile int unix_signal_pending[NSIG]; static volatile int any_unix_signal_pending; #endif +static volatile guint unix_signal_refcount[NSIG]; /* Guards all the data below */ G_LOCK_DEFINE_STATIC (unix_signal_lock); @@ -509,6 +505,7 @@ g_main_context_unref (GMainContext *context) GSource *source; GList *sl_iter; GSourceList *list; + gint i; g_return_if_fail (context != NULL); g_return_if_fail (g_atomic_int_get (&context->ref_count) > 0); @@ -520,6 +517,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); @@ -687,10 +688,9 @@ static GPrivate thread_context_stack = G_PRIVATE_INIT (free_context_stack); * 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 @@ -772,7 +772,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.) @@ -1082,6 +1082,7 @@ assign_source_id_unlocked (GMainContext *context, 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) { @@ -1109,7 +1110,8 @@ assign_source_id_unlocked (GMainContext *context, static guint g_source_attach_unlocked (GSource *source, - GMainContext *context) + GMainContext *context, + gboolean do_wakeup) { GSList *tmp_list; @@ -1134,10 +1136,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; } @@ -1161,18 +1169,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); @@ -1184,6 +1188,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); @@ -1431,8 +1437,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); } } @@ -2177,29 +2183,34 @@ g_main_context_find_source_by_user_data (GMainContext *context, /** * g_source_remove: * @tag: the ID of the source to remove. - * - * Removes the source with the given id from the default main context. - * The id of - * a #GSource is given by g_source_get_id(), or will be returned by the - * functions g_source_attach(), g_idle_add(), g_idle_add_full(), - * g_timeout_add(), g_timeout_add_full(), g_child_watch_add(), - * g_child_watch_add_full(), g_io_add_watch(), and g_io_add_watch_full(). + * + * Removes the source with the given id from the default main context. + * + * The id of a #GSource is given by g_source_get_id(), or will be + * returned by the functions g_source_attach(), g_idle_add(), + * g_idle_add_full(), g_timeout_add(), g_timeout_add_full(), + * g_child_watch_add(), g_child_watch_add_full(), g_io_add_watch(), and + * g_io_add_watch_full(). * * See also g_source_destroy(). You must use g_source_destroy() for sources * added to a non-default main context. * - * Return value: %TRUE if the source was found and removed. + * It is a programmer error to attempt to remove a non-existent source. + * + * Return value: For historical reasons, this function always returns %TRUE **/ gboolean g_source_remove (guint tag) { GSource *source; - + g_return_val_if_fail (tag > 0, FALSE); source = g_main_context_find_source_by_id (NULL, tag); if (source) g_source_destroy (source); + else + g_critical ("Source ID %u was not found when attempting to remove it", tag); return source != NULL; } @@ -2812,26 +2823,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. + * + * 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. * * Return value: The main loop recursion level in the current thread - **/ + */ int g_main_depth (void) { @@ -2852,7 +2854,7 @@ GSource * g_main_current_source (void) { GMainDispatch *dispatch = get_dispatch (); - return dispatch->dispatching_sources ? dispatch->dispatching_sources->data : NULL; + return dispatch->source; } /** @@ -2871,10 +2873,10 @@ g_main_current_source (void) * { * 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; * } @@ -2912,7 +2914,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 (); * @@ -3028,7 +3030,7 @@ g_main_dispatch (GMainContext *context) gboolean (*dispatch) (GSource *, GSourceFunc, gpointer); - GSList current_source_link; + GSource *prev_source; dispatch = source->source_funcs->dispatch; cb_funcs = source->callback_funcs; @@ -3048,26 +3050,20 @@ g_main_dispatch (GMainContext *context) UNLOCK_CONTEXT (context); - current->depth++; - /* The on-stack allocation of the GSList is unconventional, but - * we know that the lifetime of the link is bounded to this - * function as the link is kept in a thread specific list and - * not manipulated outside of this function and its descendants. - * Avoiding the overhead of a g_slist_alloc() is useful as many - * applications do little more than dispatch events. - * - * This is a performance hack - do not revert to g_slist_prepend()! - */ - current_source_link.data = source; - current_source_link.next = current->dispatching_sources; - current->dispatching_sources = ¤t_source_link; - need_destroy = ! dispatch (source, - callback, - user_data); - g_assert (current->dispatching_sources == ¤t_source_link); - current->dispatching_sources = current_source_link.next; - current->depth--; - + /* These operations are safe because 'current' is thread-local + * and not modified from anywhere but this function. + */ + prev_source = current->source; + 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--; + if (cb_funcs) cb_funcs->unref (cb_data); @@ -4816,20 +4812,40 @@ 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]) { - unix_signal_pending[SIGCHLD] = FALSE; - /* The only way we can do this is to scan all of the children. * * The docs promise that we will not reap children that we are not @@ -4873,9 +4889,8 @@ dispatch_unix_signals (void) if (!source->pending) { - if (unix_signal_pending[source->signum]) + if (pending[source->signum]) { - unix_signal_pending[source->signum] = FALSE; source->pending = TRUE; wake_source ((GSource *) source); @@ -4883,6 +4898,13 @@ dispatch_unix_signals (void) } } +} + +static void +dispatch_unix_signals (void) +{ + G_LOCK(unix_signal_lock); + dispatch_unix_signals_unlocked (); G_UNLOCK(unix_signal_lock); } @@ -4953,28 +4975,37 @@ g_unix_signal_watch_dispatch (GSource *source, } static void -ensure_unix_signal_handler_installed_unlocked (int signum) +ref_unix_signal_handler_unlocked (int signum) { - static sigset_t installed_signal_mask; - static gboolean initialized; - struct sigaction action; - - if (!initialized) + /* Ensure we have the worker context */ + g_get_worker_context (); + unix_signal_refcount[signum]++; + if (unix_signal_refcount[signum] == 1) { - sigemptyset (&installed_signal_mask); - g_get_worker_context (); - initialized = TRUE; + struct sigaction action; + action.sa_handler = g_unix_signal_handler; + sigemptyset (&action.sa_mask); +#ifdef SA_RESTART + action.sa_flags = SA_RESTART | SA_NOCLDSTOP; +#else + action.sa_flags = SA_NOCLDSTOP; +#endif + sigaction (signum, &action, NULL); } +} - if (sigismember (&installed_signal_mask, signum)) - return; - - sigaddset (&installed_signal_mask, signum); - - action.sa_handler = g_unix_signal_handler; - sigemptyset (&action.sa_mask); - action.sa_flags = SA_RESTART | SA_NOCLDSTOP; - sigaction (signum, &action, NULL); +static void +unref_unix_signal_handler_unlocked (int signum) +{ + unix_signal_refcount[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); + } } GSource * @@ -4990,11 +5021,9 @@ _g_main_create_unix_signal_watch (int signum) unix_signal_source->pending = FALSE; G_LOCK (unix_signal_lock); - ensure_unix_signal_handler_installed_unlocked (signum); + 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; - unix_signal_pending[signum] = FALSE; + dispatch_unix_signals_unlocked (); G_UNLOCK (unix_signal_lock); return source; @@ -5003,7 +5032,12 @@ _g_main_create_unix_signal_watch (int signum) static void g_unix_signal_watch_finalize (GSource *source) { + GUnixSignalWatchSource *unix_signal_source; + + unix_signal_source = (GUnixSignalWatchSource *) source; + G_LOCK (unix_signal_lock); + unref_unix_signal_handler_unlocked (unix_signal_source->signum); unix_signal_watches = g_slist_remove (unix_signal_watches, source); G_UNLOCK (unix_signal_lock); } @@ -5013,6 +5047,7 @@ g_child_watch_finalize (GSource *source) { G_LOCK (unix_signal_lock); unix_child_watches = g_slist_remove (unix_child_watches, source); + unref_unix_signal_handler_unlocked (SIGCHLD); G_UNLOCK (unix_signal_lock); } @@ -5098,7 +5133,7 @@ g_child_watch_source_new (GPid pid) g_source_add_poll (source, &child_watch_source->poll); #else /* G_OS_WIN32 */ G_LOCK (unix_signal_lock); - ensure_unix_signal_handler_installed_unlocked (SIGCHLD); + ref_unix_signal_handler_unlocked (SIGCHLD); unix_child_watches = g_slist_prepend (unix_child_watches, child_watch_source); if (waitpid (pid, &child_watch_source->child_status, WNOHANG) > 0) child_watch_source->child_exited = TRUE;