From 1b08036103a70159e7a67b2349306710edcd6654 Mon Sep 17 00:00:00 2001 From: Havoc Pennington Date: Fri, 4 Apr 2003 00:39:22 +0000 Subject: 2003-04-03 Havoc Pennington * bus/loop.h, bus/loop.c: make the mainloop an object so we can have multiple ones * bus/*.[hc]: adapt to mainloop change --- ChangeLog | 7 +++ bus/bus.c | 154 +++++++++++++++++++++++++++++++++++++++++++++++++-- bus/bus.h | 3 + bus/connection.c | 58 +++++++++++++------ bus/dispatch.c | 127 ++++++++++++++++++++++++++++++++++++++++-- bus/loop.c | 166 +++++++++++++++++++++++++++++++++++++------------------ bus/loop.h | 26 ++++++--- bus/main.c | 2 +- bus/test.c | 110 ++++++++++++++++++++++++++---------- bus/test.h | 24 ++++---- doc/TODO | 6 ++ 11 files changed, 551 insertions(+), 132 deletions(-) diff --git a/ChangeLog b/ChangeLog index a164df07..363fc3ce 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,10 @@ +2003-04-03 Havoc Pennington + + * bus/loop.h, bus/loop.c: make the mainloop an object so we can + have multiple ones + + * bus/*.[hc]: adapt to mainloop change + 2003-04-03 Havoc Pennington * bus/activation.c (load_directory): fix up memleaks diff --git a/bus/bus.c b/bus/bus.c index 381f6317..9125fc75 100644 --- a/bus/bus.c +++ b/bus/bus.c @@ -38,6 +38,7 @@ struct BusContext int refcount; char *type; char *address; + BusLoop *loop; DBusList *servers; BusConnections *connections; BusActivation *activation; @@ -48,6 +49,68 @@ struct BusContext DBusHashTable *rules_by_gid; /**< per-GID policy rules */ }; +static int server_data_slot = -1; +static int server_data_slot_refcount = 0; + +typedef struct +{ + BusContext *context; +} BusServerData; + +#define BUS_SERVER_DATA(server) (dbus_server_get_data ((server), server_data_slot)) + +static dbus_bool_t +server_data_slot_ref (void) +{ + if (server_data_slot < 0) + { + server_data_slot = dbus_server_allocate_data_slot (); + + if (server_data_slot < 0) + return FALSE; + + _dbus_assert (server_data_slot_refcount == 0); + } + + server_data_slot_refcount += 1; + + return TRUE; +} + +static void +server_data_slot_unref (void) +{ + _dbus_assert (server_data_slot_refcount > 0); + + server_data_slot_refcount -= 1; + + if (server_data_slot_refcount == 0) + { + dbus_server_free_data_slot (server_data_slot); + server_data_slot = -1; + } +} + +static BusContext* +server_get_context (DBusServer *server) +{ + BusContext *context; + BusServerData *bd; + + if (!server_data_slot_ref ()) + return NULL; + + bd = BUS_SERVER_DATA (server); + if (bd == NULL) + return NULL; + + context = bd->context; + + server_data_slot_unref (); + + return context; +} + static dbus_bool_t server_watch_callback (DBusWatch *watch, unsigned int condition, @@ -62,7 +125,13 @@ static dbus_bool_t add_server_watch (DBusWatch *watch, void *data) { - return bus_loop_add_watch (watch, server_watch_callback, data, + DBusServer *server = data; + BusContext *context; + + context = server_get_context (server); + + return bus_loop_add_watch (context->loop, + watch, server_watch_callback, server, NULL); } @@ -70,7 +139,13 @@ static void remove_server_watch (DBusWatch *watch, void *data) { - bus_loop_remove_watch (watch, server_watch_callback, data); + DBusServer *server = data; + BusContext *context; + + context = server_get_context (server); + + bus_loop_remove_watch (context->loop, + watch, server_watch_callback, server); } @@ -86,14 +161,26 @@ static dbus_bool_t add_server_timeout (DBusTimeout *timeout, void *data) { - return bus_loop_add_timeout (timeout, server_timeout_callback, data, NULL); + DBusServer *server = data; + BusContext *context; + + context = server_get_context (server); + + return bus_loop_add_timeout (context->loop, + timeout, server_timeout_callback, server, NULL); } static void remove_server_timeout (DBusTimeout *timeout, void *data) { - bus_loop_remove_timeout (timeout, server_timeout_callback, data); + DBusServer *server = data; + BusContext *context; + + context = server_get_context (server); + + bus_loop_remove_timeout (context->loop, + timeout, server_timeout_callback, server); } static void @@ -139,12 +226,22 @@ free_rule_list_func (void *data) dbus_free (list); } +static void +free_server_data (void *data) +{ + BusServerData *bd = data; + + dbus_free (bd); +} + static dbus_bool_t setup_server (BusContext *context, DBusServer *server, char **auth_mechanisms, DBusError *error) { + BusServerData *bd; + if (!dbus_server_set_auth_mechanisms (server, (const char**) auth_mechanisms)) { BUS_SET_OOM (error); @@ -175,7 +272,18 @@ setup_server (BusContext *context, BUS_SET_OOM (error); return FALSE; } + + bd = dbus_new0 (BusServerData, 1); + if (!dbus_server_set_data (server, + server_data_slot, + bd, free_server_data)) + { + dbus_free (bd); + return FALSE; + } + bd->context = context; + return TRUE; } @@ -196,8 +304,18 @@ bus_context_new (const DBusString *config_file, _DBUS_ASSERT_ERROR_IS_CLEAR (error); if (!_dbus_string_init (&full_address)) - return NULL; - + { + BUS_SET_OOM (error); + return NULL; + } + + if (!server_data_slot_ref ()) + { + BUS_SET_OOM (error); + _dbus_string_free (&full_address); + return NULL; + } + parser = NULL; context = NULL; auth_mechanisms = NULL; @@ -215,6 +333,13 @@ bus_context_new (const DBusString *config_file, context->refcount = 1; + context->loop = bus_loop_new (); + if (context->loop == NULL) + { + BUS_SET_OOM (error); + goto failed; + } + /* Build an array of auth mechanisms */ auth_mechanisms_list = bus_config_parser_get_mechanisms (parser); @@ -401,6 +526,9 @@ bus_context_new (const DBusString *config_file, _dbus_string_free (&full_address); dbus_free_string_array (auth_mechanisms); + + server_data_slot_unref (); + return NULL; } @@ -501,9 +629,17 @@ bus_context_unref (BusContext *context) context->rules_by_gid = NULL; } + if (context->loop) + { + bus_loop_unref (context->loop); + context->loop = NULL; + } + dbus_free (context->type); dbus_free (context->address); dbus_free (context); + + server_data_slot_unref (); } } @@ -532,6 +668,12 @@ bus_context_get_activation (BusContext *context) return context->activation; } +BusLoop* +bus_context_get_loop (BusContext *context) +{ + return context->loop; +} + static dbus_bool_t list_allows_user (dbus_bool_t def, DBusList **list, diff --git a/bus/bus.h b/bus/bus.h index 902f5fac..8357f7b8 100644 --- a/bus/bus.h +++ b/bus/bus.h @@ -29,6 +29,8 @@ #include #include +#include "loop.h" + typedef struct BusActivation BusActivation; typedef struct BusConnections BusConnections; typedef struct BusContext BusContext; @@ -47,6 +49,7 @@ const char* bus_context_get_type (BusContext *context) BusRegistry* bus_context_get_registry (BusContext *context); BusConnections* bus_context_get_connections (BusContext *context); BusActivation* bus_context_get_activation (BusContext *context); +BusLoop* bus_context_get_loop (BusContext *context); dbus_bool_t bus_context_allow_user (BusContext *context, unsigned long uid); BusPolicy* bus_context_create_connection_policy (BusContext *context, diff --git a/bus/connection.c b/bus/connection.c index 3c43200f..aa8d65ca 100644 --- a/bus/connection.c +++ b/bus/connection.c @@ -89,6 +89,16 @@ connection_data_slot_unref (void) } } +static BusLoop* +connection_get_loop (DBusConnection *connection) +{ + BusConnectionData *d; + + d = BUS_CONNECTION_DATA (connection); + + return bus_context_get_loop (d->connections->context); +} + void bus_connection_disconnected (DBusConnection *connection) { @@ -195,17 +205,23 @@ connection_watch_callback (DBusWatch *watch, static dbus_bool_t add_connection_watch (DBusWatch *watch, - DBusConnection *connection) + void *data) { - return bus_loop_add_watch (watch, connection_watch_callback, connection, + DBusConnection *connection = data; + + return bus_loop_add_watch (connection_get_loop (connection), + watch, connection_watch_callback, connection, NULL); } static void remove_connection_watch (DBusWatch *watch, - DBusConnection *connection) + void *data) { - bus_loop_remove_watch (watch, connection_watch_callback, connection); + DBusConnection *connection = data; + + bus_loop_remove_watch (connection_get_loop (connection), + watch, connection_watch_callback, connection); } static void @@ -226,16 +242,22 @@ connection_timeout_callback (DBusTimeout *timeout, static dbus_bool_t add_connection_timeout (DBusTimeout *timeout, - DBusConnection *connection) + void *data) { - return bus_loop_add_timeout (timeout, connection_timeout_callback, connection, NULL); + DBusConnection *connection = data; + + return bus_loop_add_timeout (connection_get_loop (connection), + timeout, connection_timeout_callback, connection, NULL); } static void remove_connection_timeout (DBusTimeout *timeout, - DBusConnection *connection) + void *data) { - bus_loop_remove_timeout (timeout, connection_timeout_callback, connection); + DBusConnection *connection = data; + + bus_loop_remove_timeout (connection_get_loop (connection), + timeout, connection_timeout_callback, connection); } static dbus_bool_t @@ -366,16 +388,16 @@ bus_connections_setup_connection (BusConnections *connections, d->group_ids = NULL; if (!dbus_connection_set_watch_functions (connection, - (DBusAddWatchFunction) add_connection_watch, - (DBusRemoveWatchFunction) remove_connection_watch, + add_connection_watch, + remove_connection_watch, NULL, connection, NULL)) goto out; if (!dbus_connection_set_timeout_functions (connection, - (DBusAddTimeoutFunction) add_connection_timeout, - (DBusRemoveTimeoutFunction) remove_connection_timeout, + add_connection_timeout, + remove_connection_timeout, NULL, connection, NULL)) goto out; @@ -400,12 +422,7 @@ bus_connections_setup_connection (BusConnections *connections, out: if (!retval) - { - if (!dbus_connection_set_data (connection, - connection_data_slot, - NULL, NULL)) - _dbus_assert_not_reached ("failed to set connection data to null"); - + { if (!dbus_connection_set_watch_functions (connection, NULL, NULL, NULL, connection, @@ -420,6 +437,11 @@ bus_connections_setup_connection (BusConnections *connections, dbus_connection_set_unix_user_function (connection, NULL, NULL, NULL); + + if (!dbus_connection_set_data (connection, + connection_data_slot, + NULL, NULL)) + _dbus_assert_not_reached ("failed to set connection data to null"); } return retval; diff --git a/bus/dispatch.c b/bus/dispatch.c index 7c65ac42..21d57ae1 100644 --- a/bus/dispatch.c +++ b/bus/dispatch.c @@ -537,8 +537,8 @@ kill_client_connection (BusContext *context, /* kick in the disconnect handler that unrefs the connection */ dbus_connection_disconnect (connection); - bus_test_flush_bus (context); - + bus_test_run_everything (context); + _dbus_assert (bus_test_client_listed (connection)); /* Run disconnect handler in test.c */ @@ -729,8 +729,8 @@ check_hello_message (BusContext *context, dbus_message_unref (message); message = NULL; - - bus_test_flush_bus (context); + + bus_test_run_everything (context); if (!dbus_connection_get_is_connected (connection)) { @@ -963,8 +963,8 @@ check_nonexistent_service_activation (BusContext *context, dbus_message_unref (message); message = NULL; - - bus_test_flush_bus (context); + + bus_test_run_everything (context); if (!dbus_connection_get_is_connected (connection)) { @@ -1028,6 +1028,116 @@ check_nonexistent_service_activation (BusContext *context, return retval; } +#define EXISTENT_SERVICE_NAME "org.freedesktop.DBus.TestSuiteEchoService" + +/* returns TRUE if the correct thing happens, + * but the correct thing may include OOM errors. + */ +static dbus_bool_t +check_existent_service_activation (BusContext *context, + DBusConnection *connection) +{ + DBusMessage *message; + dbus_int32_t serial; + dbus_bool_t retval; + DBusError error; + + dbus_error_init (&error); + + message = dbus_message_new (DBUS_SERVICE_DBUS, + DBUS_MESSAGE_ACTIVATE_SERVICE); + + if (message == NULL) + return TRUE; + + if (!dbus_message_append_args (message, + DBUS_TYPE_STRING, EXISTENT_SERVICE_NAME, + DBUS_TYPE_UINT32, 0, + DBUS_TYPE_INVALID)) + { + dbus_message_unref (message); + return TRUE; + } + + if (!dbus_connection_send (connection, message, &serial)) + { + dbus_message_unref (message); + return TRUE; + } + + dbus_message_unref (message); + message = NULL; + + bus_test_run_everything (context); + + /* now wait for the message bus to hear back from the activated service */ + bus_test_run_bus_loop (context); + + /* and process everything again */ + bus_test_run_everything (context); + + if (!dbus_connection_get_is_connected (connection)) + { + _dbus_verbose ("connection was disconnected\n"); + return TRUE; + } + + retval = FALSE; + + message = dbus_connection_pop_message (connection); + if (message == NULL) + { + _dbus_warn ("Did not receive a reply to %s %d on %p\n", + DBUS_MESSAGE_ACTIVATE_SERVICE, serial, connection); + goto out; + } + + _dbus_verbose ("Received %s on %p\n", + dbus_message_get_name (message), connection); + + if (dbus_message_get_is_error (message)) + { + if (!dbus_message_sender_is (message, DBUS_SERVICE_DBUS)) + { + _dbus_warn ("Message has wrong sender %s\n", + dbus_message_get_sender (message) ? + dbus_message_get_sender (message) : "(none)"); + goto out; + } + + if (dbus_message_name_is (message, + DBUS_ERROR_NO_MEMORY)) + { + ; /* good, this is a valid response */ + } + else if (dbus_message_name_is (message, + DBUS_ERROR_ACTIVATE_SERVICE_NOT_FOUND)) + { + ; /* good, this is expected also */ + } + else + { + _dbus_warn ("Did not expect error %s\n", + dbus_message_get_name (message)); + goto out; + } + } + else + { + _dbus_warn ("Did not expect to successfully activate %s\n", + EXISTENT_SERVICE_NAME); + goto out; + } + + retval = TRUE; + + out: + if (message) + dbus_message_unref (message); + + return retval; +} + typedef struct { Check1Func func; @@ -1153,6 +1263,11 @@ bus_dispatch_test (const DBusString *test_data_dir) if (!check_hello_message (context, baz)) _dbus_assert_not_reached ("hello message failed"); +#if 0 + check2_try_iterations (context, foo, "existent_service_activation", + check_existent_service_activation); +#endif + check2_try_iterations (context, foo, "nonexistent_service_activation", check_nonexistent_service_activation); diff --git a/bus/loop.c b/bus/loop.c index 93096dc5..a237defa 100644 --- a/bus/loop.c +++ b/bus/loop.c @@ -26,11 +26,15 @@ #include #include -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; +struct BusLoop +{ + int refcount; + DBusList *callbacks; + int callback_list_serial; + int watch_count; + int timeout_count; + int depth; /**< number of recursive runs */ +}; typedef enum { @@ -121,20 +125,21 @@ callback_free (Callback *cb) } static dbus_bool_t -add_callback (Callback *cb) +add_callback (BusLoop *loop, + Callback *cb) { - if (!_dbus_list_append (&callbacks, cb)) + if (!_dbus_list_append (&loop->callbacks, cb)) return FALSE; - callback_list_serial += 1; + loop->callback_list_serial += 1; switch (cb->type) { case CALLBACK_WATCH: - watch_count += 1; + loop->watch_count += 1; break; case CALLBACK_TIMEOUT: - timeout_count += 1; + loop->timeout_count += 1; break; } @@ -142,27 +147,66 @@ add_callback (Callback *cb) } static void -remove_callback (DBusList *link) +remove_callback (BusLoop *loop, + DBusList *link) { Callback *cb = link->data; switch (cb->type) { case CALLBACK_WATCH: - watch_count -= 1; + loop->watch_count -= 1; break; case CALLBACK_TIMEOUT: - timeout_count -= 1; + loop->timeout_count -= 1; break; } callback_free (cb); - _dbus_list_remove_link (&callbacks, link); - callback_list_serial += 1; + _dbus_list_remove_link (&loop->callbacks, link); + loop->callback_list_serial += 1; +} + +BusLoop* +bus_loop_new (void) +{ + BusLoop *loop; + + loop = dbus_new0 (BusLoop, 1); + if (loop == NULL) + return NULL; + + loop->refcount = 1; + + return loop; +} + +void +bus_loop_ref (BusLoop *loop) +{ + _dbus_assert (loop != NULL); + _dbus_assert (loop->refcount > 0); + + loop->refcount += 1; +} + +void +bus_loop_unref (BusLoop *loop) +{ + _dbus_assert (loop != NULL); + _dbus_assert (loop->refcount > 0); + + loop->refcount -= 1; + if (loop->refcount == 0) + { + + dbus_free (loop); + } } dbus_bool_t -bus_loop_add_watch (DBusWatch *watch, +bus_loop_add_watch (BusLoop *loop, + DBusWatch *watch, BusWatchFunction function, void *data, DBusFreeFunction free_data_func) @@ -173,7 +217,7 @@ bus_loop_add_watch (DBusWatch *watch, if (wcb == NULL) return FALSE; - if (!add_callback ((Callback*) wcb)) + if (!add_callback (loop, (Callback*) wcb)) { wcb->callback.free_data_func = NULL; /* don't want to have this side effect */ callback_free ((Callback*) wcb); @@ -184,16 +228,17 @@ bus_loop_add_watch (DBusWatch *watch, } void -bus_loop_remove_watch (DBusWatch *watch, +bus_loop_remove_watch (BusLoop *loop, + DBusWatch *watch, BusWatchFunction function, void *data) { DBusList *link; - link = _dbus_list_get_first_link (&callbacks); + link = _dbus_list_get_first_link (&loop->callbacks); while (link != NULL) { - DBusList *next = _dbus_list_get_next_link (&callbacks, link); + DBusList *next = _dbus_list_get_next_link (&loop->callbacks, link); Callback *this = link->data; if (this->type == CALLBACK_WATCH && @@ -201,7 +246,7 @@ bus_loop_remove_watch (DBusWatch *watch, this->data == data && WATCH_CALLBACK (this)->function == function) { - remove_callback (link); + remove_callback (loop, link); return; } @@ -214,7 +259,8 @@ bus_loop_remove_watch (DBusWatch *watch, } dbus_bool_t -bus_loop_add_timeout (DBusTimeout *timeout, +bus_loop_add_timeout (BusLoop *loop, + DBusTimeout *timeout, BusTimeoutFunction function, void *data, DBusFreeFunction free_data_func) @@ -225,7 +271,7 @@ bus_loop_add_timeout (DBusTimeout *timeout, if (tcb == NULL) return FALSE; - if (!add_callback ((Callback*) tcb)) + if (!add_callback (loop, (Callback*) tcb)) { tcb->callback.free_data_func = NULL; /* don't want to have this side effect */ callback_free ((Callback*) tcb); @@ -236,16 +282,17 @@ bus_loop_add_timeout (DBusTimeout *timeout, } void -bus_loop_remove_timeout (DBusTimeout *timeout, +bus_loop_remove_timeout (BusLoop *loop, + DBusTimeout *timeout, BusTimeoutFunction function, void *data) { DBusList *link; - link = _dbus_list_get_first_link (&callbacks); + link = _dbus_list_get_first_link (&loop->callbacks); while (link != NULL) { - DBusList *next = _dbus_list_get_next_link (&callbacks, link); + DBusList *next = _dbus_list_get_next_link (&loop->callbacks, link); Callback *this = link->data; if (this->type == CALLBACK_TIMEOUT && @@ -253,7 +300,7 @@ bus_loop_remove_timeout (DBusTimeout *timeout, this->data == data && TIMEOUT_CALLBACK (this)->function == function) { - remove_callback (link); + remove_callback (loop, link); return; } @@ -270,7 +317,8 @@ bus_loop_remove_timeout (DBusTimeout *timeout, */ dbus_bool_t -bus_loop_iterate (dbus_bool_t block) +bus_loop_iterate (BusLoop *loop, + dbus_bool_t block) { dbus_bool_t retval; DBusPollFD *fds; @@ -282,30 +330,32 @@ bus_loop_iterate (dbus_bool_t block) int initial_serial; long timeout; dbus_bool_t oom_watch_pending; + int orig_depth; retval = FALSE; fds = NULL; watches_for_fds = NULL; oom_watch_pending = FALSE; - + orig_depth = loop->depth; + #if 0 _dbus_verbose (" iterate %d timeouts %d watches\n", - timeout_count, watch_count); + loop->timeout_count, loop->watch_count); #endif - if (callbacks == NULL) + if (loop->callbacks == NULL) { - bus_loop_quit (); + bus_loop_quit (loop); goto next_iteration; } /* count enabled watches */ n_fds = 0; - link = _dbus_list_get_first_link (&callbacks); + link = _dbus_list_get_first_link (&loop->callbacks); while (link != NULL) { - DBusList *next = _dbus_list_get_next_link (&callbacks, link); + DBusList *next = _dbus_list_get_next_link (&loop->callbacks, link); Callback *cb = link->data; if (cb->type == CALLBACK_WATCH) { @@ -337,10 +387,10 @@ bus_loop_iterate (dbus_bool_t block) } i = 0; - link = _dbus_list_get_first_link (&callbacks); + link = _dbus_list_get_first_link (&loop->callbacks); while (link != NULL) { - DBusList *next = _dbus_list_get_next_link (&callbacks, link); + DBusList *next = _dbus_list_get_next_link (&loop->callbacks, link); Callback *cb = link->data; if (cb->type == CALLBACK_WATCH) { @@ -378,7 +428,7 @@ bus_loop_iterate (dbus_bool_t block) } timeout = -1; - if (timeout_count > 0) + if (loop->timeout_count > 0) { unsigned long tv_sec; unsigned long tv_usec; @@ -387,10 +437,10 @@ bus_loop_iterate (dbus_bool_t block) _dbus_get_current_time (&tv_sec, &tv_usec); - link = _dbus_list_get_first_link (&callbacks); + link = _dbus_list_get_first_link (&loop->callbacks); while (link != NULL) { - DBusList *next = _dbus_list_get_next_link (&callbacks, link); + DBusList *next = _dbus_list_get_next_link (&loop->callbacks, link); Callback *cb = link->data; if (cb->type == CALLBACK_TIMEOUT && @@ -446,9 +496,9 @@ bus_loop_iterate (dbus_bool_t block) n_ready = _dbus_poll (fds, n_fds, timeout); - initial_serial = callback_list_serial; + initial_serial = loop->callback_list_serial; - if (timeout_count > 0) + if (loop->timeout_count > 0) { unsigned long tv_sec; unsigned long tv_usec; @@ -456,16 +506,16 @@ bus_loop_iterate (dbus_bool_t block) _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); + link = _dbus_list_get_first_link (&loop->callbacks); while (link != NULL) { - DBusList *next = _dbus_list_get_next_link (&callbacks, link); + DBusList *next = _dbus_list_get_next_link (&loop->callbacks, link); Callback *cb = link->data; - if (initial_serial != callback_list_serial) + if (initial_serial != loop->callback_list_serial) goto next_iteration; - if (exited) + if (loop->depth != orig_depth) goto next_iteration; if (cb->type == CALLBACK_TIMEOUT && @@ -528,10 +578,10 @@ bus_loop_iterate (dbus_bool_t block) * approach could result in starving watches * toward the end of the list. */ - if (initial_serial != callback_list_serial) + if (initial_serial != loop->callback_list_serial) goto next_iteration; - if (exited) + if (loop->depth != orig_depth) goto next_iteration; if (fds[i].revents != 0) @@ -578,16 +628,26 @@ bus_loop_iterate (dbus_bool_t block) return retval; } - void -bus_loop_run (void) +bus_loop_run (BusLoop *loop) { - while (!exited) - bus_loop_iterate (TRUE); + int our_exit_depth; + + bus_loop_ref (loop); + + our_exit_depth = loop->depth; + loop->depth += 1; + + while (loop->depth != our_exit_depth) + bus_loop_iterate (loop, TRUE); + + bus_loop_unref (loop); } void -bus_loop_quit (void) +bus_loop_quit (BusLoop *loop) { - exited = TRUE; + _dbus_assert (loop->depth > 0); + + loop->depth -= 1; } diff --git a/bus/loop.h b/bus/loop.h index b217a776..19b3bcd4 100644 --- a/bus/loop.h +++ b/bus/loop.h @@ -26,28 +26,40 @@ #include +typedef struct BusLoop BusLoop; + typedef dbus_bool_t (* BusWatchFunction) (DBusWatch *watch, unsigned int condition, void *data); typedef void (* BusTimeoutFunction) (DBusTimeout *timeout, void *data); -dbus_bool_t bus_loop_add_watch (DBusWatch *watch, + +BusLoop* bus_loop_new (void); +void bus_loop_ref (BusLoop *loop); +void bus_loop_unref (BusLoop *loop); +dbus_bool_t bus_loop_add_watch (BusLoop *loop, + DBusWatch *watch, BusWatchFunction function, void *data, DBusFreeFunction free_data_func); -void bus_loop_remove_watch (DBusWatch *watch, +void bus_loop_remove_watch (BusLoop *loop, + DBusWatch *watch, BusWatchFunction function, void *data); -dbus_bool_t bus_loop_add_timeout (DBusTimeout *timeout, +dbus_bool_t bus_loop_add_timeout (BusLoop *loop, + DBusTimeout *timeout, BusTimeoutFunction function, void *data, DBusFreeFunction free_data_func); -void bus_loop_remove_timeout (DBusTimeout *timeout, +void bus_loop_remove_timeout (BusLoop *loop, + DBusTimeout *timeout, BusTimeoutFunction function, void *data); -void bus_loop_run (void); -void bus_loop_quit (void); -dbus_bool_t bus_loop_iterate (dbus_bool_t block); +void bus_loop_run (BusLoop *loop); +void bus_loop_quit (BusLoop *loop); +dbus_bool_t bus_loop_iterate (BusLoop *loop, + dbus_bool_t block); + #endif /* BUS_LOOP_H */ diff --git a/bus/main.c b/bus/main.c index fcde3493..099219c3 100644 --- a/bus/main.c +++ b/bus/main.c @@ -143,7 +143,7 @@ main (int argc, char **argv) } _dbus_verbose ("We are on D-Bus...\n"); - bus_loop_run (); + bus_loop_run (bus_context_get_loop (context)); bus_context_shutdown (context); bus_context_unref (context); diff --git a/bus/test.c b/bus/test.c index d6697085..00a522c6 100644 --- a/bus/test.c +++ b/bus/test.c @@ -34,11 +34,12 @@ * are different from the real handlers in connection.c */ static DBusList *clients = NULL; +static BusLoop *client_loop = NULL; static dbus_bool_t client_watch_callback (DBusWatch *watch, - unsigned int condition, - void *data) + unsigned int condition, + void *data) { DBusConnection *connection = data; dbus_bool_t retval; @@ -54,22 +55,28 @@ client_watch_callback (DBusWatch *watch, static dbus_bool_t add_client_watch (DBusWatch *watch, - DBusConnection *connection) + void *data) { - return bus_loop_add_watch (watch, client_watch_callback, connection, + DBusConnection *connection = data; + + return bus_loop_add_watch (client_loop, + watch, client_watch_callback, connection, NULL); } static void remove_client_watch (DBusWatch *watch, - DBusConnection *connection) + void *data) { - bus_loop_remove_watch (watch, client_watch_callback, connection); + DBusConnection *connection = data; + + bus_loop_remove_watch (client_loop, + watch, client_watch_callback, connection); } static void client_timeout_callback (DBusTimeout *timeout, - void *data) + void *data) { DBusConnection *connection = data; @@ -83,16 +90,20 @@ client_timeout_callback (DBusTimeout *timeout, static dbus_bool_t add_client_timeout (DBusTimeout *timeout, - DBusConnection *connection) + void *data) { - return bus_loop_add_timeout (timeout, client_timeout_callback, connection, NULL); + DBusConnection *connection = data; + + return bus_loop_add_timeout (client_loop, timeout, client_timeout_callback, connection, NULL); } static void remove_client_timeout (DBusTimeout *timeout, - DBusConnection *connection) + void *data) { - bus_loop_remove_timeout (timeout, client_timeout_callback, connection); + DBusConnection *connection = data; + + bus_loop_remove_timeout (client_loop, timeout, client_timeout_callback, connection); } static DBusHandlerResult @@ -105,9 +116,15 @@ client_disconnect_handler (DBusMessageHandler *handler, connection); _dbus_list_remove (&clients, connection); - + dbus_connection_unref (connection); + if (clients == NULL) + { + bus_loop_unref (client_loop); + client_loop = NULL; + } + return DBUS_HANDLER_RESULT_ALLOW_MORE_HANDLERS; } @@ -179,18 +196,25 @@ bus_setup_debug_client (DBusConnection *connection) } retval = FALSE; + + if (client_loop == NULL) + { + client_loop = bus_loop_new (); + if (client_loop == NULL) + goto out; + } if (!dbus_connection_set_watch_functions (connection, - (DBusAddWatchFunction) add_client_watch, - (DBusRemoveWatchFunction) remove_client_watch, + add_client_watch, + remove_client_watch, NULL, connection, NULL)) goto out; if (!dbus_connection_set_timeout_functions (connection, - (DBusAddTimeoutFunction) add_client_timeout, - (DBusRemoveTimeoutFunction) remove_client_timeout, + add_client_timeout, + remove_client_timeout, NULL, connection, NULL)) goto out; @@ -223,6 +247,12 @@ bus_setup_debug_client (DBusConnection *connection) NULL, NULL, NULL, NULL, NULL); _dbus_list_remove_last (&clients, connection); + + if (clients == NULL) + { + bus_loop_unref (client_loop); + client_loop = NULL; + } } return retval; @@ -268,25 +298,45 @@ bus_test_client_listed (DBusConnection *connection) } void -bus_test_flush_bus (BusContext *context) +bus_test_run_clients_loop (void) { - /* This is race condition city, obviously. since we're all in one - * process we can't block, we just have to wait for data we put in - * one end of the debug pipe to come out the other end... - * a more robust setup would be good. Blocking on the other - * end of pipes we've pushed data into or something. - * A simple hack might be to just make the debug server always - * poll for read on the other end of the pipe after writing. - */ - while (bus_loop_iterate (FALSE)) + if (client_loop == NULL) + return; + + /* Do one blocking wait, since we're expecting data */ + bus_loop_iterate (client_loop, TRUE); + + /* Then mop everything up */ + while (bus_loop_iterate (client_loop, FALSE)) ; -#if 0 - _dbus_sleep_milliseconds (15); -#endif - while (bus_loop_iterate (FALSE)) +} + +void +bus_test_run_bus_loop (BusContext *context) +{ + /* Do one blocking wait, since we're expecting data */ + bus_loop_iterate (bus_context_get_loop (context), TRUE); + + /* Then mop everything up */ + while (bus_loop_iterate (bus_context_get_loop (context), FALSE)) ; } +void +bus_test_run_everything (BusContext *context) +{ + int i; + + i = 0; + while (i < 2) + { + while (bus_loop_iterate (bus_context_get_loop (context), FALSE) || + (client_loop == NULL || bus_loop_iterate (client_loop, FALSE))) + ; + ++i; + } +} + BusContext* bus_context_new_test (const DBusString *test_data_dir, const char *filename) diff --git a/bus/test.h b/bus/test.h index d8ab67b8..5606bb99 100644 --- a/bus/test.h +++ b/bus/test.h @@ -32,17 +32,19 @@ #include #include "connection.h" -dbus_bool_t bus_dispatch_test (const DBusString *test_data_dir); -dbus_bool_t bus_policy_test (const DBusString *test_data_dir); -dbus_bool_t bus_config_parser_test (const DBusString *test_data_dir); -dbus_bool_t bus_setup_debug_client (DBusConnection *connection); -void bus_test_clients_foreach (BusConnectionForeachFunction function, - void *data); -dbus_bool_t bus_test_client_listed (DBusConnection *connection); -void bus_test_flush_bus (BusContext *context); - -BusContext* bus_context_new_test (const DBusString *test_data_dir, - const char *filename); +dbus_bool_t bus_dispatch_test (const DBusString *test_data_dir); +dbus_bool_t bus_policy_test (const DBusString *test_data_dir); +dbus_bool_t bus_config_parser_test (const DBusString *test_data_dir); +dbus_bool_t bus_setup_debug_client (DBusConnection *connection); +void bus_test_clients_foreach (BusConnectionForeachFunction function, + void *data); +dbus_bool_t bus_test_client_listed (DBusConnection *connection); +void bus_test_run_bus_loop (BusContext *context); +void bus_test_run_clients_loop (void); +void bus_test_run_everything (BusContext *context); +BusContext* bus_context_new_test (const DBusString *test_data_dir, + const char *filename); + #endif diff --git a/doc/TODO b/doc/TODO index f6c539dd..c4e3e830 100644 --- a/doc/TODO +++ b/doc/TODO @@ -59,3 +59,9 @@ to return an error that automatically gets turned into a message; most likely some basic spec'ing out of the GLib/Qt level stubs/skels stuff will be needed to understand the right approach. + + - sync up DBusWatch and DBusTimeout so that handle_watch() is a method on DBusWatch + similar to the way timeouts work + + - there are various bits of code to manage ref/unref of data slots, that should + be merged into a generic facility -- cgit