2003-03-15 Havoc Pennington <hp@pobox.com>
authorHavoc Pennington <hp@redhat.com>
Sat, 15 Mar 2003 20:47:16 +0000 (20:47 +0000)
committerHavoc Pennington <hp@redhat.com>
Sat, 15 Mar 2003 20:47:16 +0000 (20:47 +0000)
Make it pass the Hello handling test including all OOM codepaths.
Now to do other messages...

* bus/services.c (bus_service_remove_owner): fix crash when
removing owner from an empty list of owners
(bus_registry_ensure): don't leave service in the list of
a connection's owned services if we fail to put the service
in the hash table.

* bus/connection.c (bus_connection_preallocate_oom_error): set
error flag on the OOM error.

* dbus/dbus-connection.c (_dbus_connection_new_for_transport):
handle _dbus_transport_set_connection failure

* dbus/dbus-transport-unix.c (_dbus_transport_new_for_fd): modify
to create watches up front and simply enable/disable them as
needed.
(unix_connection_set): this can now fail on OOM

* dbus/dbus-timeout.c, dbus/dbus-watch.c: add concept
of enabling/disabling a watch or timeout.

* bus/loop.c (bus_loop_iterate): don't touch disabled
watches/timeouts

* glib/dbus-gmain.c: adapt to enable/disable watches and timeouts

25 files changed:
ChangeLog
bus/bus.c
bus/connection.c
bus/dispatch.c
bus/loop.c
bus/services.c
bus/test.c
dbus/dbus-connection-internal.h
dbus/dbus-connection.c
dbus/dbus-connection.h
dbus/dbus-server-protected.h
dbus/dbus-server-unix.c
dbus/dbus-server.c
dbus/dbus-server.h
dbus/dbus-timeout.c
dbus/dbus-timeout.h
dbus/dbus-transport-debug.c
dbus/dbus-transport-protected.h
dbus/dbus-transport-unix.c
dbus/dbus-transport.c
dbus/dbus-transport.h
dbus/dbus-watch.c
dbus/dbus-watch.h
glib/dbus-gmain.c
test/watch.c

index 5c477ee..d115e10 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,35 @@
 2003-03-15  Havoc Pennington  <hp@pobox.com>
 
+       Make it pass the Hello handling test including all OOM codepaths.
+       Now to do other messages...
+       
+       * bus/services.c (bus_service_remove_owner): fix crash when
+       removing owner from an empty list of owners
+       (bus_registry_ensure): don't leave service in the list of 
+       a connection's owned services if we fail to put the service
+       in the hash table.
+
+       * bus/connection.c (bus_connection_preallocate_oom_error): set
+       error flag on the OOM error.
+
+       * dbus/dbus-connection.c (_dbus_connection_new_for_transport):
+       handle _dbus_transport_set_connection failure
+
+       * dbus/dbus-transport-unix.c (_dbus_transport_new_for_fd): modify
+       to create watches up front and simply enable/disable them as
+       needed.
+       (unix_connection_set): this can now fail on OOM
+
+       * dbus/dbus-timeout.c, dbus/dbus-watch.c: add concept 
+       of enabling/disabling a watch or timeout.
+
+       * bus/loop.c (bus_loop_iterate): don't touch disabled
+       watches/timeouts
+
+       * glib/dbus-gmain.c: adapt to enable/disable watches and timeouts
+
+2003-03-15  Havoc Pennington  <hp@pobox.com>
+
        * bus/dispatch.c (bus_dispatch_test): OK, now finally actually
        write useful test code, after all that futzing around ;-)
 
