2003-05-11 Havoc Pennington <hp@pobox.com>
authorHavoc Pennington <hp@redhat.com>
Mon, 12 May 2003 02:44:45 +0000 (02:44 +0000)
committerHavoc Pennington <hp@redhat.com>
Mon, 12 May 2003 02:44:45 +0000 (02:44 +0000)
* dbus/dbus-marshal.c (_dbus_marshal_validate_arg): fix to avoid
calling _dbus_marshal_validate_arg() for every byte in a byte
array, etc.

* dbus/dbus-message-handler.c: use atomic reference counting to
reduce number of locks slightly; the global lock in here sucks

* dbus/dbus-connection.c
(_dbus_connection_update_dispatch_status_and_unlock): variant of
update_dispatch_status that can be called with lock held; then use
in a couple places to reduce locking/unlocking
(dbus_connection_send): hold the lock over the whole function
instead of acquiring it twice.

* dbus/dbus-timeout.c (_dbus_timeout_new): handle OOM

* bus/connection.c (bus_connections_setup_connection): fix access
to already-freed memory.

* dbus/dbus-connection.c: keep a little cache of linked list
nodes, to avoid using the global linked list alloc lock in the
normal send-message case. Instead we just use the connection lock
that we already have to take.

* dbus/dbus-list.c (_dbus_list_find_last): new function

* dbus/dbus-sysdeps.c (_dbus_atomic_inc, _dbus_atomic_dec):
change to use a struct for the atomic type; fix docs,
they return value before increment, not after increment.

* dbus/dbus-string.c (_dbus_string_append_4_aligned)
(_dbus_string_append_8_aligned): new functions to try to
microoptimize this operation.
(reallocate_for_length): break this out of set_length(), to
improve profile info, and also so we can consider inlining the
set_length() part.

* dbus/dbus-message.c (dbus_message_new_empty_header): init data
strings with some preallocation, cuts down on our calls to realloc
a fair bit. Though if we can get the "move entire string to empty
string" optimization below to kick in here, it would be better.

* dbus/dbus-string.c (_dbus_string_move): just call
_dbus_string_move_len
(_dbus_string_move_len): add a special case for moving
an entire string into an empty string; we can just
swap the string data instead of doing any reallocs.
(_dbus_string_init_preallocated): new function

15 files changed:
ChangeLog
bus/connection.c
dbus/dbus-connection.c
dbus/dbus-list.c
dbus/dbus-list.h
dbus/dbus-marshal.c
dbus/dbus-message-handler.c
dbus/dbus-message-internal.h
dbus/dbus-message.c
dbus/dbus-string.c
dbus/dbus-string.h
dbus/dbus-sysdeps.c
dbus/dbus-sysdeps.h
dbus/dbus-timeout.c
glib/test-profile.c

index cb74a1e..292693c 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,56 @@
 2003-05-11  Havoc Pennington  <hp@pobox.com>
 
+       * dbus/dbus-marshal.c (_dbus_marshal_validate_arg): fix to avoid 
+       calling _dbus_marshal_validate_arg() for every byte in a byte
+       array, etc.
+
+       * dbus/dbus-message-handler.c: use atomic reference counting to 
+       reduce number of locks slightly; the global lock in here sucks
+
+       * dbus/dbus-connection.c
+       (_dbus_connection_update_dispatch_status_and_unlock): variant of
+       update_dispatch_status that can be called with lock held; then use
+       in a couple places to reduce locking/unlocking
+       (dbus_connection_send): hold the lock over the whole function 
+       instead of acquiring it twice.
+
+       * dbus/dbus-timeout.c (_dbus_timeout_new): handle OOM
+
+       * bus/connection.c (bus_connections_setup_connection): fix access
+       to already-freed memory.
+
+       * dbus/dbus-connection.c: keep a little cache of linked list
+       nodes, to avoid using the global linked list alloc lock in the
+       normal send-message case. Instead we just use the connection lock
+       that we already have to take.
+
+       * dbus/dbus-list.c (_dbus_list_find_last): new function
+
+       * dbus/dbus-sysdeps.c (_dbus_atomic_inc, _dbus_atomic_dec):
+       change to use a struct for the atomic type; fix docs, 
+       they return value before increment, not after increment.
+
+       * dbus/dbus-string.c (_dbus_string_append_4_aligned)
+       (_dbus_string_append_8_aligned): new functions to try to
+       microoptimize this operation.
+       (reallocate_for_length): break this out of set_length(), to
+       improve profile info, and also so we can consider inlining the
+       set_length() part.
+
+       * dbus/dbus-message.c (dbus_message_new_empty_header): init data
+       strings with some preallocation, cuts down on our calls to realloc
+       a fair bit. Though if we can get the "move entire string to empty
+       string" optimization below to kick in here, it would be better.
+
+       * dbus/dbus-string.c (_dbus_string_move): just call
+       _dbus_string_move_len
+       (_dbus_string_move_len): add a special case for moving 
+       an entire string into an empty string; we can just 
+       swap the string data instead of doing any reallocs.
+       (_dbus_string_init_preallocated): new function
+
+2003-05-11  Havoc Pennington  <hp@pobox.com>
+
        Write a "test-profile" that does echo client-server with threads;
        profile reveals lock contention, memcpy/realloc of buffers, and
        UTF-8 validation as hot spots. 20% of lock contention eliminated
index 05532db..70a0eb1 100644 (file)
@@ -533,7 +533,7 @@ bus_connections_setup_connection (BusConnections *connections,
 
   d->connections = connections;
   d->connection = connection;
-
+  
   _dbus_get_current_time (&d->connection_tv_sec,
                           &d->connection_tv_usec);
   
@@ -643,18 +643,21 @@ bus_connections_setup_connection (BusConnections *connections,
 
       dbus_connection_set_dispatch_status_function (connection,
                                                     NULL, NULL, NULL);
-      
-      if (!dbus_connection_set_data (connection,
-                                     connection_data_slot,
-                                     NULL, NULL))
-        _dbus_assert_not_reached ("failed to set connection data to null");
 
       if (d->link_in_connection_list != NULL)
         {
           _dbus_assert (d->link_in_connection_list->next == NULL);
           _dbus_assert (d->link_in_connection_list->prev == NULL);
           _dbus_list_free_link (d->link_in_connection_list);
+          d->link_in_connection_list = NULL;
         }
+      
+      if (!dbus_connection_set_data (connection,
+                                     connection_data_slot,
+                                     NULL, NULL))
+        _dbus_assert_not_reached ("failed to set connection data to null");
+
+      /* "d" has now been freed */
     }
   
   return retval;
index 6309ea4..9da5fb5 100644 (file)
@@ -132,7 +132,7 @@ static dbus_bool_t _dbus_modify_sigpipe = TRUE;
  */
 struct DBusConnection
 {
-  dbus_atomic_t refcount; /**< Reference count. */
+  DBusAtomic refcount; /**< Reference count. */
 
   DBusMutex *mutex; /**< Lock on the entire DBusConnection */
 
@@ -176,6 +176,10 @@ struct DBusConnection
   DBusFreeFunction free_dispatch_status_data; /**< free dispatch_status_data */
 
   DBusDispatchStatus last_dispatch_status; /**< The last dispatch status we reported to the application. */
+
+  DBusList *link_cache; /**< A cache of linked list links to prevent contention
+                         *   for the global linked list mempool lock
+                         */
 };
 
 typedef struct
@@ -193,11 +197,12 @@ typedef struct
 
 static void reply_handler_data_free (ReplyHandlerData *data);
 
-static void               _dbus_connection_remove_timeout_locked         (DBusConnection     *connection,
-                                                                          DBusTimeout        *timeout);
-static DBusDispatchStatus _dbus_connection_get_dispatch_status_unlocked  (DBusConnection     *connection);
-static void               _dbus_connection_update_dispatch_status_locked (DBusConnection     *connection,
-                                                                          DBusDispatchStatus  new_status);
+static void               _dbus_connection_remove_timeout_locked             (DBusConnection     *connection,
+                                                                              DBusTimeout        *timeout);
+static DBusDispatchStatus _dbus_connection_get_dispatch_status_unlocked      (DBusConnection     *connection);
+static void               _dbus_connection_update_dispatch_status_and_unlock (DBusConnection     *connection,
+                                                                              DBusDispatchStatus  new_status);
+
 
 
 /**
@@ -365,6 +370,7 @@ _dbus_connection_get_message_to_send (DBusConnection *connection)
 /**
  * Notifies the connection that a message has been sent, so the
  * message can be removed from the outgoing queue.
+ * Called with the connection lock held.
  *
  * @param connection the connection.
  * @param message the message that was sent.
@@ -373,10 +379,18 @@ void
 _dbus_connection_message_sent (DBusConnection *connection,
                                DBusMessage    *message)
 {
+  DBusList *link;
+  
   _dbus_assert (_dbus_transport_get_is_authenticated (connection->transport));
-  _dbus_assert (message == _dbus_list_get_last (&connection->outgoing_messages));
   
-  _dbus_list_pop_last (&connection->outgoing_messages);
+  link = _dbus_list_get_last_link (&connection->outgoing_messages);
+  _dbus_assert (link != NULL);
+  _dbus_assert (link->data == message);
+
+  /* Save this link in the link cache */
+  _dbus_list_unlink (&connection->outgoing_messages,
+                     link);
+  _dbus_list_prepend_link (&connection->link_cache, link);
   
   connection->n_outgoing -= 1;
 
@@ -384,7 +398,10 @@ _dbus_connection_message_sent (DBusConnection *connection,
                  message, dbus_message_get_name (message),
                  connection, connection->n_outgoing);
 
-  _dbus_message_remove_size_counter (message, connection->outgoing_counter);
+  /* Save this link in the link cache also */
+  _dbus_message_remove_size_counter (message, connection->outgoing_counter,
+                                     &link);
+  _dbus_list_prepend_link (&connection->link_cache, link);
   
   dbus_message_unref (message);
   
@@ -724,7 +741,7 @@ _dbus_connection_new_for_transport (DBusTransport *transport)
   if (_dbus_modify_sigpipe)
     _dbus_disable_sigpipe ();
   
-  connection->refcount = 1;
+  connection->refcount.value = 1;
   connection->mutex = mutex;
   connection->dispatch_cond = dispatch_cond;
   connection->io_path_cond = io_path_cond;
@@ -800,8 +817,12 @@ _dbus_connection_new_for_transport (DBusTransport *transport)
 void
 _dbus_connection_ref_unlocked (DBusConnection *connection)
 {
-  _dbus_assert (connection->refcount > 0);
-  connection->refcount += 1;
+#ifdef DBUS_HAVE_ATOMIC_INT
+  _dbus_atomic_inc (&connection->refcount);
+#else
+  _dbus_assert (connection->refcount.value > 0);
+  connection->refcount.value += 1;
+#endif
 }
 
 static dbus_uint32_t
@@ -892,10 +913,9 @@ _dbus_connection_handle_watch (DBusWatch                   *watch,
   _dbus_connection_release_io_path (connection);
 
   status = _dbus_connection_get_dispatch_status_unlocked (connection);
-  
-  CONNECTION_UNLOCK (connection);
 
-  _dbus_connection_update_dispatch_status_locked (connection, status);
+  /* this calls out to user code */
+  _dbus_connection_update_dispatch_status_and_unlock (connection, status);
   
   return retval;
 }
@@ -972,9 +992,9 @@ dbus_connection_ref (DBusConnection *connection)
   _dbus_atomic_inc (&connection->refcount);
 #else
   CONNECTION_LOCK (connection);
-  _dbus_assert (connection->refcount > 0);
+  _dbus_assert (connection->refcount.value > 0);
 
-  connection->refcount += 1;
+  connection->refcount.value += 1;
   CONNECTION_UNLOCK (connection);
 #endif
 }
@@ -987,7 +1007,8 @@ free_outgoing_message (void *element,
   DBusConnection *connection = data;
 
   _dbus_message_remove_size_counter (message,
-                                     connection->outgoing_counter);
+                                     connection->outgoing_counter,
+                                     NULL);
   dbus_message_unref (message);
 }
 
@@ -1003,7 +1024,7 @@ _dbus_connection_last_unref (DBusConnection *connection)
 
   _dbus_verbose ("Finalizing connection %p\n", connection);
   
-  _dbus_assert (connection->refcount == 0);
+  _dbus_assert (connection->refcount.value == 0);
   
   /* You have to disconnect the connection before unref:ing it. Otherwise
    * you won't get the disconnected message.
@@ -1071,10 +1092,12 @@ _dbus_connection_last_unref (DBusConnection *connection)
       dbus_message_unref (message);
       _dbus_list_free_link (connection->disconnect_message_link);
     }
+
+  _dbus_list_clear (&connection->link_cache);
   
   dbus_condvar_free (connection->dispatch_cond);
   dbus_condvar_free (connection->io_path_cond);
-  dbus_condvar_free (connection->message_returned_cond);
+  dbus_condvar_free (connection->message_returned_cond);  
   
   dbus_mutex_free (connection->mutex);
   
@@ -1104,17 +1127,17 @@ dbus_connection_unref (DBusConnection *connection)
    */
   
 #ifdef DBUS_HAVE_ATOMIC_INT
-  last_unref = (_dbus_atomic_dec (&connection->refcount) == 0);
+  last_unref = (_dbus_atomic_dec (&connection->refcount) == 1);
 #else
   CONNECTION_LOCK (connection);
   
-  _dbus_assert (connection->refcount > 0);
+  _dbus_assert (connection->refcount.value > 0);
 
-  connection->refcount -= 1;
-  last_unref = (connection->refcount == 0);
+  connection->refcount.value -= 1;
+  last_unref = (connection->refcount.value == 0);
 
 #if 0
-  printf ("unref() connection %p count = %d\n", connection, connection->refcount);
+  printf ("unref() connection %p count = %d\n", connection, connection->refcount.value);
 #endif
   
   CONNECTION_UNLOCK (connection);
@@ -1203,18 +1226,8 @@ struct DBusPreallocatedSend
   DBusList *counter_link;
 };
 
