Async DBusMessage reads using the C API
Matthew Johnson
dbus at matthew.ath.cx
Mon Nov 14 07:26:29 PST 2005
On Mon, 14 Nov 2005, John (J5) Palmieri wrote:
> Attaching the patch would be nice ;-)
Whoops, try again....
Matt
>
> On Mon, 2005-11-14 at 12:54 +0000, Matthew Johnson wrote:
>> On Mon, 7 Nov 2005, John (J5) Palmieri wrote:
>>
>>> Thanks for the patch. Can you send it in unified diff format. It will
>>> also need a test case for both the dispatch and non dispatching methods.
>>> Though your example might be good enough for this it needs to be added
>>> as part of the diff and setup to run on make check.
>>
>> OK, attached is the current diff. I'm having some problems getting the
>> regression tests to run though. Firstly, make check doesn't start a
>> temporary bus to talk over, I'm not sure how to add in
>> tools/run-with-tmp-session-bus.sh.
>>
>> Secondly, if you run 'DBUS_TOP_BUILDDIR=.
>> tools/run-with-tmp-session-bus.sh make check' the services aren't
>> activated, despite having service files in the correct place, and
>> dbus-monitor doesn't show any activity on the bus.
>>
>> Finally, when the function was completing before I checked for replies
>> from the services the memleaks check reported 37 blocks unfreed, I can't
>> see where though.
>>
>> Any help is appreciated. I think all the patches to the .am and .in
>> files are correct, but I don't really know automake/conf so they may not
>> be.
>>
>> Matt
>>
>
--
Matthew Johnson
http://www.matthew.ath.cx/
-------------- next part --------------
diff -urN dbus-0.50/configure.in dbus-patched/configure.in
--- dbus-0.50/configure.in 2005-09-06 23:38:54.000000000 +0100
+++ dbus-patched/configure.in 2005-11-14 12:33:52.000000000 +0000
@@ -1311,6 +1311,8 @@
test/data/valid-service-files/debug-shell-echo-success.service
test/data/valid-service-files/debug-shell-echo-fail.service
test/data/valid-service-files/debug-python.service
+test/data/valid-service-files/debug-readwrite.service
+test/data/valid-service-files/debug-readwritedispatch.service
])
### FIXME it's bizarre that have_qt and have_glib are used
diff -urN dbus-0.50/dbus/dbus-connection.c dbus-patched/dbus/dbus-connection.c
--- dbus-0.50/dbus/dbus-connection.c 2005-08-26 18:34:59.000000000 +0100
+++ dbus-patched/dbus/dbus-connection.c 2005-11-14 12:26:48.000000000 +0000
@@ -2836,11 +2836,11 @@
* In this usage you would normally have set up a filter function to look
* at each message as it is dispatched. The loop terminates when the last
* message from the connection (the disconnected signal) is processed.
- *
- * If there are messages to dispatch, this function will
- * dbus_connection_dispatch() once, and return. If there are no
- * messages to dispatch, this function will block until it can read or
- * write, then read or write, then return.
+ *
+ * If there are messages to dispatch and the dispatch flag is set, this
+ * function will dbus_connection_dispatch() once, and return. If there are no
+ * messages to dispatch, this function will block until it can read or write,
+ * then read or write, then return.
*
* The way to think of this function is that it either makes some sort
* of progress, or it blocks.
@@ -2852,11 +2852,13 @@
*
* @param connection the connection
* @param timeout_milliseconds max time to block or -1 for infinite
+ * @param dispatch dispatch new messages or leave them on the incoming queue
* @returns #TRUE if the disconnect message has not been processed
*/
dbus_bool_t
-dbus_connection_read_write_dispatch (DBusConnection *connection,
- int timeout_milliseconds)
+_dbus_connection_read_write_dispatch (DBusConnection *connection,
+ int timeout_milliseconds,
+ dbus_bool_t dispatch)
{
DBusDispatchStatus dstatus;
dbus_bool_t dispatched_disconnected;
@@ -2865,7 +2867,7 @@
_dbus_return_val_if_fail (timeout_milliseconds >= 0 || timeout_milliseconds == -1, FALSE);
dstatus = dbus_connection_get_dispatch_status (connection);
- if (dstatus == DBUS_DISPATCH_DATA_REMAINS)
+ if (dispatch && dstatus == DBUS_DISPATCH_DATA_REMAINS)
{
_dbus_verbose ("doing dispatch in %s\n", _DBUS_FUNCTION_NAME);
dbus_connection_dispatch (connection);
@@ -2898,6 +2900,68 @@
return !dispatched_disconnected; /* TRUE if we have not processed disconnected */
}
+
+/**
+ * This function is intended for use with applications that don't want
+ * to write a main loop and deal with #DBusWatch and #DBusTimeout. An
+ * example usage would be:
+ *
+ * @code
+ * while (dbus_connection_read_write_dispatch (connection, -1))
+ * ; // empty loop body
+ * @endcode
+ *
+ * In this usage you would normally have set up a filter function to look
+ * at each message as it is dispatched. The loop terminates when the last
+ * message from the connection (the disconnected signal) is processed.
+ *
+ * If there are messages to dispatch, this function will
+ * dbus_connection_dispatch() once, and return. If there are no
+ * messages to dispatch, this function will block until it can read or
+ * write, then read or write, then return.
+ *
+ * The way to think of this function is that it either makes some sort
+ * of progress, or it blocks.
+ *
+ * The return value indicates whether the disconnect message has been
+ * processed, NOT whether the connection is connected. This is
+ * important because even after disconnecting, you want to process any
+ * messages you received prior to the disconnect.
+ *
+ * @param connection the connection
+ * @param timeout_milliseconds max time to block or -1 for infinite
+ * @returns #TRUE if the disconnect message has not been processed
+ */
+dbus_bool_t
+dbus_connection_read_write_dispatch (DBusConnection *connection,
+ int timeout_milliseconds)
+{
+ return _dbus_connection_read_write_dispatch(connection, timeout_milliseconds, TRUE);
+}
+
+/**
+ * This function is intended for use with applications that don't want to
+ * write a main loop and deal with #DBusWatch and #DBusTimeout.
+ *
+ * If there are no messages to dispatch, this function will block until it can
+ * read or write, then read or write, then return.
+ *
+ * The return value indicates whether the disconnect message has been
+ * processed, NOT whether the connection is connected. This is important
+ * because even after disconnecting, you want to process any messages you
+ * received prior to the disconnect.
+ *
+ * @param connection the connection
+ * @param timeout_milliseconds max time to block or -1 for infinite
+ * @returns #TRUE if the disconnect message has not been processed
+ */
+dbus_bool_t
+dbus_connection_read_write (DBusConnection *connection,
+ int timeout_milliseconds)
+{
+ return _dbus_connection_read_write_dispatch(connection, timeout_milliseconds, FALSE);
+}
+
/**
* Returns the first-received message from the incoming message queue,
* leaving it in the queue. If the queue is empty, returns #NULL.
@@ -4672,4 +4736,123 @@
return res;
}
+
+#ifdef DBUS_BUILD_TESTS
+
+#include <stdio.h>
+#include <stdlib.h>
+#include "dbus-test.h"
+
+static dbus_bool_t
+check_readwrite (DBusConnection *connection, const char* service);
+
+#define TEST_READWRITE_SERVICE "org.freedesktop.DBus.TestSuiteReadWrite"
+#define TEST_READWRITEDISPATCH_SERVICE "org.freedesktop.DBus.TestSuiteReadWriteDispatch"
+
+dbus_bool_t
+_dbus_connection_test()
+{
+ DBusConnection* conn;
+ DBusError err;
+ char* address;
+
+ address = getenv ("DBUS_SESSION_BUS_ADDRESS");
+ if (address == NULL) {
+ _dbus_warn ("No Session Bus\n");
+ _dbus_exit(1);
+ }
+
+ dbus_error_init(&err);
+ conn = dbus_connection_open_private(address, &err);
+
+ if (!check_readwrite (conn, TEST_READWRITE_SERVICE)) {
+ _dbus_warn ("Check ReadWrite failed\n");
+ _dbus_exit(1);
+ }
+
+ if (!check_readwrite (conn, TEST_READWRITEDISPATCH_SERVICE)) {
+ _dbus_warn ("Check ReadWriteDispatch failed\n");
+ _dbus_exit(1);
+ }
+
+ dbus_connection_close(conn);
+
+ return TRUE;
+}
+
+#define TEST_READWRITE_MESSAGE "ECHO"
+
+/* returns TRUE if the correct thing happens,
+ * but the correct thing may include OOM errors.
+ */
+static dbus_bool_t
+check_readwrite (DBusConnection *connection, const char* service)
+{
+ DBusMessage *message;
+ DBusPendingCall* pending;
+ DBusError err;
+ const char *text;
+
+ dbus_error_init(&err);
+
+ message = dbus_message_new_method_call (service,
+ "/org/freedesktop/TestSuite",
+ "org.freedesktop.TestSuite",
+ "ReadWriteTest");
+
+ if (message == NULL)
+ return FALSE;
+
+ text = TEST_READWRITE_MESSAGE;
+
+ if (!dbus_message_append_args (message,
+ DBUS_TYPE_STRING, &text,
+ DBUS_TYPE_INVALID))
+ {
+ dbus_message_unref (message);
+ return FALSE;
+ }
+
+ if (!dbus_connection_send_with_reply (connection, message, &pending, -1))
+ {
+ dbus_message_unref (message);
+ return FALSE;
+ }
+
+ dbus_message_unref (message);
+ message = NULL;
+
+ dbus_pending_call_block(pending);
+
+ message = dbus_pending_call_steal_reply(pending);
+ if (message == NULL)
+ {
+ _dbus_warn ("Failed to pop message! Should have been reply from ReadWriteTest message\n");
+ dbus_pending_call_unref(pending);
+ return FALSE;
+ }
+ dbus_pending_call_unref(pending);
+
+ if (!dbus_message_get_args (message, &err,
+ DBUS_TYPE_STRING, &text,
+ DBUS_TYPE_INVALID))
+ {
+ _dbus_warn ("Failed to get args! Should have been reply from ReadWriteTest message\n");
+ dbus_message_unref (message);
+ return FALSE;
+ }
+
+ _dbus_warn ("Got ReadWrite Test Reply: %s\n", text);
+
+ if (0 != strncmp(text, TEST_READWRITE_MESSAGE, strlen(TEST_READWRITE_MESSAGE))) {
+ _dbus_warn ("Arg was incorrect! Should have been reply from ReadWriteTest message\n");
+ dbus_message_unref (message);
+ return FALSE;
+ }
+
+ dbus_message_unref (message);
+
+ return TRUE;
+}
+#endif
/** @} */
diff -urN dbus-0.50/dbus/dbus-connection.h dbus-patched/dbus/dbus-connection.h
--- dbus-0.50/dbus/dbus-connection.h 2005-06-06 19:55:22.000000000 +0100
+++ dbus-patched/dbus/dbus-connection.h 2005-11-14 11:02:55.000000000 +0000
@@ -102,6 +102,8 @@
void dbus_connection_flush (DBusConnection *connection);
dbus_bool_t dbus_connection_read_write_dispatch (DBusConnection *connection,
int timeout_milliseconds);
+dbus_bool_t dbus_connection_read_write (DBusConnection *connection,
+ int timeout_milliseconds);
DBusMessage* dbus_connection_borrow_message (DBusConnection *connection);
void dbus_connection_return_message (DBusConnection *connection,
DBusMessage *message);
diff -urN dbus-0.50/dbus/dbus-test.c dbus-patched/dbus/dbus-test.c
--- dbus-0.50/dbus/dbus-test.c 2005-02-24 16:03:56.000000000 +0000
+++ dbus-patched/dbus/dbus-test.c 2005-11-14 11:28:16.000000000 +0000
@@ -120,6 +120,8 @@
run_test ("server", specific_test, _dbus_server_test);
+ run_test ("connections", specific_test, _dbus_connection_test);
+
run_test ("object-tree", specific_test, _dbus_object_tree_test);
run_test ("signature", specific_test, _dbus_signature_test);
diff -urN dbus-0.50/dbus/dbus-test.h dbus-patched/dbus/dbus-test.h
--- dbus-0.50/dbus/dbus-test.h 2005-02-24 16:03:56.000000000 +0000
+++ dbus-patched/dbus/dbus-test.h 2005-11-14 11:01:30.000000000 +0000
@@ -41,6 +41,7 @@
dbus_bool_t _dbus_string_test (void);
dbus_bool_t _dbus_address_test (void);
dbus_bool_t _dbus_server_test (void);
+dbus_bool_t _dbus_connection_test (void);
dbus_bool_t _dbus_message_test (const char *test_data_dir);
dbus_bool_t _dbus_auth_test (const char *test_data_dir);
dbus_bool_t _dbus_md5_test (void);
diff -urN dbus-0.50/test/data/valid-service-files/debug-readwritedispatch.service.in dbus-patched/test/data/valid-service-files/debug-readwritedispatch.service.in
--- dbus-0.50/test/data/valid-service-files/debug-readwritedispatch.service.in 1970-01-01 01:00:00.000000000 +0100
+++ dbus-patched/test/data/valid-service-files/debug-readwritedispatch.service.in 2005-11-14 12:31:24.000000000 +0000
@@ -0,0 +1,3 @@
+[D-BUS Service]
+Name=org.freedesktop.DBus.TestSuiteReadWriteDispatch
+Exec=@TEST_READWRITE_BINARY@
diff -urN dbus-0.50/test/data/valid-service-files/debug-readwrite.service.in dbus-patched/test/data/valid-service-files/debug-readwrite.service.in
--- dbus-0.50/test/data/valid-service-files/debug-readwrite.service.in 1970-01-01 01:00:00.000000000 +0100
+++ dbus-patched/test/data/valid-service-files/debug-readwrite.service.in 2005-11-09 14:19:46.000000000 +0000
@@ -0,0 +1,3 @@
+[D-BUS Service]
+Name=org.freedesktop.DBus.TestSuiteReadWrite
+Exec=@TEST_READWRITE_BINARY@
diff -urN dbus-0.50/test/Makefile.am dbus-patched/test/Makefile.am
--- dbus-0.50/test/Makefile.am 2005-08-25 01:20:41.000000000 +0100
+++ dbus-patched/test/Makefile.am 2005-11-09 12:28:26.000000000 +0000
@@ -14,7 +14,7 @@
if DBUS_BUILD_TESTS
## break-loader removed for now
-TEST_BINARIES=test-service test-shell-service shell-test spawn-test test-segfault test-exit test-sleep-forever
+TEST_BINARIES=test-readwrite test-service test-shell-service shell-test spawn-test test-segfault test-exit test-sleep-forever
#enable stand alone make check test
TESTS=shell-test
@@ -52,6 +52,8 @@
test_exit_SOURCES = \
test-exit.c
+test_readwrite_SOURCES = \
+ test-readwrite.c
test_segfault_SOURCES = \
test-segfault.c
diff -urN dbus-0.50/test/Makefile.in dbus-patched/test/Makefile.in
--- dbus-0.50/test/Makefile.in 2005-09-06 23:45:16.000000000 +0100
+++ dbus-patched/test/Makefile.in 2005-11-09 12:33:28.000000000 +0000
@@ -53,6 +53,7 @@
@DBUS_BUILD_TESTS_TRUE@ shell-test$(EXEEXT) spawn-test$(EXEEXT) \
@DBUS_BUILD_TESTS_TRUE@ test-segfault$(EXEEXT) \
@DBUS_BUILD_TESTS_TRUE@ test-exit$(EXEEXT) \
+ at DBUS_BUILD_TESTS_TRUE@ test-readwrite$(EXEEXT) \
@DBUS_BUILD_TESTS_TRUE@ test-sleep-forever$(EXEEXT)
@DBUS_GCOV_ENABLED_TRUE at am__EXEEXT_2 = decode-gcov$(EXEEXT)
PROGRAMS = $(noinst_PROGRAMS)
@@ -84,6 +85,9 @@
am_test_sleep_forever_OBJECTS = test-sleep-forever.$(OBJEXT)
test_sleep_forever_OBJECTS = $(am_test_sleep_forever_OBJECTS)
test_sleep_forever_LDADD = $(LDADD)
+am_test_readwrite_OBJECTS = test-readwrite.$(OBJEXT)
+test_readwrite_OBJECTS = $(am_test_readwrite_OBJECTS)
+test_readwrite_LDADD = $(LDADD)
DEFAULT_INCLUDES = -I. -I$(srcdir) -I$(top_builddir)
depcomp = $(SHELL) $(top_srcdir)/depcomp
am__depfiles_maybe = depfiles
@@ -98,10 +102,12 @@
SOURCES = $(decode_gcov_SOURCES) $(shell_test_SOURCES) \
$(spawn_test_SOURCES) $(test_exit_SOURCES) \
$(test_segfault_SOURCES) $(test_service_SOURCES) \
+ $(test_readwrite_SOURCES) \
$(test_shell_service_SOURCES) $(test_sleep_forever_SOURCES)
DIST_SOURCES = $(decode_gcov_SOURCES) $(shell_test_SOURCES) \
$(spawn_test_SOURCES) $(test_exit_SOURCES) \
$(test_segfault_SOURCES) $(test_service_SOURCES) \
+ $(test_readwrite_SOURCES) \
$(test_shell_service_SOURCES) $(test_sleep_forever_SOURCES)
RECURSIVE_TARGETS = all-recursive check-recursive dvi-recursive \
html-recursive info-recursive install-data-recursive \
@@ -361,7 +367,7 @@
DIST_SUBDIRS = glib python
INCLUDES = -I$(top_srcdir) $(DBUS_TEST_CFLAGS)
@DBUS_BUILD_TESTS_FALSE at TEST_BINARIES =
- at DBUS_BUILD_TESTS_TRUE@TEST_BINARIES = test-service test-shell-service shell-test spawn-test test-segfault test-exit test-sleep-forever
+ at DBUS_BUILD_TESTS_TRUE@TEST_BINARIES = test-service test-shell-service shell-test spawn-test test-segfault test-exit test-sleep-forever test-readwrite
@DBUS_BUILD_TESTS_FALSE at TESTS =
#enable stand alone make check test
@@ -383,6 +389,9 @@
spawn_test_SOURCES = \
spawn-test.c
+
+test_readwrite_SOURCES = \
+ test-readwrite.c
test_exit_SOURCES = \
test-exit.c
@@ -398,6 +407,7 @@
TEST_LIBS = $(DBUS_TEST_LIBS) $(top_builddir)/dbus/libdbus-convenience.la
test_service_LDADD = $(TEST_LIBS)
+test_readwrite_LDADD = $(TEST_LIBS)
test_shell_service_LDADD = $(TEST_LIBS)
shell_test_LDADD = $(TEST_LIBS)
spawn_test_LDADD = $(TEST_LIBS)
@@ -486,6 +496,9 @@
test-sleep-forever$(EXEEXT): $(test_sleep_forever_OBJECTS) $(test_sleep_forever_DEPENDENCIES)
@rm -f test-sleep-forever$(EXEEXT)
$(LINK) $(test_sleep_forever_LDFLAGS) $(test_sleep_forever_OBJECTS) $(test_sleep_forever_LDADD) $(LIBS)
+test-readwrite$(EXEEXT): $(test_readwrite_OBJECTS) $(test_readwrite_DEPENDENCIES)
+ @rm -f test-readwrite$(EXEEXT)
+ $(LINK) $(test_readwrite_LDFLAGS) $(test_readwrite_OBJECTS) $(test_readwrite_LDADD) $(LIBS)
mostlyclean-compile:
-rm -f *.$(OBJEXT)
@@ -499,6 +512,7 @@
@AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/test-exit.Po at am__quote@
@AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/test-segfault.Po at am__quote@
@AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/test-service.Po at am__quote@
+ at AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/test-readwrite.Po at am__quote@
@AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/test-shell-service.Po at am__quote@
@AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/test-sleep-forever.Po at am__quote@
@AMDEP_TRUE@@am__include@ @am__quote at ./$(DEPDIR)/test-utils.Po at am__quote@
diff -urN dbus-0.50/test/test-readwrite.c dbus-patched/test/test-readwrite.c
--- dbus-0.50/test/test-readwrite.c 1970-01-01 01:00:00.000000000 +0100
+++ dbus-patched/test/test-readwrite.c 2005-11-14 12:18:38.000000000 +0000
@@ -0,0 +1,107 @@
+#include <dbus/dbus.h>
+#include <stdbool.h>
+#include <unistd.h>
+#include <string.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+
+void reply_to_method_call(DBusMessage* msg, DBusConnection* conn)
+{
+
+ DBusMessage* reply;
+ DBusMessageIter args;
+ dbus_uint32_t serial = 0;
+ char* param = "";
+ fprintf(stderr, "Replying\n");
+
+ // read the arguments
+ if (!dbus_message_iter_init(msg, &args))
+ fprintf(stderr, "Message has no arguments!\n");
+ else if (DBUS_TYPE_STRING != dbus_message_iter_get_arg_type(&args))
+ fprintf(stderr, "Argument is not string!\n");
+ else
+ dbus_message_iter_get_basic(&args, ¶m);
+
+ fprintf(stderr, "Message: %s\n", param);
+ // create a reply from the message
+ reply = dbus_message_new_method_return(msg);
+
+ // add the arguments to the reply
+ dbus_message_iter_init_append(reply, &args);
+ if (!dbus_message_iter_append_basic(&args, DBUS_TYPE_STRING, ¶m)) {
+ fprintf(stderr, "Out Of Memory!\n");
+ exit(1);
+ }
+
+ fprintf(stderr, "Sending...");
+ // send the reply && flush the connection
+ if (!dbus_connection_send(conn, reply, &serial)) {
+ fprintf(stderr, "Out Of Memory!\n");
+ exit(1);
+ }
+ dbus_connection_flush(conn);
+ fprintf(stderr, "sedone\n");
+
+ // free the reply
+ dbus_message_unref(reply);
+}
+
+void main(int argc, char** argv)
+{
+ DBusMessage* msg;
+ DBusConnection* conn;
+ DBusError err;
+ int ret;
+
+ fprintf(stderr, "Listening for Ping\n");
+
+ // initialise the error
+ dbus_error_init(&err);
+
+ // connect to the bus and check for errors
+ conn = dbus_bus_get(DBUS_BUS_SESSION, &err);
+ if (dbus_error_is_set(&err)) {
+ fprintf(stderr, "Connection Error (%s)\n", err.message);
+ dbus_error_free(&err);
+ }
+ if (NULL == conn) {
+ fprintf(stderr, "Connection Null\n");
+ exit(1);
+ }
+
+ // request our name on the bus and check for errors
+ ret = dbus_bus_request_name(conn, "org.freedesktop.DBus.TestSuiteReadWrite", DBUS_NAME_FLAG_REPLACE_EXISTING |
+ DBUS_NAME_FLAG_PROHIBIT_REPLACEMENT, &err);
+ if (dbus_error_is_set(&err)) {
+ fprintf(stderr, "Name Error (%s)\n", err.message);
+ dbus_error_free(&err);
+ exit(1);
+ }
+ /*if (DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER != ret) {
+ fprintf(stderr, "Not Primary Owner (%d)\n", ret);
+ exit(1);
+ }*/
+
+ while (true) {
+ fprintf(stderr, "Blocking on readwrite...");
+ dbus_connection_read_write(conn, -1);
+ fprintf(stderr, "rwdone\n");
+ msg = dbus_connection_pop_message(conn);
+
+ // check this is a method call for the right interface & method
+ if (dbus_message_is_method_call(msg, "test.readwrite.Type", "Method")) {
+ reply_to_method_call(msg, conn);
+ break;
+ } else
+ fprintf(stderr, "Not A Message\n");
+
+ // free the message
+ dbus_message_unref(msg);
+ }
+
+ // close the connection
+ dbus_connection_close(conn);
+}
+
More information about the dbus
mailing list