3
* quiesce.c - shutdown handling.
5
* Copyright © 2013 Canonical Ltd.
6
* Author: James Hunt <james.hunt@canonical.com>
8
* This program is free software; you can redistribute it and/or modify
9
* it under the terms of the GNU General Public License version 2, as
10
* published by the Free Software Foundation.
12
* This program is distributed in the hope that it will be useful,
13
* but WITHOUT ANY WARRANTY; without even the implied warranty of
14
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15
* GNU General Public License for more details.
17
* You should have received a copy of the GNU General Public License along
18
* with this program; if not, write to the Free Software Foundation, Inc.,
19
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
24
#endif /* HAVE_CONFIG_H */
30
#include "job_process.h"
38
* Where the quiesce request originated. This determines
39
* the shutdown behaviour.
41
static QuiesceRequester quiesce_requester = QUIESCE_REQUESTER_INVALID;
46
* Current phase of shutdown.
48
static QuiescePhase quiesce_phase = QUIESCE_PHASE_NOT_QUIESCED;
53
* Maxiumum kill_timout value calculated from all running jobs used to
54
* determine how long to wait before exiting.
56
static time_t max_kill_timeout = 0;
61
* Time that a particular phase started.
63
static time_t quiesce_phase_time = 0;
65
/* External definitions */
66
extern int disable_respawn;
71
* @requester: where the quiesce request originated.
73
* Commence Session Init shutdown.
76
quiesce (QuiesceRequester requester)
78
nih_local char **env = NULL;
83
/* Quiesce already in progress */
84
if (quiesce_phase != QUIESCE_PHASE_NOT_QUIESCED)
87
quiesce_requester = requester;
89
/* System shutdown skips the wait phase to ensure all running
92
* Note that jobs which choose to start on SESSION_END_EVENT may
93
* not complete (or even start), but no guarantee is possible in
94
* the system shutdown scenario since Session Inits must not
97
quiesce_phase = (requester == QUIESCE_REQUESTER_SYSTEM)
101
reason = (requester == QUIESCE_REQUESTER_SESSION)
102
? _("logout") : _("shutdown");
104
nih_info (_("Quiescing due to %s request"), reason);
106
quiesce_phase_time = time (NULL);
108
/* Stop existing jobs from respawning */
109
disable_respawn = TRUE;
111
/* Signal that the session is ending. This may start new jobs.
113
* Note that the event doesn't actually get emitted until the
114
* next time the main loop gets a chance to run.
116
env = NIH_MUST (nih_str_array_new (NULL));
118
NIH_MUST (environ_set (&env, NULL, NULL, TRUE,
121
NIH_MUST (event_new (NULL, SESSION_END_EVENT, env));
123
if (requester == QUIESCE_REQUESTER_SYSTEM) {
124
/* We'll attempt to wait for this long, but system
125
* policy may prevent it such that we just get killed
126
* and job processes reparented to PID 1.
128
max_kill_timeout = job_class_max_kill_timeout ();
130
job_process_stop_all ();
133
/* Check every second to see if all jobs have finished. If so,
136
NIH_MUST (nih_timer_add_periodic (NULL, 1,
137
(NihTimerCb)quiesce_wait_callback, NULL));
141
* quiesce_wait_callback:
144
* @timer: timer that caused us to be called.
146
* Callback used to check if all jobs have finished and if so
147
* finalise Session Init shutdown.
150
quiesce_wait_callback (void *data, NihTimer *timer)
155
nih_assert (quiesce_phase_time);
159
nih_assert (quiesce_requester != QUIESCE_REQUESTER_INVALID);
161
if (quiesce_requester == QUIESCE_REQUESTER_SYSTEM) {
162
nih_assert (quiesce_phase == QUIESCE_PHASE_KILL);
164
if ((now - quiesce_phase_time) > max_kill_timeout)
167
} else if (quiesce_phase == QUIESCE_PHASE_WAIT) {
169
if ((now - quiesce_phase_time) > QUIESCE_DEFAULT_JOB_RUNTIME) {
170
quiesce_phase = QUIESCE_PHASE_KILL;
172
/* reset for new phase */
173
quiesce_phase_time = time (NULL);
175
max_kill_timeout = job_class_max_kill_timeout ();
176
job_process_stop_all ();
178
} else if (quiesce_phase == QUIESCE_PHASE_KILL) {
180
if ((now - quiesce_phase_time) > max_kill_timeout)
183
nih_assert_not_reached ();
186
if (! job_process_jobs_running ())
192
quiesce_show_slow_jobs ();
194
/* Note that we might skip the kill phase for the session
195
* requestor if no jobs are actually running at this point.
197
quiesce_phase = QUIESCE_PHASE_CLEANUP;
205
* quiesce_show_slow_jobs:
207
* List jobs that are still running after their expected end time.
210
quiesce_show_slow_jobs (void)
214
NIH_HASH_FOREACH (job_classes, iter) {
215
JobClass *class = (JobClass *)iter;
217
/* Note that instances get killed in a random order */
218
NIH_HASH_FOREACH (class->instances, job_iter) {
222
job = (Job *)job_iter;
224
name = job_name (job);
226
nih_warn ("job %s failed to stop", name);
238
quiesce_finalise (void)
240
nih_assert (quiesce_phase == QUIESCE_PHASE_CLEANUP);
242
nih_main_loop_exit (0);