Commit a1b0bd33 authored by Havoc Pennington's avatar Havoc Pennington
Browse files

2003-08-15 Havoc Pennington <hp@redhat.com>

	* dbus/dbus-pending-call.c (dbus_pending_call_block): implement

	* dbus/dbus-connection.c
	(dbus_connection_send_with_reply_and_block): factor out internals;
	change to convert any error replies to DBusError instead of
	returning them as a message
parent ef614207
2003-08-15 Havoc Pennington <hp@redhat.com>
* dbus/dbus-pending-call.c (dbus_pending_call_block): implement
* dbus/dbus-connection.c
(dbus_connection_send_with_reply_and_block): factor out internals;
change to convert any error replies to DBusError instead of
returning them as a message
2003-08-15 Havoc Pennington <hp@pobox.com>
* dbus/dbus-connection.c,
......
......@@ -88,15 +88,18 @@ DBusHandlerResult _dbus_message_handler_handle_message (DBusMessageHandl
DBusMessage *message);
void _dbus_connection_init_id (DBusConnection *connection,
DBusObjectID *id);
DBusPendingCall* _dbus_pending_call_new (DBusConnection *connection,
int timeout_milliseconds,
DBusTimeoutHandler timeout_handler);
void _dbus_pending_call_notify (DBusPendingCall *pending);
void _dbus_connection_remove_pending_call (DBusConnection *connection,
DBusPendingCall *pending);
DBusMessage* _dbus_connection_block_for_reply (DBusConnection *connection,
dbus_uint32_t client_serial,
int timeout_milliseconds);
void _dbus_pending_call_complete_and_unlock (DBusPendingCall *pending,
DBusMessage *message);
/**
* @addtogroup DBusPendingCallInternals DBusPendingCall implementation details
......
......@@ -620,6 +620,38 @@ _dbus_connection_remove_pending_call (DBusConnection *connection,
_dbus_connection_detach_pending_call_and_unlock (connection, pending);
}
/**
* Completes a pending call with the given message,
* or if the message is #NULL, by timing out the pending call.
*
* @param pending the pending call
* @param message the message to complete the call with, or #NULL
* to time out the call
*/
void
_dbus_pending_call_complete_and_unlock (DBusPendingCall *pending,
DBusMessage *message)
{
if (message == NULL)
{
message = pending->timeout_link->data;
_dbus_list_clear (&pending->timeout_link);
}
_dbus_verbose (" handing message %p to pending call\n", message);
_dbus_assert (pending->reply == NULL);
pending->reply = message;
dbus_message_ref (pending->reply);
dbus_pending_call_ref (pending); /* in case there's no app with a ref held */
_dbus_connection_detach_pending_call_and_unlock (pending->connection, pending);
/* Must be called unlocked since it invokes app callback */
_dbus_pending_call_notify (pending);
dbus_pending_call_unref (pending);
}
/**
* Acquire the transporter I/O path. This must be done before
* doing any I/O in the transporter. May sleep and drop the
......@@ -1745,42 +1777,31 @@ check_for_reply_unlocked (DBusConnection *connection,
}
/**
* Sends a message and blocks a certain time period while waiting for a reply.
* This function does not dispatch any message handlers until the main loop
* has been reached. This function is used to do non-reentrant "method calls."
* If a reply is received, it is returned, and removed from the incoming
* message queue. If it is not received, #NULL is returned and the
* error is set to #DBUS_ERROR_NO_REPLY. If something else goes
* wrong, result is set to whatever is appropriate, such as
* #DBUS_ERROR_NO_MEMORY or #DBUS_ERROR_DISCONNECTED.
* Blocks a certain time period while waiting for a reply.
* If no reply arrives, returns #NULL.
*
* @todo could use performance improvements (it keeps scanning
* the whole message queue for example) and has thread issues,
* see comments in source
*
* @param connection the connection
* @param message the message to send
* @param client_serial the reply serial to wait for
* @param timeout_milliseconds timeout in milliseconds or -1 for default
* @param error return location for error message
* @returns the message that is the reply or #NULL with an error code if the
* function fails.
* @returns the message that is the reply or #NULL if no reply
*/
DBusMessage *
dbus_connection_send_with_reply_and_block (DBusConnection *connection,
DBusMessage *message,
int timeout_milliseconds,
DBusError *error)
DBusMessage*
_dbus_connection_block_for_reply (DBusConnection *connection,
dbus_uint32_t client_serial,
int timeout_milliseconds)
{
dbus_uint32_t client_serial;
long start_tv_sec, start_tv_usec;
long end_tv_sec, end_tv_usec;
long tv_sec, tv_usec;
DBusDispatchStatus status;
_dbus_return_val_if_fail (connection != NULL, NULL);
_dbus_return_val_if_fail (message != NULL, NULL);
_dbus_return_val_if_fail (timeout_milliseconds >= 0 || timeout_milliseconds == -1, FALSE);
_dbus_return_val_if_error_is_set (error, NULL);
_dbus_return_val_if_fail (client_serial != 0, NULL);
_dbus_return_val_if_fail (timeout_milliseconds >= 0 || timeout_milliseconds == -1, FALSE);
if (timeout_milliseconds == -1)
timeout_milliseconds = _DBUS_DEFAULT_TIMEOUT_VALUE;
......@@ -1792,14 +1813,6 @@ dbus_connection_send_with_reply_and_block (DBusConnection *connection,
if (timeout_milliseconds > _DBUS_ONE_HOUR_IN_MILLISECONDS * 6)
timeout_milliseconds = _DBUS_ONE_HOUR_IN_MILLISECONDS * 6;
if (!dbus_connection_send (connection, message, &client_serial))
{
_DBUS_SET_OOM (error);
return NULL;
}
message = NULL;
/* Flush message queue */
dbus_connection_flush (connection);
......@@ -1894,11 +1907,6 @@ dbus_connection_send_with_reply_and_block (DBusConnection *connection,
_dbus_verbose ("dbus_connection_send_with_reply_and_block(): Waited %ld milliseconds and got no reply\n",
(tv_sec - start_tv_sec) * 1000 + (tv_usec - start_tv_usec) / 1000);
if (dbus_connection_get_is_connected (connection))
dbus_set_error (error, DBUS_ERROR_NO_REPLY, "Message did not receive a reply");
else
dbus_set_error (error, DBUS_ERROR_DISCONNECTED, "Disconnected prior to receiving a reply");
/* unlocks and calls out to user code */
_dbus_connection_update_dispatch_status_and_unlock (connection, status);
......@@ -1906,6 +1914,70 @@ dbus_connection_send_with_reply_and_block (DBusConnection *connection,
return NULL;
}
/**
* Sends a message and blocks a certain time period while waiting for
* a reply. This function does not reenter the main loop,
* i.e. messages other than the reply are queued up but not
* processed. This function is used to do non-reentrant "method
* calls."
*
* If a normal reply is received, it is returned, and removed from the
* incoming message queue. If it is not received, #NULL is returned
* and the error is set to #DBUS_ERROR_NO_REPLY. If an error reply is
* received, it is converted to a #DBusError and returned as an error,
* then the reply message is deleted. If something else goes wrong,
* result is set to whatever is appropriate, such as
* #DBUS_ERROR_NO_MEMORY or #DBUS_ERROR_DISCONNECTED.
*
* @param connection the connection
* @param message the message to send
* @param timeout_milliseconds timeout in milliseconds or -1 for default
* @param error return location for error message
* @returns the message that is the reply or #NULL with an error code if the
* function fails.
*/
DBusMessage *
dbus_connection_send_with_reply_and_block (DBusConnection *connection,
DBusMessage *message,
int timeout_milliseconds,
DBusError *error)
{
dbus_uint32_t client_serial;
DBusMessage *reply;
_dbus_return_val_if_fail (connection != NULL, NULL);
_dbus_return_val_if_fail (message != NULL, NULL);
_dbus_return_val_if_fail (timeout_milliseconds >= 0 || timeout_milliseconds == -1, FALSE);
_dbus_return_val_if_error_is_set (error, NULL);
if (!dbus_connection_send (connection, message, &client_serial))
{
_DBUS_SET_OOM (error);
return NULL;
}
reply = _dbus_connection_block_for_reply (connection,
client_serial,
timeout_milliseconds);
if (reply == NULL)
{
if (dbus_connection_get_is_connected (connection))
dbus_set_error (error, DBUS_ERROR_NO_REPLY, "Message did not receive a reply");
else
dbus_set_error (error, DBUS_ERROR_DISCONNECTED, "Disconnected prior to receiving a reply");
return NULL;
}
else if (dbus_set_error_from_message (error, reply))
{
dbus_message_unref (reply);
return NULL;
}
else
return reply;
}
/**
* Blocks until the outgoing message queue is empty.
*
......@@ -2301,6 +2373,10 @@ dbus_connection_get_dispatch_status (DBusConnection *connection)
* be part of authentication or the like.
*
* @todo some FIXME in here about handling DBUS_HANDLER_RESULT_NEED_MEMORY
*
* @todo right now a message filter gets run on replies to a pending
* call in here, but not in the case where we block without
* entering the main loop.
*
* @param connection the connection
* @returns dispatch status
......@@ -2435,18 +2511,7 @@ dbus_connection_dispatch (DBusConnection *connection)
if (pending)
{
_dbus_verbose (" handing message %p to pending call\n", message);
_dbus_assert (pending->reply == NULL);
pending->reply = message;
dbus_message_ref (pending->reply);
dbus_pending_call_ref (pending); /* in case there's no app with a ref held */
_dbus_connection_detach_pending_call_and_unlock (connection, pending);
/* Must be called unlocked since it invokes app callback */
_dbus_pending_call_notify (pending);
dbus_pending_call_unref (pending);
_dbus_pending_call_complete_and_unlock (pending, message);
pending = NULL;
......@@ -2869,6 +2934,10 @@ dbus_connection_set_unix_user_function (DBusConnection *connection,
* forgets about it. Thus the caller of this function must keep a
* reference to the message handler.
*
* @todo we don't run filters on messages while blocking without
* entering the main loop, since filters are run as part of
* dbus_connection_dispatch().
*
* @param connection the connection
* @param handler the handler
* @returns #TRUE on success, #FALSE if not enough memory.
......
......@@ -254,6 +254,31 @@ dbus_pending_call_get_reply (DBusPendingCall *pending)
return pending->reply;
}
/**
* Block until the pending call is completed. The blocking is as with
* dbus_connection_send_with_reply_and_block(); it does not enter the
* main loop or process other messages, it simply waits for the reply
* in question.
*
* @todo when you start blocking, the timeout is reset, but it should
* really only use time remaining since the pending call was created.
*
* @param pending the pending call
*/
void
dbus_pending_call_block (DBusPendingCall *pending)
{
DBusMessage *message;
message = _dbus_connection_block_for_reply (pending->connection,
pending->reply_serial,
dbus_timeout_get_interval (pending->timeout));
_dbus_connection_lock (pending->connection);
_dbus_pending_call_complete_and_unlock (pending, message);
dbus_message_unref (message);
}
/** @} */
#ifdef DBUS_BUILD_TESTS
......
......@@ -42,6 +42,7 @@ void dbus_pending_call_set_notify (DBusPendingCall *pen
void dbus_pending_call_cancel (DBusPendingCall *pending);
dbus_bool_t dbus_pending_call_get_completed (DBusPendingCall *pending);
DBusMessage* dbus_pending_call_get_reply (DBusPendingCall *pending);
void dbus_pending_call_block (DBusPendingCall *pending);
DBUS_END_DECLS;
......
......@@ -34,43 +34,43 @@
G_BEGIN_DECLS
typedef struct DBusGProxy DBusGProxy;
typedef struct DBusGPendingCall DBusGPendingCall;
typedef struct DBusPendingCall DBusPendingCall;
DBusGProxy* dbus_gproxy_new_for_service (DBusConnection *connection,
const char *service_name,
const char *interface_name);
DBusGProxy* dbus_gproxy_new_for_service_owner (DBusConnection *connection,
const char *service_name,
const char *interface_name,
GError **error);
DBusGProxy* dbus_gproxy_new_for_object_id (DBusConnection *connection,
const DBusObjectID *object_id,
const char *interface_name);
DBusGProxy* dbus_gproxy_new_for_interface (DBusConnection *connection,
const char *interface_name);
void dbus_gproxy_ref (DBusGProxy *proxy);
void dbus_gproxy_unref (DBusGProxy *proxy);
gboolean dbus_gproxy_connect_signal (DBusGProxy *proxy,
const char *signal_name,
GCallback callback,
void *data,
GFreeFunc free_data_func,
GError **error);
DBusGPendingCall* dbus_gproxy_begin_call (DBusGProxy *proxy,
const char *method,
int first_arg_type,
...);
void dbus_gproxy_oneway_call (DBusGProxy *proxy,
const char *method,
int first_arg_type,
...);
DBusGProxy* dbus_gproxy_new_for_service (DBusConnection *connection,
const char *service_name,
const char *interface_name);
DBusGProxy* dbus_gproxy_new_for_service_owner (DBusConnection *connection,
const char *service_name,
const char *interface_name,
GError **error);
DBusGProxy* dbus_gproxy_new_for_object_id (DBusConnection *connection,
const DBusObjectID *object_id,
const char *interface_name);
DBusGProxy* dbus_gproxy_new_for_interface (DBusConnection *connection,
const char *interface_name);
void dbus_gproxy_ref (DBusGProxy *proxy);
void dbus_gproxy_unref (DBusGProxy *proxy);
gboolean dbus_gproxy_connect_signal (DBusGProxy *proxy,
const char *signal_name,
GCallback callback,
void *data,
GFreeFunc free_data_func,
GError **error);
DBusPendingCall* dbus_gproxy_begin_call (DBusGProxy *proxy,
const char *method,
int first_arg_type,
...);
void dbus_gproxy_oneway_call (DBusGProxy *proxy,
const char *method,
int first_arg_type,
...);
gboolean dbus_pending_call_is_complete (DBusPendingCall *call);
void dbus_pending_call_cancel_and_free (DBusPendingCall *call);
gboolean dbus_pending_call_block_and_free (DBusPendingCall *call,
GError **error,
int first_arg_type,
...);
gboolean dbus_gpending_call_is_complete (DBusGPendingCall *call);
void dbus_gpending_call_cancel_and_free (DBusGPendingCall *call);
gboolean dbus_gpending_call_block_and_free (DBusGPendingCall *call,
GError **error,
int first_arg_type,
...);
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment