Add g_main_context_push_thread_default() etc
authorDan Winship <danw@gnome.org>
Fri, 5 Jun 2009 01:59:15 +0000 (21:59 -0400)
committerDan Winship <danw@gnome.org>
Wed, 1 Jul 2009 13:02:23 +0000 (09:02 -0400)
This allows applications to use async methods from other threads, or
in multiple independent main loops.

http://bugzilla.gnome.org/show_bug.cgi?id=579984

docs/reference/glib/glib-sections.txt
docs/reference/glib/tmpl/main.sgml
glib/glib.symbols
glib/gmain.c
glib/gmain.h

index 0a583ed..bec08ad 100644 (file)
@@ -463,6 +463,11 @@ g_main_current_source
 g_main_set_poll_func
 
 <SUBSECTION>
+g_main_context_get_thread_default
+g_main_context_push_thread_default
+g_main_context_pop_thread_default
+
+<SUBSECTION>
 g_timeout_source_new
 g_timeout_source_new_seconds
 g_timeout_add
index 9f7de38..0e5a142 100644 (file)
@@ -545,6 +545,30 @@ for the default main context.
 @Deprecated: 2.2: Use g_main_context_set_poll_func() instead.
 
 
+<!-- ##### FUNCTION g_main_context_get_thread_default ##### -->
+<para>
+
+</para>
+
+@Returns: 
+
+
+<!-- ##### FUNCTION g_main_context_push_thread_default ##### -->
+<para>
+
+</para>
+
+@context: 
+
+
+<!-- ##### FUNCTION g_main_context_pop_thread_default ##### -->
+<para>
+
+</para>
+
+@context: 
+
+
 <!-- ##### FUNCTION g_timeout_source_new ##### -->
 <para>
 
index 8bcd899..0bd7ab9 100644 (file)
@@ -622,11 +622,14 @@ g_main_context_find_source_by_funcs_user_data
 g_main_context_find_source_by_id
 g_main_context_find_source_by_user_data
 g_main_context_get_poll_func
+g_main_context_get_thread_default
 g_main_context_is_owner
 g_main_context_iteration
 g_main_context_new
 g_main_context_pending
+g_main_context_pop_thread_default
 g_main_context_prepare
+g_main_context_push_thread_default
 g_main_context_query
 g_main_context_ref
 g_main_context_release
index 6d6b594..e04c7b5 100644 (file)
@@ -529,11 +529,12 @@ g_main_context_new (void)
 /**
  * g_main_context_default:
  * 
- * Returns the default main context. This is the main context used
- * for main loop functions when a main loop is not explicitly
- * specified.
+ * Returns the global default main context. This is the main context
+ * used for main loop functions when a main loop is not explicitly
+ * specified, and corresponds to the "main" main loop. See also
+ * g_main_context_get_thread_default().
  * 
- * Return value: the default main context.
+ * Return value: the global default main context.
  **/
 GMainContext *
 g_main_context_default (void)
@@ -556,6 +557,141 @@ g_main_context_default (void)
   return default_main_context;
 }
 
+static GStaticPrivate thread_context_stack = G_STATIC_PRIVATE_INIT;
+
+static void
+free_context_stack (gpointer data)
+{
+  GQueue *stack = data;
+  GMainContext *context;
+
+  while (!g_queue_is_empty (stack))
+    {
+      context = g_queue_pop_head (stack);
+      g_main_context_release (context);
+      if (context)
+       g_main_context_unref (context);
+    }
+  g_queue_free (stack);
+}
+
+/**
+ * g_main_context_push_thread_default:
+ * @context: a #GMainContext, or %NULL for the global default context
+ *
+ * Acquires @context and sets it as the thread-default context for the
+ * current thread. This will cause certain asynchronous operations
+ * (such as most <link linkend="gio">gio</link>-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(), <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().
+ *
+ * Normally you would call this function shortly after creating a new
+ * thread, passing it a #GMainContext which will be run by a
+ * #GMainLoop in that thread, to set a new default context for all
+ * async operations in that thread. (In this case, you don't need to
+ * ever call g_main_context_pop_thread_default().) In some cases
+ * however, you may want to schedule a single operation in a
+ * non-default context, or temporarily use a non-default context in
+ * the main thread. In that case, you can wrap the call to the
+ * asynchronous operation inside a
+ * g_main_context_push_thread_default() /
+ * g_main_context_pop_thread_default() pair, but it is up to you to
+ * ensure that no other asynchronous operations accidentally get
+ * started while the non-default context is active.
+ *
+ * Beware that libraries that predate this function may not correctly
+ * handle being used from a thread with a thread-default context. Eg,
+ * see g_file_supports_thread_contexts().
+ *
+ * Since: 2.22
+ **/
+void
+g_main_context_push_thread_default (GMainContext *context)
+{
+  GQueue *stack;
+  gboolean acquired_context;
+
+  acquired_context = g_main_context_acquire (context);
+  g_return_if_fail (acquired_context);
+
+  if (context == g_main_context_default ())
+    context = NULL;
+  else if (context)
+    g_main_context_ref (context);
+
+  stack = g_static_private_get (&thread_context_stack);
+  if (!stack)
+    {
+      stack = g_queue_new ();
+      g_static_private_set (&thread_context_stack, stack,
+                           free_context_stack);
+    }
+
+  g_queue_push_head (stack, context);
+}
+
+/**
+ * g_main_context_pop_thread_default:
+ * @context: a #GMainContext object, or %NULL
+ *
+ * Pops @context off the thread-default context stack (verifying that
+ * it was on the top of the stack).
+ *
+ * Since: 2.22
+ **/
+void
+g_main_context_pop_thread_default (GMainContext *context)
+{
+  GQueue *stack;
+
+  if (context == g_main_context_default ())
+    context = NULL;
+
+  stack = g_static_private_get (&thread_context_stack);
+
+  g_return_if_fail (stack != NULL);
+  g_return_if_fail (g_queue_peek_head (stack) == context);
+
+  g_queue_pop_head (stack);
+
+  g_main_context_release (context);
+  if (context)
+    g_main_context_unref (context);
+}
+
+/**
+ * g_main_context_get_thread_default:
+ *
+ * Gets the thread-default #GMainContext for this thread. Asynchronous
+ * operations that want to be able to be run in contexts other than
+ * the default one should call this method to get a #GMainContext to
+ * add their #GSource<!-- -->s 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 threads are not initialized.)
+ *
+ * Returns: the thread-default #GMainContext, or %NULL if the
+ * thread-default context is the global default context.
+ *
+ * Since: 2.22
+ **/
+GMainContext *
+g_main_context_get_thread_default (void)
+{
+  GQueue *stack;
+
+  stack = g_static_private_get (&thread_context_stack);
+  if (stack)
+    return g_queue_peek_head (stack);
+  else
+    return NULL;
+}
+
 /* Hooks for adding to the main loop */
 
 /**
index 3f0e9cd..15fe54e 100644 (file)
@@ -158,6 +158,11 @@ void     g_main_context_remove_poll (GMainContext *context,
 gint     g_main_depth               (void);
 GSource *g_main_current_source      (void);
 
+/* GMainContexts for other threads
+ */
+void          g_main_context_push_thread_default (GMainContext *context);
+void          g_main_context_pop_thread_default  (GMainContext *context);
+GMainContext *g_main_context_get_thread_default  (void);
 
 /* GMainLoop: */