Switch GMainLoop to be ref/unref, use to make dropping reference to
authorOwen Taylor <otaylor@redhat.com>
Wed, 3 Jan 2001 20:18:40 +0000 (20:18 +0000)
committerOwen Taylor <otaylor@src.gnome.org>
Wed, 3 Jan 2001 20:18:40 +0000 (20:18 +0000)
Wed Jan  3 14:10:49 2001  Owen Taylor  <otaylor@redhat.com>

* gmain.[ch]: Switch GMainLoop to be ref/unref, use to
make dropping reference to running loop safe.

12 files changed:
ChangeLog
ChangeLog.pre-2-0
ChangeLog.pre-2-10
ChangeLog.pre-2-12
ChangeLog.pre-2-2
ChangeLog.pre-2-4
ChangeLog.pre-2-6
ChangeLog.pre-2-8
glib/gmain.c
glib/gmain.h
gmain.c
gmain.h

index 32fd7d2be19ac15980b4d9c49bce42cfd853bac9..a8fbd00008b2a97a74f89781658798923486c711 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,10 +1,15 @@
+Wed Jan  3 14:10:49 2001  Owen Taylor  <otaylor@redhat.com>
+
+       * gmain.[ch]: Switch GMainLoop to be ref/unref, use to
+       make dropping reference to running loop safe.
+
 Wed Dec 13 20:41:49 2000  Owen Taylor  <otaylor@redhat.com>
 
        * gmain.c (g_source_unref_internal): Unref callback->cb_data
        if it was still set when the source is freed. (Usually, this
        will be done by g_source_destroy.)
 
-2001-01-02  Dan Winship  <danw@helixcode.com>
+ 2001-01-02  Dan Winship  <danw@helixcode.com>
 
        * garray.h (g_array_append_val, g_array_prepend_val,
        g_array_insert_val): Use parentheses around an argument to make
index 32fd7d2be19ac15980b4d9c49bce42cfd853bac9..a8fbd00008b2a97a74f89781658798923486c711 100644 (file)
@@ -1,10 +1,15 @@
+Wed Jan  3 14:10:49 2001  Owen Taylor  <otaylor@redhat.com>
+
+       * gmain.[ch]: Switch GMainLoop to be ref/unref, use to
+       make dropping reference to running loop safe.
+
 Wed Dec 13 20:41:49 2000  Owen Taylor  <otaylor@redhat.com>
 
        * gmain.c (g_source_unref_internal): Unref callback->cb_data
        if it was still set when the source is freed. (Usually, this
        will be done by g_source_destroy.)
 
-2001-01-02  Dan Winship  <danw@helixcode.com>
+ 2001-01-02  Dan Winship  <danw@helixcode.com>
 
        * garray.h (g_array_append_val, g_array_prepend_val,
        g_array_insert_val): Use parentheses around an argument to make
index 32fd7d2be19ac15980b4d9c49bce42cfd853bac9..a8fbd00008b2a97a74f89781658798923486c711 100644 (file)
@@ -1,10 +1,15 @@
+Wed Jan  3 14:10:49 2001  Owen Taylor  <otaylor@redhat.com>
+
+       * gmain.[ch]: Switch GMainLoop to be ref/unref, use to
+       make dropping reference to running loop safe.
+
 Wed Dec 13 20:41:49 2000  Owen Taylor  <otaylor@redhat.com>
 
        * gmain.c (g_source_unref_internal): Unref callback->cb_data
        if it was still set when the source is freed. (Usually, this
        will be done by g_source_destroy.)
 
-2001-01-02  Dan Winship  <danw@helixcode.com>
+ 2001-01-02  Dan Winship  <danw@helixcode.com>
 
        * garray.h (g_array_append_val, g_array_prepend_val,
        g_array_insert_val): Use parentheses around an argument to make
index 32fd7d2be19ac15980b4d9c49bce42cfd853bac9..a8fbd00008b2a97a74f89781658798923486c711 100644 (file)
@@ -1,10 +1,15 @@
+Wed Jan  3 14:10:49 2001  Owen Taylor  <otaylor@redhat.com>
+
+       * gmain.[ch]: Switch GMainLoop to be ref/unref, use to
+       make dropping reference to running loop safe.
+
 Wed Dec 13 20:41:49 2000  Owen Taylor  <otaylor@redhat.com>
 
        * gmain.c (g_source_unref_internal): Unref callback->cb_data
        if it was still set when the source is freed. (Usually, this
        will be done by g_source_destroy.)
 
-2001-01-02  Dan Winship  <danw@helixcode.com>
+ 2001-01-02  Dan Winship  <danw@helixcode.com>
 
        * garray.h (g_array_append_val, g_array_prepend_val,
        g_array_insert_val): Use parentheses around an argument to make
index 32fd7d2be19ac15980b4d9c49bce42cfd853bac9..a8fbd00008b2a97a74f89781658798923486c711 100644 (file)
@@ -1,10 +1,15 @@
+Wed Jan  3 14:10:49 2001  Owen Taylor  <otaylor@redhat.com>
+
+       * gmain.[ch]: Switch GMainLoop to be ref/unref, use to
+       make dropping reference to running loop safe.
+
 Wed Dec 13 20:41:49 2000  Owen Taylor  <otaylor@redhat.com>
 
        * gmain.c (g_source_unref_internal): Unref callback->cb_data
        if it was still set when the source is freed. (Usually, this
        will be done by g_source_destroy.)
 
-2001-01-02  Dan Winship  <danw@helixcode.com>
+ 2001-01-02  Dan Winship  <danw@helixcode.com>
 
        * garray.h (g_array_append_val, g_array_prepend_val,
        g_array_insert_val): Use parentheses around an argument to make
index 32fd7d2be19ac15980b4d9c49bce42cfd853bac9..a8fbd00008b2a97a74f89781658798923486c711 100644 (file)
@@ -1,10 +1,15 @@
+Wed Jan  3 14:10:49 2001  Owen Taylor  <otaylor@redhat.com>
+
+       * gmain.[ch]: Switch GMainLoop to be ref/unref, use to
+       make dropping reference to running loop safe.
+
 Wed Dec 13 20:41:49 2000  Owen Taylor  <otaylor@redhat.com>
 
        * gmain.c (g_source_unref_internal): Unref callback->cb_data
        if it was still set when the source is freed. (Usually, this
        will be done by g_source_destroy.)
 
-2001-01-02  Dan Winship  <danw@helixcode.com>
+ 2001-01-02  Dan Winship  <danw@helixcode.com>
 
        * garray.h (g_array_append_val, g_array_prepend_val,
        g_array_insert_val): Use parentheses around an argument to make
index 32fd7d2be19ac15980b4d9c49bce42cfd853bac9..a8fbd00008b2a97a74f89781658798923486c711 100644 (file)
@@ -1,10 +1,15 @@
+Wed Jan  3 14:10:49 2001  Owen Taylor  <otaylor@redhat.com>
+
+       * gmain.[ch]: Switch GMainLoop to be ref/unref, use to
+       make dropping reference to running loop safe.
+
 Wed Dec 13 20:41:49 2000  Owen Taylor  <otaylor@redhat.com>
 
        * gmain.c (g_source_unref_internal): Unref callback->cb_data
        if it was still set when the source is freed. (Usually, this
        will be done by g_source_destroy.)
 
-2001-01-02  Dan Winship  <danw@helixcode.com>
+ 2001-01-02  Dan Winship  <danw@helixcode.com>
 
        * garray.h (g_array_append_val, g_array_prepend_val,
        g_array_insert_val): Use parentheses around an argument to make
index 32fd7d2be19ac15980b4d9c49bce42cfd853bac9..a8fbd00008b2a97a74f89781658798923486c711 100644 (file)
@@ -1,10 +1,15 @@
+Wed Jan  3 14:10:49 2001  Owen Taylor  <otaylor@redhat.com>
+
+       * gmain.[ch]: Switch GMainLoop to be ref/unref, use to
+       make dropping reference to running loop safe.
+
 Wed Dec 13 20:41:49 2000  Owen Taylor  <otaylor@redhat.com>
 
        * gmain.c (g_source_unref_internal): Unref callback->cb_data
        if it was still set when the source is freed. (Usually, this
        will be done by g_source_destroy.)
 
-2001-01-02  Dan Winship  <danw@helixcode.com>
+ 2001-01-02  Dan Winship  <danw@helixcode.com>
 
        * garray.h (g_array_append_val, g_array_prepend_val,
        g_array_insert_val): Use parentheses around an argument to make
