atomic reference counting for gmain.c



Hi,

the attached patch uses the new g_atomic_int_(inc|dec_and_test)
functions for atomic reference counting in gmain.c

GMainLoop and GMainContext are ported over. GSource can't be ported,
beacuse it uses guint for the reference count (like GMainLoop and
GMainContext) and is defined in a header file (unlike GMainLoop and
GMainContext) and we can't change structures in headers (that would give
us unstable ABI).

En passant I also fixed #134877.

OK to check-in?

Bye,
Sebastian
-- 
Sebastian Wilhelmi                 |            här ovanför alla molnen
mailto:seppi seppi de              |     är himmlen så förunderligt blå
http://seppi.de                    |
Index: glib/gmain.c
===================================================================
RCS file: /cvs/gnome/glib/glib/gmain.c,v
retrieving revision 1.105
diff -u -r1.105 gmain.c
--- glib/gmain.c	25 Feb 2004 23:48:21 -0000	1.105
+++ glib/gmain.c	27 Feb 2004 16:35:07 -0000
@@ -103,7 +103,7 @@
   GSList *waiters;
 #endif  
 
-  guint ref_count;
+  gint32 ref_count;
 
   GPtrArray *pending_dispatches;
   gint timeout;			/* Timeout for current iteration */
@@ -153,7 +153,7 @@
 {
   GMainContext *context;
   gboolean is_running;
-  guint ref_count;
+  gint32 ref_count;
 };
 
 struct _GTimeoutSource
@@ -589,11 +589,7 @@
   g_return_if_fail (context != NULL);
   g_return_if_fail (context->ref_count > 0); 
 
-  LOCK_CONTEXT (context);
-  
-  context->ref_count++;
-
-  UNLOCK_CONTEXT (context);
+  g_atomic_int_inc (&context->ref_count);
 }
 
 /* If DISABLE_MEM_POOLS is defined, then freeing the
@@ -616,18 +612,22 @@
 }
 #endif /* DISABLE_MEM_POOLS */
 
-static void
-g_main_context_unref_and_unlock (GMainContext *context)
+/**
+ * g_main_context_unref:
+ * @context: a #GMainContext
+ * 
+ * Decreases the reference count on a #GMainContext object by one. If
+ * the result is zero, free the context and free all associated memory.
+ **/
+void
+g_main_context_unref (GMainContext *context)
 {
   GSource *source;
+  g_return_if_fail (context != NULL);
+  g_return_if_fail (context->ref_count > 0); 
 
-  context->ref_count--;
-
-  if (context->ref_count != 0)
-    {
-      UNLOCK_CONTEXT (context);
-      return;
-    }
+  if (!g_atomic_int_dec_and_test (&context->ref_count))
+    return;
 
   G_LOCK (main_context_list);
   main_context_list = g_slist_remove (main_context_list, context);
@@ -640,7 +640,6 @@
       g_source_destroy_internal (source, context, TRUE);
       source = next;
     }
-  UNLOCK_CONTEXT (context);
 
 #ifdef G_THREADS_ENABLED  
   g_static_mutex_free (&context->mutex);
@@ -675,23 +674,6 @@
   g_free (context);
 }
 
-/**
- * g_main_context_unref:
- * @context: a #GMainContext
- * 
- * Decreases the reference count on a #GMainContext object by one. If
- * the result is zero, free the context and free all associated memory.
- **/
-void
-g_main_context_unref (GMainContext *context)
-{
-  g_return_if_fail (context != NULL);
-  g_return_if_fail (context->ref_count > 0); 
-
-  LOCK_CONTEXT (context);
-  g_main_context_unref_and_unlock (context);
-}
-
 #ifdef G_THREADS_ENABLED
 static void 
 g_main_context_init_pipe (GMainContext *context)
@@ -2494,29 +2476,11 @@
   g_return_val_if_fail (loop != NULL, NULL);
   g_return_val_if_fail (loop->ref_count > 0, NULL);
 
-  LOCK_CONTEXT (loop->context);
-  loop->ref_count++;
-  UNLOCK_CONTEXT (loop->context);
+  g_atomic_int_inc (&loop->ref_count);
 
   return loop;
 }
 
-static void
-g_main_loop_unref_and_unlock (GMainLoop *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.
-       */
-      g_main_context_unref_and_unlock (loop->context);
-  g_free (loop);
-    }
-  else
-    UNLOCK_CONTEXT (loop->context);
-}
-
 /**
  * g_main_loop_unref:
  * @loop: a #GMainLoop
@@ -2530,9 +2494,11 @@
   g_return_if_fail (loop != NULL);
   g_return_if_fail (loop->ref_count > 0);
 
-  LOCK_CONTEXT (loop->context);
-  
-  g_main_loop_unref_and_unlock (loop);
+  if (!g_atomic_int_dec_and_test (&loop->ref_count))
+    return;
+
+  g_main_context_unref (loop->context);
+  g_free (loop);
 }
 
 /**
@@ -2567,7 +2533,7 @@
       
       LOCK_CONTEXT (loop->context);
 
-      loop->ref_count++;
+      g_atomic_int_inc (&loop->ref_count);
 
       if (!loop->is_running)
 	loop->is_running = TRUE;
@@ -2602,7 +2568,7 @@
       return;
     }
 
-  loop->ref_count++;
+  g_atomic_int_inc (&loop->ref_count);
   loop->is_running = TRUE;
   while (loop->is_running)
     g_main_context_iterate (loop->context, TRUE, TRUE, self);
@@ -3392,15 +3358,20 @@
 #endif
 
       /* We were woken up.  Wake up all other contexts in all other threads */
-      G_UNLOCK (main_context_list);
+      G_LOCK (main_context_list);
       for (list = main_context_list; list; list = list->next)
 	{
 	  GMainContext *context;
 
 	  context = list->data;
-	  g_main_context_wakeup (context);
+	  if (context->ref_count > 0)
+	    /* Due to racing conditions we can find ref_count == 0, in
+	     * that case, however, the context is still not destroyed
+	     * and no poll can be active, otherwise the ref_count
+	     * wouldn't be 0 */
+	    g_main_context_wakeup (context);
 	}
-      G_LOCK (main_context_list);
+      G_UNLOCK (main_context_list);
     }
   return NULL;
 }


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]