dbus-marshal-validate: Check brackets in signature nest correctly
[platform/upstream/dbus.git] / dbus / dbus-resources.c
index 7c7aabd..0617eae 100644 (file)
@@ -20,6 +20,8 @@
  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
  *
  */
+
+#include <config.h>
 #include <dbus/dbus-resources.h>
 #include <dbus/dbus-internals.h>
 
@@ -56,11 +58,18 @@ struct DBusCounter
   long size_value;       /**< current size counter value */
   long unix_fd_value;    /**< current unix fd counter value */
 
+#ifdef DBUS_ENABLE_STATS
+  long peak_size_value;     /**< largest ever size counter value */
+  long peak_unix_fd_value;  /**< largest ever unix fd counter value */
+#endif
+
   long notify_size_guard_value;    /**< call notify function when crossing this size value */
   long notify_unix_fd_guard_value; /**< call notify function when crossing this unix fd value */
 
   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 */
@@ -81,19 +90,19 @@ _dbus_counter_new (void)
 {
   DBusCounter *counter;
 
-  counter = dbus_new (DBusCounter, 1);
+  counter = dbus_new0 (DBusCounter, 1);
   if (counter == NULL)
     return NULL;
-  
+
   counter->refcount = 1;
-  counter->size_value = 0;
-  counter->unix_fd_value = 0;
 
-  counter->notify_size_guard_value = 0;
-  counter->notify_unix_fd_guard_value = 0;
-  counter->notify_function = NULL;
-  counter->notify_data = NULL;
-  
+  _dbus_rmutex_new_at_location (&counter->mutex);
+  if (counter->mutex == NULL)
+  {
+    dbus_free (counter);
+    counter = NULL;
+  }
+
   return counter;
 }
 
@@ -106,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;
 }
 
@@ -122,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);
 
-  if (counter->refcount == 0)
+  _dbus_rmutex_unlock (counter->mutex);
+
+  if (last_ref)
     {
-      
+      _dbus_rmutex_free_at_location (&counter->mutex);
       dbus_free (counter);
     }
 }
@@ -136,8 +156,9 @@ _dbus_counter_unref (DBusCounter *counter)
 /**
  * Adjusts the value of the size counter by the given
  * delta which may be positive or negative.
- * Calls the notify function from _dbus_counter_set_notify()
- * if that function has been specified.
+ *
+ * This function may be called with locks held. After calling it, when
+ * any relevant locks are no longer held you must call _dbus_counter_notify().
  *
  * @param counter the counter
  * @param delta value to add to the size counter's current value
@@ -146,10 +167,19 @@ 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;
 
+#ifdef DBUS_ENABLE_STATS
+  if (counter->peak_size_value < counter->size_value)
+    counter->peak_size_value = counter->size_value;
+#endif
+
 #if 0
   _dbus_verbose ("Adjusting counter %ld by %ld = %ld\n",
                  old, delta, counter->size_value);
@@ -160,14 +190,44 @@ _dbus_counter_adjust_size (DBusCounter *counter,
         counter->size_value >= counter->notify_size_guard_value) ||
        (old >= counter->notify_size_guard_value &&
         counter->size_value < counter->notify_size_guard_value)))
-    (* counter->notify_function) (counter, counter->notify_data);
+    counter->notify_pending = TRUE;
+
+  _dbus_rmutex_unlock (counter->mutex);
+}
+
+/**
+ * Calls the notify function from _dbus_counter_set_notify(),
+ * if that function has been specified and the counter has crossed the
+ * guard value (in either direction) since the last call to this function.
+ *
+ * This function must not be called with locks held, since it can call out
+ * to user code.
+ */
+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;
+      notify_function = counter->notify_function;
+      notify_data = counter->notify_data;
+    }
+  _dbus_rmutex_unlock (counter->mutex);
+
+  if (notify_function != NULL)
+    (* notify_function) (counter, notify_data);
 }
 
 /**
  * Adjusts the value of the unix fd counter by the given
  * delta which may be positive or negative.
- * Calls the notify function from _dbus_counter_set_notify()
- * if that function has been specified.
+ *
+ * This function may be called with locks held. After calling it, when
+ * any relevant locks are no longer held you must call _dbus_counter_notify().
  *
  * @param counter the counter
  * @param delta value to add to the unix fds counter's current value
@@ -176,10 +236,19 @@ 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;
 
+#ifdef DBUS_ENABLE_STATS
+  if (counter->peak_unix_fd_value < counter->unix_fd_value)
+    counter->peak_unix_fd_value = counter->unix_fd_value;
+#endif
+
 #if 0
   _dbus_verbose ("Adjusting counter %ld by %ld = %ld\n",
                  old, delta, counter->unix_fd_value);
@@ -190,7 +259,9 @@ _dbus_counter_adjust_unix_fd (DBusCounter *counter,
         counter->unix_fd_value >= counter->notify_unix_fd_guard_value) ||
        (old >= counter->notify_unix_fd_guard_value &&
         counter->unix_fd_value < counter->notify_unix_fd_guard_value)))
-    (* counter->notify_function) (counter, counter->notify_data);
+    counter->notify_pending = TRUE;
+
+  _dbus_rmutex_unlock (counter->mutex);
 }
 
 /**
@@ -235,10 +306,27 @@ _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
+long
+_dbus_counter_get_peak_size_value (DBusCounter *counter)
+{
+  return counter->peak_size_value;
 }
 
+long
+_dbus_counter_get_peak_unix_fd_value (DBusCounter *counter)
+{
+  return counter->peak_unix_fd_value;
+}
+#endif
+
 /** @} */  /* end of resource limits exported API */