-
-/**
- * Preallocates resources needed to send a message, allowing the message 
- * to be sent without the possibility of memory allocation failure.
- * Allows apps to create a future guarantee that they can send
- * a message regardless of memory shortages.
- *
- * @param connection the connection we're preallocating for.
- * @returns the preallocated resources, or #NULL
- */
-DBusPreallocatedSend*
-dbus_connection_preallocate_send (DBusConnection *connection)
+static DBusPreallocatedSend*
+_dbus_connection_preallocate_send_unlocked (DBusConnection *connection)
 {
   DBusPreallocatedSend *preallocated;
 
@@ -1224,21 +1237,35 @@ dbus_connection_preallocate_send (DBusConnection *connection)
   if (preallocated == NULL)
     return NULL;
 
-  CONNECTION_LOCK (connection);
-  
-  preallocated->queue_link = _dbus_list_alloc_link (NULL);
-  if (preallocated->queue_link == NULL)
-    goto failed_0;
+  if (connection->link_cache != NULL)
+    {
+      preallocated->queue_link =
+        _dbus_list_pop_first_link (&connection->link_cache);
+      preallocated->queue_link->data = NULL;
+    }
+  else
+    {
+      preallocated->queue_link = _dbus_list_alloc_link (NULL);
+      if (preallocated->queue_link == NULL)
+        goto failed_0;
+    }
   
-  preallocated->counter_link = _dbus_list_alloc_link (connection->outgoing_counter);
-  if (preallocated->counter_link == NULL)
-    goto failed_1;
+  if (connection->link_cache != NULL)
+    {
+      preallocated->counter_link =
+        _dbus_list_pop_first_link (&connection->link_cache);
+      preallocated->counter_link->data = connection->outgoing_counter;
+    }
+  else
+    {
+      preallocated->counter_link = _dbus_list_alloc_link (connection->outgoing_counter);
+      if (preallocated->counter_link == NULL)
+        goto failed_1;
+    }
 
   _dbus_counter_ref (preallocated->counter_link->data);
 
   preallocated->connection = connection;
-
-  CONNECTION_UNLOCK (connection);
   
   return preallocated;
   
@@ -1246,13 +1273,37 @@ dbus_connection_preallocate_send (DBusConnection *connection)
   _dbus_list_free_link (preallocated->queue_link);
  failed_0:
   dbus_free (preallocated);
-
-  CONNECTION_UNLOCK (connection);
   
   return NULL;
 }
 
 /**
+ * Preallocates resources needed to send a message, allowing the message 
+ * to be sent without the possibility of memory allocation failure.
+ * Allows apps to create a future guarantee that they can send
+ * a message regardless of memory shortages.
+ *
+ * @param connection the connection we're preallocating for.
+ * @returns the preallocated resources, or #NULL
+ */
+DBusPreallocatedSend*
+dbus_connection_preallocate_send (DBusConnection *connection)
+{
+  DBusPreallocatedSend *preallocated;
+
+  _dbus_return_val_if_fail (connection != NULL, NULL);
+
+  CONNECTION_LOCK (connection);
+  
+  preallocated =
+    _dbus_connection_preallocate_send_unlocked (connection);
+
+  CONNECTION_UNLOCK (connection);
+
+  return preallocated;
+}
+
+/**
  * Frees preallocated message-sending resources from
  * dbus_connection_preallocate_send(). Should only
  * be called if the preallocated resources are not used
@@ -1266,43 +1317,23 @@ dbus_connection_free_preallocated_send (DBusConnection       *connection,
                                         DBusPreallocatedSend *preallocated)
 {
   _dbus_return_if_fail (connection != NULL);
-  _dbus_return_if_fail (preallocated != NULL);
+  _dbus_return_if_fail (preallocated != NULL);  
   _dbus_return_if_fail (connection == preallocated->connection);
-  
+
   _dbus_list_free_link (preallocated->queue_link);
   _dbus_counter_unref (preallocated->counter_link->data);
   _dbus_list_free_link (preallocated->counter_link);
   dbus_free (preallocated);
 }
 
-/**
- * Sends a message using preallocated resources. This function cannot fail.
- * It works identically to dbus_connection_send() in other respects.
- * Preallocated resources comes from dbus_connection_preallocate_send().
- * This function "consumes" the preallocated resources, they need not
- * be freed separately.
- *
- * @param connection the connection
- * @param preallocated the preallocated resources
- * @param message the message to send
- * @param client_serial return location for client serial assigned to the message
- */
-void
-dbus_connection_send_preallocated (DBusConnection       *connection,
-                                   DBusPreallocatedSend *preallocated,
-                                   DBusMessage          *message,
-                                   dbus_uint32_t        *client_serial)
+static void
+_dbus_connection_send_preallocated_unlocked (DBusConnection       *connection,
+                                             DBusPreallocatedSend *preallocated,
+                                             DBusMessage          *message,
+                                             dbus_uint32_t        *client_serial)
 {
   dbus_uint32_t serial;
 
-  _dbus_return_if_fail (connection != NULL);
-  _dbus_return_if_fail (preallocated != NULL);
-  _dbus_return_if_fail (message != NULL);
-  _dbus_return_if_fail (preallocated->connection == connection);
-  _dbus_return_if_fail (dbus_message_get_name (message) != NULL);
-  
-  CONNECTION_LOCK (connection);
-
   preallocated->queue_link->data = message;
   _dbus_list_prepend_link (&connection->outgoing_messages,
                            preallocated->queue_link);
@@ -1343,8 +1374,37 @@ dbus_connection_send_preallocated (DBusConnection       *connection,
                                      connection->n_outgoing);
   
   _dbus_connection_wakeup_mainloop (connection);
+}
 
-  CONNECTION_UNLOCK (connection);
+/**
+ * Sends a message using preallocated resources. This function cannot fail.
+ * It works identically to dbus_connection_send() in other respects.
+ * Preallocated resources comes from dbus_connection_preallocate_send().
+ * This function "consumes" the preallocated resources, they need not
+ * be freed separately.
+ *
+ * @param connection the connection
+ * @param preallocated the preallocated resources
+ * @param message the message to send
+ * @param client_serial return location for client serial assigned to the message
+ */
+void
+dbus_connection_send_preallocated (DBusConnection       *connection,
+                                   DBusPreallocatedSend *preallocated,
+                                   DBusMessage          *message,
+                                   dbus_uint32_t        *client_serial)
+{
+  _dbus_return_if_fail (connection != NULL);
+  _dbus_return_if_fail (preallocated != NULL);
+  _dbus_return_if_fail (message != NULL);
+  _dbus_return_if_fail (preallocated->connection == connection);
+  _dbus_return_if_fail (dbus_message_get_name (message) != NULL);
+  
+  CONNECTION_LOCK (connection);
+  _dbus_connection_send_preallocated_unlocked (connection,
+                                               preallocated,
+                                               message, client_serial);
+  CONNECTION_UNLOCK (connection);  
 }
 
 /**
@@ -1374,15 +1434,22 @@ dbus_connection_send (DBusConnection *connection,
 
   _dbus_return_val_if_fail (connection != NULL, FALSE);
   _dbus_return_val_if_fail (message != NULL, FALSE);
+
+  CONNECTION_LOCK (connection);
   
-  preallocated = dbus_connection_preallocate_send (connection);
+  preallocated = _dbus_connection_preallocate_send_unlocked (connection);
   if (preallocated == NULL)
     {
+      CONNECTION_UNLOCK (connection);
       return FALSE;
     }
   else
     {
-      dbus_connection_send_preallocated (connection, preallocated, message, client_serial);
+      _dbus_connection_send_preallocated_unlocked (connection,
+                                                   preallocated,
+                                                   message,
+                                                   client_serial);
+      CONNECTION_UNLOCK (connection);
       return TRUE;
     }
 }
@@ -1409,10 +1476,9 @@ reply_handler_timeout (void *data)
   reply_handler_data->timeout_added = FALSE;
 
   status = _dbus_connection_get_dispatch_status_unlocked (connection);
-  
-  CONNECTION_UNLOCK (connection);
 
-  _dbus_connection_update_dispatch_status_locked (connection, status);
+  /* Unlocks, and calls out to user code */
+  _dbus_connection_update_dispatch_status_and_unlock (connection, status);
   
   return TRUE;
 }
@@ -1711,13 +1777,12 @@ dbus_connection_send_with_reply_and_block (DBusConnection     *connection,
       if (reply != NULL)
         {          
           status = _dbus_connection_get_dispatch_status_unlocked (connection);
-          
-          CONNECTION_UNLOCK (connection);
 
           _dbus_verbose ("dbus_connection_send_with_reply_and_block(): got reply %s\n",
                          dbus_message_get_name (reply));
 
-          _dbus_connection_update_dispatch_status_locked (connection, status);
+          /* Unlocks, and calls out to user code */
+          _dbus_connection_update_dispatch_status_and_unlock (connection, status);
           
           return reply;
         }
@@ -1771,10 +1836,9 @@ dbus_connection_send_with_reply_and_block (DBusConnection     *connection,
     dbus_set_error (error, DBUS_ERROR_NO_REPLY, "Message did not receive a reply");
   else
     dbus_set_error (error, DBUS_ERROR_DISCONNECTED, "Disconnected prior to receiving a reply");
-  
-  CONNECTION_UNLOCK (connection);
 
-  _dbus_connection_update_dispatch_status_locked (connection, status);
+  /* unlocks and calls out to user code */
+  _dbus_connection_update_dispatch_status_and_unlock (connection, status);
 
   return NULL;
 }
@@ -1806,10 +1870,9 @@ dbus_connection_flush (DBusConnection *connection)
                                    -1);
 
   status = _dbus_connection_get_dispatch_status_unlocked (connection);
