summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorTeemu Ikonen <tpikonen@mailbox.org>2022-01-10 23:34:24 +0200
committerTeemu Ikonen <tpikonen@mailbox.org>2022-01-16 19:00:34 +0200
commitcece6abb0899223a72563c7c8bfbc4f1bcd33eb2 (patch)
treec475319a9ede8dfa21ba243c8ff5e27404afd5d7 /src
parent7320075e2d58dcd8d7ed903044aa9cc48996b37f (diff)
downloadgeoclue-cece6abb0899223a72563c7c8bfbc4f1bcd33eb2.tar.gz
service-manager: Replace agent wait timeout with a queue
When GeoClue is started with D-Bus activation, the agent is not started yet and the starting client currently has to wait AGENT_WAIT_TIMEOUT (=20 s) before being started. Replace the agent wait timeout with a FIFO queue which is processed as soon as the agent connects. Handle the case where client vanishes before agent is connected. Remove the now unused var priv->init_time. Fixes #141.
Diffstat (limited to 'src')
-rw-r--r--src/gclue-service-manager.c74
1 files changed, 59 insertions, 15 deletions
diff --git a/src/gclue-service-manager.c b/src/gclue-service-manager.c
index 69fba51..ba06c35 100644
--- a/src/gclue-service-manager.c
+++ b/src/gclue-service-manager.c
@@ -31,11 +31,6 @@
#include "gclue-locator.h"
#include "gclue-config.h"
-/* 20 seconds as milliseconds */
-#define AGENT_WAIT_TIMEOUT 20000
-/* 20 seconds as microseconds */
-#define AGENT_WAIT_TIMEOUT_USEC (20 * G_USEC_PER_SEC)
-
static void
gclue_service_manager_manager_iface_init (GClueDBusManagerIface *iface);
static void
@@ -46,10 +41,10 @@ struct _GClueServiceManagerPrivate
GDBusConnection *connection;
GList *clients;
GHashTable *agents;
+ GQueue *clients_waiting_agent;
guint last_client_id;
guint num_clients;
- gint64 init_time;
GClueLocator *locator;
};
@@ -189,6 +184,9 @@ complete_get_client (OnClientInfoNewReadyData *data)
char *path;
guint32 user_id;
+ /* Disconnect on_peer_vanished_before_completion, if it's there */
+ g_signal_handlers_disconnect_by_data (info, data);
+
user_id = gclue_client_info_get_user_id (info);
agent_proxy = g_hash_table_lookup (priv->agents,
GINT_TO_POINTER (user_id));
@@ -266,6 +264,30 @@ out:
}
static void
+on_peer_vanished_before_completion (GClueClientInfo *info,
+ gpointer user_data)
+{
+ OnClientInfoNewReadyData *data = (OnClientInfoNewReadyData *) user_data;
+ GClueServiceManager *self = GCLUE_SERVICE_MANAGER (data->manager);
+ GClueServiceManagerPrivate *priv = self->priv;
+ const char *bus_name;
+
+ bus_name = gclue_client_info_get_bus_name (info);
+ g_debug ("Client `%s` vanished before agent appeared",
+ bus_name);
+ g_signal_handlers_disconnect_by_data (info,
+ user_data);
+ g_dbus_method_invocation_return_error (data->invocation,
+ G_DBUS_ERROR,
+ G_DBUS_ERROR_DISCONNECTED,
+ "%s vanished before completion",
+ bus_name);
+ g_queue_remove (priv->clients_waiting_agent, data);
+ on_client_info_new_ready_data_free (data);
+ g_object_unref (info);
+}
+
+static void
on_client_info_new_ready (GObject *source_object,
GAsyncResult *res,
gpointer user_data)
@@ -276,7 +298,6 @@ on_client_info_new_ready (GObject *source_object,
GClueAgent *agent_proxy;
GError *error = NULL;
guint32 user_id;
- gint64 now;
info = gclue_client_info_new_finish (res, &error);
if (info == NULL) {
@@ -285,7 +306,7 @@ on_client_info_new_ready (GObject *source_object,
G_DBUS_ERROR_FAILED,
error->message);
g_error_free (error);
- g_slice_free (OnClientInfoNewReadyData, data);
+ on_client_info_new_ready_data_free (data);
return;
}
@@ -295,16 +316,20 @@ on_client_info_new_ready (GObject *source_object,
user_id = gclue_client_info_get_user_id (info);
agent_proxy = g_hash_table_lookup (priv->agents,
GINT_TO_POINTER (user_id));
- now = g_get_monotonic_time ();
- if (agent_proxy == NULL &&
- now < (priv->init_time + AGENT_WAIT_TIMEOUT_USEC)) {
+ if (agent_proxy == NULL) {
/* Its possible that geoclue was just launched on GetClient
* call, in which case agents need some time to register
* themselves to us.
*/
- g_timeout_add (AGENT_WAIT_TIMEOUT,
- (GSourceFunc) complete_get_client,
- user_data);
+ g_queue_push_tail (priv->clients_waiting_agent, data);
+ g_signal_connect
+ (info,
+ "peer-vanished",
+ G_CALLBACK (on_peer_vanished_before_completion),
+ user_data);
+ g_debug ("Client `%s` waiting for agent for user ID '%u'",
+ gclue_client_info_get_bus_name (info), user_id);
+
return;
}
@@ -435,6 +460,7 @@ on_agent_proxy_ready (GObject *source_object,
guint32 user_id;
GClueAgent *agent;
GError *error = NULL;
+ GList *l;
agent = gclue_agent_proxy_new_for_bus_finish (res, &error);
if (agent == NULL)
@@ -451,6 +477,19 @@ on_agent_proxy_ready (GObject *source_object,
gclue_dbus_manager_complete_add_agent (data->manager, data->invocation);
+ l = priv->clients_waiting_agent->head;
+ while (l != NULL) {
+ GList *next = l->next;
+ OnClientInfoNewReadyData *d =
+ (OnClientInfoNewReadyData *) l->data;
+
+ if (gclue_client_info_get_user_id(d->client_info) == user_id) {
+ complete_get_client (d);
+ g_queue_delete_link (priv->clients_waiting_agent, l);
+ }
+ l = next;
+ }
+
goto out;
error_out:
@@ -548,6 +587,11 @@ gclue_service_manager_finalize (GObject *object)
priv->clients = NULL;
}
g_clear_pointer (&priv->agents, g_hash_table_unref);
+ if (priv->clients_waiting_agent != NULL) {
+ g_queue_free_full (priv->clients_waiting_agent,
+ on_client_info_new_ready_data_free);
+ priv->clients_waiting_agent = NULL;
+ }
/* Chain up to the parent class */
G_OBJECT_CLASS (gclue_service_manager_parent_class)->finalize (object);
@@ -670,7 +714,7 @@ gclue_service_manager_init (GClueServiceManager *manager)
g_direct_equal,
NULL,
g_object_unref);
- manager->priv->init_time = g_get_monotonic_time ();
+ manager->priv->clients_waiting_agent = g_queue_new ();
}
static gboolean