diff options
Diffstat (limited to 'glib')
-rw-r--r-- | glib/dbus-gmain.c | 116 | ||||
-rw-r--r-- | glib/test-dbus-glib.c | 50 | ||||
-rw-r--r-- | glib/test-profile.c | 223 | ||||
-rw-r--r-- | glib/test-thread-client.c | 95 | ||||
-rw-r--r-- | glib/test-thread-server.c | 248 | ||||
-rw-r--r-- | glib/test-thread.h | 1 |
6 files changed, 695 insertions, 38 deletions
diff --git a/glib/dbus-gmain.c b/glib/dbus-gmain.c index 54a2d462..68ba22d7 100644 --- a/glib/dbus-gmain.c +++ b/glib/dbus-gmain.c @@ -60,14 +60,53 @@ struct DBusGSource { GSource source; /**< the parent GSource */ - GList *poll_fds; /**< descriptors we're watching */ - GHashTable *watches; /**< hash of DBusWatch objects */ + GList *watch_fds; /**< descriptors we're watching */ GMainContext *context; /**< the GMainContext to use, NULL for default */ void *connection_or_server; /**< DBusConnection or DBusServer */ }; +typedef struct +{ + int refcount; + + GPollFD poll_fd; + DBusWatch *watch; + + unsigned int removed : 1; +} WatchFD; + +static WatchFD * +watch_fd_new (void) +{ + WatchFD *watch_fd; + + watch_fd = g_new0 (WatchFD, 1); + watch_fd->refcount = 1; + + return watch_fd; +} + +static void +watch_fd_ref (WatchFD *watch_fd) +{ + watch_fd->refcount += 1; +} + +static void +watch_fd_unref (WatchFD *watch_fd) +{ + watch_fd->refcount -= 1; + + if (watch_fd->refcount == 0) + { + g_assert (watch_fd->removed); + + g_free (watch_fd); + } +} + static dbus_int32_t connection_slot = -1; static dbus_int32_t server_slot = -1; @@ -124,13 +163,13 @@ dbus_gsource_check (GSource *source) DBusGSource *dbus_source = (DBusGSource *)source; GList *list; - list = dbus_source->poll_fds; + list = dbus_source->watch_fds; while (list) { - GPollFD *poll_fd = list->data; + WatchFD *watch_fd = list->data; - if (poll_fd->revents != 0) + if (watch_fd->poll_fd.revents != 0) return TRUE; list = list->next; @@ -160,35 +199,35 @@ dbus_gsource_dispatch (GSource *source, DBusGSource *dbus_source = (DBusGSource *)source; GList *copy, *list; - /* We need to traverse a copy of the list, since it can change in - dbus_watch_handle(). */ - copy = g_list_copy (dbus_source->poll_fds); - + /* Make a copy of the list and ref all WatchFDs */ + copy = g_list_copy (dbus_source->watch_fds); + g_list_foreach (copy, (GFunc)watch_fd_ref, NULL); + list = copy; while (list) { - GPollFD *poll_fd = list->data; + WatchFD *watch_fd = list->data; - if (poll_fd->revents != 0) + if (!watch_fd->removed && watch_fd->poll_fd.revents != 0) { - DBusWatch *watch = g_hash_table_lookup (dbus_source->watches, poll_fd); guint condition = 0; - if (poll_fd->revents & G_IO_IN) + if (watch_fd->poll_fd.revents & G_IO_IN) condition |= DBUS_WATCH_READABLE; - if (poll_fd->revents & G_IO_OUT) + if (watch_fd->poll_fd.revents & G_IO_OUT) condition |= DBUS_WATCH_WRITABLE; - if (poll_fd->revents & G_IO_ERR) + if (watch_fd->poll_fd.revents & G_IO_ERR) condition |= DBUS_WATCH_ERROR; - if (poll_fd->revents & G_IO_HUP) + if (watch_fd->poll_fd.revents & G_IO_HUP) condition |= DBUS_WATCH_HANGUP; - dbus_watch_handle (watch, condition); + dbus_watch_handle (watch_fd->watch, condition); } list = list->next; } + g_list_foreach (copy, (GFunc)watch_fd_unref, NULL); g_list_free (copy); return TRUE; @@ -238,7 +277,7 @@ static dbus_bool_t add_watch (DBusWatch *watch, gpointer data) { - GPollFD *poll_fd; + WatchFD *watch_fd; DBusGSource *dbus_source; guint flags; @@ -246,23 +285,24 @@ add_watch (DBusWatch *watch, return TRUE; dbus_source = data; - - poll_fd = g_new (GPollFD, 1); - poll_fd->fd = dbus_watch_get_fd (watch); - poll_fd->events = 0; + + watch_fd = watch_fd_new (); + watch_fd->poll_fd.fd = dbus_watch_get_fd (watch); + watch_fd->poll_fd.events = 0; flags = dbus_watch_get_flags (watch); - dbus_watch_set_data (watch, poll_fd, NULL); + dbus_watch_set_data (watch, watch_fd, (DBusFreeFunction)watch_fd_unref); if (flags & DBUS_WATCH_READABLE) - poll_fd->events |= G_IO_IN; + watch_fd->poll_fd.events |= G_IO_IN; if (flags & DBUS_WATCH_WRITABLE) - poll_fd->events |= G_IO_OUT; - poll_fd->events |= G_IO_ERR | G_IO_HUP; + watch_fd->poll_fd.events |= G_IO_OUT; + watch_fd->poll_fd.events |= G_IO_ERR | G_IO_HUP; - g_source_add_poll ((GSource *)dbus_source, poll_fd); + watch_fd->watch = watch; + + g_source_add_poll ((GSource *)dbus_source, &watch_fd->poll_fd); - dbus_source->poll_fds = g_list_prepend (dbus_source->poll_fds, poll_fd); - g_hash_table_insert (dbus_source->watches, poll_fd, watch); + dbus_source->watch_fds = g_list_prepend (dbus_source->watch_fds, watch_fd); return TRUE; } @@ -272,21 +312,22 @@ remove_watch (DBusWatch *watch, gpointer data) { DBusGSource *dbus_source = data; - GPollFD *poll_fd; + WatchFD *watch_fd; - poll_fd = dbus_watch_get_data (watch); - if (poll_fd == NULL) + watch_fd = dbus_watch_get_data (watch); + if (watch_fd == NULL) return; /* probably a not-enabled watch that was added */ + + watch_fd->removed = TRUE; + watch_fd->watch = NULL; - dbus_source->poll_fds = g_list_remove (dbus_source->poll_fds, poll_fd); - g_hash_table_remove (dbus_source->watches, poll_fd); - g_source_remove_poll ((GSource *)dbus_source, poll_fd); + dbus_source->watch_fds = g_list_remove (dbus_source->watch_fds, watch_fd); + + g_source_remove_poll ((GSource *)dbus_source, &watch_fd->poll_fd); dbus_watch_set_data (watch, NULL, NULL); /* needed due to watch_toggled * breaking add/remove symmetry */ - - g_free (poll_fd); } static void @@ -390,7 +431,6 @@ create_source (void *connection_or_server, source = g_source_new (funcs, sizeof (DBusGSource)); dbus_source = (DBusGSource *)source; - dbus_source->watches = g_hash_table_new (NULL, NULL); dbus_source->connection_or_server = connection_or_server; dbus_source->context = context; diff --git a/glib/test-dbus-glib.c b/glib/test-dbus-glib.c new file mode 100644 index 00000000..d963ee3d --- /dev/null +++ b/glib/test-dbus-glib.c @@ -0,0 +1,50 @@ +/* -*- mode: C; c-file-style: "gnu" -*- */ +#include "dbus-glib.h" +#include <stdio.h> + +int +main (int argc, char **argv) +{ + DBusConnection *connection; + DBusMessage *message, *reply; + GMainLoop *loop; + DBusError error; + + if (argc < 2) + { + g_printerr ("Give the server address as an argument\n"); + return 1; + } + + loop = g_main_loop_new (NULL, FALSE); + + dbus_error_init (&error); + connection = dbus_connection_open (argv[1], &error); + if (connection == NULL) + { + g_printerr ("Failed to open connection to %s: %s\n", argv[1], + error.message); + dbus_error_free (&error); + return 1; + } + + dbus_connection_setup_with_g_main (connection, NULL); + + message = dbus_message_new (DBUS_MESSAGE_HELLO, + DBUS_SERVICE_DBUS); + + dbus_error_init (&error); + reply = dbus_connection_send_with_reply_and_block (connection, message, -1, &error); + if (reply == NULL) + { + g_printerr ("Error on hello message: %s\n", error.message); + dbus_error_free (&error); + return 1; + } + + g_print ("reply name: %s\n", dbus_message_get_name (reply)); + + g_main_loop_run (loop); + + return 0; +} diff --git a/glib/test-profile.c b/glib/test-profile.c new file mode 100644 index 00000000..f213c676 --- /dev/null +++ b/glib/test-profile.c @@ -0,0 +1,223 @@ +/* -*- mode: C; c-file-style: "gnu" -*- */ +/* test-profile.c Program that does basic message-response for timing + * + * Copyright (C) 2003 Red Hat Inc. + * + * Licensed under the Academic Free License version 1.2 + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * + */ + +#include <config.h> +#include <glib.h> +#include "dbus-glib.h" +#include <stdlib.h> + +#define N_CLIENT_THREADS 1 +#define N_ITERATIONS 1000 +#define PAYLOAD_SIZE 30 +#define ECHO_MESSAGE "org.freedesktop.DBus.Test.EchoProfile" +static const char *address; +static unsigned char *payload; + +static void +send_echo_message (DBusConnection *connection) +{ + DBusMessage *message; + + message = dbus_message_new (ECHO_MESSAGE, NULL); + dbus_message_append_args (message, + DBUS_TYPE_STRING, "Hello World!", + DBUS_TYPE_INT32, 123456, +#if 1 + DBUS_TYPE_ARRAY, DBUS_TYPE_BYTE, + payload, PAYLOAD_SIZE, +#endif + DBUS_TYPE_INVALID); + + dbus_connection_send (connection, message, NULL); + dbus_message_unref (message); + dbus_connection_flush (connection); +} + +static DBusHandlerResult +client_filter (DBusMessageHandler *handler, + DBusConnection *connection, + DBusMessage *message, + void *user_data) +{ + int *iterations = user_data; + + if (dbus_message_has_name (message, DBUS_MESSAGE_LOCAL_DISCONNECT)) + { + g_printerr ("Client thread disconnected\n"); + exit (1); + } + else if (dbus_message_has_name (message, + ECHO_MESSAGE)) + { + *iterations += 1; + if (*iterations >= N_ITERATIONS) + { + g_print ("Completed %d iterations\n", N_ITERATIONS); + exit (0); + } + send_echo_message (connection); + } + + return DBUS_HANDLER_RESULT_ALLOW_MORE_HANDLERS; +} + +static void* +thread_func (void *data) +{ + DBusError error; + GMainContext *context; + GMainLoop *loop; + DBusMessageHandler *handler; + DBusConnection *connection; + int iterations; + + g_printerr ("Starting client thread\n"); + + dbus_error_init (&error); + connection = dbus_connection_open (address, &error); + if (connection == NULL) + { + g_printerr ("could not open connection: %s\n", error.message); + dbus_error_free (&error); + exit (1); + } + + iterations = 1; + + handler = dbus_message_handler_new (client_filter, + &iterations, NULL); + + if (!dbus_connection_add_filter (connection, + handler)) + g_error ("no memory"); + + /* FIXME we leak the handler */ + + context = g_main_context_new (); + loop = g_main_loop_new (context, FALSE); + + dbus_connection_setup_with_g_main (connection, context); + + g_printerr ("Client thread sending message to prime pingpong\n"); + send_echo_message (connection); + g_printerr ("Client thread sent message\n"); + + g_printerr ("Client thread entering main loop\n"); + g_main_loop_run (loop); + g_printerr ("Client thread exiting main loop\n"); + + g_main_loop_unref (loop); + g_main_context_unref (context); + + return NULL; +} + +static DBusHandlerResult +server_filter (DBusMessageHandler *handler, + DBusConnection *connection, + DBusMessage *message, + void *user_data) +{ + if (dbus_message_has_name (message, DBUS_MESSAGE_LOCAL_DISCONNECT)) + { + g_printerr ("Server thread disconnected\n"); + exit (1); + } + else if (dbus_message_has_name (message, + ECHO_MESSAGE)) + { + send_echo_message (connection); + } + + return DBUS_HANDLER_RESULT_ALLOW_MORE_HANDLERS; +} + +static void +new_connection_callback (DBusServer *server, + DBusConnection *new_connection, + void *user_data) +{ + DBusMessageHandler *handler; + + dbus_connection_ref (new_connection); + dbus_connection_setup_with_g_main (new_connection, NULL); + + handler = dbus_message_handler_new (server_filter, + NULL, NULL); + + if (!dbus_connection_add_filter (new_connection, + handler)) + g_error ("no memory"); + + + /* FIXME we leak the handler */ +} + +int +main (int argc, char *argv[]) +{ + GMainLoop *loop; + DBusError error; + DBusServer *server; + int i; + + g_thread_init (NULL); + dbus_gthread_init (); + + dbus_error_init (&error); + server = dbus_server_listen ("unix:tmpdir="DBUS_TEST_SOCKET_DIR, + &error); + if (server == NULL) + { + g_printerr ("Could not start server: %s\n", + error.message); + return 1; + } + + address = dbus_server_get_address (server); + payload = g_malloc (PAYLOAD_SIZE); + + dbus_server_set_new_connection_function (server, + new_connection_callback, + NULL, NULL); + + loop = g_main_loop_new (NULL, FALSE); + + dbus_server_setup_with_g_main (server, NULL); + + for (i = 0; i < N_CLIENT_THREADS; i++) + { + g_thread_create (thread_func, NULL, FALSE, NULL); + } + + g_printerr ("Server thread entering main loop\n"); + g_main_loop_run (loop); + g_printerr ("Server thread exiting main loop\n"); + + dbus_server_unref (server); + + g_main_loop_unref (loop); + + return 0; +} + diff --git a/glib/test-thread-client.c b/glib/test-thread-client.c new file mode 100644 index 00000000..02ebdf67 --- /dev/null +++ b/glib/test-thread-client.c @@ -0,0 +1,95 @@ +#include <glib.h> +#include "dbus-glib.h" +#include <stdio.h> +#include <string.h> +#include <unistd.h> + +#include "test-thread.h" + +DBusConnection *connection; + +static gpointer +thread_func (gpointer data) +{ + gint32 threadnr = GPOINTER_TO_INT (data); + guint32 counter = 0; + DBusMessageIter iter; + DBusMessage *message; + char *str; + + while (1) + { + message = dbus_message_new ("org.freedesktop.ThreadTest", NULL); + + dbus_message_append_iter_init (message, &iter); + + if (!dbus_message_iter_append_int32 (&iter, threadnr)) + { + g_print ("thread %d: append threadnr failed\n", threadnr); + } + + if (!dbus_message_iter_append_uint32 (&iter, counter)) + { + g_print ("thread %d: append counter (%d) failed\n", threadnr, counter); + } + + str = g_strdup_printf ("Thread %d-%d\n", threadnr, counter); + if (!dbus_message_iter_append_string (&iter, str)) + { + g_print ("thread %d: append string (%s) failed\n", threadnr, str); + } + g_free (str); + + if (!dbus_connection_send (connection, + message, + NULL)) + { + g_print ("thread %d: send message failed\n", threadnr); + } + + dbus_message_unref (message); + + counter ++; + } + + return NULL; +} + +int +main (int argc, char *argv[]) +{ + GMainLoop *loop; + DBusError error; + int i; + + g_thread_init (NULL); + dbus_gthread_init (); + + if(argc < 2) + { + g_error("Need an address as argv[1]\n"); + return 1; + } + + dbus_error_init (&error); + connection = dbus_connection_open (argv[1], &error); + if (connection == NULL) + { + g_printerr ("could not open connection: %s\n", error.message); + dbus_error_free (&error); + return 1; + } + + dbus_connection_setup_with_g_main (connection, NULL); + + for (i = 0; i < N_TEST_THREADS; i++) + { + g_thread_create (thread_func, GINT_TO_POINTER (i), FALSE, NULL); + } + + loop = g_main_loop_new (NULL, FALSE); + g_main_run (loop); + + return 0; +} + diff --git a/glib/test-thread-server.c b/glib/test-thread-server.c new file mode 100644 index 00000000..00044a79 --- /dev/null +++ b/glib/test-thread-server.c @@ -0,0 +1,248 @@ +#include <glib.h> +#include "dbus-glib.h" +#include <stdio.h> +#include <string.h> + +#include "test-thread.h" + +typedef struct { + guint32 counters[N_TEST_THREADS]; +} ThreadTestData; + +static ThreadTestData * +thread_test_data_new (void) +{ + ThreadTestData *data; + + data = g_new0 (ThreadTestData, 1); + + return data; +} + +static void +thread_test_data_free (ThreadTestData *data) +{ + g_free (data); +} + +static DBusMessageHandler *disconnect_handler; +static DBusMessageHandler *filter_handler; +static dbus_int32_t handler_slot = -1; + +static DBusHandlerResult +handle_test_message (DBusMessageHandler *handler, + DBusConnection *connection, + DBusMessage *message, + void *user_data) +{ + ThreadTestData *data = user_data; + DBusMessageIter iter; + gint32 threadnr; + guint32 counter; + char *str, *expected_str; + GString *counter_str; + int i; + + dbus_message_iter_init (message, &iter); + + if (dbus_message_iter_get_arg_type (&iter) != DBUS_TYPE_INT32) + { + g_print ("First arg not right type\n"); + goto out; + } + threadnr = dbus_message_iter_get_int32 (&iter); + if (threadnr < 0 || threadnr >= N_TEST_THREADS) + { + g_print ("Invalid thread nr\n"); + goto out; + } + + if (! dbus_message_iter_next (&iter)) + { + g_print ("Couldn't get second arg\n"); + goto out; + } + + if (dbus_message_iter_get_arg_type (&iter) != DBUS_TYPE_UINT32) + { + g_print ("Second arg not right type\n"); + goto out; + } + + counter = dbus_message_iter_get_uint32 (&iter); + + if (counter != data->counters[threadnr]) + { + g_print ("Thread %d, counter %d, expected %d\n", threadnr, counter, data->counters[threadnr]); + goto out; + } + data->counters[threadnr]++; + + if (! dbus_message_iter_next (&iter)) + { + g_print ("Couldn't get third arg\n"); + goto out; + } + + if (dbus_message_iter_get_arg_type (&iter) != DBUS_TYPE_STRING) + { + g_print ("Third arg not right type\n"); + goto out; + } + + str = dbus_message_iter_get_string (&iter); + + if (str == NULL) + { + g_print ("No third arg\n"); + goto out; + } + + expected_str = g_strdup_printf ("Thread %d-%d\n", threadnr, counter); + if (strcmp (expected_str, str) != 0) + { + g_print ("Wrong string '%s', expected '%s'\n", str, expected_str); + goto out; + } + g_free (str); + g_free (expected_str); + + if (dbus_message_iter_next (&iter)) + { + g_print ("Extra args on end of message\n"); + goto out; + } + + dbus_connection_flush (connection); + + counter_str = g_string_new (""); + for (i = 0; i < N_TEST_THREADS; i++) + { + g_string_append_printf (counter_str, "%d ", data->counters[i]); + } + g_print ("%s\r", counter_str->str); + g_string_free (counter_str, TRUE); + + out: + return DBUS_HANDLER_RESULT_ALLOW_MORE_HANDLERS; +} + +static DBusHandlerResult +handle_filter (DBusMessageHandler *handler, + DBusConnection *connection, + DBusMessage *message, + void *user_data) +{ + return DBUS_HANDLER_RESULT_ALLOW_MORE_HANDLERS; +} + +static DBusHandlerResult +handle_disconnect (DBusMessageHandler *handler, + DBusConnection *connection, + DBusMessage *message, + void *user_data) +{ + g_print ("connection disconnected\n"); + dbus_connection_unref (connection); + + return DBUS_HANDLER_RESULT_ALLOW_MORE_HANDLERS; +} + + +static void +new_connection_callback (DBusServer *server, + DBusConnection *new_connection, + void *user_data) +{ + const char *test_messages[] = { "org.freedesktop.ThreadTest" }; + const char *disconnect_messages[] = { "org.freedesktop.Local.Disconnect" }; + DBusMessageHandler *test_message_handler; + ThreadTestData * data; + + g_print ("new_connection_callback\n"); + + dbus_connection_ref (new_connection); + dbus_connection_setup_with_g_main (new_connection, NULL); + + data = thread_test_data_new (); + + test_message_handler = + dbus_message_handler_new (handle_test_message, + data, (DBusFreeFunction)thread_test_data_free); + + if (!dbus_connection_register_handler (new_connection, + test_message_handler, + test_messages, 1)) + goto nomem; + + if (!dbus_connection_set_data (new_connection, + handler_slot, + test_message_handler, + (DBusFreeFunction)dbus_message_handler_unref)) + goto nomem; + + if (!dbus_connection_register_handler (new_connection, + disconnect_handler, + disconnect_messages, 1)) + goto nomem; + + if (!dbus_connection_add_filter (new_connection, + filter_handler)) + goto nomem; + + return; + + nomem: + g_error ("no memory to setup new connection"); +} + +int +main (int argc, char *argv[]) +{ + GMainLoop *loop; + DBusServer *server; + DBusError error; + + g_thread_init (NULL); + dbus_gthread_init (); + + if (argc < 2) + { + fprintf (stderr, "Give the server address as an argument\n"); + return 1; + } + + dbus_error_init (&error); + server = dbus_server_listen (argv[1], &error); + if (server == NULL) + { + fprintf (stderr, "Failed to start server on %s: %s\n", + argv[1], error.message); + dbus_error_free (&error); + return 1; + } + + if (!dbus_connection_allocate_data_slot (&handler_slot)) + g_error ("no memory for data slot"); + + filter_handler = + dbus_message_handler_new (handle_filter, NULL, NULL); + if (filter_handler == NULL) + g_error ("no memory for handler"); + + disconnect_handler = + dbus_message_handler_new (handle_disconnect, NULL, NULL); + if (disconnect_handler == NULL) + g_error ("no memory for handler"); + + dbus_server_set_new_connection_function (server, + new_connection_callback, + NULL, NULL); + + dbus_server_setup_with_g_main (server, NULL); + + loop = g_main_loop_new (NULL, FALSE); + g_main_run (loop); + + return 0; +} diff --git a/glib/test-thread.h b/glib/test-thread.h new file mode 100644 index 00000000..8c78fba2 --- /dev/null +++ b/glib/test-thread.h @@ -0,0 +1 @@ +#define N_TEST_THREADS 5 |