diff --git a/glib/gmain.h b/glib/gmain.h
index 3f0e9cd..15fe54e 100644
--- a/glib/gmain.h
+++ b/glib/gmain.h
@@ -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: */
 
diff --git a/glib/gmain.c b/glib/gmain.c
index 331c0a8..71061cf 100644
--- a/glib/gmain.c
+++ b/glib/gmain.c
@@ -521,7 +521,8 @@ g_main_context_new (void)
  * 
  * Returns the default main context. This is the main context used
  * for main loop functions when a main loop is not explicitly
- * specified.
+ * specified, and corresponds to the "main" main loop. See also
+ * g_main_context_get_thread_default().
  * 
  * Return value: the default main context.
  **/
@@ -546,6 +547,116 @@ g_main_context_default (void)
   return default_main_context;
 }
 
+static GStaticPrivate thread_context_stack = G_STATIC_PRIVATE_INIT;
+
+/**
+ * g_main_context_push_thread_default:
+ * @context: a #GMainContext, or %NULL for the global default context
+ *
+ * Sets @context as the thread-default context for the current thread.
+ * This will cause certain asynchronous operations (such as most
+ * 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 default main 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().
+ *
+ * In general, you should only call this function immediately after
+ * creating a new thread, passing it a #GMainContext which is (or will
+ * be) owned by that thread, to set a new default context for
+ * operations in that thread (and you should not need to use
+ * g_main_context_pop_thread_default()). In some cases however, it may
+ * be necessary to schedule a single operation in a non-default
+ * context. In that case, you may 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 on the top of the stack.
+ *
+ * Beware that libraries that predate this function may not correctly
+ * handle being run in a thread with a thread-default context, and may
+ * erroneously send their results to the main context instead. Also,
+ * some libraries may do some of their event handling in the main
+ * context even for operations started from another context, in which
+ * case operations started in other threads may not complete if the
+ * main thread is not running.
+ *
+ * Since: 2.22
+ **/
+void
+g_main_context_push_thread_default (GMainContext *context)
+{
+  GSList *l;
+
+  if (context == g_main_context_default ())
+    context = NULL;
+  else if (context)
+    g_main_context_ref (context);
+
+  l = g_static_private_get (&thread_context_stack);
+  l = g_slist_prepend (l, context);
+  g_static_private_set (&thread_context_stack, l, NULL);
+}
+
+/**
+ * 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)
+{
+  GSList *l;
+
+  if (context == g_main_context_default ())
+    context = NULL;
+
+  l = g_static_private_get (&thread_context_stack);
+
+  g_return_if_fail (l != NULL);
+  g_return_if_fail (l->data == context);
+
+  l = g_slist_delete_link (l, l);
+  g_static_private_set (&thread_context_stack, l, NULL);
+
+  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 global
+ * default main context is also the thread-default context.
+ *
+ * Since: 2.22
+ **/
+GMainContext *
+g_main_context_get_thread_default (void)
+{
+  GSList *l;
+
+  l = g_static_private_get (&thread_context_stack);
+  if (l == NULL)
+    return NULL;
+
+  return l->data;
+}
+
 /* Hooks for adding to the main loop */
 
 /**
diff --git a/gio/gasynchelper.c b/gio/gasynchelper.c
index 61ef35a..6387bf9 100644
--- a/gio/gasynchelper.c
+++ b/gio/gasynchelper.c
@@ -36,41 +36,6 @@
  *
  **/
 
