* 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 <http://www.gnu.org/licenses/>.
*/
/*
#ifdef HAVE_SYS_TIME_H
#include <sys/time.h>
#endif /* HAVE_SYS_TIME_H */
-#ifdef HAVE_UNISTD_H
+#ifdef G_OS_UNIX
#include <unistd.h>
-#endif /* HAVE_UNISTD_H */
+#endif /* G_OS_UNIX */
#include <errno.h>
#include <string.h>
#include <windows.h>
#endif /* G_OS_WIN32 */
+#include "glib_trace.h"
+
#include "gmain.h"
#include "garray.h"
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);
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);
* 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(), <emphasis>not</emphasis> 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
* 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 #GSource<!-- -->s 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.)
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 ();
GMainContext *context,
gboolean have_lock)
{
+ TRACE (GLIB_MAIN_SOURCE_DESTROY (g_source_get_name (source)));
+
if (!have_lock)
LOCK_CONTEXT (context);
* many things that the user could do. Instead, you can use the
* following techniques:
*
- * <orderedlist>
- * <listitem>
- * <para>
- * Use gtk_widget_set_sensitive() or modal dialogs to prevent
- * the user from interacting with elements while the main
- * loop is recursing.
- * </para>
- * </listitem>
- * <listitem>
- * <para>
- * 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.
- * </para>
- * </listitem>
- * </orderedlist>
+ * 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)
{
* {
* 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;
* }
* GDK_THREADS_ENTER ();
* if (!g_source_is_destroyed (g_main_current_source ()))
* {
- * /<!-- -->* do stuff with self *<!-- -->/
+ * /* do stuff with self */
* }
* GDK_THREADS_LEAVE ();
*
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--;
}
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.
*
if (!source->pending)
{
- if (unix_signal_pending[source->signum])
+ if (pending[source->signum])
{
source->pending = TRUE;
}
}
- 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);
}
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;