-I$(top_srcdir)/gmodule, fix from Michael Meeks
[platform/upstream/glib.git] / gmain.c
diff --git a/gmain.c b/gmain.c
index d87022c..29af3b0 100644 (file)
--- a/gmain.c
+++ b/gmain.c
@@ -131,11 +131,12 @@ struct _GMainLoop
 {
   GMainContext *context;
   gboolean is_running;
+  guint ref_count;
 
 #ifdef G_THREADS_ENABLED
   GMutex *mutex;
   GCond *sem_cond;
-#endif G_THREADS_ENABLED  
+#endif /* G_THREADS_ENABLED */
 };
 
 struct _GTimeoutSource
@@ -514,6 +515,7 @@ g_main_context_destroy (GMainContext *context)
   
   g_mem_chunk_destroy (context->poll_chunk);
 
+#ifdef G_THREADS_ENABLED
   if (g_thread_supported())
     {
 #ifndef G_OS_WIN32
@@ -523,6 +525,7 @@ g_main_context_destroy (GMainContext *context)
       CloseHandle (context->wake_up_semaphore);
 #endif
     }
+#endif
   
   g_free (context);
 }
@@ -752,6 +755,7 @@ g_source_attach (GSource      *source,
   source->context = context;
   result = source->id = context->next_id++;
 
+  source->ref_count++;
   g_source_list_add (source, context);
 
   tmp_list = source->poll_fds;
@@ -781,6 +785,7 @@ g_source_destroy_internal (GSource      *source,
   
   if (!SOURCE_DESTROYED (source))
     {
+      GSList *tmp_list;
       gpointer old_cb_data;
       GSourceCallbackFuncs *old_cb_funcs;
       
@@ -799,6 +804,13 @@ g_source_destroy_internal (GSource      *source,
          LOCK_CONTEXT (context);
        }
       
+      tmp_list = source->poll_fds;
+      while (tmp_list)
+       {
+         g_main_context_remove_poll_unlocked (context, tmp_list->data);
+         tmp_list = tmp_list->next;
+       }
+      
       g_source_unref_internal (source, context, TRUE);
     }
 
@@ -893,7 +905,8 @@ g_source_add_poll (GSource *source,
   
   g_return_if_fail (source != NULL);
   g_return_if_fail (fd != NULL);
-
+  g_return_if_fail (!SOURCE_DESTROYED (source));
+  
   context = source->context;
 
   if (context)
@@ -1161,9 +1174,8 @@ g_source_unref_internal (GSource      *source,
                         GMainContext *context,
                         gboolean      have_lock)
 {
-  gpointer cb_data = NULL;
-  GSourceCallbackFuncs *cb_funcs = NULL;
-  GSList *tmp_list;
+  gpointer old_cb_data = NULL;
+  GSourceCallbackFuncs *old_cb_funcs = NULL;
 
   g_return_if_fail (source != NULL);
   
@@ -1173,33 +1185,37 @@ g_source_unref_internal (GSource      *source,
   source->ref_count--;
   if (source->ref_count == 0)
     {
+      old_cb_data = source->callback_data;
+      old_cb_funcs = source->callback_funcs;
+
+      source->callback_data = NULL;
+      source->callback_funcs = NULL;
+
       if (context && !SOURCE_DESTROYED (source))
        {
          g_warning (G_STRLOC ": ref_count == 0, but source is still attached to a context!");
          source->ref_count++;
        }
-      else
-       {
-         g_source_list_remove (source, context);
-         
-         tmp_list = source->poll_fds;
-         while (tmp_list)
-           {
-             g_main_context_remove_poll_unlocked (context, tmp_list->data);
-             tmp_list = tmp_list->next;
-           }
-       }
+      else if (context)
+       g_source_list_remove (source, context);
+
+      if (source->source_funcs->destroy)
+       source->source_funcs->destroy (source);
+      
+      g_slist_free (source->poll_fds);
+      source->poll_fds = NULL;
+      g_free (source);
     }
   
   if (!have_lock && context)
     UNLOCK_CONTEXT (context);
 
-  if (cb_data)
+  if (old_cb_funcs)
     {
       if (have_lock)
        UNLOCK_CONTEXT (context);
       
-      cb_funcs->unref (cb_data);
+      old_cb_funcs->unref (old_cb_data);
 
       if (have_lock)
        LOCK_CONTEXT (context);
@@ -1600,7 +1616,7 @@ g_main_context_prepare (GMainContext *context,
     }
   
   context->poll_waiting = TRUE;
-#endif G_THREADS_ENABLED  
+#endif /* G_THREADS_ENABLED */
 
 #if 0
   /* If recursing, finish up current dispatch, before starting over */
@@ -1727,8 +1743,10 @@ g_main_context_query (GMainContext *context,
       pollrec = pollrec->next;
     }
 
+#ifdef G_THREADS_ENABLED
   context->poll_changed = FALSE;
-
+#endif
+  
   if (timeout)
     {
       *timeout = context->timeout;
@@ -1783,14 +1801,14 @@ g_main_context_check (GMainContext *context,
     }
   else
     context->poll_waiting = FALSE;
-#endif /* G_THREADS_ENABLED */
 
   /* If the set of poll file descriptors changed, bail out
    * and let the main loop rerun
    */
   if (context->poll_changed)
     return 0;
-
+#endif /* G_THREADS_ENABLED */
+  
   pollrec = context->poll_records;
   i = 0;
   while (i < n_fds)
@@ -1995,19 +2013,80 @@ g_main_loop_new (GMainContext *context,
   loop = g_new0 (GMainLoop, 1);
   loop->context = context;
   loop->is_running = is_running != FALSE;
-
+  loop->ref_count = 1;
+  
 #ifdef G_THREADS_ENABLED
   if (g_thread_supported ())
     loop->mutex = g_mutex_new ();
   else
     loop->mutex = NULL;
   loop->sem_cond = NULL;
-#endif G_THREADS_ENABLED  
+#endif /* G_THREADS_ENABLED */
 
   return loop;
 }
 
 /**
+ * g_main_loop_ref:
+ * @loop: a #GMainLoop
+ * 
+ * Increase the reference count on a #GMainLoop object by one.
+ * 
+ * Return value: @loop
+ **/
+GMainLoop *
+g_main_loop_ref (GMainLoop *loop)
+{
+  g_return_val_if_fail (loop != NULL, NULL);
+
+  LOCK_LOOP (loop);
+  loop->ref_count++;
+  UNLOCK_LOOP (loop);
+
+  return loop;
+}
+
+static void
+main_loop_destroy (GMainLoop *loop)
+{
+#ifdef G_THREADS_ENABLED
+  g_mutex_free (loop->mutex);
+  if (loop->sem_cond)
+    g_cond_free (loop->sem_cond);
+#endif /* G_THREADS_ENABLED */  
+  
+  g_free (loop);
+}
+
+/**
+ * g_main_loop_unref:
+ * @loop: a #GMainLoop
+ * 
+ * Decreases the reference count on a #GMainLoop object by one. If
+ * the result is zero, free the loop and free all associated memory.
+ **/
+void
+g_main_loop_unref (GMainLoop *loop)
+{
+  g_return_if_fail (loop != NULL);
+  g_return_if_fail (loop->ref_count > 0);
+
+  LOCK_LOOP (loop);
+  
+  loop->ref_count--;
+  if (loop->ref_count == 0)
+    {
+      /* When the ref_count is 0, there can be nobody else using the
+       * loop, so it is safe to unlock before destroying.
+       */
+      UNLOCK_LOOP (loop);
+      main_loop_destroy (loop);
+    }
+  else
+    UNLOCK_LOOP (loop);
+}
+
+/**
  * g_main_loop_run:
  * @loop: a #GMainLoop
  * 
@@ -2021,11 +2100,16 @@ g_main_loop_run (GMainLoop *loop)
 {
   g_return_if_fail (loop != NULL);
 
+  /* The assumption here is that a reference is held to the loop
+   * until we recursively iterate
+   */
 #ifdef G_THREADS_ENABLED
   if (loop->context->thread != g_thread_self ())
     {
       LOCK_LOOP (loop);
 
+      loop->ref_count++;
+      
       if (!g_thread_supported ())
        {
          g_warning ("g_main_loop_run() was called from second thread but"
@@ -2042,8 +2126,6 @@ g_main_loop_run (GMainLoop *loop)
          while (loop->is_running)
            g_cond_wait (loop->sem_cond, loop->mutex);
        }
-       
-      UNLOCK_LOOP (loop);
     }
   else
 #endif /* G_THREADS_ENABLED */    
@@ -2059,6 +2141,7 @@ g_main_loop_run (GMainLoop *loop)
       
       LOCK_LOOP (loop);
 
+      loop->ref_count++;
       loop->is_running = TRUE;
       while (loop->is_running)
        {
@@ -2066,8 +2149,19 @@ g_main_loop_run (GMainLoop *loop)
          g_main_context_iterate (loop->context, TRUE, TRUE);
          LOCK_LOOP (loop);
        }
+    }
+
+  /* We inline this here rather than calling g_main_loop_unref() to
+   * avoid an extra unlock/lock.
+   */
+  loop->ref_count--;
+  if (loop->ref_count == 0)
+    {
       UNLOCK_LOOP (loop);
+      main_loop_destroy (loop);
     }
+  else
+    UNLOCK_LOOP (loop);
 }
 
 /**
@@ -2085,8 +2179,10 @@ g_main_loop_quit (GMainLoop *loop)
   LOCK_LOOP (loop);
   loop->is_running = FALSE;
 
+#ifdef G_THREADS_ENABLED
   if (loop->sem_cond)
     g_cond_broadcast (loop->sem_cond);
+#endif
   
   UNLOCK_LOOP (loop);
 
@@ -2097,28 +2193,6 @@ g_main_loop_quit (GMainLoop *loop)
 }
 
 /**
- * g_main_loop_destroy:
- * @loop: a #GMainLoop
- * 
- * Destroy a #GMainLoop object and free all associated memory.
- * The loop must not currently be running via g_main_run().
- **/
-void 
-g_main_loop_destroy (GMainLoop *loop)
-{
-  g_return_if_fail (loop != NULL);
-  g_return_if_fail (!loop->is_running);
-
-#ifdef G_THREADS_ENABLED
-  g_mutex_free (loop->mutex);
-  if (loop->sem_cond)
-    g_cond_free (loop->sem_cond);
-#endif /* G_THREADS_ENABLED */  
-
-  g_free (loop);
-}
-
-/**
  * g_main_loop_is_running:
  * @loop: a #GMainLoop.
  * 
@@ -2426,8 +2500,6 @@ g_main_context_set_poll_func (GMainContext *context,
   UNLOCK_CONTEXT (context);
 }
 
-#ifdef G_OS_WIN32
-
 /**
  * g_main_context_get_poll_func:
  * @context: a #GMainContext
@@ -2439,7 +2511,7 @@ g_main_context_set_poll_func (GMainContext *context,
 GPollFunc
 g_main_context_get_poll_func (GMainContext *context)
 {
-  GPollFunc *result;
+  GPollFunc result;
   
   if (!context)
     context = g_main_context_default ();
@@ -2447,9 +2519,9 @@ g_main_context_get_poll_func (GMainContext *context)
   LOCK_CONTEXT (context);
   result = context->poll_func;
   UNLOCK_CONTEXT (context);
-}
 
-#endif
+  return result;
+}
 
 /* HOLDS: context's lock */
 /* Wake the main loop up from a poll() */
@@ -2463,7 +2535,7 @@ g_main_context_wakeup (GMainContext *context)
 #ifndef G_OS_WIN32
       write (context->wake_up_pipe[1], "A", 1);
 #else
-      ReleaseSemaphore (context->context->wake_up_semaphore, 1, NULL);
+      ReleaseSemaphore (context->wake_up_semaphore, 1, NULL);
 #endif
     }
 #endif
@@ -2618,6 +2690,7 @@ g_timeout_add_full (gint           priority,
                    GDestroyNotify notify)
 {
   GSource *source;
+  guint id;
   
   g_return_val_if_fail (function != NULL, 0);
 
@@ -2627,7 +2700,10 @@ g_timeout_add_full (gint           priority,
     g_source_set_priority (source, priority);
 
   g_source_set_callback (source, function, data, notify);
-  return g_source_attach (source, NULL);
+  id = g_source_attach (source, NULL);
+  g_source_unref (source);
+
+  return id;
 }
 
 /**
@@ -2731,6 +2807,7 @@ g_idle_add_full (gint           priority,
                 GDestroyNotify notify)
 {
   GSource *source;
+  guint id;
   
   g_return_val_if_fail (function != NULL, 0);
 
@@ -2740,7 +2817,10 @@ g_idle_add_full (gint           priority,
     g_source_set_priority (source, priority);
 
   g_source_set_callback (source, function, data, notify);
-  return g_source_attach (source, NULL);
+  id = g_source_attach (source, NULL);
+  g_source_unref (source);
+
+  return id;
 }
 
 /**