-static void
-async_result_free (gpointer data)
-{
-  GAsyncResultData *res = data;
-
-  if (res->error)
-    g_error_free (res->error);
-
-  g_object_unref (res->async_object);
-  
-  g_free (res);
-}
-
-void
-_g_queue_async_result (GAsyncResultData *result,
-		       gpointer          async_object,
-		       GError           *error,
-		       gpointer          user_data,
-		       GSourceFunc       source_func)
-{
-  GSource *source;
-
-  g_return_if_fail (G_IS_OBJECT (async_object));
-  
-  result->async_object = g_object_ref (async_object);
-  result->user_data = user_data;
-  result->error = error;
-
-  source = g_idle_source_new ();
-  g_source_set_priority (source, G_PRIORITY_DEFAULT);
-  g_source_set_callback (source, source_func, result, async_result_free);
-  g_source_attach (source, NULL);
-  g_source_unref (source);
-}
-
 /*************************************************************************
  *             fd source                                                 *
  ************************************************************************/
diff --git a/gio/gfilemonitor.c b/gio/gfilemonitor.c
index 41444e3..211625d 100644
--- a/gio/gfilemonitor.c
+++ b/gio/gfilemonitor.c
@@ -47,8 +47,13 @@ static void file_change_free (FileChange *change);
  * g_file_monitor(), g_file_monitor_file(), or
  * g_file_monitor_directory().
  *
- * To get informed about changes to the file or directory you
- * are monitoring, connect to the #GFileMonitor::changed signal.
+ * To get informed about changes to the file or directory you are
+ * monitoring, connect to the #GFileMonitor::changed signal. The
+ * signal will be emitted in the <link
+ * linkend="FIXME-giocontext">thread-default main context</link>
+ * (though if the global default main context is blocked, this may
+ * cause notifications to be blocked even if the thread-default
+ * context is still running).
  **/
 
 G_LOCK_DEFINE_STATIC(cancelled);
@@ -77,11 +82,13 @@ struct _GFileMonitorPrivate {
   /* Rate limiting change events */
   GHashTable *rate_limiter;
 
-  guint pending_file_change_id;
+  GSource pending_file_change_source;
   GSList *pending_file_changes; /* FileChange */
 
   GSource *timeout;
   guint32 timeout_fires_at;
+
+  GMainContext *context;
 };
 
 enum {
@@ -169,6 +176,9 @@ g_file_monitor_finalize (GObject *object)
 
   g_hash_table_destroy (monitor->priv->rate_limiter);
 
+  if (monitor->priv->context)
+    g_main_context_unref (monitor->priv->context);
+
   G_OBJECT_CLASS (g_file_monitor_parent_class)->finalize (object);
 }
 
@@ -181,10 +191,11 @@ g_file_monitor_dispose (GObject *object)
   monitor = G_FILE_MONITOR (object);
   priv = monitor->priv;
 
-  if (priv->pending_file_change_id)
+  if (priv->pending_file_change_source)
     {
-      g_source_remove (priv->pending_file_change_id);
-      priv->pending_file_change_id = 0;
+      g_source_destroy (priv->pending_file_change_source);
+      g_source_unref (priv->pending_file_change_source);
+      priv->pending_file_change_source = NULL;
     }
   g_slist_foreach (priv->pending_file_changes, (GFunc) file_change_free, NULL);
   g_slist_free (priv->pending_file_changes);
@@ -257,6 +268,7 @@ g_file_monitor_init (GFileMonitor *monitor)
   monitor->priv->rate_limit_msec = DEFAULT_RATE_LIMIT_MSECS;
   monitor->priv->rate_limiter = g_hash_table_new_full (g_file_hash, (GEqualFunc)g_file_equal,
 						       NULL, (GDestroyNotify) rate_limiter_free);
+  monitor->priv->context = g_main_context_get_thread_default ();
 }
 
 /**
@@ -362,7 +374,7 @@ emit_cb (gpointer data)
   
   pending = g_slist_reverse (monitor->priv->pending_file_changes);
   monitor->priv->pending_file_changes = NULL;
-  monitor->priv->pending_file_change_id = 0;
+  monitor->priv->pending_file_change_source = NULL;
 
   g_object_ref (monitor);
   for (iter = pending; iter; iter = iter->next)
@@ -399,17 +411,17 @@ emit_in_idle (GFileMonitor      *monitor,
     change->other_file = NULL;
   change->event_type = event_type;
 
-  if (!priv->pending_file_change_id)
+  if (!priv->pending_file_change_source)
     {
       source = g_idle_source_new ();
+      priv->pending_file_change_source = source;
       g_source_set_priority (source, 0);
 
-      /* We don't ref here - instead dispose will free any
+      /* We don't ref monitor here - instead dispose will free any
        * pending idles.
        */
       g_source_set_callback (source, emit_cb, monitor, NULL);