index 61957e213d43b08052001b49aad1937d10ce72e0..29af3b0e7e991e83f508d9f7c8231814a2899803 100644 (file)
@@ -131,6 +131,7 @@ struct _GMainLoop
 {
   GMainContext *context;
   gboolean is_running;
+  guint ref_count;
 
 #ifdef G_THREADS_ENABLED
   GMutex *mutex;
@@ -2012,7 +2013,8 @@ 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 ();
@@ -2024,6 +2026,66 @@ g_main_loop_new (GMainContext *context,
   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
@@ -2038,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"
@@ -2059,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 */    
@@ -2076,6 +2141,7 @@ g_main_loop_run (GMainLoop *loop)
       
       LOCK_LOOP (loop);
 
+      loop->ref_count++;
       loop->is_running = TRUE;
       while (loop->is_running)
        {
@@ -2083,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);
 }
 
 /**
@@ -2115,28 +2192,6 @@ g_main_loop_quit (GMainLoop *loop)
   UNLOCK_CONTEXT (loop->context);
 }
 
-/**
- * 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.
index dd500c6e83c6b7863dadf8eab8a1d4d1f50e72a3..193876f2f32671c3f10242c0ba235c6ccd111184 100644 (file)
@@ -174,7 +174,8 @@ GMainLoop *g_main_loop_new        (GMainContext *context,
                                   gboolean      is_running);
 void       g_main_loop_run        (GMainLoop    *loop);
 void       g_main_loop_quit       (GMainLoop    *loop);
-void       g_main_loop_destroy    (GMainLoop    *loop);
+GMainLoop *g_main_loop_ref        (GMainLoop    *loop);
+void       g_main_loop_unref      (GMainLoop    *loop);
 gboolean   g_main_loop_is_running (GMainLoop    *loop);
 
 /* GSource: */
@@ -237,7 +238,7 @@ void g_get_current_time                     (GTimeVal       *result);
 #define        g_main_new(is_running)  g_main_loop_new (NULL, is_running);
 #define         g_main_run(loop)        g_main_loop_run(loop)
 #define         g_main_quit(loop)       g_main_loop_quit(loop)
-#define         g_main_destroy(loop)    g_main_loop_destroy(loop)
+#define         g_main_destroy(loop)    g_main_loop_unref(loop)
 #define         g_main_is_running(loop) g_main_loop_is_running(loop)
 
 /* Source manipulation by ID */
diff --git a/gmain.c b/gmain.c
index 61957e213d43b08052001b49aad1937d10ce72e0..29af3b0e7e991e83f508d9f7c8231814a2899803 100644 (file)
--- a/gmain.c
+++ b/gmain.c
@@ -131,6 +131,7 @@ struct _GMainLoop
 {
   GMainContext *context;
   gboolean is_running;
+  guint ref_count;
 
 #ifdef G_THREADS_ENABLED
   GMutex *mutex;
@@ -2012,7 +2013,8 @@ 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 ();
@@ -2024,6 +2026,66 @@ g_main_loop_new (GMainContext *context,
   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
@@ -2038,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"
@@ -2059,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 */    
@@ -2076,6 +2141,7 @@ g_main_loop_run (GMainLoop *loop)
       
       LOCK_LOOP (loop);
 
+      loop->ref_count++;
       loop->is_running = TRUE;
       while (loop->is_running)
        {
@@ -2083,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);
 }
 
 /**
@@ -2115,28 +2192,6 @@ g_main_loop_quit (GMainLoop *loop)
   UNLOCK_CONTEXT (loop->context);
 }
 
-/**
- * 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.
diff --git a/gmain.h b/gmain.h
index dd500c6e83c6b7863dadf8eab8a1d4d1f50e72a3..193876f2f32671c3f10242c0ba235c6ccd111184 100644 (file)
--- a/gmain.h
+++ b/gmain.h
@@ -174,7 +174,8 @@ GMainLoop *g_main_loop_new        (GMainContext *context,
                                   gboolean      is_running);
 void       g_main_loop_run        (GMainLoop    *loop);
 void       g_main_loop_quit       (GMainLoop    *loop);
-void       g_main_loop_destroy    (GMainLoop    *loop);
+GMainLoop *g_main_loop_ref        (GMainLoop    *loop);
+void       g_main_loop_unref      (GMainLoop    *loop);
 gboolean   g_main_loop_is_running (GMainLoop    *loop);
 
 /* GSource: */
@@ -237,7 +238,7 @@ void g_get_current_time                     (GTimeVal       *result);
 #define        g_main_new(is_running)  g_main_loop_new (NULL, is_running);
 #define         g_main_run(loop)        g_main_loop_run(loop)
 #define         g_main_quit(loop)       g_main_loop_quit(loop)
-#define         g_main_destroy(loop)    g_main_loop_destroy(loop)
+#define         g_main_destroy(loop)    g_main_loop_unref(loop)
 #define         g_main_is_running(loop) g_main_loop_is_running(loop)
 
 /* Source manipulation by ID */