index b717cac..2270f53 100644 (file)
--- a/bus/bus.c
+++ b/bus/bus.c
@@ -161,6 +161,7 @@ bus_context_new (const char  *address,
   if (!dbus_server_set_watch_functions (context->server,
                                         (DBusAddWatchFunction) add_server_watch,
                                         (DBusRemoveWatchFunction) remove_server_watch,
+                                        NULL,
                                         context,
                                         NULL))
     {
@@ -171,6 +172,7 @@ bus_context_new (const char  *address,
   if (!dbus_server_set_timeout_functions (context->server,
                                           (DBusAddTimeoutFunction) add_server_timeout,
                                           (DBusRemoveTimeoutFunction) remove_server_timeout,
+                                          NULL,
                                           context, NULL))
     {
       BUS_SET_OOM (error);
@@ -192,13 +194,13 @@ bus_context_shutdown (BusContext  *context)
     return;
   
   if (!dbus_server_set_watch_functions (context->server,
-                                        NULL, NULL,
+                                        NULL, NULL, NULL,
                                         context,
                                         NULL))
     _dbus_assert_not_reached ("setting watch functions to NULL failed");
   
   if (!dbus_server_set_timeout_functions (context->server,
-                                          NULL, NULL,
+                                          NULL, NULL, NULL,
                                           context,
                                           NULL))
     _dbus_assert_not_reached ("setting timeout functions to NULL failed");
index 1c699c6..ee3612a 100644 (file)
@@ -107,13 +107,13 @@ bus_connection_disconnected (DBusConnection *connection)
   
   /* no more watching */
   if (!dbus_connection_set_watch_functions (connection,
-                                            NULL, NULL,
+                                            NULL, NULL, NULL,
                                             connection,
                                             NULL))
     _dbus_assert_not_reached ("setting watch functions to NULL failed");
 
   if (!dbus_connection_set_timeout_functions (connection,
-                                              NULL, NULL,
+                                              NULL, NULL, NULL,
                                               connection,
                                               NULL))
     _dbus_assert_not_reached ("setting timeout functions to NULL failed");
@@ -288,6 +288,7 @@ bus_connections_setup_connection (BusConnections *connections,
   if (!dbus_connection_set_watch_functions (connection,
                                             (DBusAddWatchFunction) add_connection_watch,
                                             (DBusRemoveWatchFunction) remove_connection_watch,
+                                            NULL,
                                             connection,
                                             NULL))
     {
@@ -298,6 +299,7 @@ bus_connections_setup_connection (BusConnections *connections,
   if (!dbus_connection_set_timeout_functions (connection,
                                               (DBusAddTimeoutFunction) add_connection_timeout,
                                               (DBusRemoveTimeoutFunction) remove_connection_timeout,
+                                              NULL,
                                               connection, NULL))
     {
       dbus_connection_disconnect (connection);
@@ -442,6 +444,8 @@ bus_connection_preallocate_oom_error (DBusConnection *connection)
       return FALSE;
     }
 
+  dbus_message_set_is_error (message, TRUE);
+  
   /* set reply serial to placeholder value just so space is already allocated
    * for it.
    */
@@ -603,6 +607,9 @@ bus_transaction_send_message (BusTransaction *transaction,
   BusConnectionData *d;
   DBusList *link;
 
+  _dbus_verbose ("  trying to add message %s to transaction\n",
+                 dbus_message_get_name (message));
+  
   if (!dbus_connection_get_is_connected (connection))
     return TRUE; /* silently ignore disconnected connections */
   
@@ -789,6 +796,9 @@ bus_transaction_send_error_reply (BusTransaction  *transaction,
 
   _dbus_assert (error != NULL);
   _DBUS_ASSERT_ERROR_IS_SET (error);
+
+  _dbus_verbose ("  trying to add error %s to transaction\n",
+                 error->name);
   
   reply = dbus_message_new_error_reply (in_reply_to,
                                         error->name,
index ac2fb15..d0def78 100644 (file)
@@ -514,6 +514,7 @@ check_hello_connection (BusContext *context)
 
   if (!bus_setup_debug_client (connection))
     {
+      dbus_connection_disconnect (connection);
       dbus_connection_unref (connection);
       return TRUE;
     }
@@ -582,9 +583,6 @@ bus_dispatch_test (const DBusString *test_data_dir)
                              &error);
   if (context == NULL)
     _dbus_assert_not_reached ("could not alloc context");
-
-  check1_try_iterations (context, "create_and_hello",
-                         check_hello_connection);
   
   foo = dbus_connection_open ("debug-pipe:name=test-server", &result);
   if (foo == NULL)
@@ -610,8 +608,14 @@ bus_dispatch_test (const DBusString *test_data_dir)
   if (!check_hello_message (context, baz))
     _dbus_assert_not_reached ("hello message failed");
 
+  check1_try_iterations (context, "create_and_hello",
+                         check_hello_connection);
+
+  dbus_connection_disconnect (foo);
   dbus_connection_unref (foo);
+  dbus_connection_disconnect (bar);
   dbus_connection_unref (bar);
+  dbus_connection_disconnect (baz);
   dbus_connection_unref (baz);
   
   return TRUE;
index 1061474..ea0ec10 100644 (file)
@@ -294,9 +294,26 @@ bus_loop_iterate (dbus_bool_t block)
       bus_loop_quit ();
       goto next_iteration;
     }
+
+  /* count enabled watches */
+  n_fds = 0;
+  link = _dbus_list_get_first_link (&callbacks);
+  while (link != NULL)
+    {
+      DBusList *next = _dbus_list_get_next_link (&callbacks, link);
+      Callback *cb = link->data;
+      if (cb->type == CALLBACK_WATCH)
+        {
+          WatchCallback *wcb = WATCH_CALLBACK (cb);
+
+          if (dbus_watch_get_enabled (wcb->watch))
+            ++n_fds;
+        }
       
-  n_fds = watch_count;
+      link = next;
+    }
 
+  /* fill our array of fds and watches */
   if (n_fds > 0)
     {
       fds = dbus_new0 (DBusPollFD, n_fds);
@@ -323,18 +340,21 @@ bus_loop_iterate (dbus_bool_t block)
             {
               unsigned int flags;
               WatchCallback *wcb = WATCH_CALLBACK (cb);
+
+              if (dbus_watch_get_enabled (wcb->watch))
+                {
+                  watches_for_fds[i] = wcb;
                   
-              watches_for_fds[i] = wcb;
-                  
-              flags = dbus_watch_get_flags (wcb->watch);
+                  flags = dbus_watch_get_flags (wcb->watch);
                   
-              fds[i].fd = dbus_watch_get_fd (wcb->watch);
-              if (flags & DBUS_WATCH_READABLE)
-                fds[i].events |= _DBUS_POLLIN;
-              if (flags & DBUS_WATCH_WRITABLE)
-                fds[i].events |= _DBUS_POLLOUT;
+                  fds[i].fd = dbus_watch_get_fd (wcb->watch);
+                  if (flags & DBUS_WATCH_READABLE)
+                    fds[i].events |= _DBUS_POLLIN;
+                  if (flags & DBUS_WATCH_WRITABLE)
+                    fds[i].events |= _DBUS_POLLOUT;
 
-              ++i;
+                  ++i;
+                }
             }
               
           link = next;
@@ -359,7 +379,8 @@ bus_loop_iterate (dbus_bool_t block)
           DBusList *next = _dbus_list_get_next_link (&callbacks, link);
           Callback *cb = link->data;
 
-          if (cb->type == CALLBACK_TIMEOUT)
+          if (cb->type == CALLBACK_TIMEOUT &&
+              dbus_timeout_get_enabled (TIMEOUT_CALLBACK (cb)->timeout))
             {
               TimeoutCallback *tcb = TIMEOUT_CALLBACK (cb);
               unsigned long interval;
@@ -427,7 +448,8 @@ bus_loop_iterate (dbus_bool_t block)
           if (exited)
             goto next_iteration;
               
-          if (cb->type == CALLBACK_TIMEOUT)
+          if (cb->type == CALLBACK_TIMEOUT &&
+              dbus_timeout_get_enabled (TIMEOUT_CALLBACK (cb)->timeout))
             {
               TimeoutCallback *tcb = TIMEOUT_CALLBACK (cb);
               unsigned long interval;
@@ -513,7 +535,8 @@ bus_loop_iterate (dbus_bool_t block)
                * weird POLLFOO thing like POLLWRBAND
                */
                   
-              if (condition != 0)
+              if (condition != 0 &&
+                  dbus_watch_get_enabled (wcb->watch))
                 {
                   (* wcb->function) (wcb->watch,
                                      condition,
index 9508b2f..92f6cdf 100644 (file)
@@ -170,6 +170,8 @@ bus_registry_ensure (BusRegistry               *registry,
                                        service->name,
                                        service))
     {
+      bus_connection_remove_owned_service (owner_if_created,
+                                           service);
       _dbus_list_clear (&service->owners);
       dbus_free (service->name);
       _dbus_mem_pool_dealloc (registry->service_pool, service);
@@ -290,7 +292,11 @@ bus_service_remove_owner (BusService     *service,
         return FALSE;
     }
 
-  if (_dbus_list_length_is_one (&service->owners))
+  if (service->owners == NULL)
+    {
+      _dbus_assert_not_reached ("Tried to remove owner of a service that has no owners");
+    }
+  else if (_dbus_list_length_is_one (&service->owners))
     {
       /* We are the only owner - send service deleted */
       if (!bus_driver_send_service_deleted (service->name,
@@ -301,6 +307,7 @@ bus_service_remove_owner (BusService     *service,
     {
       DBusList *link;
       link = _dbus_list_get_first (&service->owners);
+      _dbus_assert (link != NULL);
       link = _dbus_list_get_next_link (&service->owners, link);
 
       if (link != NULL)
@@ -320,7 +327,8 @@ bus_service_remove_owner (BusService     *service,
   if (service->owners == NULL)
     {
       /* Delete service (already sent message that it was deleted above) */
-      _dbus_hash_table_remove_string (service->registry->service_hash, service->name);
+      _dbus_hash_table_remove_string (service->registry->service_hash,
+                                      service->name);
       
       dbus_free (service->name);
       _dbus_mem_pool_dealloc (service->registry->service_pool, service);
index 8d8aa49..fe4cdc4 100644 (file)
@@ -127,6 +127,7 @@ bus_setup_debug_client (DBusConnection *connection)
   if (!dbus_connection_set_watch_functions (connection,
                                             (DBusAddWatchFunction) add_client_watch,
                                             (DBusRemoveWatchFunction) remove_client_watch,
+                                            NULL,
                                             connection,
                                             NULL))
     goto out;
@@ -134,6 +135,7 @@ bus_setup_debug_client (DBusConnection *connection)
   if (!dbus_connection_set_timeout_functions (connection,
                                               (DBusAddTimeoutFunction) add_client_timeout,
                                               (DBusRemoveTimeoutFunction) remove_client_timeout,
+                                              NULL,
                                               connection, NULL))
     goto out;
 
@@ -148,9 +150,9 @@ bus_setup_debug_client (DBusConnection *connection)
                                           _DBUS_N_ELEMENTS (to_handle));
       
       dbus_connection_set_watch_functions (connection,
-                                           NULL, NULL, NULL, NULL);
+                                           NULL, NULL, NULL, NULL, NULL);
       dbus_connection_set_timeout_functions (connection,
-                                             NULL, NULL, NULL, NULL);
+                                             NULL, NULL, NULL, NULL, NULL);
     }
   
   dbus_message_handler_unref (disconnect_handler);
index 64c4cf3..4d3ed13 100644 (file)
@@ -55,10 +55,16 @@ dbus_bool_t     _dbus_connection_add_watch              (DBusConnection *connect
                                                          DBusWatch      *watch);
 void            _dbus_connection_remove_watch           (DBusConnection *connection,
                                                          DBusWatch      *watch);
+void            _dbus_connection_toggle_watch           (DBusConnection *connection,
+                                                         DBusWatch      *watch,
+                                                         dbus_bool_t     enabled);
 dbus_bool_t     _dbus_connection_add_timeout            (DBusConnection *connection,
                                                         DBusTimeout    *timeout);
 void            _dbus_connection_remove_timeout         (DBusConnection *connection,
                                                         DBusTimeout    *timeout);
+void            _dbus_connection_toggle_timeout         (DBusConnection *connection,
+                                                         DBusTimeout    *timeout,
+                                                         dbus_bool_t     enabled);
 DBusConnection* _dbus_connection_new_for_transport      (DBusTransport  *transport);
 
 void            _dbus_connection_do_iteration           (DBusConnection *connection,
index c5df561..780c410 100644 (file)
@@ -331,6 +331,25 @@ _dbus_connection_remove_watch (DBusConnection *connection,
 }
 
 /**
+ * Toggles a watch and notifies app via connection's
+ * DBusWatchToggledFunction if available. It's an error to call this
+ * function on a watch that was not previously added.
+ *
+ * @param connection the connection.
+ * @param timeout the timeout to toggle.
+ * @param enabled whether to enable or disable
+ */
+void
+_dbus_connection_toggle_watch (DBusConnection *connection,
+                               DBusWatch      *watch,
+                               dbus_bool_t     enabled)
+{
+  if (connection->watches) /* null during finalize */
+    _dbus_watch_list_toggle_watch (connection->watches,
+                                   watch, enabled);
+}
+
+/**
  * Adds a timeout using the connection's DBusAddTimeoutFunction if
  * available. Otherwise records the timeout to be added when said
  * function is available. Also re-adds the timeout if the
@@ -378,6 +397,24 @@ _dbus_connection_remove_timeout_locked (DBusConnection *connection,
   dbus_mutex_unlock (connection->mutex);
 }
 
+/**
+ * Toggles a timeout and notifies app via connection's
+ * DBusTimeoutToggledFunction if available. It's an error to call this
+ * function on a timeout that was not previously added.
+ *
+ * @param connection the connection.
+ * @param timeout the timeout to toggle.
+ * @param enabled whether to enable or disable
+ */
+void
+_dbus_connection_toggle_timeout (DBusConnection *connection,
+                                 DBusTimeout      *timeout,
+                                 dbus_bool_t     enabled)
+{
+  if (connection->timeouts) /* null during finalize */
+    _dbus_timeout_list_toggle_timeout (connection->timeouts,
+                                       timeout, enabled);
+}
 
 /**
  * Tells the connection that the transport has been disconnected.
@@ -598,8 +635,10 @@ _dbus_connection_new_for_transport (DBusTransport *transport)
 
   connection->disconnect_message_link = disconnect_link;
   
-  _dbus_transport_ref (transport);
-  _dbus_transport_set_connection (transport, connection);
+  if (!_dbus_transport_set_connection (transport, connection))
+    goto error;
+
+  _dbus_transport_ref (transport);  
   
   return connection;
   
@@ -1793,8 +1832,18 @@ dbus_connection_dispatch_message (DBusConnection *connection)
  * poll(). When using Qt, typically the DBusAddWatchFunction would
  * create a QSocketNotifier. When using GLib, the DBusAddWatchFunction
  * could call g_io_add_watch(), or could be used as part of a more
- * elaborate GSource.
- *
+ * elaborate GSource. Note that when a watch is added, it may
+ * not be enabled.
+ *
+ * The DBusWatchToggledFunction notifies the application that the
+ * watch has been enabled or disabled. Call dbus_watch_get_enabled()
+ * to check this. A disabled watch should have no effect, and enabled
+ * watch should be added to the main loop. This feature is used
+ * instead of simply adding/removing the watch because
+ * enabling/disabling can be done without memory allocation.  The
+ * toggled function may be NULL if a main loop re-queries
+ * dbus_watch_get_enabled() every time anyway.
+ * 
  * The DBusWatch can be queried for the file descriptor to watch using
  * dbus_watch_get_fd(), and for the events to watch for using
  * dbus_watch_get_flags(). The flags returned by
@@ -1825,6 +1874,7 @@ dbus_connection_dispatch_message (DBusConnection *connection)
  * @param connection the connection.
  * @param add_function function to begin monitoring a new descriptor.
  * @param remove_function function to stop monitoring a descriptor.
+ * @param toggled_function function to notify of enable/disable
  * @param data data to pass to add_function and remove_function.
  * @param free_data_function function to be called to free the data.
  * @returns #FALSE on failure (no memory)
@@ -1833,6 +1883,7 @@ dbus_bool_t
 dbus_connection_set_watch_functions (DBusConnection              *connection,
                                      DBusAddWatchFunction         add_function,
                                      DBusRemoveWatchFunction      remove_function,
+                                     DBusWatchToggledFunction     toggled_function,
                                      void                        *data,
                                      DBusFreeFunction             free_data_function)
 {
@@ -1844,6 +1895,7 @@ dbus_connection_set_watch_functions (DBusConnection              *connection,
   
   retval = _dbus_watch_list_set_functions (connection->watches,
                                            add_function, remove_function,
+                                           toggled_function,
                                            data, free_data_function);
   
   dbus_mutex_unlock (connection->mutex);
@@ -1859,6 +1911,16 @@ dbus_connection_set_watch_functions (DBusConnection              *connection,
  * When using Qt, typically the DBusAddTimeoutFunction would create a
  * QTimer. When using GLib, the DBusAddTimeoutFunction would call
  * g_timeout_add.
+ * 
+ * The DBusTimeoutToggledFunction notifies the application that the
+ * timeout has been enabled or disabled. Call
+ * dbus_timeout_get_enabled() to check this. A disabled timeout should
+ * have no effect, and enabled timeout should be added to the main
+ * loop. This feature is used instead of simply adding/removing the
+ * timeout because enabling/disabling can be done without memory
+ * allocation. With Qt, QTimer::start() and QTimer::stop() can be used
+ * to enable and disable. The toggled function may be NULL if a main
+ * loop re-queries dbus_timeout_get_enabled() every time anyway.
  *
  * The DBusTimeout can be queried for the timer interval using
  * dbus_timeout_get_interval(). dbus_timeout_handle() should
@@ -1869,6 +1931,7 @@ dbus_connection_set_watch_functions (DBusConnection              *connection,
  * @param connection the connection.
  * @param add_function function to add a timeout.
  * @param remove_function function to remove a timeout.
+ * @param toggled_function function to notify of enable/disable
  * @param data data to pass to add_function and remove_function.
  * @param free_data_function function to be called to free the data.
  * @returns #FALSE on failure (no memory)
@@ -1877,6 +1940,7 @@ dbus_bool_t
 dbus_connection_set_timeout_functions   (DBusConnection            *connection,
                                         DBusAddTimeoutFunction     add_function,
                                         DBusRemoveTimeoutFunction  remove_function,
+                                         DBusTimeoutToggledFunction toggled_function,
                                         void                      *data,
                                         DBusFreeFunction           free_data_function)
 {
@@ -1888,6 +1952,7 @@ dbus_connection_set_timeout_functions   (DBusConnection            *connection,
   
   retval = _dbus_timeout_list_set_functions (connection->timeouts,
                                              add_function, remove_function,
+                                             toggled_function,
                                              data, free_data_function);
   
   dbus_mutex_unlock (connection->mutex);
index bf0983e..78a8d58 100644 (file)
@@ -56,15 +56,19 @@ typedef enum
                                  *   can be present in current state). */
 } DBusWatchFlags;
 
-typedef dbus_bool_t (* DBusAddWatchFunction)      (DBusWatch      *watch,
-                                                   void           *data);
-typedef void        (* DBusRemoveWatchFunction)   (DBusWatch      *watch,
-                                                   void           *data);
-typedef void        (* DBusWakeupMainFunction)    (void           *data);
-typedef dbus_bool_t (* DBusAddTimeoutFunction)    (DBusTimeout    *timeout,
-                                                   void           *data);
-typedef void        (* DBusRemoveTimeoutFunction) (DBusTimeout    *timeout,
-                                                   void           *data);
+typedef dbus_bool_t (* DBusAddWatchFunction)       (DBusWatch      *watch,
+                                                    void           *data);
+typedef void        (* DBusWatchToggledFunction)   (DBusWatch      *watch,
+                                                    void           *data);
+typedef void        (* DBusRemoveWatchFunction)    (DBusWatch      *watch,
+                                                    void           *data);
+typedef void        (* DBusWakeupMainFunction)     (void           *data);
+typedef dbus_bool_t (* DBusAddTimeoutFunction)     (DBusTimeout    *timeout,
+                                                    void           *data);
+typedef void        (* DBusTimeoutToggledFunction) (DBusTimeout    *timeout,
+                                                    void           *data);
+typedef void        (* DBusRemoveTimeoutFunction)  (DBusTimeout    *timeout,
+                                                    void           *data);
 
 DBusConnection* dbus_connection_open                   (const char     *address,
                                                        DBusResultCode *result);
@@ -100,11 +104,13 @@ DBusMessage *dbus_connection_send_with_reply_and_block (DBusConnection     *conn
 dbus_bool_t dbus_connection_set_watch_functions      (DBusConnection            *connection,
                                                       DBusAddWatchFunction       add_function,
                                                       DBusRemoveWatchFunction    remove_function,
+                                                      DBusWatchToggledFunction   toggled_function,
                                                       void                      *data,
                                                       DBusFreeFunction           free_data_function);
 dbus_bool_t dbus_connection_set_timeout_functions    (DBusConnection            *connection,
                                                       DBusAddTimeoutFunction     add_function,
                                                       DBusRemoveTimeoutFunction  remove_function,
+                                                      DBusTimeoutToggledFunction toggled_function,
                                                       void                      *data,
                                                       DBusFreeFunction           free_data_function);
 void        dbus_connection_set_wakeup_main_function (DBusConnection            *connection,
@@ -118,20 +124,21 @@ void        dbus_connection_handle_watch             (DBusConnection
 
 
 
-int          dbus_watch_get_fd    (DBusWatch        *watch);
-unsigned int dbus_watch_get_flags (DBusWatch        *watch);
-void*        dbus_watch_get_data  (DBusWatch        *watch);
-void         dbus_watch_set_data  (DBusWatch        *watch,
-                                   void             *data,
-                                   DBusFreeFunction  free_data_function);
-
-int   dbus_timeout_get_interval (DBusTimeout      *timeout);
-void* dbus_timeout_get_data     (DBusTimeout      *timeout);
-void  dbus_timeout_set_data     (DBusTimeout      *timeout,
-                                void             *data,
-                                DBusFreeFunction  free_data_function);
-void  dbus_timeout_handle       (DBusTimeout      *timeout);
+int          dbus_watch_get_fd      (DBusWatch        *watch);
+unsigned int dbus_watch_get_flags   (DBusWatch        *watch);
+void*        dbus_watch_get_data    (DBusWatch        *watch);
+void         dbus_watch_set_data    (DBusWatch        *watch,
+                                     void             *data,
+                                     DBusFreeFunction  free_data_function);
+dbus_bool_t  dbus_watch_get_enabled (DBusWatch        *watch);
 
+int         dbus_timeout_get_interval (DBusTimeout      *timeout);
+void*       dbus_timeout_get_data     (DBusTimeout      *timeout);
+void        dbus_timeout_set_data     (DBusTimeout      *timeout,
+                                       void             *data,
+                                       DBusFreeFunction  free_data_function);
+void        dbus_timeout_handle       (DBusTimeout      *timeout);
+dbus_bool_t dbus_timeout_get_enabled  (DBusTimeout      *timeout);
 
 /* Handlers */
 dbus_bool_t dbus_connection_add_filter         (DBusConnection      *connection,
index 24b805c..bbedeea 100644 (file)
@@ -78,16 +78,22 @@ struct DBusServer
 };
 
 dbus_bool_t _dbus_server_init_base      (DBusServer             *server,
-                                        const DBusServerVTable *vtable);
+                                         const DBusServerVTable *vtable);
 void        _dbus_server_finalize_base  (DBusServer             *server);
 dbus_bool_t _dbus_server_add_watch      (DBusServer             *server,
-                                        DBusWatch              *watch);
+                                         DBusWatch              *watch);
 void        _dbus_server_remove_watch   (DBusServer             *server,
-                                        DBusWatch              *watch);
+                                         DBusWatch              *watch);
+void        _dbus_server_toggle_watch   (DBusServer             *server,
+                                         DBusWatch              *watch,
+                                         dbus_bool_t             enabled);
 dbus_bool_t _dbus_server_add_timeout    (DBusServer             *server,
-                                        DBusTimeout            *timeout);
+                                         DBusTimeout            *timeout);
 void        _dbus_server_remove_timeout (DBusServer             *server,
-                                        DBusTimeout            *timeout);
+                                         DBusTimeout            *timeout);
+void        _dbus_server_toggle_timeout (DBusServer             *server,
+                                         DBusTimeout            *timeout,
+                                         dbus_bool_t             enabled);
 
 
 
index 0a98c53..a181a92 100644 (file)
@@ -204,7 +204,8 @@ _dbus_server_new_for_fd (int fd)
   DBusWatch *watch;
 
   watch = _dbus_watch_new (fd,
-                           DBUS_WATCH_READABLE);
+                           DBUS_WATCH_READABLE,
+                           TRUE);
   if (watch == NULL)
     return NULL;
   
index 80ee6fc..48703e1 100644 (file)
@@ -146,6 +146,25 @@ _dbus_server_remove_watch  (DBusServer *server,
 }
 
 /**
+ * Toggles a watch and notifies app via server's
+ * DBusWatchToggledFunction if available. It's an error to call this
+ * function on a watch that was not previously added.
+ *
+ * @param server the server.
+ * @param timeout the timeout to toggle.
+ * @param enabled whether to enable or disable
+ */
+void
+_dbus_server_toggle_watch (DBusServer  *server,
+                           DBusWatch   *watch,
+                           dbus_bool_t  enabled)
+{
+  if (server->watches) /* null during finalize */
+    _dbus_watch_list_toggle_watch (server->watches,
+                                   watch, enabled);
+}
+
+/**
  * Adds a timeout for this server, chaining out to
  * application-provided timeout handlers. The timeout should be
  * repeatedly handled with dbus_timeout_handle() at its given interval
@@ -174,6 +193,26 @@ _dbus_server_remove_timeout (DBusServer  *server,
   _dbus_timeout_list_remove_timeout (server->timeouts, timeout);  
 }
 
+/**
+ * Toggles a timeout and notifies app via server's
+ * DBusTimeoutToggledFunction if available. It's an error to call this
+ * function on a timeout that was not previously added.
+ *
+ * @param server the server.
+ * @param timeout the timeout to toggle.
+ * @param enabled whether to enable or disable
+ */
+void
+_dbus_server_toggle_timeout (DBusServer  *server,
+                             DBusTimeout *timeout,
+                             dbus_bool_t  enabled)
+{
+  if (server->timeouts) /* null during finalize */
+    _dbus_timeout_list_toggle_timeout (server->timeouts,
+                                       timeout, enabled);
+}
+
+
 /** @} */
 
 /**
@@ -405,6 +444,7 @@ dbus_server_set_new_connection_function (DBusServer                *server,
  * @param server the server.
  * @param add_function function to begin monitoring a new descriptor.
  * @param remove_function function to stop monitoring a descriptor.
+ * @param toggled_function function to notify when the watch is enabled/disabled
  * @param data data to pass to add_function and remove_function.
  * @param free_data_function function to be called to free the data.
  * @returns #FALSE on failure (no memory)
@@ -413,12 +453,14 @@ dbus_bool_t
 dbus_server_set_watch_functions (DBusServer              *server,
                                  DBusAddWatchFunction     add_function,
                                  DBusRemoveWatchFunction  remove_function,
+                                 DBusWatchToggledFunction toggled_function,
                                  void                    *data,
                                  DBusFreeFunction         free_data_function)
 {
   return _dbus_watch_list_set_functions (server->watches,
                                          add_function,
                                          remove_function,
+                                         toggled_function,
                                          data,
                                          free_data_function);
 }
@@ -433,6 +475,7 @@ dbus_server_set_watch_functions (DBusServer              *server,
  * @param server the server.
  * @param add_function function to add a timeout.
  * @param remove_function function to remove a timeout.
+ * @param toggled_function function to notify when the timeout is enabled/disabled
  * @param data data to pass to add_function and remove_function.
  * @param free_data_function function to be called to free the data.
  * @returns #FALSE on failure (no memory)
@@ -441,11 +484,13 @@ dbus_bool_t
 dbus_server_set_timeout_functions (DBusServer                *server,
                                   DBusAddTimeoutFunction     add_function,
                                   DBusRemoveTimeoutFunction  remove_function,
+                                   DBusTimeoutToggledFunction toggled_function,
                                   void                      *data,
                                   DBusFreeFunction           free_data_function)
 {
   return _dbus_timeout_list_set_functions (server->timeouts,
                                            add_function, remove_function,
+                                           toggled_function,
                                            data, free_data_function); 
 }
 
index 6665335..589237f 100644 (file)
@@ -52,11 +52,13 @@ void        dbus_server_set_new_connection_function (DBusServer                *
 dbus_bool_t dbus_server_set_watch_functions         (DBusServer                *server,
                                                      DBusAddWatchFunction       add_function,
                                                      DBusRemoveWatchFunction    remove_function,
+                                                     DBusWatchToggledFunction   toggled_function,
                                                      void                      *data,
                                                      DBusFreeFunction           free_data_function);
 dbus_bool_t dbus_server_set_timeout_functions       (DBusServer                *server,
                                                      DBusAddTimeoutFunction     add_function,
                                                      DBusRemoveTimeoutFunction  remove_function,
+                                                     DBusTimeoutToggledFunction toggled_function,
                                                      void                      *data,
                                                      DBusFreeFunction           free_data_function);
 void        dbus_server_handle_watch                (DBusServer                *server,
index 09e54b3..9825872 100644 (file)
@@ -44,6 +44,7 @@ struct DBusTimeout
   
   void *data;                                 /**< Application data. */
   DBusFreeFunction free_data_function;         /**< Free the application data. */
+  unsigned int enabled : 1;                    /**< True if timeout is active. */
 };
 
 /**
@@ -69,6 +70,8 @@ _dbus_timeout_new (int                 interval,
   timeout->handler = handler;
   timeout->handler_data = data;
   timeout->free_handler_data_function = free_data_function;
+
+  timeout->enabled = TRUE;
   
   return timeout;
 }
@@ -130,6 +133,7 @@ struct DBusTimeoutList
 
   DBusAddTimeoutFunction add_timeout_function;       /**< Callback for adding a timeout. */
   DBusRemoveTimeoutFunction remove_timeout_function; /**< Callback for removing a timeout. */
+  DBusTimeoutToggledFunction timeout_toggled_function; /**< Callback when timeout is enabled/disabled */
   void *timeout_data;                                /**< Data for timeout callbacks */
   DBusFreeFunction timeout_free_data_function;       /**< Free function for timeout callback data */
 };
@@ -162,7 +166,7 @@ _dbus_timeout_list_free (DBusTimeoutList *timeout_list)
 {
   /* free timeout_data and remove timeouts as a side effect */
   _dbus_timeout_list_set_functions (timeout_list,
-                                   NULL, NULL, NULL, NULL);
+                                   NULL, NULL, NULL, NULL, NULL);
 
   _dbus_list_foreach (&timeout_list->timeouts,
                      (DBusForeachFunction) _dbus_timeout_unref,
@@ -179,6 +183,7 @@ _dbus_timeout_list_free (DBusTimeoutList *timeout_list)
  * @param timeout_list the timeout list
  * @param add_function the add timeout function.
  * @param remove_function the remove timeout function.
+ * @param toggled_function toggle notify function, or #NULL
  * @param data the data for those functions.
  * @param free_data_function the function to free the data.
  * @returns #FALSE if no memory
@@ -188,6 +193,7 @@ dbus_bool_t
 _dbus_timeout_list_set_functions (DBusTimeoutList           *timeout_list,
                                  DBusAddTimeoutFunction     add_function,
                                  DBusRemoveTimeoutFunction  remove_function,
+                                  DBusTimeoutToggledFunction toggled_function,
                                  void                      *data,
                                  DBusFreeFunction           free_data_function)
 {
@@ -239,6 +245,7 @@ _dbus_timeout_list_set_functions (DBusTimeoutList           *timeout_list,
 
   timeout_list->add_timeout_function = add_function;
   timeout_list->remove_timeout_function = remove_function;
+  timeout_list->timeout_toggled_function = toggled_function;
   timeout_list->timeout_data = data;
   timeout_list->timeout_free_data_function = free_data_function;
 
@@ -297,6 +304,31 @@ _dbus_timeout_list_remove_timeout (DBusTimeoutList *timeout_list,
   _dbus_timeout_unref (timeout);
 }
 
+/**
+ * Sets a timeout to the given enabled state, invoking the
+ * application's DBusTimeoutToggledFunction if appropriate.
+ *
+ * @param timeout_list the timeout list.
+ * @param timeout the timeout to toggle.
+ * @param enabled #TRUE to enable
+ */
+void
+_dbus_timeout_list_toggle_timeout (DBusTimeoutList           *timeout_list,
+                                   DBusTimeout               *timeout,
+                                   dbus_bool_t                enabled)
+{
+  enabled = !!enabled;
+  
+  if (enabled == timeout->enabled)
+    return;
+
+  timeout->enabled = enabled;
+  
+  if (timeout_list->timeout_toggled_function != NULL)
+    (* timeout_list->timeout_toggled_function) (timeout,
+                                                timeout_list->timeout_data);
+}
+
 /** @} */
 
 /**
@@ -380,3 +412,19 @@ dbus_timeout_handle (DBusTimeout *timeout)
 {
   (* timeout->handler) (timeout->handler_data);
 }
+
+
+/**
+ * Returns whether a timeout is enabled or not. If not
+ * enabled, it should not be polled by the main loop.
+ *
+ * @param timeout the DBusTimeout object
+ * @returns #TRUE if the timeout is enabled
+ */
+dbus_bool_t
+dbus_timeout_get_enabled (DBusTimeout *timeout)
+{
+  return timeout->enabled;
+}
+
+/** @} end public API docs */
index 2d7112a..0ff5dc5 100644 (file)
@@ -46,12 +46,16 @@ void             _dbus_timeout_list_free           (DBusTimeoutList           *t
 dbus_bool_t      _dbus_timeout_list_set_functions  (DBusTimeoutList           *timeout_list,
                                                    DBusAddTimeoutFunction     add_function,
                                                    DBusRemoveTimeoutFunction  remove_function,
+                                                    DBusTimeoutToggledFunction toggled_function,
                                                    void                      *data,
                                                    DBusFreeFunction           free_data_function);
 dbus_bool_t      _dbus_timeout_list_add_timeout    (DBusTimeoutList           *timeout_list,
                                                    DBusTimeout               *timeout);
 void             _dbus_timeout_list_remove_timeout (DBusTimeoutList           *timeout_list,
                                                    DBusTimeout               *timeout);
+void             _dbus_timeout_list_toggle_timeout (DBusTimeoutList           *timeout_list,
+                                                    DBusTimeout               *timeout,
+                                                    dbus_bool_t                enabled);
 
 
 DBUS_END_DECLS;
index 42d1efd..a7db3a6 100644 (file)
@@ -147,10 +147,8 @@ check_timeout (DBusTransport *transport)
     {
       if (!debug_transport->timeout_added)
         {
-          /* FIXME; messages_pending is going to have to
-           * handle OOM somehow (probably being part of
-           * PreallocatedSend). See also dbus-transport-unix.c
-           * check_write_watch()
+          /* FIXME this can be fixed now, by enabling/disabling
+           * the timeout instead of adding it here
            */
           while (!_dbus_connection_add_timeout (transport->connection,
                                                 debug_transport->timeout))
@@ -203,10 +201,11 @@ debug_disconnect (DBusTransport *transport)
 {
 }
 
-static void
+static dbus_bool_t
 debug_connection_set (DBusTransport *transport)
 {
   check_timeout (transport);
+  return TRUE;
 }
 
 static void
index 46dfe14..0f6c45e 100644 (file)
@@ -49,7 +49,7 @@ struct DBusTransportVTable
   void (* disconnect)         (DBusTransport *transport);
   /**< Disconnect this transport. */
 
-  void (* connection_set)     (DBusTransport *transport);
+  dbus_bool_t (* connection_set)     (DBusTransport *transport);
   /**< Called when transport->connection has been filled in */
 
   void (* messages_pending)   (DBusTransport *transport,
index 3c5fe84..23ab7c5 100644 (file)
@@ -117,6 +117,12 @@ check_write_watch (DBusTransport *transport)
 
   if (transport->connection == NULL)
     return;
+
+  if (transport->disconnected)
+    {
+      _dbus_assert (unix_transport->write_watch == NULL);
+      return;
+    }
   
   _dbus_transport_ref (transport);
 
@@ -126,51 +132,10 @@ check_write_watch (DBusTransport *transport)
     need_write_watch = transport->send_credentials_pending ||
       _dbus_auth_do_work (transport->auth) == DBUS_AUTH_STATE_HAVE_BYTES_TO_SEND;
 
-  if (transport->disconnected)
-    need_write_watch = FALSE;
-  
-  if (need_write_watch &&
-      unix_transport->write_watch == NULL)
-    {
-      unix_transport->write_watch =
-        _dbus_watch_new (unix_transport->fd,
-                         DBUS_WATCH_WRITABLE);
-
-      /* FIXME this is total crack. The proper fix is probably to
-       * allocate the write watch on transport creation, keep it
-       * allocated. But that doesn't solve needing memory to add the
-       * watch.  messages_pending is going to have to handle OOM
-       * somehow (probably being part of PreallocatedSend)
-       */
-      if (unix_transport->write_watch == NULL)
-        goto out;
+  _dbus_connection_toggle_watch (transport->connection,
+                                 unix_transport->write_watch,
+                                 need_write_watch);
 
-      if (!_dbus_connection_add_watch (transport->connection,
-                                       unix_transport->write_watch))
-        {
-          _dbus_watch_invalidate (unix_transport->write_watch);
-          _dbus_watch_unref (unix_transport->write_watch);
-          unix_transport->write_watch = NULL;
-        }
-    }
-  else if (!need_write_watch &&
-           unix_transport->write_watch != NULL)
-    {
-      _dbus_connection_remove_watch (transport->connection,
-                                     unix_transport->write_watch);
-      _dbus_watch_invalidate (unix_transport->write_watch);
-      _dbus_watch_unref (unix_transport->write_watch);
-      unix_transport->write_watch = NULL;
-    }
-  else
-    {
-#if 0
-      _dbus_verbose ("Write watch is unchanged from %p on fd %d\n",
-                     unix_transport->write_watch, unix_transport->fd);
-#endif
-    }
-  
- out:
   _dbus_transport_unref (transport);
 }
 
@@ -182,6 +147,12 @@ check_read_watch (DBusTransport *transport)
 
   if (transport->connection == NULL)
     return;
+
+  if (transport->disconnected)
+    {
+      _dbus_assert (unix_transport->read_watch == NULL);
+      return;
+    }
   
   _dbus_transport_ref (transport);
 
@@ -192,57 +163,10 @@ check_read_watch (DBusTransport *transport)
     need_read_watch = transport->receive_credentials_pending ||
       _dbus_auth_do_work (transport->auth) == DBUS_AUTH_STATE_WAITING_FOR_INPUT;
 
-#if 0
-  _dbus_verbose ("need_read_watch = %d authenticated = %d\n",
-                 need_read_watch, _dbus_transport_get_is_authenticated (transport));
-#endif
-  
-  if (transport->disconnected)
-    need_read_watch = FALSE;
-  
-  if (need_read_watch &&
-      unix_transport->read_watch == NULL)
-    {
-      _dbus_verbose ("Adding read watch to unix fd %d\n",
-                     unix_transport->fd);
-      
-      unix_transport->read_watch =
-        _dbus_watch_new (unix_transport->fd,
-                         DBUS_WATCH_READABLE);
+  _dbus_connection_toggle_watch (transport->connection,
+                                 unix_transport->read_watch,
+                                 need_read_watch);
 
-      /* we can maybe add it some other time, just silently bomb */
-      if (unix_transport->read_watch == NULL)
-        goto out;
-
-      if (!_dbus_connection_add_watch (transport->connection,
-                                       unix_transport->read_watch))
-        {
-          _dbus_watch_invalidate (unix_transport->read_watch);
-          _dbus_watch_unref (unix_transport->read_watch);
-          unix_transport->read_watch = NULL;
-        }
-    }
-  else if (!need_read_watch &&
-           unix_transport->read_watch != NULL)
-    {
-      _dbus_verbose ("Removing read watch from unix fd %d\n",
-                     unix_transport->fd);
-      
-      _dbus_connection_remove_watch (transport->connection,
-                                     unix_transport->read_watch);
-      _dbus_watch_invalidate (unix_transport->read_watch);
-      _dbus_watch_unref (unix_transport->read_watch);
-      unix_transport->read_watch = NULL;
-    }
-  else
-    {
-#if 0
-      _dbus_verbose ("Read watch is unchanged from %p on fd %d\n",
-                     unix_transport->read_watch, unix_transport->fd);
-#endif
-    }
-  
- out:
   _dbus_transport_unref (transport);
 }
 
@@ -908,11 +832,27 @@ unix_disconnect (DBusTransport *transport)
   unix_transport->fd = -1;
 }
 
-static void
+static dbus_bool_t
 unix_connection_set (DBusTransport *transport)
 {
+  DBusTransportUnix *unix_transport = (DBusTransportUnix*) transport;
+  
+  if (!_dbus_connection_add_watch (transport->connection,
+                                   unix_transport->write_watch))
+    return FALSE;
+
+  if (!_dbus_connection_add_watch (transport->connection,
+                                   unix_transport->read_watch))
+    {
+      _dbus_connection_remove_watch (transport->connection,
+                                     unix_transport->write_watch);
+      return FALSE;
+    }
+
   check_read_watch (transport);
   check_write_watch (transport);
+
+  return TRUE;
 }
 
 static void
@@ -1120,19 +1060,24 @@ _dbus_transport_new_for_fd (int         fd,
 
   if (!_dbus_string_init (&unix_transport->encoded_message,
                           _DBUS_INT_MAX))
-    {
-      dbus_free (unix_transport);
-      return NULL;
-    }
+    goto failed_0;
+
+  unix_transport->write_watch = _dbus_watch_new (fd,
+                                                 DBUS_WATCH_WRITABLE,
+                                                 FALSE);
+  if (unix_transport->write_watch == NULL)
+    goto failed_1;
+  
+  unix_transport->read_watch = _dbus_watch_new (fd,
+                                                DBUS_WATCH_READABLE,
+                                                FALSE);
+  if (unix_transport->read_watch == NULL)
+    goto failed_2;
   
   if (!_dbus_transport_init_base (&unix_transport->base,
                                   &unix_vtable,
                                   server))
-    {
-      _dbus_string_free (&unix_transport->encoded_message);
-      dbus_free (unix_transport);
-      return NULL;
-    }
+    goto failed_3;
   
   unix_transport->fd = fd;
   unix_transport->message_bytes_written = 0;
@@ -1140,11 +1085,18 @@ _dbus_transport_new_for_fd (int         fd,
   /* These values should probably be tunable or something. */     
   unix_transport->max_bytes_read_per_iteration = 2048;
   unix_transport->max_bytes_written_per_iteration = 2048;
-
-  check_read_watch ((DBusTransport*) unix_transport);
-  check_write_watch ((DBusTransport*) unix_transport);
   
   return (DBusTransport*) unix_transport;
+
+ failed_3:
+  _dbus_watch_unref (unix_transport->read_watch);
+ failed_2:
+  _dbus_watch_unref (unix_transport->write_watch);
+ failed_1:
+  _dbus_string_free (&unix_transport->encoded_message);  
+ failed_0:
+  dbus_free (unix_transport);
+  return NULL;
 }
 
 /**
index 03fea75..8c6c7f1 100644 (file)
@@ -427,8 +427,9 @@ _dbus_transport_handle_watch (DBusTransport           *transport,
  *
  * @param transport the transport.
  * @param connection the connection.
+ * @returns #FALSE if not enough memory
  */
-void
+dbus_bool_t
 _dbus_transport_set_connection (DBusTransport  *transport,
                                 DBusConnection *connection)
 {
@@ -438,8 +439,11 @@ _dbus_transport_set_connection (DBusTransport  *transport,
   transport->connection = connection;
 
   _dbus_transport_ref (transport);
-  (* transport->vtable->connection_set) (transport);
+  if (!(* transport->vtable->connection_set) (transport))
+    transport->connection = NULL;
   _dbus_transport_unref (transport);
+
+  return transport->connection != NULL;
 }
 
 /**
index 5e7de3e..1f01788 100644 (file)
@@ -40,7 +40,7 @@ dbus_bool_t    _dbus_transport_get_is_authenticated       (DBusTransport  *trans
 void           _dbus_transport_handle_watch               (DBusTransport  *transport,
                                                            DBusWatch      *watch,
                                                            unsigned int    condition);
-void           _dbus_transport_set_connection             (DBusTransport  *transport,
+dbus_bool_t    _dbus_transport_set_connection             (DBusTransport  *transport,
                                                            DBusConnection *connection);
 void           _dbus_transport_messages_pending           (DBusTransport  *transport,
                                                            int             queue_length);
index ef2a0ed..1fdbc7a 100644 (file)
@@ -1,7 +1,7 @@
 /* -*- mode: C; c-file-style: "gnu" -*- */
 /* dbus-watch.c DBusWatch implementation
  *
- * Copyright (C) 2002  Red Hat Inc.
+ * Copyright (C) 2002, 2003  Red Hat Inc.
  *
  * Licensed under the Academic Free License version 1.2
  * 
@@ -40,6 +40,7 @@ struct DBusWatch
   unsigned int flags;                  /**< Conditions to watch. */
   void *data;                          /**< Application data. */
   DBusFreeFunction free_data_function; /**< Free the application data. */
+  unsigned int enabled : 1;            /**< Whether it's enabled. */
 };
 
 /**
@@ -47,11 +48,13 @@ struct DBusWatch
  * implementation.
  * @param fd the file descriptor to be watched.
  * @param flags the conditions to watch for on the descriptor.
+ * @param enabled the initial enabled state
  * @returns the new DBusWatch object.
  */
 DBusWatch*
 _dbus_watch_new (int          fd,
-                 unsigned int flags)
+                 unsigned int flags,
+                 dbus_bool_t  enabled)
 {
   DBusWatch *watch;
 
@@ -63,6 +66,7 @@ _dbus_watch_new (int          fd,
   watch->refcount = 1;
   watch->fd = fd;
   watch->flags = flags;
+  watch->enabled = enabled;
 
   return watch;
 }
@@ -160,6 +164,7 @@ struct DBusWatchList
 
   DBusAddWatchFunction add_watch_function;    /**< Callback for adding a watch. */
   DBusRemoveWatchFunction remove_watch_function; /**< Callback for removing a watch. */
+  DBusWatchToggledFunction watch_toggled_function; /**< Callback on toggling enablement */
   void *watch_data;                           /**< Data for watch callbacks */
   DBusFreeFunction watch_free_data_function;  /**< Free function for watch callback data */
 };
@@ -192,7 +197,7 @@ _dbus_watch_list_free (DBusWatchList *watch_list)
 {
   /* free watch_data and removes watches as a side effect */
   _dbus_watch_list_set_functions (watch_list,
-                                  NULL, NULL, NULL, NULL);
+                                  NULL, NULL, NULL, NULL, NULL);
   
   _dbus_list_foreach (&watch_list->watches,
                       (DBusForeachFunction) _dbus_watch_unref,
@@ -210,6 +215,7 @@ _dbus_watch_list_free (DBusWatchList *watch_list)
  * @param watch_list the watch list.
  * @param add_function the add watch function.
  * @param remove_function the remove watch function.
+ * @param toggled_function function on toggling enabled flag, or #NULL
  * @param data the data for those functions.
  * @param free_data_function the function to free the data.
  * @returns #FALSE if not enough memory
@@ -219,6 +225,7 @@ dbus_bool_t
 _dbus_watch_list_set_functions (DBusWatchList           *watch_list,
                                 DBusAddWatchFunction     add_function,
                                 DBusRemoveWatchFunction  remove_function,
+                                DBusWatchToggledFunction toggled_function,
                                 void                    *data,
                                 DBusFreeFunction         free_data_function)
 {
@@ -270,6 +277,7 @@ _dbus_watch_list_set_functions (DBusWatchList           *watch_list,
   
   watch_list->add_watch_function = add_function;
   watch_list->remove_watch_function = remove_function;
+  watch_list->watch_toggled_function = toggled_function;
   watch_list->watch_data = data;
   watch_list->watch_free_data_function = free_data_function;
 
@@ -328,6 +336,31 @@ _dbus_watch_list_remove_watch  (DBusWatchList *watch_list,
   _dbus_watch_unref (watch);
 }
 
+/**
+ * Sets a watch to the given enabled state, invoking the
+ * application's DBusWatchToggledFunction if appropriate.
+ *
+ * @param watch_list the watch list.
+ * @param watch the watch to toggle.
+ * @param enabled #TRUE to enable
+ */
+void
+_dbus_watch_list_toggle_watch (DBusWatchList           *watch_list,
+                               DBusWatch               *watch,
+                               dbus_bool_t              enabled)
+{
+  enabled = !!enabled;
+  
+  if (enabled == watch->enabled)
+    return;
+
+  watch->enabled = enabled;
+  
+  if (watch_list->watch_toggled_function != NULL)
+    (* watch_list->watch_toggled_function) (watch,
+                                            watch_list->watch_data);
+}
+
 /** @} */
 
 /**
@@ -419,4 +452,17 @@ dbus_watch_set_data (DBusWatch        *watch,
   watch->free_data_function = free_data_function;
 }
 
+/**
+ * Returns whether a watch is enabled or not. If not
+ * enabled, it should not be polled by the main loop.
+ *
+ * @param watch the DBusWatch object
+ * @returns #TRUE if the watch is enabled
+ */
+dbus_bool_t
+dbus_watch_get_enabled (DBusWatch *watch)
+{
+  return watch->enabled;
+}
+
 /** @} */
index 9d85737..7a9ec57 100644 (file)
@@ -33,7 +33,8 @@ DBUS_BEGIN_DECLS;
 typedef struct DBusWatchList DBusWatchList;
 
 DBusWatch* _dbus_watch_new        (int           fd,
-                                   unsigned int  flags);
+                                   unsigned int  flags,
+                                   dbus_bool_t   enabled);
 void       _dbus_watch_ref        (DBusWatch    *watch);
 void       _dbus_watch_unref      (DBusWatch    *watch);
 void       _dbus_watch_invalidate (DBusWatch    *watch);
@@ -46,13 +47,16 @@ void           _dbus_watch_list_free          (DBusWatchList           *watch_li
 dbus_bool_t    _dbus_watch_list_set_functions (DBusWatchList           *watch_list,
                                                DBusAddWatchFunction     add_function,
                                                DBusRemoveWatchFunction  remove_function,
+                                               DBusWatchToggledFunction toggled_function,
                                                void                    *data,
                                                DBusFreeFunction         free_data_function);
 dbus_bool_t    _dbus_watch_list_add_watch     (DBusWatchList           *watch_list,
                                                DBusWatch               *watch);
 void           _dbus_watch_list_remove_watch  (DBusWatchList           *watch_list,
                                                DBusWatch               *watch);
-
+void           _dbus_watch_list_toggle_watch  (DBusWatchList           *watch_list,
+                                               DBusWatch               *watch,
+                                               dbus_bool_t              enabled);
 
 
 DBUS_END_DECLS;
index 6ce1388..5eb75d1 100644 (file)
@@ -238,6 +238,9 @@ add_watch (DBusWatch *watch,
   GPollFD *poll_fd;
   DBusGSource *dbus_source;
   guint flags;
+
+  if (!dbus_watch_get_enabled (watch))
+    return TRUE;
   
   dbus_source = data;
   
@@ -269,6 +272,8 @@ remove_watch (DBusWatch *watch,
   GPollFD *poll_fd;
   
   poll_fd = dbus_watch_get_data (watch);
+  if (poll_fd == NULL)
+    return; /* probably a not-enabled watch that was added */
   
   dbus_source->poll_fds = g_list_remove (dbus_source->poll_fds, poll_fd);
   g_hash_table_remove (dbus_source->watches, poll_fd);
@@ -277,6 +282,19 @@ remove_watch (DBusWatch *watch,
   g_free (poll_fd);
 }
 
+static void
+watch_toggled (DBusWatch *watch,
+               void      *data)
+{
+  /* Because we just exit on OOM, enable/disable is
+   * no different from add/remove
+   */
+  if (dbus_watch_get_enabled (watch))
+    add_watch (watch, data);
+  else
+    remove_watch (watch, data);
+}
+
 static gboolean
 timeout_handler (gpointer data)
 {
@@ -293,6 +311,9 @@ add_timeout (DBusTimeout *timeout,
 {
   guint timeout_tag;
 
+  if (!dbus_timeout_get_enabled (timeout))
+    return TRUE;
+  
   timeout_tag = g_timeout_add (dbus_timeout_get_interval (timeout),
                               timeout_handler, timeout);
   
@@ -308,10 +329,25 @@ remove_timeout (DBusTimeout *timeout,
   guint timeout_tag;
   
   timeout_tag = GPOINTER_TO_UINT (dbus_timeout_get_data (timeout));
-  
-  g_source_remove (timeout_tag);
+
+  if (timeout_tag != 0) /* if 0, probably timeout was disabled */
+    g_source_remove (timeout_tag);
+}
+
+static void
+timeout_toggled (DBusTimeout *timeout,
+                 void        *data)
+{
+  /* Because we just exit on OOM, enable/disable is
+   * no different from add/remove
+   */
+  if (dbus_timeout_get_enabled (timeout))
+    add_timeout (timeout, data);
+  else
+    remove_timeout (timeout, data);
 }
 
+
 static void
 free_source (GSource *source)
 {
@@ -363,12 +399,14 @@ dbus_connection_setup_with_g_main (DBusConnection *connection)
   if (!dbus_connection_set_watch_functions (connection,
                                             add_watch,
                                             remove_watch,
+                                            watch_toggled,
                                             source, NULL))
     goto nomem;
 
   if (!dbus_connection_set_timeout_functions (connection,
                                               add_timeout,
                                               remove_timeout,
+                                              timeout_toggled,
                                               NULL, NULL))
     goto nomem;
     
@@ -412,11 +450,13 @@ dbus_server_setup_with_g_main (DBusServer *server)
   dbus_server_set_watch_functions (server,
                                    add_watch,
                                    remove_watch,
+                                   watch_toggled,
                                    source, NULL);
 
   dbus_server_set_timeout_functions (server,
                                      add_timeout,
                                      remove_timeout,
+                                     timeout_toggled,
                                      NULL, NULL);
   
   g_source_attach (source, NULL);
index 73f5e97..bdb1830 100644 (file)
@@ -237,24 +237,28 @@ do_mainloop (void)
       while (link != NULL)
         {
           DBusList *next = _dbus_list_get_next_link (&watches, link);
-          int fd;
           DBusWatch *watch;
-          unsigned int flags;
           
           watch = link->data;
-          
-          fd = dbus_watch_get_fd (watch);
-          flags = dbus_watch_get_flags (watch);
-          
-          max_fd = MAX (max_fd, fd);
-          
-          if (flags & DBUS_WATCH_READABLE)
-            FD_SET (fd, &read_set);
-
-          if (flags & DBUS_WATCH_WRITABLE)
-            FD_SET (fd, &write_set);
 
-          FD_SET (fd, &err_set);
+          if (dbus_watch_get_enabled (watch))
+            {
+              int fd;
+              unsigned int flags;
+
+              fd = dbus_watch_get_fd (watch);
+              flags = dbus_watch_get_flags (watch);
+              
+              max_fd = MAX (max_fd, fd);
+              
+              if (flags & DBUS_WATCH_READABLE)
+                FD_SET (fd, &read_set);
+              
+              if (flags & DBUS_WATCH_WRITABLE)
+                FD_SET (fd, &write_set);
+              
+              FD_SET (fd, &err_set);
+            }
           
           link = next;
         }
@@ -266,10 +270,7 @@ do_mainloop (void)
       while (link != NULL)
         {
           DBusList *next = _dbus_list_get_next_link (&watches, link);
-          int fd;
           DBusWatch *watch;
-          unsigned int flags;
-          unsigned int condition;
 
           if (initial_watch_serial != watch_list_serial)
             {
@@ -286,44 +287,52 @@ do_mainloop (void)
             }
           
           watch = link->data;
+
+          if (dbus_watch_get_enabled (watch))
+            {
+              int fd;
+              unsigned int flags;
+              unsigned int condition;
+
           
-          fd = dbus_watch_get_fd (watch);
-          flags = dbus_watch_get_flags (watch);
+              fd = dbus_watch_get_fd (watch);
+              flags = dbus_watch_get_flags (watch);
 
-          condition = 0;
+              condition = 0;
           
-          if ((flags & DBUS_WATCH_READABLE) &&
-              FD_ISSET (fd, &read_set))
-            condition |= DBUS_WATCH_READABLE;
+              if ((flags & DBUS_WATCH_READABLE) &&
+                  FD_ISSET (fd, &read_set))
+                condition |= DBUS_WATCH_READABLE;
 
-          if ((flags & DBUS_WATCH_WRITABLE) &&
-              FD_ISSET (fd, &write_set))
-            condition |= DBUS_WATCH_WRITABLE;
+              if ((flags & DBUS_WATCH_WRITABLE) &&
+                  FD_ISSET (fd, &write_set))
+                condition |= DBUS_WATCH_WRITABLE;
 
-          if (FD_ISSET (fd, &err_set))
-            condition |= DBUS_WATCH_ERROR;
+              if (FD_ISSET (fd, &err_set))
+                condition |= DBUS_WATCH_ERROR;
 
-          if (condition != 0)
-            {
-              WatchData *wd;
+              if (condition != 0)
+                {
+                  WatchData *wd;
 
-              wd = dbus_watch_get_data (watch);
+                  wd = dbus_watch_get_data (watch);
 
-              if (wd->type == WATCH_CONNECTION)
-                {
-                  DBusConnection *connection = wd->data;
+                  if (wd->type == WATCH_CONNECTION)
+                    {
+                      DBusConnection *connection = wd->data;
 
-                  dbus_connection_handle_watch (connection,
+                      dbus_connection_handle_watch (connection,
+                                                    watch,
+                                                    condition);
+                    }
+                  else if (wd->type == WATCH_SERVER)
+                    {
+                      DBusServer *server = wd->data;
+                  
+                      dbus_server_handle_watch (server,
                                                 watch,
                                                 condition);
-                }
-              else if (wd->type == WATCH_SERVER)
-                {
-                  DBusServer *server = wd->data;
-                  
-                  dbus_server_handle_watch (server,
-                                            watch,
-                                            condition);
+                    }
                 }
             }
           
@@ -345,6 +354,7 @@ setup_connection (DBusConnection *connection)
   if (!dbus_connection_set_watch_functions (connection,
                                             (DBusAddWatchFunction) add_connection_watch,
                                             (DBusRemoveWatchFunction) remove_connection_watch,
+                                            NULL,
                                             connection,
                                             NULL))
     _dbus_assert_not_reached ("not enough memory");
@@ -359,6 +369,7 @@ setup_server (DBusServer *server)
   if (!dbus_server_set_watch_functions (server,
                                         (DBusAddWatchFunction) add_server_watch,
                                         (DBusRemoveWatchFunction) remove_server_watch,
+                                        NULL,
                                         server,
                                         NULL))
     _dbus_assert_not_reached ("not enough memory");