To get the state of the user, the user_get_state() is used. This function will check if the user->slice_job or the user->service_job are set then it will automatically return USER_OPENING. This is buggy in the context of user closing:
At logout or D-Bus TerminateUser() calls user_stop() user_stop() => session_stop() on sessions => session_stop_scope() on sessions => user_get_state() == USER_CLOSING or USER_ACTIVE or USER_ONLINE (incorrect) (depends on session closing execution and if we have finished the session scope jobs or not, if all the scopes are being queued then their session->scope_job will be set which means all sessions are in the OPENING_STATE, so user state will be USER_ONLINE). The previous patch improves session_get_state() logic, and if scopes are being queued then sessions are in SESSION_CLOSING state which makes user_get_state() return USER_CLOSING. At user_stop() user_stop_slice() queues the slice and sets user->slice_job user_stop_service() queue the service and sets user->service_job => user_get_state() == USER_OPENING (incorrect) After the slice and service jobs are removed the state will be again correct. => user_get_state() == USER_CLOSING (correct) To fix this and make sure that the state will always be USER_CLOSING we add a flag that is used to differentiate between USER_OPENING and USER_CLOSING when 'slice_job' and 'service_job' are set. The 'slice_opening' flag for 'user->slice_job' and 'service_opening' for 'user->service_job' are set to true only during real user opening. During user closing they are already in the false state. Update user_get_state() to check if they are set if so this is USER_OPENING, otherwise we are in the USER_CLOSING. --- src/login/logind-dbus.c | 2 ++ src/login/logind-user.c | 5 ++++- src/login/logind-user.h | 2 ++ 3 files changed, 8 insertions(+), 1 deletion(-) diff --git a/src/login/logind-dbus.c b/src/login/logind-dbus.c index 0123a34..a7452b1 100644 --- a/src/login/logind-dbus.c +++ b/src/login/logind-dbus.c @@ -2000,11 +2000,13 @@ int match_job_removed(sd_bus *bus, sd_bus_message *message, void *userdata, sd_b /* Clean this up after session_send_create_reply() */ free(user->service_job); user->service_job = NULL; + user->service_opening = false; } if (streq_ptr(path, user->slice_job)) { free(user->slice_job); user->slice_job = NULL; + user->slice_opening = false; } user_save(user); diff --git a/src/login/logind-user.c b/src/login/logind-user.c index 0e46560..200763d 100644 --- a/src/login/logind-user.c +++ b/src/login/logind-user.c @@ -352,6 +352,7 @@ static int user_start_slice(User *u) { free(u->slice_job); u->slice_job = job; + u->slice_opening = true; } } @@ -385,6 +386,7 @@ static int user_start_service(User *u) { free(u->service_job); u->service_job = job; + u->service_opening = true; } } @@ -637,7 +639,8 @@ UserState user_get_state(User *u) { assert(u); - if (u->slice_job || u->service_job) + if ((u->slice_job && u->slice_opening) || + (u->service_job && u->service_opening)) return USER_OPENING; LIST_FOREACH(sessions_by_user, i, u->sessions) { diff --git a/src/login/logind-user.h b/src/login/logind-user.h index 0062880..ac43361 100644 --- a/src/login/logind-user.h +++ b/src/login/logind-user.h @@ -61,6 +61,8 @@ struct User { bool in_gc_queue:1; bool started:1; + bool service_opening:1; /* User service is being created */ + bool slice_opening:1; /* User slice is being created */ LIST_HEAD(Session, sessions); LIST_FIELDS(User, gc_queue); -- 1.8.3.1 _______________________________________________ systemd-devel mailing list systemd-devel@lists.freedesktop.org http://lists.freedesktop.org/mailman/listinfo/systemd-devel