Re: thread-safety of counters

Adrian Szyndela <[email protected]>
Newsgroups gmane.comp.freedesktop.dbus
Message-ID <[email protected]>
W dniu 25.02.2015 o 09:54, Adrian Szyndela pisze:
> I just need a few answers, and I'll prepare a patch:
> an existing mutex or a new one? If an existing, then which one? If a new
> one, then to what objects should it be added? Counters? Messages?

I'll try to answer myself.

We can't use existing mutexes from DBusConnection, because there might
be already no connection object while freeing a message.

Using one of global locks seems to make no sense for local objects.

I found only one more mutex, in DBusServer, but that is not relevant.

So, to use a mutex, we need to introduce a new one. As it is needed only
for DBusCounter objects locally, it seems natural to introduce such
mutex in there.

I attach a patch that does exactly this.

> some rationale for "mutex vs. atomic"?

For future reference: an example. In _dbus_counter_notify()
notify_function is called depending on notify_pending field value. On
the other hand _dbus_counter_set_notify() can be called from
_dbus_transport_finalize_base() at the same time, interfering with
_dbus_counter_notify(). This one would be hard to fix with atomics.

_______________________________________________
dbus mailing list
[email protected]
http://lists.freedesktop.org/mailman/listinfo/dbus
mutex-counters.patch (text/x-patch, 3.8 KB)
diff --git a/dbus/dbus-resources.c b/dbus/dbus-resources.c
index 80fb55b..f76fd9f 100644
--- a/dbus/dbus-resources.c
+++ b/dbus/dbus-resources.c
@@ -69,6 +69,7 @@ struct DBusCounter
   DBusCounterNotifyFunction notify_function; /**< notify function */
   void *notify_data; /**< data for notify function */
   dbus_bool_t notify_pending : 1; /**< TRUE if the guard value has been crossed */
+  DBusRMutex *mutex;    /**< Lock on the entire DBusCounter */
 };
 
 /** @} */  /* end of resource limits internals docs */
@@ -95,6 +96,13 @@ _dbus_counter_new (void)
 
   counter->refcount = 1;
 
+  _dbus_rmutex_new_at_location (&counter->mutex);
+  if (counter->mutex == NULL)
+  {
+    dbus_free (counter);
+	counter = NULL;
+  }
+
   return counter;
 }
 
@@ -107,10 +115,14 @@ _dbus_counter_new (void)
 DBusCounter *
 _dbus_counter_ref (DBusCounter *counter)
 {
+  _dbus_rmutex_lock (counter->mutex);
+
   _dbus_assert (counter->refcount > 0);
   
   counter->refcount += 1;
 
+  _dbus_rmutex_unlock (counter->mutex);
+
   return counter;
 }
 
@@ -123,13 +135,20 @@ _dbus_counter_ref (DBusCounter *counter)
 void
 _dbus_counter_unref (DBusCounter *counter)
 {
+  dbus_bool_t last_ref = FALSE;
+
+  _dbus_rmutex_lock (counter->mutex);
+
   _dbus_assert (counter->refcount > 0);
 
   counter->refcount -= 1;
+  last_ref = counter->refcount == 0;
+
+  _dbus_rmutex_unlock (counter->mutex);
 
-  if (counter->refcount == 0)
+  if (last_ref)
     {
-      
+      _dbus_rmutex_free_at_location (&counter->mutex);
       dbus_free (counter);
     }
 }
@@ -148,7 +167,11 @@ void
 _dbus_counter_adjust_size (DBusCounter *counter,
                            long         delta)
 {
-  long old = counter->size_value;
+  long old = 0;
+
+  _dbus_rmutex_lock (counter->mutex);
+  
+  old = counter->size_value;
 
   counter->size_value += delta;
 
@@ -168,6 +191,8 @@ _dbus_counter_adjust_size (DBusCounter *counter,
        (old >= counter->notify_size_guard_value &&
         counter->size_value < counter->notify_size_guard_value)))
     counter->notify_pending = TRUE;
+
+  _dbus_rmutex_unlock (counter->mutex);
 }
 
 /**
@@ -181,11 +206,20 @@ _dbus_counter_adjust_size (DBusCounter *counter,
 void
 _dbus_counter_notify (DBusCounter *counter)
 {
+  DBusCounterNotifyFunction notify_function = NULL;
+  void *notify_data = NULL;
+
+  _dbus_rmutex_lock (counter->mutex);
   if (counter->notify_pending)
     {
       counter->notify_pending = FALSE;
-      (* counter->notify_function) (counter, counter->notify_data);
+	  notify_function = counter->notify_function;
+	  notify_data = counter->notify_data;
     }
+  _dbus_rmutex_unlock (counter->mutex);
+
+  if (notify_function != NULL)
+    (* notify_function) (counter, notify_data);
 }
 
 /**
@@ -202,7 +236,11 @@ void
 _dbus_counter_adjust_unix_fd (DBusCounter *counter,
                               long         delta)
 {
-  long old = counter->unix_fd_value;
+  long old = 0;
+
+  _dbus_rmutex_lock (counter->mutex);
+
+  old = counter->unix_fd_value;
   
   counter->unix_fd_value += delta;
 
@@ -222,6 +260,8 @@ _dbus_counter_adjust_unix_fd (DBusCounter *counter,
        (old >= counter->notify_unix_fd_guard_value &&
         counter->unix_fd_value < counter->notify_unix_fd_guard_value)))
     counter->notify_pending = TRUE;
+
+  _dbus_rmutex_unlock (counter->mutex);
 }
 
 /**
@@ -266,11 +306,13 @@ _dbus_counter_set_notify (DBusCounter               *counter,
                           DBusCounterNotifyFunction  function,
                           void                      *user_data)
 {
+  _dbus_rmutex_lock (counter->mutex);
   counter->notify_size_guard_value = size_guard_value;
   counter->notify_unix_fd_guard_value = unix_fd_guard_value;
   counter->notify_function = function;
   counter->notify_data = user_data;
   counter->notify_pending = FALSE;
+  _dbus_rmutex_unlock (counter->mutex);
 }
 
 #ifdef DBUS_ENABLE_STATS
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.