-  
-  CONNECTION_UNLOCK (connection);
 
-  _dbus_connection_update_dispatch_status_locked (connection, status);
+  /* Unlocks and calls out to user code */
+  _dbus_connection_update_dispatch_status_and_unlock (connection, status);
 }
 
 /* Call with mutex held. Will drop it while waiting and re-acquire
@@ -2052,7 +2115,7 @@ _dbus_connection_release_dispatch (DBusConnection *connection)
 
 static void
 _dbus_connection_failed_pop (DBusConnection *connection,
-                            DBusList *message_link)
+                            DBusList       *message_link)
 {
   _dbus_list_prepend_link (&connection->incoming_messages,
                           message_link);
@@ -2082,14 +2145,15 @@ _dbus_connection_get_dispatch_status_unlocked (DBusConnection *connection)
 }
 
 static void
-_dbus_connection_update_dispatch_status_locked (DBusConnection    *connection,
-                                                DBusDispatchStatus new_status)
+_dbus_connection_update_dispatch_status_and_unlock (DBusConnection    *connection,
+                                                    DBusDispatchStatus new_status)
 {
   dbus_bool_t changed;
   DBusDispatchStatusFunction function;
   void *data;
-  
-  CONNECTION_LOCK (connection);
+
+  /* We have the lock */
+
   _dbus_connection_ref_unlocked (connection);
 
   changed = new_status != connection->last_dispatch_status;
@@ -2098,7 +2162,8 @@ _dbus_connection_update_dispatch_status_locked (DBusConnection    *connection,
 
   function = connection->dispatch_status_function;
   data = connection->dispatch_status_data;
-  
+
+  /* We drop the lock */
   CONNECTION_UNLOCK (connection);
   
   if (changed && function)
@@ -2166,15 +2231,15 @@ dbus_connection_dispatch (DBusConnection *connection)
   DBusDispatchStatus status;
 
   _dbus_return_val_if_fail (connection != NULL, DBUS_DISPATCH_COMPLETE);
-  
-  status = dbus_connection_get_dispatch_status (connection);
+
+  CONNECTION_LOCK (connection);
+  status = _dbus_connection_get_dispatch_status_unlocked (connection);
   if (status != DBUS_DISPATCH_DATA_REMAINS)
     {
-      _dbus_connection_update_dispatch_status_locked (connection, status);
+      /* unlocks and calls out to user code */
+      _dbus_connection_update_dispatch_status_and_unlock (connection, status);
       return status;
     }
-
-  CONNECTION_LOCK (connection);
   
   /* We need to ref the connection since the callback could potentially
    * drop the last ref to it
@@ -2195,11 +2260,10 @@ dbus_connection_dispatch (DBusConnection *connection)
       /* another thread dispatched our stuff */
 
       _dbus_connection_release_dispatch (connection);
-      CONNECTION_UNLOCK (connection);
 
-      status = dbus_connection_get_dispatch_status (connection);
+      status = _dbus_connection_get_dispatch_status_unlocked (connection);
 
-      _dbus_connection_update_dispatch_status_locked (connection, status);
+      _dbus_connection_update_dispatch_status_and_unlock (connection, status);
       
       dbus_connection_unref (connection);
       
@@ -2217,10 +2281,12 @@ dbus_connection_dispatch (DBusConnection *connection)
   if (!_dbus_list_copy (&connection->filter_list, &filter_list_copy))
     {
       _dbus_connection_release_dispatch (connection);
-      CONNECTION_UNLOCK (connection);
+
       _dbus_connection_failed_pop (connection, message_link);
 
-      _dbus_connection_update_dispatch_status_locked (connection, DBUS_DISPATCH_NEED_MEMORY);
+      /* unlocks and calls user code */
+      _dbus_connection_update_dispatch_status_and_unlock (connection,
+                                                          DBUS_DISPATCH_NEED_MEMORY);
 
       dbus_connection_unref (connection);
       
@@ -2320,15 +2386,16 @@ dbus_connection_dispatch (DBusConnection *connection)
   
  out:
   _dbus_connection_release_dispatch (connection);
-  CONNECTION_UNLOCK (connection);
+
   _dbus_list_free_link (message_link);
   dbus_message_unref (message); /* don't want the message to count in max message limits
                                  * in computing dispatch status
                                  */
   
-  status = dbus_connection_get_dispatch_status (connection);
+  status = _dbus_connection_get_dispatch_status_unlocked (connection);
 
-  _dbus_connection_update_dispatch_status_locked (connection, status);
+  /* unlocks and calls user code */
+  _dbus_connection_update_dispatch_status_and_unlock (connection, status);
   
   dbus_connection_unref (connection);
   
index 235ed27..5d2bcd4 100644 (file)
@@ -454,20 +454,43 @@ _dbus_list_remove_last (DBusList **list,
 {
   DBusList *link;
 
+  link = _dbus_list_find_last (list, data);
+  if (link)
+    {
+      _dbus_list_remove_link (list, link);
+      return TRUE;
+    }
+  else
+    return FALSE;
+}
+
+/**
+ * Finds a value in the list. Returns the last link
+ * with value equal to the given data pointer.
+ * This is a linear-time operation.
+ * Returns #NULL if no value found that matches.
+ *
+ * @param list address of the list head.
+ * @param data the value to find.
+ * @returns the link if found
+ */
+DBusList*
+_dbus_list_find_last (DBusList **list,
+                      void      *data)
+{
+  DBusList *link;
+
   link = _dbus_list_get_last_link (list);
 
   while (link != NULL)
     {
       if (link->data == data)
-        {
-          _dbus_list_remove_link (list, link);
-          return TRUE;
-        }
+        return link;
       
       link = _dbus_list_get_prev_link (list, link);
     }
 
-  return FALSE;
+  return NULL;
 }
 
 /**
index f3b37ef..7aa6c96 100644 (file)
@@ -60,6 +60,8 @@ dbus_bool_t _dbus_list_remove_last        (DBusList **list,
                                            void      *data);
 void        _dbus_list_remove_link        (DBusList **list,
                                            DBusList  *link);
+DBusList*   _dbus_list_find_last          (DBusList **list,
+                                           void      *data);
 void        _dbus_list_clear              (DBusList **list);
 DBusList*   _dbus_list_get_first_link     (DBusList **list);
 DBusList*   _dbus_list_get_last_link      (DBusList **list);
index 82de8ff..ad15ae2 100644 (file)
@@ -430,13 +430,11 @@ marshal_4_octets (DBusString   *str,
 {
   _dbus_assert (sizeof (value) == 4);
   
-  if (!_dbus_string_align_length (str, sizeof (dbus_uint32_t)))
-    return FALSE;
-  
   if (byte_order != DBUS_COMPILER_BYTE_ORDER)
     value = DBUS_UINT32_SWAP_LE_BE (value);
 
-  return _dbus_string_append_len (str, (const char *)&value, sizeof (dbus_uint32_t));
+  return _dbus_string_append_4_aligned (str,
+                                        (const unsigned char *)&value);
 }
 
 static dbus_bool_t
@@ -445,14 +443,12 @@ marshal_8_octets (DBusString *str,
                   DBusOctets8 value)
 {
   _dbus_assert (sizeof (value) == 8);
-
-  if (!_dbus_string_align_length (str, 8))
-    return FALSE;
   
   if (byte_order != DBUS_COMPILER_BYTE_ORDER)
     pack_8_octets (value, byte_order, (unsigned char*) &value); /* pack into self, swapping as we go */
 
-  return _dbus_string_append_len (str, (const char *)&value, 8);
+  return _dbus_string_append_8_aligned (str,
+                                        (const unsigned char *)&value);
 }
 
 /**
@@ -1646,6 +1642,99 @@ _dbus_marshal_validate_type   (const DBusString *str,
   return FALSE;
 }
 
+/* Faster validator for array data that doesn't call
+ * validate_arg for each value
+ */
+static dbus_bool_t
+validate_array_data (const DBusString *str,
+                     int              byte_order,
+                     int               depth,
+                     int               type,
+                     int               array_type_pos,
+                     int               pos,
+                     int              *new_pos,
+                     int               end)
+{
+  switch (type)
+    {
+    case DBUS_TYPE_INVALID:
+      return FALSE;
+      break;
+
+    case DBUS_TYPE_NIL:
+      break;
+
+    case DBUS_TYPE_STRING:
+    case DBUS_TYPE_NAMED:      
+    case DBUS_TYPE_ARRAY:
+    case DBUS_TYPE_DICT:
+      /* This clean recursion to validate_arg is what we
+       * are doing logically for all types, but we don't
+       * really want to call validate_arg for every byte
+       * in a byte array, so the primitive types are
+       * special-cased.
+       */
+      while (pos < end)
+        {
+          if (!_dbus_marshal_validate_arg (str, byte_order, depth,
+                                           type, array_type_pos, pos, &pos))
+            return FALSE;
+        }
+      break;
+      
+    case DBUS_TYPE_BYTE:
+      pos = end;
+      break;
+      
+    case DBUS_TYPE_BOOLEAN:
+      while (pos < end)
+        {
+          unsigned char c;
+          
+          c = _dbus_string_get_byte (str, pos);
+          
+          if (!(c == 0 || c == 1))
+            {
+              _dbus_verbose ("boolean value must be either 0 or 1, not %d\n", c);
+              return FALSE;
+            }
+          
+          ++pos;
+        }
+      break;
+      
+    case DBUS_TYPE_INT32:
+    case DBUS_TYPE_UINT32:
+      /* Call validate arg one time to check alignment padding
+       * at start of array
+       */
+      if (!_dbus_marshal_validate_arg (str, byte_order, depth,
+                                       type, array_type_pos, pos, &pos))
+        return FALSE;
+      pos = _DBUS_ALIGN_VALUE (end, 4);
+      break;
+
+    case DBUS_TYPE_INT64:
+    case DBUS_TYPE_UINT64:
+    case DBUS_TYPE_DOUBLE:
+      /* Call validate arg one time to check alignment padding
+       * at start of array
+       */
+      if (!_dbus_marshal_validate_arg (str, byte_order, depth,
+                                       type, array_type_pos, pos, &pos))
+        return FALSE;
+      pos = _DBUS_ALIGN_VALUE (end, 8);
+      break;
+      
+    default:
+      _dbus_verbose ("Unknown message arg type %d\n", type);
+      return FALSE;
+    }
+
+  *new_pos = pos;
+
+  return TRUE;
+}
 
 /** 
  * Validates an argument of a specific type, checking that it
@@ -1726,7 +1815,7 @@ _dbus_marshal_validate_arg (const DBusString *str,
         
        c = _dbus_string_get_byte (str, pos);
 
-       if (c != 0 && c != 1)
+       if (!(c == 0 || c == 1))
          {
            _dbus_verbose ("boolean value must be either 0 or 1, not %d\n", c);
            return FALSE;
@@ -1874,13 +1963,11 @@ _dbus_marshal_validate_arg (const DBusString *str,
           }
        
        end = pos + len;
-        
-       while (pos < end)
-         {
-           if (!_dbus_marshal_validate_arg (str, byte_order, depth + 1,
-                                            array_type, array_type_pos, pos, &pos))
-             return FALSE;
-         }
+
+        if (!validate_array_data (str, byte_order, depth + 1,
+                                  array_type, array_type_pos,
+                                  pos, &pos, end))
+          return FALSE;
 
         if (pos < end)
           {
@@ -1888,7 +1975,7 @@ _dbus_marshal_validate_arg (const DBusString *str,
              * but the check is here just to be paranoid.
              */
             _dbus_verbose ("array length %d specified was longer than actual array contents by %d\n",
-                    len, end - pos);
+                           len, end - pos);
             return FALSE;
           }
         
