[gdm] Defer get_user requests until manager loaded
- From: Ray Strode <halfline src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gdm] Defer get_user requests until manager loaded
- Date: Wed, 15 Sep 2010 15:43:39 +0000 (UTC)
commit 885da996c1dde9b81eebea76936751f5ccbdbd52
Author: Ray Strode <rstrode redhat com>
Date: Tue Sep 14 17:22:13 2010 -0400
Defer get_user requests until manager loaded
There is a period of time when first starting up that
get_user calls will fail to function properly because
it communicates with the accounts service synchronously
while the user manager is doing it's initial bring up
asynchronously.
This commit makes get_user asynchronous like the rest of
the user manager code, and also enforces an ordering
requirement that get_user requests are deferred until
after the user manager is loaded.
gui/simple-greeter/gdm-user-manager.c | 244 ++++++++++++++++++++++++++++-----
1 files changed, 212 insertions(+), 32 deletions(-)
---
diff --git a/gui/simple-greeter/gdm-user-manager.c b/gui/simple-greeter/gdm-user-manager.c
index 305fd93..178bf90 100644
--- a/gui/simple-greeter/gdm-user-manager.c
+++ b/gui/simple-greeter/gdm-user-manager.c
@@ -131,6 +131,24 @@ typedef struct
char *x11_display;
} GdmUserManagerNewSession;
+typedef enum {
+ GDM_USER_MANAGER_GET_USER_STATE_UNFETCHED = 0,
+ GDM_USER_MANAGER_GET_USER_STATE_WAIT_FOR_LOADED,
+ GDM_USER_MANAGER_GET_USER_STATE_ASK_ACCOUNTS_SERVICE,
+ GDM_USER_MANAGER_GET_USER_STATE_FETCHED
+} GdmUserManagerGetUserState;
+
+typedef struct
+{
+ GdmUserManager *manager;
+ GdmUserManagerGetUserState state;
+ GdmUser *user;
+ char *username;
+ char *object_path;
+
+ DBusGProxyCall *call;
+} GdmUserManagerFetchUserRequest;
+
struct GdmUserManagerPrivate
{
GHashTable *users_by_name;
@@ -145,6 +163,7 @@ struct GdmUserManagerPrivate
GSList *new_sessions;
GSList *new_users;
+ GSList *fetch_user_requests;
GFileMonitor *passwd_monitor;
GFileMonitor *shells_monitor;
@@ -203,6 +222,12 @@ static void set_is_loaded (GdmUserManager *manager, gboolean is_loaded);
static void on_new_user_loaded (GdmUser *user,
GParamSpec *pspec,
GdmUserManager *manager);
+static void give_up_and_fetch_user_locally (GdmUserManager *manager,
+ GdmUserManagerFetchUserRequest *request);
+static void fetch_user_locally (GdmUserManager *manager,
+ GdmUser *user,
+ const char *username);
+static void fetch_user_incrementally (GdmUserManagerFetchUserRequest *request);
static gpointer user_manager_object = NULL;
@@ -1058,37 +1083,80 @@ failed:
unload_new_session (new_session);
}
-static char *
-get_user_object_path_from_accounts_service (GdmUserManager *manager,
- const char *name)
+static void
+on_find_user_by_name_finished (DBusGProxy *proxy,
+ DBusGProxyCall *call,
+ GdmUserManagerFetchUserRequest *request)
{
+ GdmUserManager *manager;
GError *error;
char *object_path;
gboolean res;
- g_assert (manager->priv->accounts_proxy != NULL);
+ g_assert (request->call == call);
error = NULL;
object_path = NULL;
- res = dbus_g_proxy_call (manager->priv->accounts_proxy,
- "FindUserByName",
- &error,
- G_TYPE_STRING,
- name,
- G_TYPE_INVALID,
- DBUS_TYPE_G_OBJECT_PATH,
- &object_path,
- G_TYPE_INVALID);
+ manager = request->manager;
+ res = dbus_g_proxy_end_call (manager->priv->accounts_proxy,
+ call,
+ &error,
+ DBUS_TYPE_G_OBJECT_PATH,
+ &object_path,
+ G_TYPE_INVALID);
if (! res) {
if (error != NULL) {
- g_debug ("GdmUserManager: Failed to find user %s: %s", name, error->message);
+ g_debug ("GdmUserManager: Failed to find user %s: %s",
+ request->username, error->message);
g_error_free (error);
} else {
- g_debug ("GdmUserManager: Failed to find user %s", name);
+ g_debug ("GdmUserManager: Failed to find user %s",
+ request->username);
}
- return NULL;
+ give_up_and_fetch_user_locally (manager, request);
+ return;
+ }
+
+ g_debug ("GdmUserManager: Found object path of user '%s': %s",
+ request->username, object_path);
+ request->object_path = object_path;
+ request->state++;
+
+ fetch_user_incrementally (request);
+}
+
+static void
+find_user_in_accounts_service (GdmUserManager *manager,
+ GdmUserManagerFetchUserRequest *request)
+{
+ DBusGProxyCall *call;
+
+ g_debug ("GdmUserManager: Looking for user %s in accounts service",
+ request->username);
+
+ g_assert (manager->priv->accounts_proxy != NULL);
+
+ call = dbus_g_proxy_begin_call (manager->priv->accounts_proxy,
+ "FindUserByName",
+ (DBusGProxyCallNotify)
+ on_find_user_by_name_finished,
+ request,
+ NULL,
+ G_TYPE_STRING,
+ request->username,
+ G_TYPE_INVALID);
+
+ if (call == NULL) {
+ g_warning ("GdmUserManager: failed to make FindUserByName('%s') call",
+ request->username);
+ goto failed;
}
- return object_path;
+
+ request->call = call;
+ return;
+
+failed:
+ give_up_and_fetch_user_locally (manager, request);
}
static void
@@ -1531,6 +1599,127 @@ load_new_session_incrementally (GdmUserManagerNewSession *new_session)
}
}
+static void
+free_fetch_user_request (GdmUserManagerFetchUserRequest *request)
+{
+ GdmUserManager *manager;
+
+ manager = request->manager;
+
+ manager->priv->fetch_user_requests = g_slist_remove (manager->priv->fetch_user_requests, request);
+ g_free (request->username);
+ g_free (request->object_path);
+ g_slice_free (GdmUserManagerFetchUserRequest, request);
+}
+
+static void
+give_up_and_fetch_user_locally (GdmUserManager *manager,
+ GdmUserManagerFetchUserRequest *request)
+{
+
+ g_debug ("GdmUserManager: account service unavailable, "
+ "fetching user %s locally",
+ request->username);
+ fetch_user_locally (manager, request->user, request->username);
+ request->state = GDM_USER_MANAGER_GET_USER_STATE_UNFETCHED;
+}
+
+static void
+on_user_manager_maybe_ready_for_request (GdmUserManager *manager,
+ GParamSpec *pspec,
+ GdmUserManagerFetchUserRequest *request)
+{
+ if (!manager->priv->is_loaded) {
+ return;
+ }
+
+ g_signal_handlers_disconnect_by_func (manager, on_user_manager_maybe_ready_for_request, request);
+
+ request->state++;
+ fetch_user_incrementally (request);
+}
+
+static void
+fetch_user_incrementally (GdmUserManagerFetchUserRequest *request)
+{
+ GdmUserManager *manager;
+
+ g_debug ("GdmUserManager: finding user %s state %d",
+ request->username, request->state);
+ manager = request->manager;
+ switch (request->state) {
+ case GDM_USER_MANAGER_GET_USER_STATE_WAIT_FOR_LOADED:
+ if (manager->priv->is_loaded) {
+ request->state++;
+ fetch_user_incrementally (request);
+ } else {
+ g_debug ("GdmUserManager: waiting for user manager to load before finding user %s",
+ request->username);
+ g_signal_connect (manager, "notify::is-loaded",
+ G_CALLBACK (on_user_manager_maybe_ready_for_request), request);
+
+ }
+ break;
+
+ case GDM_USER_MANAGER_GET_USER_STATE_ASK_ACCOUNTS_SERVICE:
+ if (manager->priv->accounts_proxy == NULL) {
+ give_up_and_fetch_user_locally (manager, request);
+ } else {
+ find_user_in_accounts_service (manager, request);
+ }
+ break;
+ case GDM_USER_MANAGER_GET_USER_STATE_FETCHED:
+ g_debug ("GdmUserManager: user %s fetched", request->username);
+ _gdm_user_update_from_object_path (request->user, request->object_path);
+ break;
+ case GDM_USER_MANAGER_GET_USER_STATE_UNFETCHED:
+ g_debug ("GdmUserManager: user %s was not fetched", request->username);
+ break;
+ default:
+ g_assert_not_reached ();
+ }
+
+ if (request->state == GDM_USER_MANAGER_GET_USER_STATE_FETCHED ||
+ request->state == GDM_USER_MANAGER_GET_USER_STATE_UNFETCHED) {
+ g_debug ("GdmUserManager: finished handling request for user %s",
+ request->username);
+ free_fetch_user_request (request);
+ }
+}
+
+static void
+fetch_user_from_accounts_service (GdmUserManager *manager,
+ GdmUser *user,
+ const char *username)
+{
+ GdmUserManagerFetchUserRequest *request;
+
+ request = g_slice_new0 (GdmUserManagerFetchUserRequest);
+
+ request->manager = manager;
+ request->username = g_strdup (username);
+ request->user = user;
+ request->state = GDM_USER_MANAGER_GET_USER_STATE_UNFETCHED + 1;
+
+ manager->priv->fetch_user_requests = g_slist_prepend (manager->priv->fetch_user_requests,
+ request);
+ fetch_user_incrementally (request);
+}
+
+static void
+fetch_user_locally (GdmUserManager *manager,
+ GdmUser *user,
+ const char *username)
+{
+ struct passwd *pwent;
+
+ get_pwent_for_name (username, &pwent);
+
+ if (pwent != NULL) {
+ _gdm_user_update_from_pwent (user, pwent);
+ }
+}
+
/**
* gdm_manager_get_user:
* @manager: the manager to query.
@@ -1557,22 +1746,9 @@ gdm_user_manager_get_user (GdmUserManager *manager,
user = create_new_user (manager);
if (manager->priv->accounts_proxy != NULL) {
- char *object_path;
-
- object_path = get_user_object_path_from_accounts_service (manager, username);
-
- if (object_path != NULL) {
- _gdm_user_update_from_object_path (user, object_path);
- g_free (object_path);
- }
+ fetch_user_from_accounts_service (manager, user, username);
} else {
- struct passwd *pwent;
-
- get_pwent_for_name (username, &pwent);
-
- if (pwent != NULL) {
- _gdm_user_update_from_pwent (user, pwent);
- }
+ fetch_user_locally (manager, user, username);
}
}
@@ -2769,6 +2945,10 @@ gdm_user_manager_finalize (GObject *object)
(GFunc) unload_new_session, NULL);
g_slist_free (manager->priv->new_sessions);
+ g_slist_foreach (manager->priv->fetch_user_requests,
+ (GFunc) free_fetch_user_request, NULL);
+ g_slist_free (manager->priv->fetch_user_requests);
+
node = manager->priv->new_users;
while (node != NULL) {
GdmUser *user;
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]