From 3bea935316ff048e68dea6a26c2e8e9fd314477f Mon Sep 17 00:00:00 2001 From: Havoc Pennington Date: Fri, 14 Mar 2003 01:27:58 +0000 Subject: [PATCH] 2003-03-13 Havoc Pennington * dbus/dbus-timeout.c (_dbus_timeout_list_set_functions): handle out of memory * dbus/dbus-watch.c (_dbus_watch_list_set_functions): handle out of memory * dbus/dbus-connection.h: Make AddWatchFunction and AddTimeoutFunction return a bool so they can fail on out-of-memory * bus/bus.c (bus_context_new): set up timeout handlers * bus/connection.c (bus_connections_setup_connection): set up timeout handlers * glib/dbus-gmain.c: adapt to the fact that set_functions stuff can fail * bus/bus.c (bus_context_new): adapt to changes * bus/connection.c: adapt to changes * test/watch.c: adapt to DBusWatch changes * bus/dispatch.c (bus_dispatch_test): started adding this but didn't finish --- ChangeLog | 28 ++++ bus/Makefile.am | 2 +- bus/bus.c | 68 +++++++- bus/connection.c | 77 +++++++-- bus/dispatch.c | 85 +++++++++- bus/loop.c | 415 +++++++++++++++++++++++++++++++++++++++++-------- bus/loop.h | 34 ++-- bus/test-main.c | 25 +++ bus/test.h | 2 +- dbus/dbus-connection.c | 36 +++-- dbus/dbus-connection.h | 54 ++++--- dbus/dbus-server.c | 22 +-- dbus/dbus-server.h | 45 +++--- dbus/dbus-timeout.c | 58 +++++-- dbus/dbus-timeout.h | 2 +- dbus/dbus-watch.c | 58 +++++-- dbus/dbus-watch.h | 2 +- glib/dbus-gmain.c | 28 ++-- test/watch.c | 54 +++++-- 19 files changed, 866 insertions(+), 229 deletions(-) diff --git a/ChangeLog b/ChangeLog index 5ba1f65..5784a26 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,31 @@ +2003-03-13 Havoc Pennington + + * dbus/dbus-timeout.c (_dbus_timeout_list_set_functions): handle + out of memory + + * dbus/dbus-watch.c (_dbus_watch_list_set_functions): handle out + of memory + + * dbus/dbus-connection.h: Make AddWatchFunction and + AddTimeoutFunction return a bool so they can fail on out-of-memory + + * bus/bus.c (bus_context_new): set up timeout handlers + + * bus/connection.c (bus_connections_setup_connection): set up + timeout handlers + + * glib/dbus-gmain.c: adapt to the fact that set_functions stuff + can fail + + * bus/bus.c (bus_context_new): adapt to changes + + * bus/connection.c: adapt to changes + + * test/watch.c: adapt to DBusWatch changes + + * bus/dispatch.c (bus_dispatch_test): started adding this but + didn't finish + 2003-03-14 Anders Carlsson * bus/dispatch.c (send_service_nonexistent_error): Fix typo. diff --git a/bus/Makefile.am b/bus/Makefile.am index f8cff91..9c2f08b 100644 --- a/bus/Makefile.am +++ b/bus/Makefile.am @@ -60,7 +60,7 @@ noinst_PROGRAMS=$(TESTS) bus_test_SOURCES= \ test-main.c -bus_test_LDADD= $(top_builddir)/dbus/libdbus-convenience.la libdbus-daemon.la +bus_test_LDADD= $(top_builddir)/dbus/libdbus-1.la libdbus-daemon.la ## mop up the gcov files clean-local: diff --git a/bus/bus.c b/bus/bus.c index 7ac0bee..e376ae4 100644 --- a/bus/bus.c +++ b/bus/bus.c @@ -49,12 +49,12 @@ server_watch_callback (DBusWatch *watch, dbus_server_handle_watch (context->server, watch, condition); } -static void +static dbus_bool_t add_server_watch (DBusWatch *watch, BusContext *context) { - bus_loop_add_watch (watch, server_watch_callback, context, - NULL); + return bus_loop_add_watch (watch, server_watch_callback, context, + NULL); } static void @@ -65,6 +65,27 @@ remove_server_watch (DBusWatch *watch, } static void +server_timeout_callback (DBusTimeout *timeout, + void *data) +{ + dbus_timeout_handle (timeout); +} + +static dbus_bool_t +add_server_timeout (DBusTimeout *timeout, + BusContext *context) +{ + return bus_loop_add_timeout (timeout, server_timeout_callback, context, NULL); +} + +static void +remove_server_timeout (DBusTimeout *timeout, + BusContext *context) +{ + bus_loop_remove_timeout (timeout, server_timeout_callback, context); +} + +static void new_connection_callback (DBusServer *server, DBusConnection *new_connection, void *data) @@ -136,11 +157,24 @@ bus_context_new (const char *address, new_connection_callback, context, NULL); - dbus_server_set_watch_functions (context->server, - (DBusAddWatchFunction) add_server_watch, - (DBusRemoveWatchFunction) remove_server_watch, - context, - NULL); + if (!dbus_server_set_watch_functions (context->server, + (DBusAddWatchFunction) add_server_watch, + (DBusRemoveWatchFunction) remove_server_watch, + context, + NULL)) + { + BUS_SET_OOM (error); + goto failed; + } + + if (!dbus_server_set_timeout_functions (context->server, + (DBusAddTimeoutFunction) add_server_timeout, + (DBusRemoveTimeoutFunction) remove_server_timeout, + context, NULL)) + { + BUS_SET_OOM (error); + goto failed; + } return context; @@ -152,6 +186,22 @@ bus_context_new (const char *address, void bus_context_shutdown (BusContext *context) { + if (context->server == NULL || + !dbus_server_get_is_connected (context->server)) + return; + + if (!dbus_server_set_watch_functions (context->server, + NULL, NULL, + context, + NULL)) + _dbus_assert_not_reached ("setting watch functions to NULL failed"); + + if (!dbus_server_set_timeout_functions (context->server, + NULL, NULL, + context, + NULL)) + _dbus_assert_not_reached ("setting timeout functions to NULL failed"); + dbus_server_disconnect (context->server); } @@ -170,6 +220,8 @@ bus_context_unref (BusContext *context) if (context->refcount == 0) { + bus_context_shutdown (context); + if (context->registry) bus_registry_unref (context->registry); if (context->connections) diff --git a/bus/connection.c b/bus/connection.c index cdc8be7..f046339 100644 --- a/bus/connection.c +++ b/bus/connection.c @@ -108,11 +108,18 @@ bus_connection_disconnected (DBusConnection *connection) bus_dispatch_remove_connection (connection); /* no more watching */ - dbus_connection_set_watch_functions (connection, - NULL, NULL, - connection, - NULL); - + if (!dbus_connection_set_watch_functions (connection, + NULL, NULL, + connection, + NULL)) + _dbus_assert_not_reached ("setting watch functions to NULL failed"); + + if (!dbus_connection_set_timeout_functions (connection, + NULL, NULL, + connection, + NULL)) + _dbus_assert_not_reached ("setting timeout functions to NULL failed"); + bus_connection_remove_transactions (connection); _dbus_list_remove (&d->connections->list, connection); @@ -140,12 +147,12 @@ connection_watch_callback (DBusWatch *watch, dbus_connection_unref (connection); } -static void +static dbus_bool_t add_connection_watch (DBusWatch *watch, DBusConnection *connection) { - bus_loop_add_watch (watch, connection_watch_callback, connection, - NULL); + return bus_loop_add_watch (watch, connection_watch_callback, connection, + NULL); } static void @@ -156,6 +163,27 @@ remove_connection_watch (DBusWatch *watch, } static void +connection_timeout_callback (DBusTimeout *timeout, + void *data) +{ + dbus_timeout_handle (timeout); +} + +static dbus_bool_t +add_connection_timeout (DBusTimeout *timeout, + DBusConnection *connection) +{ + return bus_loop_add_timeout (timeout, connection_timeout_callback, connection, NULL); +} + +static void +remove_connection_timeout (DBusTimeout *timeout, + DBusConnection *connection) +{ + bus_loop_remove_timeout (timeout, connection_timeout_callback, connection); +} + +static void free_connection_data (void *data) { BusConnectionData *d = data; @@ -249,18 +277,35 @@ bus_connections_setup_connection (BusConnections *connections, dbus_connection_disconnect (connection); return FALSE; } - - dbus_connection_ref (connection); - dbus_connection_set_watch_functions (connection, - (DBusAddWatchFunction) add_connection_watch, - (DBusRemoveWatchFunction) remove_connection_watch, - connection, - NULL); + if (!dbus_connection_set_watch_functions (connection, + (DBusAddWatchFunction) add_connection_watch, + (DBusRemoveWatchFunction) remove_connection_watch, + connection, + NULL)) + { + dbus_connection_disconnect (connection); + return FALSE; + } + + if (!dbus_connection_set_timeout_functions (connection, + (DBusAddTimeoutFunction) add_connection_timeout, + (DBusRemoveTimeoutFunction) remove_connection_timeout, + connection, NULL)) + { + dbus_connection_disconnect (connection); + return FALSE; + } + /* Setup the connection with the dispatcher */ if (!bus_dispatch_add_connection (connection)) - return FALSE; + { + dbus_connection_disconnect (connection); + return FALSE; + } + + dbus_connection_ref (connection); return TRUE; } diff --git a/bus/dispatch.c b/bus/dispatch.c index 5970591..04d68ec 100644 --- a/bus/dispatch.c +++ b/bus/dispatch.c @@ -27,6 +27,7 @@ #include "services.h" #include "utils.h" #include "bus.h" +#include "test.h" #include #include @@ -142,11 +143,9 @@ send_service_nonexistent_error (BusTransaction *transaction, return TRUE; } -static DBusHandlerResult -bus_dispatch_message_handler (DBusMessageHandler *handler, - DBusConnection *connection, - DBusMessage *message, - void *user_data) +static void +bus_dispatch (DBusConnection *connection, + DBusMessage *message) { const char *sender, *service_name, *message_name; DBusError error; @@ -313,6 +312,15 @@ bus_dispatch_message_handler (DBusMessageHandler *handler, } dbus_connection_unref (connection); +} + +static DBusHandlerResult +bus_dispatch_message_handler (DBusMessageHandler *handler, + DBusConnection *connection, + DBusMessage *message, + void *user_data) +{ + bus_dispatch (connection, message); return DBUS_HANDLER_RESULT_ALLOW_MORE_HANDLERS; } @@ -361,3 +369,70 @@ bus_dispatch_remove_connection (DBusConnection *connection) NULL, NULL); } + + +#ifdef DBUS_BUILD_TESTS + +static void +run_test_bus (BusContext *context) +{ + + +} + +static dbus_bool_t +check_hello_message (BusContext *context, + DBusConnection *connection) +{ + DBusMessage *message; + dbus_int32_t serial; + + message = dbus_message_new (DBUS_SERVICE_DBUS, + DBUS_MESSAGE_HELLO); + + if (message == NULL) + _dbus_assert_not_reached ("no memory"); + + if (!dbus_connection_send (connection, message, &serial)) + _dbus_assert_not_reached ("no memory"); + + return TRUE; +} + +dbus_bool_t +bus_dispatch_test (const DBusString *test_data_dir) +{ + BusContext *context; + DBusError error; + const char *activation_dirs[] = { NULL, NULL }; + DBusConnection *foo; + DBusConnection *bar; + DBusConnection *baz; + DBusResultCode result; + + return TRUE; /* FIXME */ + + dbus_error_init (&error); + context = bus_context_new ("debug:name=test-server", + activation_dirs, + &error); + if (context == NULL) + _dbus_assert_not_reached ("could not alloc context"); + + foo = dbus_connection_open ("debug:name=test-server", &result); + if (foo == NULL) + _dbus_assert_not_reached ("could not alloc connection"); + + bar = dbus_connection_open ("debug:name=test-server", &result); + if (bar == NULL) + _dbus_assert_not_reached ("could not alloc connection"); + + baz = dbus_connection_open ("debug:name=test-server", &result); + if (baz == NULL) + _dbus_assert_not_reached ("could not alloc connection"); + + + + return TRUE; +} +#endif /* DBUS_BUILD_TESTS */ diff --git a/bus/loop.c b/bus/loop.c index 25ebc71..b114d26 100644 --- a/bus/loop.c +++ b/bus/loop.c @@ -26,20 +26,46 @@ #include #include -static DBusList *watches = NULL; -static int watch_list_serial = 0; +static DBusList *callbacks = NULL; +static int callback_list_serial = 0; +static int watch_count = 0; +static int timeout_count = 0; static dbus_bool_t exited = FALSE; +typedef enum +{ + CALLBACK_WATCH, + CALLBACK_TIMEOUT +} CallbackType; + typedef struct { - DBusWatch *watch; - BusWatchFunction function; + CallbackType type; void *data; DBusFreeFunction free_data_func; +} Callback; + +typedef struct +{ + Callback callback; + BusWatchFunction function; + DBusWatch *watch; } WatchCallback; -dbus_bool_t -bus_loop_add_watch (DBusWatch *watch, +typedef struct +{ + Callback callback; + DBusTimeout *timeout; + BusTimeoutFunction function; + unsigned long last_tv_sec; + unsigned long last_tv_usec; +} TimeoutCallback; + +#define WATCH_CALLBACK(callback) ((WatchCallback*)callback) +#define TIMEOUT_CALLBACK(callback) ((TimeoutCallback*)callback) + +static WatchCallback* +watch_callback_new (DBusWatch *watch, BusWatchFunction function, void *data, DBusFreeFunction free_data_func) @@ -48,20 +74,108 @@ bus_loop_add_watch (DBusWatch *watch, cb = dbus_new (WatchCallback, 1); if (cb == NULL) - return FALSE; + return NULL; cb->watch = watch; cb->function = function; - cb->data = data; - cb->free_data_func = free_data_func; + cb->callback.type = CALLBACK_WATCH; + cb->callback.data = data; + cb->callback.free_data_func = free_data_func; + + return cb; +} - if (!_dbus_list_append (&watches, cb)) +static TimeoutCallback* +timeout_callback_new (DBusTimeout *timeout, + BusTimeoutFunction function, + void *data, + DBusFreeFunction free_data_func) +{ + TimeoutCallback *cb; + + cb = dbus_new (TimeoutCallback, 1); + if (cb == NULL) + return NULL; + + cb->timeout = timeout; + cb->function = function; + _dbus_get_current_time (&cb->last_tv_sec, + &cb->last_tv_usec); + cb->callback.type = CALLBACK_TIMEOUT; + cb->callback.data = data; + cb->callback.free_data_func = free_data_func; + + return cb; +} + +static void +callback_free (Callback *cb) +{ + if (cb->free_data_func) + (* cb->free_data_func) (cb->data); + + dbus_free (cb); +} + +static dbus_bool_t +add_callback (Callback *cb) +{ + if (!_dbus_list_append (&callbacks, cb)) + return FALSE; + + callback_list_serial += 1; + + switch (cb->type) { - dbus_free (cb); - return FALSE; + case CALLBACK_WATCH: + watch_count += 1; + break; + case CALLBACK_TIMEOUT: + timeout_count += 1; + break; } + + return TRUE; +} + +static void +remove_callback (DBusList *link) +{ + Callback *cb = link->data; + + switch (cb->type) + { + case CALLBACK_WATCH: + watch_count -= 1; + break; + case CALLBACK_TIMEOUT: + timeout_count -= 1; + break; + } + + callback_free (cb); + _dbus_list_remove_link (&callbacks, link); + callback_list_serial += 1; +} + +dbus_bool_t +bus_loop_add_watch (DBusWatch *watch, + BusWatchFunction function, + void *data, + DBusFreeFunction free_data_func) +{ + WatchCallback *wcb; + + wcb = watch_callback_new (watch, function, data, free_data_func); + if (wcb == NULL) + return FALSE; - watch_list_serial += 1; + if (!add_callback ((Callback*) wcb)) + { + wcb->callback.free_data_func = NULL; /* don't want to have this side effect */ + callback_free ((Callback*) wcb); + return FALSE; + } return TRUE; } @@ -73,23 +187,18 @@ bus_loop_remove_watch (DBusWatch *watch, { DBusList *link; - link = _dbus_list_get_first_link (&watches); + link = _dbus_list_get_first_link (&callbacks); while (link != NULL) { - DBusList *next = _dbus_list_get_next_link (&watches, link); - WatchCallback *cb = link->data; + DBusList *next = _dbus_list_get_next_link (&callbacks, link); + Callback *this = link->data; - if (cb->watch == watch && - cb->function == function && - cb->data == data) + if (this->type == CALLBACK_WATCH && + WATCH_CALLBACK (this)->watch == watch && + this->data == data && + WATCH_CALLBACK (this)->function == function) { - _dbus_list_remove_link (&watches, link); - - watch_list_serial += 1; - - if (cb->free_data_func) - (* cb->free_data_func) (cb->data); - dbus_free (cb); + remove_callback (link); return; } @@ -101,6 +210,58 @@ bus_loop_remove_watch (DBusWatch *watch, watch, function, data); } +dbus_bool_t +bus_loop_add_timeout (DBusTimeout *timeout, + BusTimeoutFunction function, + void *data, + DBusFreeFunction free_data_func) +{ + TimeoutCallback *tcb; + + tcb = timeout_callback_new (timeout, function, data, free_data_func); + if (tcb == NULL) + return FALSE; + + if (!add_callback ((Callback*) tcb)) + { + tcb->callback.free_data_func = NULL; /* don't want to have this side effect */ + callback_free ((Callback*) tcb); + return FALSE; + } + + return TRUE; +} + +void +bus_loop_remove_timeout (DBusTimeout *timeout, + BusTimeoutFunction function, + void *data) +{ + DBusList *link; + + link = _dbus_list_get_first_link (&callbacks); + while (link != NULL) + { + DBusList *next = _dbus_list_get_next_link (&callbacks, link); + Callback *this = link->data; + + if (this->type == CALLBACK_TIMEOUT && + TIMEOUT_CALLBACK (this)->timeout == timeout && + this->data == data && + TIMEOUT_CALLBACK (this)->function == function) + { + remove_callback (link); + + return; + } + + link = next; + } + + _dbus_warn ("could not find timeout %p function %p data %p to remove\n", + timeout, function, data); +} + void bus_loop_run (void) { @@ -113,59 +274,187 @@ bus_loop_run (void) DBusList *link; int n_ready; int initial_serial; + long timeout; fds = NULL; watches_for_fds = NULL; - n_fds = _dbus_list_get_length (&watches); - - if (n_fds == 0) + if (callbacks == NULL) { bus_loop_quit (); goto next_iteration; } - fds = dbus_new0 (DBusPollFD, n_fds); - while (fds == NULL) + n_fds = watch_count; + + if (n_fds > 0) { - bus_wait_for_memory (); fds = dbus_new0 (DBusPollFD, n_fds); + while (fds == NULL) + { + bus_wait_for_memory (); + fds = dbus_new0 (DBusPollFD, n_fds); + } + + watches_for_fds = dbus_new (WatchCallback*, n_fds); + while (watches_for_fds == NULL) + { + bus_wait_for_memory (); + watches_for_fds = dbus_new (WatchCallback*, n_fds); + } + + i = 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) + { + unsigned int flags; + WatchCallback *wcb = WATCH_CALLBACK (cb); + + watches_for_fds[i] = wcb; + + 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; + + ++i; + } + + link = next; + } + + _dbus_assert (i == n_fds); } - watches_for_fds = dbus_new (WatchCallback*, n_fds); - while (watches_for_fds == NULL) + timeout = -1; + if (timeout_count > 0) { - bus_wait_for_memory (); - watches_for_fds = dbus_new (WatchCallback*, n_fds); + unsigned long tv_sec; + unsigned long tv_usec; + + _dbus_get_current_time (&tv_sec, &tv_usec); + + 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_TIMEOUT) + { + TimeoutCallback *tcb = TIMEOUT_CALLBACK (cb); + unsigned long interval; + unsigned long elapsed; + + if (tcb->last_tv_sec > tv_sec || + (tcb->last_tv_sec == tv_sec && + tcb->last_tv_usec > tv_usec)) + { + /* Clock went backward, pretend timeout + * was just installed. + */ + tcb->last_tv_sec = tv_sec; + tcb->last_tv_usec = tv_usec; + _dbus_verbose ("System clock went backward\n"); + } + + interval = dbus_timeout_get_interval (tcb->timeout); + + elapsed = + (tv_sec - tcb->last_tv_sec) * 1000 + + (tv_usec - tcb->last_tv_usec) / 1000; + + if (interval < elapsed) + timeout = 0; + else if (timeout < 0) + timeout = interval - elapsed; + else + timeout = MIN (((unsigned long)timeout), interval - elapsed); + + _dbus_assert (timeout >= 0); + + if (timeout == 0) + break; /* it's not going to get shorter... */ + } + + link = next; + } } - i = 0; - link = _dbus_list_get_first_link (&watches); - while (link != NULL) + n_ready = _dbus_poll (fds, n_fds, timeout); + + initial_serial = callback_list_serial; + + if (timeout_count > 0) { - DBusList *next = _dbus_list_get_next_link (&watches, link); - WatchCallback *cb = link->data; - int flags; - - watches_for_fds[i] = cb; + unsigned long tv_sec; + unsigned long tv_usec; - flags = dbus_watch_get_flags (cb->watch); - - fds[i].fd = dbus_watch_get_fd (cb->watch); - if (flags & DBUS_WATCH_READABLE) - fds[i].events |= _DBUS_POLLIN; - if (flags & DBUS_WATCH_WRITABLE) - fds[i].events |= _DBUS_POLLOUT; - - link = next; - ++i; - } + _dbus_get_current_time (&tv_sec, &tv_usec); + + /* It'd be nice to avoid this O(n) thingy here */ + link = _dbus_list_get_first_link (&callbacks); + while (link != NULL) + { + DBusList *next = _dbus_list_get_next_link (&callbacks, link); + Callback *cb = link->data; + + if (initial_serial != callback_list_serial) + goto next_iteration; + + if (exited) + goto next_iteration; + + if (cb->type == CALLBACK_TIMEOUT) + { + TimeoutCallback *tcb = TIMEOUT_CALLBACK (cb); + unsigned long interval; + unsigned long elapsed; + + if (tcb->last_tv_sec > tv_sec || + (tcb->last_tv_sec == tv_sec && + tcb->last_tv_usec > tv_usec)) + { + /* Clock went backward, pretend timeout + * was just installed. + */ + tcb->last_tv_sec = tv_sec; + tcb->last_tv_usec = tv_usec; + _dbus_verbose ("System clock went backward\n"); + goto next_timeout; + } + + interval = dbus_timeout_get_interval (tcb->timeout); - n_ready = _dbus_poll (fds, n_fds, -1); + elapsed = + (tv_sec - tcb->last_tv_sec) * 1000 + + (tv_usec - tcb->last_tv_usec) / 1000; + if (interval <= elapsed) + { + /* Save last callback time and fire this timeout */ + tcb->last_tv_sec = tv_sec; + tcb->last_tv_usec = tv_usec; + + (* tcb->function) (tcb->timeout, + cb->data); + } + } + + next_timeout: + link = next; + } + } + if (n_ready > 0) { - initial_serial = watch_list_serial; i = 0; while (i < n_fds) { @@ -173,7 +462,7 @@ bus_loop_run (void) * approach could result in starving watches * toward the end of the list. */ - if (initial_serial != watch_list_serial) + if (initial_serial != callback_list_serial) goto next_iteration; if (exited) @@ -181,10 +470,10 @@ bus_loop_run (void) if (fds[i].revents != 0) { - WatchCallback *cb; + WatchCallback *wcb; unsigned int condition; - cb = watches_for_fds[i]; + wcb = watches_for_fds[i]; condition = 0; if (fds[i].revents & _DBUS_POLLIN) @@ -201,9 +490,9 @@ bus_loop_run (void) */ if (condition != 0) - (* cb->function) (cb->watch, - condition, - cb->data); + (* wcb->function) (wcb->watch, + condition, + ((Callback*)wcb)->data); } ++i; diff --git a/bus/loop.h b/bus/loop.h index e2b5e50..cd49865 100644 --- a/bus/loop.h +++ b/bus/loop.h @@ -26,19 +26,29 @@ #include -typedef void (* BusWatchFunction) (DBusWatch *watch, - unsigned int condition, - void *data); +typedef void (* BusWatchFunction) (DBusWatch *watch, + unsigned int condition, + void *data); +typedef void (* BusTimeoutFunction) (DBusTimeout *timeout, + void *data); + +dbus_bool_t bus_loop_add_watch (DBusWatch *watch, + BusWatchFunction function, + void *data, + DBusFreeFunction free_data_func); +void bus_loop_remove_watch (DBusWatch *watch, + BusWatchFunction function, + void *data); +dbus_bool_t bus_loop_add_timeout (DBusTimeout *timeout, + BusTimeoutFunction function, + void *data, + DBusFreeFunction free_data_func); +void bus_loop_remove_timeout (DBusTimeout *timeout, + BusTimeoutFunction function, + void *data); +void bus_loop_run (void); +void bus_loop_quit (void); -dbus_bool_t bus_loop_add_watch (DBusWatch *watch, - BusWatchFunction function, - void *data, - DBusFreeFunction free_data_func); -void bus_loop_remove_watch (DBusWatch *watch, - BusWatchFunction function, - void *data); -void bus_loop_run (void); -void bus_loop_quit (void); #endif /* BUS_LOOP_H */ diff --git a/bus/test-main.c b/bus/test-main.c index 27c06f4..503d996 100644 --- a/bus/test-main.c +++ b/bus/test-main.c @@ -22,16 +22,41 @@ */ #include "test.h" +#include +#include +#include +#include + +static void +die (const char *failure) +{ + fprintf (stderr, "Unit test failed: %s\n", failure); + exit (1); +} int main (int argc, char **argv) { #ifdef DBUS_BUILD_TESTS + const char *dir; + DBusString test_data_dir; + + if (argc > 1) + dir = argv[1]; + else + dir = _dbus_getenv ("DBUS_TEST_DATA"); + + if (dir == NULL) + dir = ""; + _dbus_string_init_const (&test_data_dir, dir); + if (!bus_dispatch_test (&test_data_dir)) + die ("dispatch"); return 0; #else /* DBUS_BUILD_TESTS */ + return 0; #endif } diff --git a/bus/test.h b/bus/test.h index 2d39ac9..82c0c43 100644 --- a/bus/test.h +++ b/bus/test.h @@ -31,7 +31,7 @@ #include #include -dbus_bool_t bus_test_foo (const DBusString *test_data_dir); +dbus_bool_t bus_dispatch_test (const DBusString *test_data_dir); #endif diff --git a/dbus/dbus-connection.c b/dbus/dbus-connection.c index bfc27e2..19fe717 100644 --- a/dbus/dbus-connection.c +++ b/dbus/dbus-connection.c @@ -1810,31 +1810,44 @@ dbus_connection_dispatch_message (DBusConnection *connection) * * It is not allowed to reference a DBusWatch after it has been passed * to remove_function. + * + * If #FALSE is returned due to lack of memory, the failure may be due + * to a #FALSE return from the new add_function. If so, the + * add_function may have been called successfully one or more times, + * but the remove_function will also have been called to remove any + * successful adds. i.e. if #FALSE is returned the net result + * should be that dbus_connection_set_watch_functions() has no effect, + * but the add_function and remove_function may have been called. * * @param connection the connection. * @param add_function function to begin monitoring a new descriptor. * @param remove_function function to stop monitoring a descriptor. * @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) */ -void +dbus_bool_t dbus_connection_set_watch_functions (DBusConnection *connection, DBusAddWatchFunction add_function, DBusRemoveWatchFunction remove_function, void *data, DBusFreeFunction free_data_function) { + dbus_bool_t retval; + dbus_mutex_lock (connection->mutex); /* ref connection for slightly better reentrancy */ _dbus_connection_ref_unlocked (connection); - _dbus_watch_list_set_functions (connection->watches, - add_function, remove_function, - data, free_data_function); + retval = _dbus_watch_list_set_functions (connection->watches, + add_function, remove_function, + data, free_data_function); dbus_mutex_unlock (connection->mutex); /* drop our paranoid refcount */ dbus_connection_unref (connection); + + return retval; } /** @@ -1855,25 +1868,30 @@ dbus_connection_set_watch_functions (DBusConnection *connection, * @param remove_function function to remove a timeout. * @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) */ -void +dbus_bool_t dbus_connection_set_timeout_functions (DBusConnection *connection, DBusAddTimeoutFunction add_function, DBusRemoveTimeoutFunction remove_function, void *data, DBusFreeFunction free_data_function) { + dbus_bool_t retval; + dbus_mutex_lock (connection->mutex); /* ref connection for slightly better reentrancy */ _dbus_connection_ref_unlocked (connection); - _dbus_timeout_list_set_functions (connection->timeouts, - add_function, remove_function, - data, free_data_function); + retval = _dbus_timeout_list_set_functions (connection->timeouts, + add_function, remove_function, + data, free_data_function); dbus_mutex_unlock (connection->mutex); /* drop our paranoid refcount */ - dbus_connection_unref (connection); + dbus_connection_unref (connection); + + return retval; } /** diff --git a/dbus/dbus-connection.h b/dbus/dbus-connection.h index 6b48013..bf0983e 100644 --- a/dbus/dbus-connection.h +++ b/dbus/dbus-connection.h @@ -56,17 +56,15 @@ typedef enum * can be present in current state). */ } DBusWatchFlags; -typedef void (* DBusAddWatchFunction) (DBusWatch *watch, - void *data); - -typedef void (* DBusRemoveWatchFunction) (DBusWatch *watch, - void *data); - -typedef void (* DBusWakeupMainFunction) (void *data); -typedef void (* DBusAddTimeoutFunction) (DBusTimeout *timeout, - void *data); -typedef void (* DBusRemoveTimeoutFunction) (DBusTimeout *timeout, - void *data); +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); DBusConnection* dbus_connection_open (const char *address, DBusResultCode *result); @@ -99,24 +97,24 @@ DBusMessage *dbus_connection_send_with_reply_and_block (DBusConnection *conn DBusError *error); +dbus_bool_t dbus_connection_set_watch_functions (DBusConnection *connection, + DBusAddWatchFunction add_function, + DBusRemoveWatchFunction remove_function, + void *data, + DBusFreeFunction free_data_function); +dbus_bool_t dbus_connection_set_timeout_functions (DBusConnection *connection, + DBusAddTimeoutFunction add_function, + DBusRemoveTimeoutFunction remove_function, + void *data, + DBusFreeFunction free_data_function); +void dbus_connection_set_wakeup_main_function (DBusConnection *connection, + DBusWakeupMainFunction wakeup_main_function, + void *data, + DBusFreeFunction free_data_function); +void dbus_connection_handle_watch (DBusConnection *connection, + DBusWatch *watch, + unsigned int condition); -void dbus_connection_set_watch_functions (DBusConnection *connection, - DBusAddWatchFunction add_function, - DBusRemoveWatchFunction remove_function, - void *data, - DBusFreeFunction free_data_function); -void dbus_connection_set_timeout_functions (DBusConnection *connection, - DBusAddTimeoutFunction add_function, - DBusRemoveTimeoutFunction remove_function, - void *data, - DBusFreeFunction free_data_function); -void dbus_connection_set_wakeup_main_function (DBusConnection *connection, - DBusWakeupMainFunction wakeup_main_function, - void *data, - DBusFreeFunction free_data_function); -void dbus_connection_handle_watch (DBusConnection *connection, - DBusWatch *watch, - unsigned int condition); diff --git a/dbus/dbus-server.c b/dbus/dbus-server.c index 0065e51..99a5a2a 100644 --- a/dbus/dbus-server.c +++ b/dbus/dbus-server.c @@ -392,19 +392,20 @@ dbus_server_set_new_connection_function (DBusServer *server, * @param remove_function function to stop monitoring a descriptor. * @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) */ -void +dbus_bool_t dbus_server_set_watch_functions (DBusServer *server, DBusAddWatchFunction add_function, DBusRemoveWatchFunction remove_function, void *data, DBusFreeFunction free_data_function) { - _dbus_watch_list_set_functions (server->watches, - add_function, - remove_function, - data, - free_data_function); + return _dbus_watch_list_set_functions (server->watches, + add_function, + remove_function, + data, + free_data_function); } /** @@ -419,17 +420,18 @@ dbus_server_set_watch_functions (DBusServer *server, * @param remove_function function to remove a timeout. * @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) */ -void +dbus_bool_t dbus_server_set_timeout_functions (DBusServer *server, DBusAddTimeoutFunction add_function, DBusRemoveTimeoutFunction remove_function, void *data, DBusFreeFunction free_data_function) { - _dbus_timeout_list_set_functions (server->timeouts, - add_function, remove_function, - data, free_data_function); + return _dbus_timeout_list_set_functions (server->timeouts, + add_function, remove_function, + data, free_data_function); } /** diff --git a/dbus/dbus-server.h b/dbus/dbus-server.h index fc3a57e..6665335 100644 --- a/dbus/dbus-server.h +++ b/dbus/dbus-server.h @@ -45,31 +45,28 @@ void dbus_server_ref (DBusServer *server); void dbus_server_unref (DBusServer *server); void dbus_server_disconnect (DBusServer *server); dbus_bool_t dbus_server_get_is_connected (DBusServer *server); +void dbus_server_set_new_connection_function (DBusServer *server, + DBusNewConnectionFunction function, + void *data, + DBusFreeFunction free_data_function); +dbus_bool_t dbus_server_set_watch_functions (DBusServer *server, + DBusAddWatchFunction add_function, + DBusRemoveWatchFunction remove_function, + void *data, + DBusFreeFunction free_data_function); +dbus_bool_t dbus_server_set_timeout_functions (DBusServer *server, + DBusAddTimeoutFunction add_function, + DBusRemoveTimeoutFunction remove_function, + void *data, + DBusFreeFunction free_data_function); +void dbus_server_handle_watch (DBusServer *server, + DBusWatch *watch, + unsigned int condition); +void dbus_server_set_max_connections (DBusServer *server, + int max_connections); +int dbus_server_get_max_connections (DBusServer *server); +int dbus_server_get_n_connections (DBusServer *server); -void dbus_server_set_new_connection_function (DBusServer *server, - DBusNewConnectionFunction function, - void *data, - DBusFreeFunction free_data_function); -void dbus_server_set_watch_functions (DBusServer *server, - DBusAddWatchFunction add_function, - DBusRemoveWatchFunction remove_function, - void *data, - DBusFreeFunction free_data_function); -void dbus_server_set_timeout_functions (DBusServer *server, - DBusAddTimeoutFunction add_function, - DBusRemoveTimeoutFunction remove_function, - void *data, - DBusFreeFunction free_data_function); -void dbus_server_handle_watch (DBusServer *server, - DBusWatch *watch, - unsigned int condition); - - -void dbus_server_set_max_connections (DBusServer *server, - int max_connections); -int dbus_server_get_max_connections (DBusServer *server); - -int dbus_server_get_n_connections (DBusServer *server); int dbus_server_allocate_data_slot (void); void dbus_server_free_data_slot (int slot); diff --git a/dbus/dbus-timeout.c b/dbus/dbus-timeout.c index 379aeee..408de42 100644 --- a/dbus/dbus-timeout.c +++ b/dbus/dbus-timeout.c @@ -181,15 +181,50 @@ _dbus_timeout_list_free (DBusTimeoutList *timeout_list) * @param remove_function the remove timeout function. * @param data the data for those functions. * @param free_data_function the function to free the data. + * @returns #FALSE if no memory * */ -void +dbus_bool_t _dbus_timeout_list_set_functions (DBusTimeoutList *timeout_list, DBusAddTimeoutFunction add_function, DBusRemoveTimeoutFunction remove_function, void *data, DBusFreeFunction free_data_function) { + /* Add timeouts with the new function, failing on OOM */ + if (add_function != NULL) + { + DBusList *link; + + link = _dbus_list_get_first_link (&timeout_list->timeouts); + while (link != NULL) + { + DBusList *next = _dbus_list_get_next_link (&timeout_list->timeouts, + link); + + if (!(* add_function) (link->data, data)) + { + /* remove it all again and return FALSE */ + DBusList *link2; + + link2 = _dbus_list_get_first_link (&timeout_list->timeouts); + while (link2 != link) + { + DBusList *next = _dbus_list_get_next_link (&timeout_list->timeouts, + link2); + + (* remove_function) (link2->data, data); + + link2 = next; + } + + return FALSE; + } + + link = next; + } + } + /* Remove all current timeouts from previous timeout handlers */ if (timeout_list->remove_timeout_function != NULL) @@ -207,13 +242,7 @@ _dbus_timeout_list_set_functions (DBusTimeoutList *timeout_list, timeout_list->timeout_data = data; timeout_list->timeout_free_data_function = free_data_function; - /* Re-add all pending timeouts */ - if (timeout_list->add_timeout_function != NULL) - { - _dbus_list_foreach (&timeout_list->timeouts, - (DBusForeachFunction) timeout_list->add_timeout_function, - timeout_list->timeout_data); - } + return TRUE; } /** @@ -234,14 +263,21 @@ _dbus_timeout_list_add_timeout (DBusTimeoutList *timeout_list, _dbus_timeout_ref (timeout); if (timeout_list->add_timeout_function != NULL) - (* timeout_list->add_timeout_function) (timeout, - timeout_list->timeout_data); + { + if (!(* timeout_list->add_timeout_function) (timeout, + timeout_list->timeout_data)) + { + _dbus_list_remove_last (&timeout_list->timeouts, timeout); + _dbus_timeout_unref (timeout); + return FALSE; + } + } return TRUE; } /** - * Removes a timeout from the watch list, invoking the + * Removes a timeout from the timeout list, invoking the * application's DBusRemoveTimeoutFunction if appropriate. * * @param timeout_list the timeout list. diff --git a/dbus/dbus-timeout.h b/dbus/dbus-timeout.h index b596bfa..9de12e8 100644 --- a/dbus/dbus-timeout.h +++ b/dbus/dbus-timeout.h @@ -44,7 +44,7 @@ void _dbus_timeout_unref (DBusTimeout *timeout); DBusTimeoutList *_dbus_timeout_list_new (void); void _dbus_timeout_list_free (DBusTimeoutList *timeout_list); -void _dbus_timeout_list_set_functions (DBusTimeoutList *timeout_list, +dbus_bool_t _dbus_timeout_list_set_functions (DBusTimeoutList *timeout_list, DBusAddTimeoutFunction add_function, DBusRemoveTimeoutFunction remove_function, void *data, diff --git a/dbus/dbus-watch.c b/dbus/dbus-watch.c index 681da93..ef2a0ed 100644 --- a/dbus/dbus-watch.c +++ b/dbus/dbus-watch.c @@ -159,7 +159,7 @@ struct DBusWatchList DBusList *watches; /**< Watch objects. */ DBusAddWatchFunction add_watch_function; /**< Callback for adding a watch. */ - DBusAddWatchFunction remove_watch_function; /**< Callback for removing a watch. */ + DBusRemoveWatchFunction remove_watch_function; /**< Callback for removing a watch. */ void *watch_data; /**< Data for watch callbacks */ DBusFreeFunction watch_free_data_function; /**< Free function for watch callback data */ }; @@ -212,15 +212,50 @@ _dbus_watch_list_free (DBusWatchList *watch_list) * @param remove_function the remove watch function. * @param data the data for those functions. * @param free_data_function the function to free the data. + * @returns #FALSE if not enough memory * */ -void +dbus_bool_t _dbus_watch_list_set_functions (DBusWatchList *watch_list, DBusAddWatchFunction add_function, DBusRemoveWatchFunction remove_function, void *data, DBusFreeFunction free_data_function) { + /* Add watches with the new watch function, failing on OOM */ + if (add_function != NULL) + { + DBusList *link; + + link = _dbus_list_get_first_link (&watch_list->watches); + while (link != NULL) + { + DBusList *next = _dbus_list_get_next_link (&watch_list->watches, + link); + + if (!(* add_function) (link->data, data)) + { + /* remove it all again and return FALSE */ + DBusList *link2; + + link2 = _dbus_list_get_first_link (&watch_list->watches); + while (link2 != link) + { + DBusList *next = _dbus_list_get_next_link (&watch_list->watches, + link2); + + (* remove_function) (link2->data, data); + + link2 = next; + } + + return FALSE; + } + + link = next; + } + } + /* Remove all current watches from previous watch handlers */ if (watch_list->remove_watch_function != NULL) @@ -238,13 +273,7 @@ _dbus_watch_list_set_functions (DBusWatchList *watch_list, watch_list->watch_data = data; watch_list->watch_free_data_function = free_data_function; - /* Re-add all pending watches */ - if (watch_list->add_watch_function != NULL) - { - _dbus_list_foreach (&watch_list->watches, - (DBusForeachFunction) watch_list->add_watch_function, - watch_list->watch_data); - } + return TRUE; } /** @@ -265,8 +294,15 @@ _dbus_watch_list_add_watch (DBusWatchList *watch_list, _dbus_watch_ref (watch); if (watch_list->add_watch_function != NULL) - (* watch_list->add_watch_function) (watch, - watch_list->watch_data); + { + if (!(* watch_list->add_watch_function) (watch, + watch_list->watch_data)) + { + _dbus_list_remove_last (&watch_list->watches, watch); + _dbus_watch_unref (watch); + return FALSE; + } + } return TRUE; } diff --git a/dbus/dbus-watch.h b/dbus/dbus-watch.h index 869605a..9d85737 100644 --- a/dbus/dbus-watch.h +++ b/dbus/dbus-watch.h @@ -43,7 +43,7 @@ void _dbus_watch_sanitize_condition (DBusWatch *watch, DBusWatchList* _dbus_watch_list_new (void); void _dbus_watch_list_free (DBusWatchList *watch_list); -void _dbus_watch_list_set_functions (DBusWatchList *watch_list, +dbus_bool_t _dbus_watch_list_set_functions (DBusWatchList *watch_list, DBusAddWatchFunction add_function, DBusRemoveWatchFunction remove_function, void *data, diff --git a/glib/dbus-gmain.c b/glib/dbus-gmain.c index 4052373..b0ec7c4 100644 --- a/glib/dbus-gmain.c +++ b/glib/dbus-gmain.c @@ -231,7 +231,7 @@ dbus_server_dispatch (GSource *source, return TRUE; } -static void +static dbus_bool_t add_watch (DBusWatch *watch, gpointer data) { @@ -257,6 +257,8 @@ add_watch (DBusWatch *watch, dbus_source->poll_fds = g_list_prepend (dbus_source->poll_fds, poll_fd); g_hash_table_insert (dbus_source->watches, poll_fd, watch); + + return TRUE; } static void @@ -285,7 +287,7 @@ timeout_handler (gpointer data) return FALSE; } -static void +static dbus_bool_t add_timeout (DBusTimeout *timeout, void *data) { @@ -295,6 +297,8 @@ add_timeout (DBusTimeout *timeout, timeout_handler, timeout); dbus_timeout_set_data (timeout, GUINT_TO_POINTER (timeout_tag), NULL); + + return TRUE; } static void @@ -356,16 +360,18 @@ dbus_connection_setup_with_g_main (DBusConnection *connection) source = create_source (connection, &dbus_connection_funcs); - dbus_connection_set_watch_functions (connection, - add_watch, - remove_watch, - source, NULL); + if (!dbus_connection_set_watch_functions (connection, + add_watch, + remove_watch, + source, NULL)) + goto nomem; - dbus_connection_set_timeout_functions (connection, - add_timeout, - remove_timeout, - NULL, NULL); - + if (!dbus_connection_set_timeout_functions (connection, + add_timeout, + remove_timeout, + NULL, NULL)) + goto nomem; + dbus_connection_set_wakeup_main_function (connection, wakeup_main, NULL, NULL); diff --git a/test/watch.c b/test/watch.c index d8e91b7..73f5e97 100644 --- a/test/watch.c +++ b/test/watch.c @@ -45,19 +45,26 @@ free_watch_data (void *data) dbus_free (wd); } -static void +static dbus_bool_t add_connection_watch (DBusWatch *watch, DBusConnection *connection) { WatchData *wd; + if (!_dbus_list_append (&watches, watch)) + return FALSE; + wd = dbus_new0 (WatchData, 1); + if (wd == NULL) + { + _dbus_list_remove_last (&watches, watch); + return FALSE; + } wd->type = WATCH_CONNECTION; wd->data = connection; - dbus_connection_ref (connection); - - _dbus_list_append (&watches, watch); + dbus_connection_ref (connection); + dbus_watch_set_data (watch, wd, free_watch_data); watch_list_serial += 1; @@ -67,6 +74,8 @@ add_connection_watch (DBusWatch *watch, dbus_watch_get_flags (watch) & DBUS_WATCH_WRITABLE ? "write " : "", dbus_watch_get_fd (watch)); #endif + + return TRUE; } static void @@ -86,19 +95,26 @@ remove_connection_watch (DBusWatch *watch, #endif } -static void +static dbus_bool_t add_server_watch (DBusWatch *watch, DBusServer *server) { WatchData *wd; + if (!_dbus_list_append (&watches, watch)) + return FALSE; + wd = dbus_new0 (WatchData, 1); + if (wd == NULL) + { + _dbus_list_remove_last (&watches, watch); + return FALSE; + } + wd->type = WATCH_SERVER; wd->data = server; dbus_server_ref (server); - - _dbus_list_append (&watches, watch); dbus_watch_set_data (watch, wd, free_watch_data); @@ -109,6 +125,8 @@ add_server_watch (DBusWatch *watch, dbus_watch_get_flags (watch) & DBUS_WATCH_WRITABLE ? "write " : "", dbus_watch_get_fd (watch)); #endif + + return TRUE; } static void @@ -324,11 +342,12 @@ quit_mainloop (void) void setup_connection (DBusConnection *connection) { - dbus_connection_set_watch_functions (connection, - (DBusAddWatchFunction) add_connection_watch, - (DBusRemoveWatchFunction) remove_connection_watch, - connection, - NULL); + if (!dbus_connection_set_watch_functions (connection, + (DBusAddWatchFunction) add_connection_watch, + (DBusRemoveWatchFunction) remove_connection_watch, + connection, + NULL)) + _dbus_assert_not_reached ("not enough memory"); dbus_connection_ref (connection); _dbus_list_append (&connections, connection); @@ -337,9 +356,10 @@ setup_connection (DBusConnection *connection) void setup_server (DBusServer *server) { - dbus_server_set_watch_functions (server, - (DBusAddWatchFunction) add_server_watch, - (DBusRemoveWatchFunction) remove_server_watch, - server, - NULL); + if (!dbus_server_set_watch_functions (server, + (DBusAddWatchFunction) add_server_watch, + (DBusRemoveWatchFunction) remove_server_watch, + server, + NULL)) + _dbus_assert_not_reached ("not enough memory"); } -- 2.7.4