-      priv->pending_file_change_id = g_source_attach (source, NULL);
-      g_source_unref (source);
+      g_source_attach (source, monitor->priv->context);
     }
   /* We reverse this in the processor */
   priv->pending_file_changes = g_slist_prepend (priv->pending_file_changes, change);
@@ -565,7 +577,7 @@ rate_limiter_timeout (gpointer timeout_data)
     {
       source = g_timeout_source_new (data.min_time + 1); /* + 1 to make sure we've really passed the time */
       g_source_set_callback (source, rate_limiter_timeout, monitor, NULL);
-      g_source_attach (source, NULL);
+      g_source_attach (source, monitor->priv->context);
       
       monitor->priv->timeout = source;
       monitor->priv->timeout_fires_at = data.time_now + data.min_time; 
@@ -617,7 +629,7 @@ update_rate_limiter_timeout (GFileMonitor *monitor,
     {
       source = g_timeout_source_new (data.min_time + 1);  /* + 1 to make sure we've really passed the time */
       g_source_set_callback (source, rate_limiter_timeout, monitor, NULL);
-      g_source_attach (source, NULL);
+      g_source_attach (source, monitor->priv->context);
       
       monitor->priv->timeout = source;
       monitor->priv->timeout_fires_at = data.time_now + data.min_time; 
@@ -635,7 +647,8 @@ update_rate_limiter_timeout (GFileMonitor *monitor,
  * has taken place. Should be called from file monitor 
  * implementations only.
  *
- * The signal will be emitted from an idle handler.
+ * The signal will be emitted from an idle handler (in the <link
+ * linkend="FIXME-giocontext">thread-default main context</link>).
  **/
 void
 g_file_monitor_emit_event (GFileMonitor      *monitor,
diff --git a/gio/gioscheduler.c b/gio/gioscheduler.c
index 14b59fe..2e98754 100644
--- a/gio/gioscheduler.c
+++ b/gio/gioscheduler.c
@@ -55,6 +55,7 @@ struct _GIOSchedulerJob {
 
   gint io_priority;
   GCancellable *cancellable;
+  GMainContext *context;
 
   guint idle_tag;
 };
@@ -72,6 +73,8 @@ g_io_job_free (GIOSchedulerJob *job)
 {
   if (job->cancellable)
     g_object_unref (job->cancellable);
+  if (job->context)
+    g_main_context_unref (job->context);
   g_free (job);
 }
 
@@ -173,6 +176,8 @@ io_job_thread (gpointer data,
 
   if (job->cancellable)
     g_cancellable_push_current (job->cancellable);
+  if (job->context)
+    g_main_context_push_thread_default (job->context);
 
   do 
     {
@@ -180,6 +185,8 @@ io_job_thread (gpointer data,
     }
   while (result);
 
+  if (job->context)
+    g_main_context_pop_thread_default (job->context);
   if (job->cancellable)
     g_cancellable_pop_current (job->cancellable);
 
@@ -194,9 +201,13 @@ run_job_at_idle (gpointer data)
 
   if (job->cancellable)
     g_cancellable_push_current (job->cancellable);
+  if (job->context)
+    g_main_context_push_thread_default (job->context);
   
   result = job->job_func (job, job->cancellable, job->data);
   
+  if (job->context)
+    g_main_context_pop_thread_default (job->context);
   if (job->cancellable)
     g_cancellable_pop_current (job->cancellable);
 
@@ -242,6 +253,10 @@ g_io_scheduler_push_job (GIOSchedulerJobFunc  job_func,
   if (cancellable)
     job->cancellable = g_object_ref (cancellable);
 
+  job->context = g_main_context_get_thread_default ();
+  if (job->context)
+    g_main_context_ref (job->context);
+
   G_LOCK (active_jobs);
   active_jobs = g_slist_prepend (active_jobs, job);
   job->active_link = active_jobs;
@@ -341,12 +356,12 @@ mainloop_proxy_free (MainLoopProxy *proxy)
 /**
  * g_io_scheduler_job_send_to_mainloop:
  * @job: a #GIOSchedulerJob
- * @func: a #GSourceFunc callback that will be called in the main thread
+ * @func: a #GSourceFunc callback that will be called in the original thread
  * @user_data: data to pass to @func
  * @notify: a #GDestroyNotify for @user_data, or %NULL
  * 
- * Used from an I/O job to send a callback to be run in the 
- * main loop (main thread), waiting for the result (and thus 
+ * Used from an I/O job to send a callback to be run in the thread
+ * that the job was started from, waiting for the result (and thus
  * blocking the I/O job).
  *
  * Returns: The return value of @func
@@ -389,7 +404,7 @@ g_io_scheduler_job_send_to_mainloop (GIOSchedulerJob *job,
   g_source_set_callback (source, mainloop_proxy_func, proxy,
 			 NULL);
 
-  id = g_source_attach (source, NULL);
+  id = g_source_attach (source, job->context);
   g_source_unref (source);
 
   g_cond_wait (proxy->ack_condition, proxy->ack_lock);
@@ -404,14 +419,14 @@ g_io_scheduler_job_send_to_mainloop (GIOSchedulerJob *job,
 /**
  * g_io_scheduler_job_send_to_mainloop_async:
  * @job: a #GIOSchedulerJob
- * @func: a #GSourceFunc callback that will be called in the main thread
+ * @func: a #GSourceFunc callback that will be called in the original thread
  * @user_data: data to pass to @func
  * @notify: a #GDestroyNotify for @user_data, or %NULL
  * 
- * Used from an I/O job to send a callback to be run asynchronously 
- * in the main loop (main thread). The callback will be run when the 
- * main loop is available, but at that time the I/O job might have 
- * finished. The return value from the callback is ignored.
+ * Used from an I/O job to send a callback to be run asynchronously in
+ * the thread that the job was started from. The callback will be run
+ * when the main loop is available, but at that time the I/O job might
+ * have finished. The return value from the callback is ignored.
  *
  * Note that if you are passing the @user_data from g_io_scheduler_push_job()
  * on to this function you have to ensure that it is not freed before
@@ -452,7 +467,7 @@ g_io_scheduler_job_send_to_mainloop_async (GIOSchedulerJob *job,
   g_source_set_callback (source, mainloop_proxy_func, proxy,
 			 (GDestroyNotify)mainloop_proxy_free);
 
-  id = g_source_attach (source, NULL);
+  id = g_source_attach (source, job->context);
   g_source_unref (source);
 }
 
diff --git a/gio/gsimpleasyncresult.c b/gio/gsimpleasyncresult.c
index e071d96..efd966b 100644
--- a/gio/gsimpleasyncresult.c
+++ b/gio/gsimpleasyncresult.c
@@ -89,11 +89,12 @@
  * 
  * GSimpleAsyncResult can integrate into GLib's event loop, #GMainLoop, 
  * or it can use #GThread<!-- -->s if available. 
- * g_simple_async_result_complete() will finish an I/O task directly within 
- * the main event loop. g_simple_async_result_complete_in_idle() will 
- * integrate the I/O task into the main event loop as an idle function and 
+ * g_simple_async_result_complete() will finish an I/O task directly
+ * from the point where it is called. g_simple_async_result_complete_in_idle()
+ * will finish it from an idle handler in the <link
+ * linkend="FIXME-giocontext">thread-default main context</link>.
  * g_simple_async_result_run_in_thread() will run the job in a separate 
- * thread.
+ * thread and then deliver the result to the thread-default main context.
  * 
  * To set the results of an asynchronous function, 
  * g_simple_async_result_set_op_res_gpointer(), 
@@ -119,6 +120,7 @@ struct _GSimpleAsyncResult
   GObject *source_object;
   GAsyncReadyCallback callback;
   gpointer user_data;
+  GMainContext *context;
   GError *error;
   gboolean failed;
   gboolean handle_cancellation;
@@ -163,6 +165,9 @@ g_simple_async_result_finalize (GObject *object)
   if (simple->source_object)
     g_object_unref (simple->source_object);
 
+  if (simple->context)
+    g_main_context_unref (simple->context);
+
   clear_op_res (simple);
 
   if (simple->error)
@@ -183,6 +188,10 @@ static void
 g_simple_async_result_init (GSimpleAsyncResult *simple)
 {
   simple->handle_cancellation = TRUE;
+
+  simple->context = g_main_context_get_thread_default ();
+  if (simple->context)
+    g_main_context_ref (simple->context);
 }
 
 /**
@@ -547,10 +556,10 @@ g_simple_async_result_set_error (GSimpleAsyncResult *simple,
  * g_simple_async_result_complete:
  * @simple: a #GSimpleAsyncResult.
  * 
- * Completes an asynchronous I/O job.
- * Must be called in the main thread, as it invokes the callback that
- * should be called in the main thread. If you are in a different thread
- * use g_simple_async_result_complete_in_idle().
+ * Completes an asynchronous I/O job immediately. Must be called in
+ * the thread where the asynchronous result was to be delivered, as it
+ * invokes the callback directly. If you are in a different thread use
+ * g_simple_async_result_complete_in_idle().
  **/
 void
 g_simple_async_result_complete (GSimpleAsyncResult *simple)
@@ -577,14 +586,14 @@ complete_in_idle_cb (gpointer data)
  * g_simple_async_result_complete_in_idle:
  * @simple: a #GSimpleAsyncResult.
  * 
- * Completes an asynchronous function in the main event loop using 
- * an idle function.
+ * Completes an asynchronous function in an idle handler in the <link
+ * linkend="FIXME-giocontext">thread-default main loop</link> of the
+ * thread that @simple was initially created in.
  **/
 void
 g_simple_async_result_complete_in_idle (GSimpleAsyncResult *simple)
 {
   GSource *source;
-  guint id;
   
   g_return_if_fail (G_IS_SIMPLE_ASYNC_RESULT (simple));
   
@@ -594,7 +603,7 @@ g_simple_async_result_complete_in_idle (GSimpleAsyncResult *simple)
   g_source_set_priority (source, G_PRIORITY_DEFAULT);
   g_source_set_callback (source, complete_in_idle_cb, simple, g_object_unref);
 
-  id = g_source_attach (source, NULL);
+  g_source_attach (source, simple->context);
   g_source_unref (source);
 }
 
@@ -638,7 +647,6 @@ run_in_thread (GIOSchedulerJob *job,
   RunInThreadData *data = _data;
   GSimpleAsyncResult *simple = data->simple;
   GSource *source;
-  guint id;
   
   if (simple->handle_cancellation &&
       g_cancellable_is_cancelled (c))
@@ -655,7 +663,7 @@ run_in_thread (GIOSchedulerJob *job,
   g_source_set_priority (source, G_PRIORITY_DEFAULT);
   g_source_set_callback (source, complete_in_idle_cb_for_thread, data, NULL);
 
-  id = g_source_attach (source, NULL);
+  g_source_attach (source, simple->context);
   g_source_unref (source);
 
   return FALSE;
@@ -668,7 +676,9 @@ run_in_thread (GIOSchedulerJob *job,
  * @io_priority: the io priority of the request.
  * @cancellable: optional #GCancellable object, %NULL to ignore. 
  * 
- * Runs the asynchronous job in a separated thread.
+ * Runs the asynchronous job in a separate thread and then calls
+ * g_simple_async_result_complete_in_idle() on @simple to return
+ * the result to the appropriate main loop.
  **/
 void
 g_simple_async_result_run_in_thread (GSimpleAsyncResult     *simple,
diff --git a/gio/gsocketclient.c b/gio/gsocketclient.c
index 74e6e80..e34686c 100644
--- a/gio/gsocketclient.c
+++ b/gio/gsocketclient.c
@@ -796,7 +796,7 @@ g_socket_client_enumerator_callback (GObject      *object,
 	  g_source_set_callback (source,
 				 (GSourceFunc) g_socket_client_socket_callback,
 				 data, NULL);
-	  g_source_attach (source, NULL);
+	  g_source_attach (source, g_main_context_get_thread_default ());
 	  g_source_unref (source);
 
 	  g_object_unref (address);
diff --git a/gio/gsocketinputstream.c b/gio/gsocketinputstream.c
index 6c0c68a..daa8906 100644
--- a/gio/gsocketinputstream.c
+++ b/gio/gsocketinputstream.c
@@ -195,7 +195,7 @@ g_socket_input_stream_read_async (GInputStream        *stream,
       g_source_set_callback (source,
                              (GSourceFunc) g_socket_input_stream_read_ready,
                              g_object_ref (input_stream), g_object_unref);
-      g_source_attach (source, NULL);
+      g_source_attach (source, g_main_context_get_thread_default ());
       g_source_unref (source);
     }
   else
diff --git a/gio/gsocketlistener.c b/gio/gsocketlistener.c
index 4a19e25..de606aa 100644
--- a/gio/gsocketlistener.c
+++ b/gio/gsocketlistener.c
@@ -649,7 +649,7 @@ g_socket_listener_accept_socket_async (GSocketListener     *listener,
 			       accept_ready,
 			       data,
 			       cancellable,
-			       NULL);
+			       g_main_context_get_thread_default ());
 }
 
 /**
diff --git a/gio/gsocketoutputstream.c b/gio/gsocketoutputstream.c
index 98d5c47..e2c517b 100644
--- a/gio/gsocketoutputstream.c
+++ b/gio/gsocketoutputstream.c
@@ -197,7 +197,7 @@ g_socket_output_stream_write_async (GOutputStream        *stream,
       g_source_set_callback (source,
                              (GSourceFunc) g_socket_output_stream_write_ready,
                              g_object_ref (output_stream), g_object_unref);
-      g_source_attach (source, NULL);
+      g_source_attach (source, g_main_context_get_thread_default ());
       g_source_unref (source);
     }
   else
diff --git a/gio/gtcpconnection.c b/gio/gtcpconnection.c
index 6ae3c71..907e3cc 100644
--- a/gio/gtcpconnection.c
+++ b/gio/gtcpconnection.c
@@ -336,7 +336,7 @@ g_tcp_connection_close_async (GIOStream           *stream,
       g_source_set_callback (source,
 			     (GSourceFunc) close_read_ready,
 			     data, (GDestroyNotify)close_async_data_free);
-      g_source_attach (source, NULL);
+      g_source_attach (source, g_main_context_get_thread_default ());
       g_source_unref (source);
 
       return;
diff --git a/gio/gunixinputstream.c b/gio/gunixinputstream.c
index 9a8e8e3..2813aad 100644
--- a/gio/gunixinputstream.c
+++ b/gio/gunixinputstream.c
@@ -507,7 +507,7 @@ g_unix_input_stream_read_async (GInputStream        *stream,
 			     cancellable);
   
   g_source_set_callback (source, (GSourceFunc)read_async_cb, data, g_free);
-  g_source_attach (source, NULL);
+  g_source_attach (source, g_main_context_get_thread_default ());
  
   g_source_unref (source);
 }
@@ -635,7 +635,7 @@ g_unix_input_stream_close_async (GInputStream        *stream,
   
   idle = g_idle_source_new ();
   g_source_set_callback (idle, (GSourceFunc)close_async_cb, data, close_async_data_free);
-  g_source_attach (idle, NULL);
+  g_source_attach (idle, g_main_context_get_thread_default ());
   g_source_unref (idle);
 }
 
diff --git a/gio/gunixoutputstream.c b/gio/gunixoutputstream.c
index 6c11e85..69c4c27 100644
--- a/gio/gunixoutputstream.c
+++ b/gio/gunixoutputstream.c
@@ -479,7 +479,7 @@ g_unix_output_stream_write_async (GOutputStream       *stream,
   GUnixOutputStream *unix_stream;
   WriteAsyncData *data;
 
-  unix_stream = G_UNIX_OUTPUT_STREAM (stream);
+n  unix_stream = G_UNIX_OUTPUT_STREAM (stream);
 
   data = g_new0 (WriteAsyncData, 1);
   data->count = count;
@@ -494,7 +494,7 @@ g_unix_output_stream_write_async (GOutputStream       *stream,
 			     cancellable);
   
   g_source_set_callback (source, (GSourceFunc)write_async_cb, data, g_free);
-  g_source_attach (source, NULL);
+  g_source_attach (source, g_main_context_get_thread_default ());
   
   g_source_unref (source);
 }
@@ -591,7 +591,7 @@ g_unix_output_stream_close_async (GOutputStream        *stream,
   
   idle = g_idle_source_new ();
   g_source_set_callback (idle, (GSourceFunc)close_async_cb, data, g_free);
-  g_source_attach (idle, NULL);
+  g_source_attach (idle, g_main_context_get_thread_default ());
   g_source_unref (idle);
 }
 
diff --git a/gio/gunixresolver.c b/gio/gunixresolver.c
index 34d7c1c..aa6abae 100644
--- a/gio/gunixresolver.c
+++ b/gio/gunixresolver.c
@@ -85,21 +85,16 @@ g_unix_resolver_finalize (GObject *object)
  *      a. The resolution completes: g_unix_resolver_watch() sees that
  *         the request has completed, and calls
  *         g_unix_resolver_request_complete(), which detaches the
- *         "cancelled" signal handler (if it was present) and then
- *         immediately completes the async_result (since
- *         g_unix_resolver_watch() is already run from main-loop
- *         time.) After completing the async_result, it unrefs it,
- *         causing the req to be freed as well.
+ *         "cancelled" signal handler (if it was present), queues the
+ *         async_result to be completed, and then unrefs it.
  *
  *      b. The resolution is cancelled: request_cancelled() calls
  *         _g_asyncns_cancel() to cancel the resolution. Then it calls
  *         g_unix_resolver_request_complete(), which detaches the
  *         signal handler, and queues async_result to complete in an
- *         idle handler. It then unrefs the async_result to ensure
- *         that after its callback runs, it will be destroyed, in turn
- *         causing the req to be freed. Because the asyncns resolution
- *         was cancelled, g_unix_resolver_watch() will never be
- *         triggered for this req.
+ *         idle handler. Because the asyncns resolution was cancelled,
+ *         g_unix_resolver_watch() will never be triggered for this
+ *         req.
  *
  *    Since there's only a single thread, it's not possible for the
  *    request to both complete and be cancelled "at the same time",
@@ -174,8 +169,7 @@ g_unix_resolver_request_free (GUnixResolverRequest *req)
 }
 
 static void
-g_unix_resolver_request_complete (GUnixResolverRequest *req,
-                                  gboolean              need_idle)
+g_unix_resolver_request_complete (GUnixResolverRequest *req)
 {
   if (req->cancellable)
     {
@@ -184,16 +178,11 @@ g_unix_resolver_request_complete (GUnixResolverRequest *req,
       req->cancellable = NULL;
     }
 
-  if (need_idle)
-    g_simple_async_result_complete_in_idle (req->async_result);
-  else
-    g_simple_async_result_complete (req->async_result);
-
-  /* If we completed_in_idle, that will have taken an extra ref on
-   * req->async_result; if not, then we're already done. Either way we
-   * need to unref the async_result to make sure it eventually is
-   * destroyed, causing req to be freed.
+  /* We always complete in idle, even if we were called from
+   * g_unix_resolver_watch(), since we might have been started
+   * under a non-default g_main_context_get_thread_default().
    */
+  g_simple_async_result_complete_in_idle (req->async_result);
   g_object_unref (req->async_result);
 }
 
@@ -211,7 +200,7 @@ request_cancelled (GCancellable *cancellable,
   g_simple_async_result_set_from_error (req->async_result, error);
   g_error_free (error);
 
-  g_unix_resolver_request_complete (req, TRUE);
+  g_unix_resolver_request_complete (req);
 }
 
 static gboolean
@@ -235,7 +224,7 @@ g_unix_resolver_watch (GIOChannel   *iochannel,
          (qy = _g_asyncns_getnext (gur->asyncns)) != NULL)
     {
       req = _g_asyncns_getuserdata (gur->asyncns, qy);
-      g_unix_resolver_request_complete (req, FALSE);
+      g_unix_resolver_request_complete (req);
     }
 
   return TRUE;
diff --git a/gio/gwin32resolver.c b/gio/gwin32resolver.c
index cab45cc..5251270 100644
--- a/gio/gwin32resolver.c
+++ b/gio/gwin32resolver.c
@@ -95,7 +95,7 @@ struct GWin32ResolverRequest {
   HANDLE *event;
   GSimpleAsyncResult *async_result;
   gboolean complete;
-  guint cancelled_idle;
+  GSource *cancelled_idle;
 
   union {
     struct {
@@ -167,8 +167,9 @@ request_completed (gpointer user_data)
   /* Clean up cancellation-related stuff first */
   if (req->cancelled_idle)
     {
-      g_source_remove (req->cancelled_idle);
-      req->cancelled_idle = 0;
+      g_source_destroy (req->cancelled_idle);
+      g_source_unref (req->cancelled_idle);
+      req->cancelled_idle = NULL;
     }
   if (req->cancellable)
     {
@@ -197,7 +198,7 @@ request_cancelled_idle (gpointer user_data)
   GWin32ResolverRequest *req = user_data;
   GError *error = NULL;
 
-  req->cancelled_idle = 0;
+  req->cancelled_idle = NULL;
 
   g_cancellable_set_error_if_cancelled (req->cancellable, &error);
   g_simple_async_result_set_from_error (req->async_result, error);
@@ -216,6 +217,7 @@ request_cancelled (GCancellable *cancellable,
                    gpointer      user_data)
 {
   GWin32ResolverRequest *req = user_data;
+  GSource *source;
 
   if (req->cancellable)
     {
@@ -226,9 +228,13 @@ request_cancelled (GCancellable *cancellable,
 
   /* We need to wait until main-loop-time to actually complete the
    * result; we don't use _complete_in_idle() here because we need to
-   * keep track of the source id.
+   * keep track of the source so we can potentially cancel it before
+   * it runs.
    */
-  req->cancelled_idle = g_idle_add (request_cancelled_idle, req);
+  req->cancelled_idle = source = g_idle_source_new ();
+  g_source_set_callback (source, (GSourceFunc)request_cancelled_idle, req, NULL);
+  g_source_attach (source, g_main_context_get_thread_default ());
+  g_source_unref (source);
 }
 
 static DWORD WINAPI
@@ -473,7 +479,7 @@ g_win32_handle_source_add (HANDLE      handle,
   g_source_add_poll (source, &hsource->pollfd);
 
   g_source_set_callback (source, callback, user_data, NULL);
-  g_source_attach (source, NULL);
+  g_source_attach (source, g_io_context_get_thread_default ());
   return source;
 }
 