index a978ba0..f38e510 100644 (file)
@@ -1,7 +1,7 @@
 /* -*- mode: C; c-file-style: "gnu" -*- */
 /* dbus-message-handler.c Sender/receiver of messages.
  *
- * Copyright (C) 2002  Red Hat Inc.
+ * Copyright (C) 2002, 2003 Red Hat Inc.
  *
  * Licensed under the Academic Free License version 1.2
  * 
@@ -47,7 +47,7 @@ _DBUS_DEFINE_GLOBAL_LOCK (message_handler);
  */
 struct DBusMessageHandler
 {
-  int refcount;                                   /**< reference count */
+  DBusAtomic refcount;                            /**< reference count */
 
   DBusHandleMessageFunction function;             /**< handler function */
   void                     *user_data;            /**< user data for function */
@@ -176,7 +176,7 @@ dbus_message_handler_new (DBusHandleMessageFunction function,
   if (handler == NULL)
     return NULL;
   
-  handler->refcount = 1;
+  handler->refcount.value = 1;
   handler->function = function;
   handler->user_data = user_data;
   handler->free_user_data = free_user_data;
@@ -194,12 +194,8 @@ void
 dbus_message_handler_ref (DBusMessageHandler *handler)
 {
   _dbus_return_if_fail (handler != NULL);
-  
-  _DBUS_LOCK (message_handler);
-  _dbus_assert (handler != NULL);
-  
-  handler->refcount += 1;
-  _DBUS_UNLOCK (message_handler);
+
+  _dbus_atomic_inc (&handler->refcount);
 }
 
 /**
@@ -211,21 +207,13 @@ dbus_message_handler_ref (DBusMessageHandler *handler)
 void
 dbus_message_handler_unref (DBusMessageHandler *handler)
 {
-  int refcount;
+  dbus_bool_t last_unref;
 
   _dbus_return_if_fail (handler != NULL);
-  
-  _DBUS_LOCK (message_handler);
-  
-  _dbus_assert (handler != NULL);
-  _dbus_assert (handler->refcount > 0);
 
-  handler->refcount -= 1;
-  refcount = handler->refcount;
-  
-  _DBUS_UNLOCK (message_handler);
+  last_unref = (_dbus_atomic_dec (&handler->refcount) == 1);
   
-  if (refcount == 0)
+  if (last_unref)
     {
       DBusList *link;
       
index eb4123c..53711f3 100644 (file)
@@ -44,7 +44,8 @@ dbus_bool_t _dbus_message_add_size_counter      (DBusMessage  *message,
 void        _dbus_message_add_size_counter_link (DBusMessage  *message,
                                                  DBusList     *link);
 void        _dbus_message_remove_size_counter   (DBusMessage  *message,
-                                                 DBusCounter  *counter);
+                                                 DBusCounter  *counter,
+                                                 DBusList    **link_return);
 
 DBusMessageLoader* _dbus_message_loader_new                   (void);
 void               _dbus_message_loader_ref                   (DBusMessageLoader  *loader);
index 2920910..7c89d73 100644 (file)
@@ -81,7 +81,7 @@ typedef struct
  */
 struct DBusMessage
 {
-  volatile dbus_atomic_t refcount; /**< Reference count */
+  DBusAtomic refcount; /**< Reference count */
 
   DBusString header; /**< Header network data, stored
                       * separately from body so we can
@@ -772,15 +772,26 @@ _dbus_message_add_size_counter (DBusMessage *message,
  * the counter by the size of this message.
  *
  * @param message the message
+ * @param link_return return the link used
  * @param counter the counter
  */
 void
 _dbus_message_remove_size_counter (DBusMessage  *message,
-                                   DBusCounter  *counter)
+                                   DBusCounter  *counter,
+                                   DBusList    **link_return)
 {
-  if (!_dbus_list_remove_last (&message->size_counters,
-                               counter))
-    _dbus_assert_not_reached ("Removed a message size counter that was not added");
+  DBusList *link;
+
+  link = _dbus_list_find_last (&message->size_counters,
+                               counter);
+  _dbus_assert (link != NULL);
+
+  _dbus_list_unlink (&message->size_counters,
+                     link);
+  if (link_return)
+    *link_return = link;
+  else
+    _dbus_list_free_link (link);
 
   _dbus_counter_adjust (counter, message->size_counter_delta);
 
@@ -898,7 +909,7 @@ dbus_message_new_empty_header (void)
   if (message == NULL)
     return NULL;
   
-  message->refcount = 1;
+  message->refcount.value = 1;
   message->byte_order = DBUS_COMPILER_BYTE_ORDER;
   message->client_serial = 0;
   message->reply_serial = 0;
@@ -910,13 +921,13 @@ dbus_message_new_empty_header (void)
       ++i;
     }
   
-  if (!_dbus_string_init (&message->header))
+  if (!_dbus_string_init_preallocated (&message->header, 64))
     {
       dbus_free (message);
       return NULL;
     }
   
-  if (!_dbus_string_init (&message->body))
+  if (!_dbus_string_init_preallocated (&message->body, 64))
     {
       _dbus_string_free (&message->header);
       dbus_free (message);
@@ -1076,7 +1087,7 @@ dbus_message_copy (const DBusMessage *message)
   if (retval == NULL)
     return NULL;
   
-  retval->refcount = 1;
+  retval->refcount.value = 1;
   retval->byte_order = message->byte_order;
   retval->client_serial = message->client_serial;
   retval->reply_serial = message->reply_serial;
@@ -1134,12 +1145,12 @@ dbus_message_copy (const DBusMessage *message)
 void
 dbus_message_ref (DBusMessage *message)
 {
-  volatile dbus_atomic_t refcount;
+  dbus_int32_t old_refcount;
 
   _dbus_return_if_fail (message != NULL);
   
-  refcount = _dbus_atomic_inc (&message->refcount);
-  _dbus_assert (refcount > 1);
+  old_refcount = _dbus_atomic_inc (&message->refcount);
+  _dbus_assert (old_refcount >= 1);
 }
 
 static void
@@ -1163,15 +1174,15 @@ free_size_counter (void *element,
 void
 dbus_message_unref (DBusMessage *message)
 {
 volatile dbus_atomic_t refcount;
dbus_int32_t old_refcount;
 
   _dbus_return_if_fail (message != NULL);
   
-  refcount = _dbus_atomic_dec (&message->refcount);
+  old_refcount = _dbus_atomic_dec (&message->refcount);
   
-  _dbus_assert (refcount >= 0);
+  _dbus_assert (old_refcount >= 0);
 
-  if (refcount == 0)
+  if (old_refcount == 1)
     {
       _dbus_list_foreach (&message->size_counters,
                           free_size_counter, message);
index 65d2fb1..c6f929a 100644 (file)
@@ -169,14 +169,17 @@ undo_alignment (DBusRealString *real)
 }
 
 /**
- * Initializes a string. The string starts life with zero length.  The
- * string must eventually be freed with _dbus_string_free().
+ * Initializes a string that can be up to the given allocation size
+ * before it has to realloc. The string starts life with zero length.
+ * The string must eventually be freed with _dbus_string_free().
  * 
  * @param str memory to hold the string
+ * @param allocate_size amount to preallocate
  * @returns #TRUE on success, #FALSE if no memory
  */
 dbus_bool_t
-_dbus_string_init (DBusString *str)
+_dbus_string_init_preallocated (DBusString *str,
+                                int         allocate_size)
 {
   DBusRealString *real;
   
@@ -192,11 +195,11 @@ _dbus_string_init (DBusString *str)
    * an existing string, e.g. in _dbus_string_steal_data()
    */
   
-  real->str = dbus_malloc (ALLOCATION_PADDING);
+  real->str = dbus_malloc (ALLOCATION_PADDING + allocate_size);
   if (real->str == NULL)
     return FALSE;  
   
-  real->allocated = ALLOCATION_PADDING;
+  real->allocated = ALLOCATION_PADDING + allocate_size;
   real->len = 0;
   real->str[real->len] = '\0';
   
@@ -211,6 +214,19 @@ _dbus_string_init (DBusString *str)
   return TRUE;
 }
 
+/**
+ * Initializes a string. The string starts life with zero length.  The
+ * string must eventually be freed with _dbus_string_free().
+ * 
+ * @param str memory to hold the string
+ * @returns #TRUE on success, #FALSE if no memory
+ */
+dbus_bool_t
+_dbus_string_init (DBusString *str)
+{
+  return _dbus_string_init_preallocated (str, 0);
+}
+
 /* The max length thing is sort of a historical artifact
  * from a feature that turned out to be dumb; perhaps
  * we should purge it entirely. The problem with
@@ -345,56 +361,65 @@ _dbus_string_lock (DBusString *str)
 #endif /* DBUS_BUILD_TESTS */
 
 static dbus_bool_t
-set_length (DBusRealString *real,
-            int             new_length)
+reallocate_for_length (DBusRealString *real,
+                       int             new_length)
 {
-  /* Note, we are setting the length without nul termination */
-
-  /* exceeding max length is the same as failure to allocate memory */
-  if (new_length > real->max_length)
-    return FALSE;
-  
-  if (new_length > (real->allocated - ALLOCATION_PADDING))
-    {
-      int new_allocated;
-      char *new_str;
+  int new_allocated;
+  char *new_str;
 
-      /* at least double our old allocation to avoid O(n), avoiding
-       * overflow
-       */
-      if (real->allocated > (MAX_MAX_LENGTH + ALLOCATION_PADDING) / 2)
-        new_allocated = MAX_MAX_LENGTH + ALLOCATION_PADDING;
-      else
-        new_allocated = real->allocated * 2;
+  /* at least double our old allocation to avoid O(n), avoiding
+   * overflow
+   */
+  if (real->allocated > (MAX_MAX_LENGTH + ALLOCATION_PADDING) / 2)
+    new_allocated = MAX_MAX_LENGTH + ALLOCATION_PADDING;
+  else
+    new_allocated = real->allocated * 2;
 
-      /* if you change the code just above here, run the tests without
-       * the following before you commit
-       */
+  /* if you change the code just above here, run the tests without
+   * the following before you commit
+   */
 #ifdef DBUS_BUILD_TESTS
-      new_allocated = 0; /* ensure a realloc every time so that we go
-                          * through all malloc failure codepaths
-                          */
+  new_allocated = 0; /* ensure a realloc every time so that we go
+                      * through all malloc failure codepaths
+                      */
 #endif
       
-      /* But be sure we always alloc at least space for the new length */
-      new_allocated = MAX (new_allocated, new_length + ALLOCATION_PADDING);
-        
-      new_str = dbus_realloc (real->str - real->align_offset, new_allocated);
-      if (new_str == NULL)
-        return FALSE;
+  /* But be sure we always alloc at least space for the new length */
+  new_allocated = MAX (new_allocated, new_length + ALLOCATION_PADDING);
 
-      real->str = new_str + real->align_offset;
-      real->allocated = new_allocated;
-      fixup_alignment (real);
-    }
+  _dbus_assert (new_allocated >= real->allocated); /* code relies on this */
+  new_str = dbus_realloc (real->str - real->align_offset, new_allocated);
+  if (new_str == NULL)
+    return FALSE;
 
-  real->len = new_length;
-  real->str[real->len] = '\0';
+  real->str = new_str + real->align_offset;
+  real->allocated = new_allocated;
+  fixup_alignment (real);
 
   return TRUE;
 }
 
 static dbus_bool_t
+set_length (DBusRealString *real,
+            int             new_length)
+{
+  /* Note, we are setting the length not including nul termination */
+
+  /* exceeding max length is the same as failure to allocate memory */
+  if (new_length > real->max_length)
+    return FALSE;
+  else if (new_length > (real->allocated - ALLOCATION_PADDING) &&
+           !reallocate_for_length (real, new_length))
+    return FALSE;
+  else
+    {
+      real->len = new_length;
+      real->str[real->len] = '\0';
+      return TRUE;
+    }
+}
+
+static dbus_bool_t
 open_gap (int             len,
           DBusRealString *dest,
           int             insert_at)
@@ -795,17 +820,10 @@ _dbus_string_set_length (DBusString *str,
   return set_length (real, length);
 }
 
-/**
- * Align the length of a string to a specific alignment (typically 4 or 8)
- * by appending nul bytes to the string.
- *
- * @param str a string
- * @param alignment the alignment
- * @returns #FALSE if no memory
- */
-dbus_bool_t
-_dbus_string_align_length (DBusString *str,
-                           int         alignment)
+static dbus_bool_t
+align_length_then_lengthen (DBusString *str,
+                            int         alignment,
+                            int         then_lengthen_by)
 {
   unsigned long new_len; /* ulong to avoid _DBUS_ALIGN_VALUE overflow */
   int delta;
@@ -814,8 +832,9 @@ _dbus_string_align_length (DBusString *str,
   _dbus_assert (alignment <= 8); /* it has to be a bug if > 8 */
 
   new_len = _DBUS_ALIGN_VALUE (real->len, alignment);
-  if (new_len > (unsigned long) real->max_length)
+  if (new_len > (unsigned long) real->max_length - then_lengthen_by)
     return FALSE;
+  new_len += then_lengthen_by;
   
   delta = new_len - real->len;
   _dbus_assert (delta >= 0);
@@ -826,12 +845,38 @@ _dbus_string_align_length (DBusString *str,
   if (!set_length (real, new_len))
     return FALSE;
 
-  memset (real->str + (new_len - delta),
-          '\0', delta);
-
+  /* delta == padding + then_lengthen_by
+   * new_len == old_len + padding + then_lengthen_by
+   */
+  if (then_lengthen_by < delta)
+    {
+      unsigned int i;
+      i = new_len - delta;
+      while (i < (new_len - then_lengthen_by))
+        {
+          real->str[i] = '\0';
+          ++i;
+        }
+    }
+      
   return TRUE;
 }
 
+/**
+ * Align the length of a string to a specific alignment (typically 4 or 8)
+ * by appending nul bytes to the string.
+ *
+ * @param str a string
+ * @param alignment the alignment
+ * @returns #FALSE if no memory
+ */
+dbus_bool_t
+_dbus_string_align_length (DBusString *str,
+                           int         alignment)
+{
+  return align_length_then_lengthen (str, alignment, 0);
+}
+
 static dbus_bool_t
 append (DBusRealString *real,
         const char     *buffer,
@@ -874,6 +919,74 @@ _dbus_string_append (DBusString *str,
 }
 
 /**
+ * Appends 4 bytes aligned on a 4 byte boundary
+ * with any alignment padding initialized to 0.
+ *
+ * @param str the DBusString
+ * @param octets 4 bytes to append
+ * @returns #FALSE if not enough memory.
+ */
+dbus_bool_t
+_dbus_string_append_4_aligned (DBusString         *str,
+                               const unsigned char octets[4])
+{
+  dbus_uint32_t *p;
+  DBUS_STRING_PREAMBLE (str);
+  
+  if (!align_length_then_lengthen (str, 4, 4))
+    return FALSE;
+
+  p = (dbus_uint32_t*) (real->str + (real->len - 4));
+  *p = *((dbus_uint32_t*)octets);
+
+  return TRUE;
+}
+
+/**
+ * Appends 8 bytes aligned on an 8 byte boundary
+ * with any alignment padding initialized to 0.
+ *
+ * @param str the DBusString
+ * @param octets 4 bytes to append
+ * @returns #FALSE if not enough memory.
+ */
+dbus_bool_t
+_dbus_string_append_8_aligned (DBusString         *str,
+                               const unsigned char octets[8])
+{
+#ifdef DBUS_HAVE_INT64
+  dbus_uint64_t *p;
+  DBUS_STRING_PREAMBLE (str);
+  
+  if (!align_length_then_lengthen (str, 8, 8))
+    return FALSE;
+
+  p = (dbus_uint64_t*) (real->str + (real->len - 8));
+  *p = *((dbus_uint64_t*)octets);
+#else
+  char *p;
+  DBUS_STRING_PREAMBLE (str);
+  
+  if (!align_length_then_lengthen (str, 8, 8))
+    return FALSE;
+
+  p = real->str + (real->len - 8);
+  
+  *p++ = octets[0];
+  *p++ = octets[1];
+  *p++ = octets[2];
+  *p++ = octets[3];
+  *p++ = octets[4];
+  *p++ = octets[5];
+  *p++ = octets[6];
+  *p++ = octets[7];
+  _dbus_assert (p == (real->str + real->len));
+#endif
+
+  return TRUE;
+}
+
+/**
  * Appends block of bytes with the given length to a DBusString.
  *
  * @param str the DBusString
@@ -1080,18 +1193,12 @@ _dbus_string_move (DBusString       *source,
                    DBusString       *dest,
                    int               insert_at)
 {
-  DBUS_STRING_COPY_PREAMBLE (source, start, dest, insert_at);
+  DBusRealString *real_source = (DBusRealString*) source;
+  _dbus_assert (start <= real_source->len);
   
-  if (!copy (real_source, start,
-             real_source->len - start,
-             real_dest,
-             insert_at))
-    return FALSE;
-
-  delete (real_source, start,
-          real_source->len - start);
-
-  return TRUE;
+  return _dbus_string_move_len (source, start,
+                                real_source->len - start,
+                                dest, insert_at);
 }
 
 /**
@@ -1121,6 +1228,9 @@ _dbus_string_copy (const DBusString *source,
 /**
  * Like _dbus_string_move(), but can move a segment from
  * the middle of the source string.
+ *
+ * @todo this doesn't do anything with max_length field.
+ * we should probably just kill the max_length field though.
  * 
  * @param source the source string
  * @param start first byte of source string to move
@@ -1141,15 +1251,48 @@ _dbus_string_move_len (DBusString       *source,
   _dbus_assert (len >= 0);
   _dbus_assert ((start + len) <= real_source->len);
 
-  if (!copy (real_source, start, len,
-             real_dest,
-             insert_at))
-    return FALSE;
 
-  delete (real_source, start,
-          len);
+  if (len == 0)
+    {
+      return TRUE;
+    }
+  else if (start == 0 &&
+           len == real_source->len &&
+           real_dest->len == 0)
+    {
+      /* Short-circuit moving an entire existing string to an empty string
+       * by just swapping the buffers.
+       */
+      /* we assume ->constant doesn't matter as you can't have
+       * a constant string involved in a move.
+       */
+#define ASSIGN_DATA(a, b) do {                  \
+        (a)->str = (b)->str;                    \
+        (a)->len = (b)->len;                    \
+        (a)->allocated = (b)->allocated;        \
+        (a)->align_offset = (b)->align_offset;  \
+      } while (0)
+      
+      DBusRealString tmp;
 
-  return TRUE;
+      ASSIGN_DATA (&tmp, real_source);
+      ASSIGN_DATA (real_source, real_dest);
+      ASSIGN_DATA (real_dest, &tmp);
+
+      return TRUE;
+    }
+  else
+    {
+      if (!copy (real_source, start, len,
+                 real_dest,
+                 insert_at))
+        return FALSE;
+      
+      delete (real_source, start,
+              len);
+      
+      return TRUE;
+    }
 }
 
 /**
index b9b298a..8fa1380 100644 (file)
@@ -51,6 +51,8 @@ void          _dbus_string_init_const            (DBusString        *str,
 void          _dbus_string_init_const_len        (DBusString        *str,
                                                   const char        *value,
                                                   int                len);
+dbus_bool_t   _dbus_string_init_preallocated     (DBusString        *str,
+                                                  int                allocate_size);
 void          _dbus_string_free                  (DBusString        *str);
 void          _dbus_string_lock                  (DBusString        *str);
 char*         _dbus_string_get_data              (DBusString        *str);
@@ -105,6 +107,10 @@ dbus_bool_t   _dbus_string_append_byte           (DBusString        *str,
                                                   unsigned char      byte);
 dbus_bool_t   _dbus_string_append_unichar        (DBusString        *str,
                                                   dbus_unichar_t     ch);
+dbus_bool_t   _dbus_string_append_4_aligned      (DBusString        *str,
+                                                  const unsigned char octets[4]);
+dbus_bool_t   _dbus_string_append_8_aligned      (DBusString        *str,
+                                                  const unsigned char octets[8]);
 void          _dbus_string_delete                (DBusString        *str,
                                                   int                start,
                                                   int                len);
index c813a83..e2975c3 100644 (file)
@@ -1792,19 +1792,18 @@ _dbus_getgid (void)
 
 _DBUS_DEFINE_GLOBAL_LOCK (atomic);
 
-
 #ifdef DBUS_USE_ATOMIC_INT_486
 /* Taken from CVS version 1.7 of glibc's sysdeps/i386/i486/atomicity.h */
 /* Since the asm stuff here is gcc-specific we go ahead and use "inline" also */
-static inline dbus_atomic_t
-atomic_exchange_and_add (volatile dbus_atomic_t *atomic,
-                         volatile dbus_atomic_t  val)
+static inline dbus_int32_t
+atomic_exchange_and_add (DBusAtomic            *atomic,
+                         volatile dbus_int32_t  val)
 {
-  register dbus_atomic_t result;
+  register dbus_int32_t result;
 
   __asm__ __volatile__ ("lock; xaddl %0,%1"
-                        : "=r" (result), "=m" (*atomic) 
-                       : "0" (val), "m" (*atomic));
+                        : "=r" (result), "=m" (atomic->value)
+                       : "0" (val), "m" (atomic->value));
   return result;
 }
 #endif
@@ -1813,12 +1812,12 @@ atomic_exchange_and_add (volatile dbus_atomic_t *atomic,
  * Atomically increments an integer
  *
  * @param atomic pointer to the integer to increment
- * @returns the value after incrementing
+ * @returns the value before incrementing
  *
  * @todo implement arch-specific faster atomic ops
  */
-dbus_atomic_t
-_dbus_atomic_inc (volatile dbus_atomic_t *atomic)
+dbus_int32_t
+_dbus_atomic_inc (DBusAtomic *atomic)
 {
 #ifdef DBUS_USE_ATOMIC_INT_486
   return atomic_exchange_and_add (atomic, 1);
@@ -1837,12 +1836,12 @@ _dbus_atomic_inc (volatile dbus_atomic_t *atomic)
  * Atomically decrement an integer
  *
  * @param atomic pointer to the integer to decrement
- * @returns the value after decrementing
+ * @returns the value before decrementing
  *
  * @todo implement arch-specific faster atomic ops
  */
-dbus_atomic_t
-_dbus_atomic_dec (volatile dbus_atomic_t *atomic)
+dbus_int32_t
+_dbus_atomic_dec (DBusAtomic *atomic)
 {
 #ifdef DBUS_USE_ATOMIC_INT_486
   return atomic_exchange_and_add (atomic, -1);
index 2ae455b..7a4696f 100644 (file)
@@ -169,10 +169,14 @@ unsigned long _dbus_getpid (void);
 dbus_uid_t    _dbus_getuid (void);
 dbus_gid_t    _dbus_getgid (void);
 
-typedef dbus_int32_t dbus_atomic_t;
+typedef struct DBusAtomic DBusAtomic;
+struct DBusAtomic
+{
+  volatile dbus_int32_t value;
+};
 
-dbus_atomic_t _dbus_atomic_inc (volatile dbus_atomic_t *atomic);
-dbus_atomic_t _dbus_atomic_dec (volatile dbus_atomic_t *atomic);
+dbus_int32_t _dbus_atomic_inc (DBusAtomic *atomic);
+dbus_int32_t _dbus_atomic_dec (DBusAtomic *atomic);
 
 #define _DBUS_POLLIN      0x0001    /* There is data to read */
 #define _DBUS_POLLPRI     0x0002    /* There is urgent data to read */
index 625fbb7..289d634 100644 (file)
@@ -64,6 +64,9 @@ _dbus_timeout_new (int                 interval,
   DBusTimeout *timeout;
 
   timeout = dbus_new0 (DBusTimeout, 1);
+  if (timeout == NULL)
+    return NULL;
+  
   timeout->refcount = 1;
   timeout->interval = interval;
 
index 6173f3a..d53f762 100644 (file)
 #include <stdlib.h>
 
 #define N_CLIENT_THREADS 1
-#define N_ITERATIONS 2000
+#define N_ITERATIONS 100
+#define PAYLOAD_SIZE 1000
 #define ECHO_MESSAGE "org.freedesktop.DBus.Test.EchoProfile"
 static const char *address;
+static unsigned char *payload;
 
 static void
 send_echo_message (DBusConnection *connection)
@@ -40,7 +42,12 @@ send_echo_message (DBusConnection *connection)
   dbus_message_append_args (message,
                             DBUS_TYPE_STRING, "Hello World!",
                             DBUS_TYPE_INT32, 123456,
+#if 1
+                            DBUS_TYPE_ARRAY, DBUS_TYPE_BYTE,
+                            payload, PAYLOAD_SIZE,
+#endif
                             DBUS_TYPE_INVALID);
+  
   dbus_connection_send (connection, message, NULL);
   dbus_message_unref (message);
   dbus_connection_flush (connection);
@@ -63,12 +70,12 @@ client_filter (DBusMessageHandler *handler,
                                   ECHO_MESSAGE))
     {
       *iterations += 1;
-      send_echo_message (connection);
-      if (*iterations > N_ITERATIONS)
+      if (*iterations >= N_ITERATIONS)
         {
           g_print ("Completed %d iterations\n", N_ITERATIONS);
           exit (0);
         }
+      send_echo_message (connection);
     }
   
   return DBUS_HANDLER_RESULT_ALLOW_MORE_HANDLERS;
@@ -95,7 +102,7 @@ thread_func (void *data)
       exit (1);
     }
 
-  iterations = 0;
+  iterations = 1;
   
   handler = dbus_message_handler_new (client_filter,
                                       &iterations, NULL);
@@ -188,6 +195,7 @@ main (int argc, char *argv[])
     }
 
   address = dbus_server_get_address (server);
+  payload = g_malloc (PAYLOAD_SIZE);
   
   dbus_server_set_new_connection_function (server,
                                            new_connection_callback,