diff options
author | Ray Strode <rstrode@redhat.com> | 2010-06-24 12:22:19 -0400 |
---|---|---|
committer | Ray Strode <rstrode@redhat.com> | 2010-08-17 13:41:32 -0400 |
commit | 36e72382eb19c31ee9e59b72f27cb8537ef960dd (patch) | |
tree | 471a65316462bdbffb6d197c658dfe7b4ead2670 /gui | |
parent | 1f91e3c16567312e6c52b84857f2f5373dd929f0 (diff) | |
download | gdm-36e72382eb19c31ee9e59b72f27cb8537ef960dd.tar.gz |
Make loading new sessions asynchronous
Since loading new sessions is a fairly drawn out
process, with multiple IPC calls, etc, blocking
is not really very nice.
This commit changes it to be asynchronous.
Note, this commit only fixes the non-accounts-service
code path. A future commit will handle the accounts
service code path.
https://bugzilla.gnome.org/show_bug.cgi?id=622639
(cherry picked from commit 0098535140426ff9b8c3aeecc612c8559b670c4e)
Diffstat (limited to 'gui')
-rw-r--r-- | gui/simple-greeter/gdm-user-manager.c | 392 |
1 files changed, 296 insertions, 96 deletions
diff --git a/gui/simple-greeter/gdm-user-manager.c b/gui/simple-greeter/gdm-user-manager.c index 2f0e1cfc..31b5f0f4 100644 --- a/gui/simple-greeter/gdm-user-manager.c +++ b/gui/simple-greeter/gdm-user-manager.c @@ -105,6 +105,32 @@ typedef struct DBusGProxy *proxy; } GdmUserManagerSeat; +typedef enum { + GDM_USER_MANAGER_NEW_SESSION_STATE_UNLOADED = 0, + GDM_USER_MANAGER_NEW_SESSION_STATE_GET_PROXY, + GDM_USER_MANAGER_NEW_SESSION_STATE_GET_UID, + GDM_USER_MANAGER_NEW_SESSION_STATE_GET_X11_DISPLAY, + GDM_USER_MANAGER_NEW_SESSION_STATE_MAYBE_ADD, + GDM_USER_MANAGER_NEW_SESSION_STATE_LOADED, +} GdmUserManagerNewSessionState; + +typedef struct +{ + GdmUserManager *manager; + GdmUserManagerNewSessionState state; + char *id; + + union { + DBusGProxyCall *get_unix_user_call; + DBusGProxyCall *get_x11_display_call; + }; + + DBusGProxy *proxy; + + uid_t uid; + char *x11_display; +} GdmUserManagerNewSession; + struct GdmUserManagerPrivate { GHashTable *users_by_name; @@ -117,6 +143,8 @@ struct GdmUserManagerPrivate GdmUserManagerSeat seat; + GSList *new_sessions; + GFileMonitor *passwd_monitor; GFileMonitor *shells_monitor; @@ -167,6 +195,8 @@ static void load_users (GdmUserManager *manager); static void queue_load_seat_and_users (GdmUserManager *manager); static void monitor_local_users (GdmUserManager *manager); +static void load_new_session_incrementally (GdmUserManagerNewSession *new_session); + static gpointer user_manager_object = NULL; G_DEFINE_TYPE (GdmUserManager, gdm_user_manager, G_TYPE_OBJECT) @@ -597,50 +627,6 @@ failed: unload_seat (manager); } -static char * -get_x11_display_for_session (DBusGConnection *connection, - const char *session_id) -{ - DBusGProxy *proxy; - GError *error; - char *x11_display; - gboolean res; - - proxy = NULL; - x11_display = NULL; - - proxy = dbus_g_proxy_new_for_name (connection, - CK_NAME, - session_id, - CK_SESSION_INTERFACE); - if (proxy == NULL) { - g_warning ("Failed to connect to the ConsoleKit session object"); - goto out; - } - - error = NULL; - res = dbus_g_proxy_call (proxy, - "GetX11Display", - &error, - G_TYPE_INVALID, - G_TYPE_STRING, &x11_display, - G_TYPE_INVALID); - if (! res) { - if (error != NULL) { - g_debug ("GdmUserManager: Failed to identify the x11 display: %s", error->message); - g_error_free (error); - } else { - g_debug ("GdmUserManager: Failed to identify the x11 display"); - } - } - out: - if (proxy != NULL) { - g_object_unref (proxy); - } - - return x11_display; -} - static gint match_name_cmpfunc (gconstpointer a, gconstpointer b) @@ -899,49 +885,121 @@ failed: unload_seat (manager); } -static gboolean -get_uid_from_session_id (GdmUserManager *manager, - const char *session_id, - uid_t *uidp) +static void +unload_new_session (GdmUserManagerNewSession *new_session) { - DBusGProxy *proxy; - GError *error; - guint uid; - gboolean res; + GdmUserManager *manager; + + manager = new_session->manager; + + manager->priv->new_sessions = g_slist_remove (manager->priv->new_sessions, + new_session); + + if (new_session->proxy != NULL) { + g_object_unref (new_session->proxy); + } + + g_free (new_session->x11_display); + g_free (new_session->id); + + g_slice_free (GdmUserManagerNewSession, new_session); +} + +static void +get_proxy_for_new_session (GdmUserManagerNewSession *new_session) +{ + GdmUserManager *manager; + DBusGProxy *proxy; + + manager = new_session->manager; proxy = dbus_g_proxy_new_for_name (manager->priv->connection, CK_NAME, - session_id, + new_session->id, CK_SESSION_INTERFACE); if (proxy == NULL) { - g_warning ("Failed to connect to the ConsoleKit session object"); - return FALSE; + g_warning ("Failed to connect to the ConsoleKit '%s' object", + new_session->id); + unload_new_session (new_session); + return; } + new_session->proxy = proxy; + new_session->state++; + + load_new_session_incrementally (new_session); +} + +static void +on_get_unix_user_finished (DBusGProxy *proxy, + DBusGProxyCall *call, + GdmUserManagerNewSession *new_session) +{ + GdmUserManager *manager; + GError *error; + guint uid; + gboolean res; + + manager = new_session->manager; + + g_assert (new_session->get_unix_user_call == call); + error = NULL; - res = dbus_g_proxy_call (proxy, - "GetUnixUser", - &error, - G_TYPE_INVALID, - G_TYPE_UINT, &uid, - G_TYPE_INVALID); - g_object_unref (proxy); + + uid = (guint) -1; + res = dbus_g_proxy_end_call (proxy, + call, + &error, + G_TYPE_UINT, &uid, + G_TYPE_INVALID); + new_session->get_unix_user_call = NULL; if (! res) { if (error != NULL) { - g_warning ("Failed to query the session: %s", error->message); + g_debug ("Failed to get uid of session '%s': %s", + new_session->id, error->message); g_error_free (error); } else { - g_warning ("Failed to query the session"); + g_debug ("Failed to get uid of session '%s'", + new_session->id); } - return FALSE; + unload_new_session (new_session); + return; } - if (uidp != NULL) { - *uidp = (uid_t) uid; + g_debug ("GdmUserManager: Found uid of session '%s': %u", + new_session->id, uid); + + new_session->uid = (uid_t) uid; + new_session->state++; + + load_new_session_incrementally (new_session); +} + +static void +get_uid_for_new_session (GdmUserManagerNewSession *new_session) +{ + DBusGProxyCall *call; + + g_assert (new_session->proxy != NULL); + + call = dbus_g_proxy_begin_call (new_session->proxy, + "GetUnixUser", + (DBusGProxyCallNotify) + on_get_unix_user_finished, + new_session, + NULL, + G_TYPE_INVALID); + if (call == NULL) { + g_warning ("GdmUserManager: failed to make GetUnixUser call"); + goto failed; } - return TRUE; + new_session->get_unix_user_call = call; + return; + +failed: + unload_new_session (new_session); } static char * @@ -1040,41 +1098,95 @@ on_list_cached_users_finished (DBusGProxy *proxy, } static void -maybe_add_session (GdmUserManager *manager, - const char *session_id) +on_get_x11_display_finished (DBusGProxy *proxy, + DBusGProxyCall *call, + GdmUserManagerNewSession *new_session) { - uid_t uid; - gboolean res; - struct passwd *pwent; - GdmUser *user; - char *x11_display; + GError *error; + char *x11_display; + gboolean res; + + g_assert (new_session->get_x11_display_call == call); + + error = NULL; + x11_display = NULL; + res = dbus_g_proxy_end_call (proxy, + call, + &error, + G_TYPE_STRING, + &x11_display, + G_TYPE_INVALID); + new_session->get_x11_display_call = NULL; - res = get_uid_from_session_id (manager, session_id, &uid); if (! res) { - g_warning ("Unable to lookup user for session"); + if (error != NULL) { + g_debug ("Failed to get the x11 display of session '%s': %s", + new_session->id, error->message); + g_error_free (error); + } else { + g_debug ("Failed to get the x11 display of session '%s'", + new_session->id); + } + unload_new_session (new_session); return; } - errno = 0; - pwent = getpwuid (uid); - if (pwent == NULL) { - g_warning ("Unable to lookup user ID %d: %s", (int)uid, g_strerror (errno)); - return; + g_debug ("GdmUserManager: Found x11 display of session '%s': %s", + new_session->id, x11_display); + + new_session->x11_display = x11_display; + new_session->state++; + + load_new_session_incrementally (new_session); +} + +static void +get_x11_display_for_new_session (GdmUserManagerNewSession *new_session) +{ + DBusGProxyCall *call; + + g_assert (new_session->proxy != NULL); + + call = dbus_g_proxy_begin_call (new_session->proxy, + "GetX11Display", + (DBusGProxyCallNotify) + on_get_x11_display_finished, + new_session, + NULL, + G_TYPE_INVALID); + if (call == NULL) { + g_warning ("GdmUserManager: failed to make GetX11Display call"); + goto failed; } - /* skip if doesn't have an x11 display */ - x11_display = get_x11_display_for_session (manager->priv->connection, session_id); - if (x11_display == NULL || x11_display[0] == '\0') { - g_debug ("GdmUserManager: not adding session without a x11 display: %s", session_id); - g_free (x11_display); - return; + new_session->get_x11_display_call = call; + return; + +failed: + unload_new_session (new_session); +} + +static void +maybe_add_new_session (GdmUserManagerNewSession *new_session) +{ + GdmUserManager *manager; + struct passwd *pwent; + GdmUser *user; + + manager = GDM_USER_MANAGER (new_session->manager); + + errno = 0; + pwent = getpwuid (new_session->uid); + if (pwent == NULL) { + g_warning ("Unable to lookup user ID %d: %s", + (int) new_session->uid, g_strerror (errno)); + goto failed; } - g_free (x11_display); /* check exclusions up front */ if (username_in_exclude_list (manager, pwent->pw_name)) { g_debug ("GdmUserManager: excluding user '%s'", pwent->pw_name); - return; + goto failed; } user = gdm_user_manager_get_user (manager, pwent->pw_name); @@ -1082,7 +1194,7 @@ maybe_add_session (GdmUserManager *manager, return; } - add_session_for_user (manager, user, session_id); + add_session_for_user (manager, user, new_session->id); /* if we haven't yet gotten the login frequency then at least add one because the session exists */ @@ -1090,6 +1202,29 @@ maybe_add_session (GdmUserManager *manager, _gdm_user_update_login_frequency (user, 1); } + manager->priv->seat.state = GDM_USER_MANAGER_SEAT_STATE_LOADED; + unload_new_session (new_session); + return; + +failed: + unload_new_session (new_session); +} + +static void +load_new_session (GdmUserManager *manager, + const char *session_id) +{ + GdmUserManagerNewSession *new_session; + + new_session = g_slice_new0 (GdmUserManagerNewSession); + + new_session->manager = manager; + new_session->id = g_strdup (session_id); + new_session->state = GDM_USER_MANAGER_NEW_SESSION_STATE_UNLOADED + 1; + + manager->priv->new_sessions = g_slist_prepend (manager->priv->new_sessions, + new_session); + load_new_session_incrementally (new_session); } static void @@ -1099,7 +1234,20 @@ seat_session_added (DBusGProxy *seat_proxy, { g_debug ("GdmUserManager: Session added: %s", session_id); - maybe_add_session (manager, session_id); + load_new_session (manager, session_id); +} + +static gint +match_new_session_cmpfunc (gconstpointer a, + gconstpointer b) +{ + GdmUserManagerNewSession *new_session; + const char *session_id; + + new_session = (GdmUserManagerNewSession *) a; + session_id = (const char *) b; + + return strcmp (new_session->id, session_id); } static void @@ -1107,11 +1255,37 @@ seat_session_removed (DBusGProxy *seat_proxy, const char *session_id, GdmUserManager *manager) { - GdmUser *user; - char *username; + GdmUser *user; + GSList *found; + char *username; g_debug ("GdmUserManager: Session removed: %s", session_id); + found = g_slist_find_custom (manager->priv->new_sessions, + session_id, + match_new_session_cmpfunc); + + if (found != NULL) { + GdmUserManagerNewSession *new_session; + + new_session = (GdmUserManagerNewSession *) found->data; + + if (new_session->state > GDM_USER_MANAGER_NEW_SESSION_STATE_GET_X11_DISPLAY) { + g_debug ("GdmUserManager: New session for uid %d on " + "x11 display %s removed before fully loading", + (int) new_session->uid, new_session->x11_display); + } else if (new_session->state > GDM_USER_MANAGER_NEW_SESSION_STATE_GET_UID) { + g_debug ("GdmUserManager: New session for uid %d " + "removed before fully loading", + (int) new_session->uid); + } else { + g_debug ("GdmUserManager: New session removed " + "before fully loading"); + } + unload_new_session (new_session); + return; + } + /* since the session object may already be gone * we can't query CK directly */ @@ -1261,6 +1435,29 @@ get_accounts_proxy (GdmUserManager *manager) } } +static void +load_new_session_incrementally (GdmUserManagerNewSession *new_session) +{ + switch (new_session->state) { + case GDM_USER_MANAGER_NEW_SESSION_STATE_GET_PROXY: + get_proxy_for_new_session (new_session); + break; + case GDM_USER_MANAGER_NEW_SESSION_STATE_GET_UID: + get_uid_for_new_session (new_session); + break; + case GDM_USER_MANAGER_NEW_SESSION_STATE_GET_X11_DISPLAY: + get_x11_display_for_new_session (new_session); + break; + case GDM_USER_MANAGER_NEW_SESSION_STATE_MAYBE_ADD: + maybe_add_new_session (new_session); + break; + case GDM_USER_MANAGER_NEW_SESSION_STATE_LOADED: + break; + default: + g_assert_not_reached (); + } +} + /** * gdm_manager_get_user: * @manager: the manager to query. @@ -1973,7 +2170,7 @@ load_sessions_from_array (GdmUserManager *manager, int i; for (i = 0; i < number_of_sessions; i++) { - maybe_add_session (manager, session_ids[i]); + load_new_session (manager, session_ids[i]); } } @@ -2466,7 +2663,6 @@ gdm_user_manager_init (GdmUserManager *manager) return; } - get_seat_proxy (manager); get_accounts_proxy (manager); manager->priv->seat.state = GDM_USER_MANAGER_SEAT_STATE_UNLOADED; @@ -2489,6 +2685,10 @@ gdm_user_manager_finalize (GObject *object) signal_pid (manager->priv->ck_history_pid, SIGTERM); } + g_slist_foreach (manager->priv->new_sessions, + (GFunc) unload_new_session, NULL); + g_slist_free (manager->priv->new_sessions); + unload_seat (manager); if (manager->priv->exclude_usernames != NULL) { |