]>
git.saurik.com Git - apple/xnu.git/blob - bsd/kern/kern_shutdown.c
2 * Copyright (c) 2000-2006 Apple Computer, Inc. All rights reserved.
4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. The rights granted to you under the License
10 * may not be used to create, or enable the creation or redistribution of,
11 * unlawful or unlicensed copies of an Apple operating system, or to
12 * circumvent, violate, or enable the circumvention or violation of, any
13 * terms of an Apple operating system software license agreement.
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
18 * The Original Code and all software distributed under the License are
19 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
22 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
23 * Please see the License for the specific language governing rights and
24 * limitations under the License.
26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
29 * File: bsd/kern/kern_shutdown.c
31 * Copyright (C) 1989, NeXT, Inc.
35 #include <sys/param.h>
36 #include <sys/systm.h>
37 #include <sys/kernel.h>
39 #include <sys/proc_internal.h>
41 #include <sys/reboot.h>
43 #include <sys/vnode_internal.h>
44 #include <sys/file_internal.h>
45 #include <sys/clist.h>
46 #include <sys/callout.h>
48 #include <sys/msgbuf.h>
49 #include <sys/ioctl.h>
50 #include <sys/signal.h>
52 #include <kern/task.h>
53 #include <sys/quota.h>
54 #include <ufs/ufs/inode.h>
56 #include <kern/processor.h>
57 #include <kern/thread.h>
59 #endif /* NCPUS > 1 */
60 #include <vm/vm_kern.h>
61 #include <mach/vm_param.h>
62 #include <sys/filedesc.h>
63 #include <mach/host_priv.h>
64 #include <mach/host_reboot.h>
66 #include <bsm/audit_kernel.h>
68 #include <kern/sched_prim.h> /* for thread_block() */
69 #include <kern/host.h> /* for host_priv_self() */
70 #include <net/if_var.h> /* for if_down_all() */
71 #include <sys/buf_internal.h> /* for count_busy_buffers() */
72 #include <sys/mount_internal.h> /* for vfs_unmountall() */
73 #include <mach/task.h> /* for task_suspend() */
74 #include <sys/sysproto.h> /* abused for sync() */
75 #include <kern/clock.h> /* for delay_for_interval() */
77 /* XXX should be in a header file somewhere, but isn't */
78 extern void md_prepare_for_shutdown(int, int, char *);
81 static int shutting_down
= 0;
83 static void proc_shutdown(void);
84 int in_shutdown(void);
86 extern void IOSystemShutdownNotification(void);
95 int signo
; /* the signal to be posted */
96 int setsdstate
; /* shutdown state to be set */
99 static int sd_filt1(proc_t
, void *);
100 static int sd_filt2(proc_t
, void *);
101 static int sd_callback1(proc_t p
, void * arg
);
102 static int sd_callback2(proc_t p
, void * arg
);
103 static int sd_callback3(proc_t p
, void * arg
);
106 boot(int paniced
, int howto
, char *command
)
108 struct proc
*p
= current_proc(); /* XXX */
109 int hostboot_option
=0;
112 funnel_state
= thread_funnel_set(kernel_flock
, TRUE
);
115 * Temporary hack to notify the power management root domain
116 * that the system will shut down.
118 IOSystemShutdownNotification();
122 md_prepare_for_shutdown(paniced
, howto
, command
);
124 if ((howto
&RB_NOSYNC
)==0 && waittime
< 0) {
129 printf("syncing disks... ");
132 * Release vnodes held by texts before sync.
135 /* handle live procs (deallocate their root and current directories). */
142 sync(p
, (void *)NULL
, (int *)NULL
);
145 * Now that all processes have been terminated and system is
146 * sync'ed up, suspend init
149 if (initproc
&& p
!= initproc
)
150 task_suspend(initproc
->task
);
153 * Unmount filesystems
157 /* Wait for the buffer cache to clean remaining dirty buffers */
158 for (iter
= 0; iter
< 100; iter
++) {
159 nbusy
= count_busy_buffers();
162 printf("%d ", nbusy
);
163 delay_for_interval( 1 * nbusy
, 1000 * 1000);
166 printf("giving up\n");
173 * Can't just use an splnet() here to disable the network
174 * because that will lock out softints which the disk
175 * drivers depend on to finish DMAs.
178 #endif /* NETWORKING */
180 if (howto
& RB_POWERDOWN
)
181 hostboot_option
= HOST_REBOOT_HALT
;
183 hostboot_option
= HOST_REBOOT_HALT
;
184 if (paniced
== RB_PANIC
)
185 hostboot_option
= HOST_REBOOT_HALT
;
187 if (howto
& RB_UPSDELAY
) {
188 hostboot_option
= HOST_REBOOT_UPSDELAY
;
191 host_reboot(host_priv_self(), hostboot_option
);
193 thread_funnel_set(kernel_flock
, FALSE
);
197 sd_filt1(proc_t p
, void * args
)
199 proc_t self
= current_proc();
200 struct sd_filterargs
* sf
= (struct sd_filterargs
*)args
;
201 int delayterm
= sf
-> delayterm
;
202 int shutdownstate
= sf
->shutdownstate
;
204 if (((p
->p_flag
&P_SYSTEM
) != 0) || (p
->p_ppid
== 0)
205 ||(p
== self
) || (p
->p_stat
== SZOMB
)
206 || (p
->p_shutdownstate
!= shutdownstate
)
207 ||((delayterm
== 0) && ((p
->p_lflag
& P_LDELAYTERM
) == P_LDELAYTERM
))
208 || ((p
->p_sigcatch
& sigmask(SIGTERM
))== 0)) {
217 sd_callback1(proc_t p
, void * args
)
219 struct sd_iterargs
* sd
= (struct sd_iterargs
*)args
;
220 int signo
= sd
->signo
;
221 int setsdstate
= sd
->setsdstate
;
224 p
->p_shutdownstate
= setsdstate
;
225 if (p
->p_stat
!= SZOMB
) {
230 return(PROC_RETURNED
);
235 sd_filt2(proc_t p
, void * args
)
237 proc_t self
= current_proc();
238 struct sd_filterargs
* sf
= (struct sd_filterargs
*)args
;
239 int delayterm
= sf
-> delayterm
;
240 int shutdownstate
= sf
->shutdownstate
;
242 if (((p
->p_flag
&P_SYSTEM
) != 0) || (p
->p_ppid
== 0)
243 ||(p
== self
) || (p
->p_stat
== SZOMB
)
244 || (p
->p_shutdownstate
== shutdownstate
)
245 ||((delayterm
== 0) && ((p
->p_lflag
& P_LDELAYTERM
) == P_LDELAYTERM
))) {
253 sd_callback2(proc_t p
, void * args
)
255 struct sd_iterargs
* sd
= (struct sd_iterargs
*)args
;
256 int signo
= sd
->signo
;
257 int setsdstate
= sd
->setsdstate
;
260 p
->p_shutdownstate
= setsdstate
;
261 if (p
->p_stat
!= SZOMB
) {
267 return(PROC_RETURNED
);
272 sd_callback3(proc_t p
, void * args
)
274 struct sd_iterargs
* sd
= (struct sd_iterargs
*)args
;
275 int setsdstate
= sd
->setsdstate
;
278 p
->p_shutdownstate
= setsdstate
;
279 if (p
->p_stat
!= SZOMB
) {
281 * NOTE: following code ignores sig_lock and plays
282 * with exit_thread correctly. This is OK unless we
283 * are a multiprocessor, in which case I do not
284 * understand the sig_lock. This needs to be fixed.
287 if (p
->exit_thread
) { /* someone already doing it */
289 /* give him a chance */
290 thread_block(THREAD_CONTINUE_NULL
);
292 p
->exit_thread
= current_thread();
295 exit1(p
, 1, (int *)NULL
);
300 return(PROC_RETURNED
);
307 * Shutdown down proc system (release references to current and root
308 * dirs for each process).
310 * POSIX modifications:
312 * For POSIX fcntl() file locking call vno_lockrelease() on
313 * the file to release all of its record locks, if any.
319 struct proc
*p
, *self
;
322 struct sd_filterargs sfargs
;
323 struct sd_iterargs sdargs
;
326 * Kill as many procs as we can. (Except ourself...)
328 self
= (struct proc
*)current_proc();
331 * Signal the init with SIGTERM so that he does not launch
335 if (p
&& p
!= self
) {
340 printf("Killing all processes ");
344 * send SIGTERM to those procs interested in catching one
346 sfargs
.delayterm
= delayterm
;
347 sfargs
.shutdownstate
= 0;
348 sdargs
.signo
= SIGTERM
;
349 sdargs
.setsdstate
= 1;
351 /* post a SIGTERM to all that catch SIGTERM and not marked for delay */
352 proc_rebootscan(sd_callback1
, (void *)&sdargs
, sd_filt1
, (void *)&sfargs
);
355 * now wait for up to 30 seconds to allow those procs catching SIGTERM
357 * as soon as these procs have exited, we'll continue on to the next step
359 for (i
= 0; i
< 300; i
++) {
361 * sleep for a tenth of a second
362 * and then check to see if the tasks that were sent a
363 * SIGTERM have exited
365 delay_for_interval(100, 1000 * 1000);
371 for (p
= allproc
.lh_first
; p
; p
= p
->p_list
.le_next
) {
372 if (p
->p_shutdownstate
== 1) {
384 * log the names of the unresponsive tasks
390 for (p
= allproc
.lh_first
; p
; p
= p
->p_list
.le_next
) {
391 if (p
->p_shutdownstate
== 1) {
392 printf("%s[%d]: didn't act on SIGTERM\n", p
->p_comm
, p
->p_pid
);
398 delay_for_interval(1000 * 5, 1000 * 1000);
402 * send a SIGKILL to all the procs still hanging around
404 sfargs
.delayterm
= delayterm
;
405 sfargs
.shutdownstate
= 2;
406 sdargs
.signo
= SIGKILL
;
407 sdargs
.setsdstate
= 2;
409 /* post a SIGTERM to all that catch SIGTERM and not marked for delay */
410 proc_rebootscan(sd_callback2
, (void *)&sdargs
, sd_filt2
, (void *)&sfargs
);
413 * wait for up to 60 seconds to allow these procs to exit normally
415 * History: The delay interval was changed from 100 to 200
416 * for NFS requests in particular.
418 for (i
= 0; i
< 300; i
++) {
419 delay_for_interval(200, 1000 * 1000);
424 for (p
= allproc
.lh_first
; p
; p
= p
->p_list
.le_next
) {
425 if (p
->p_shutdownstate
== 2)
436 * if we still have procs that haven't exited, then brute force 'em
438 sfargs
.delayterm
= delayterm
;
439 sfargs
.shutdownstate
= 3;
441 sdargs
.setsdstate
= 3;
443 /* post a SIGTERM to all that catch SIGTERM and not marked for delay */
444 proc_rebootscan(sd_callback3
, (void *)&sdargs
, sd_filt2
, (void *)&sfargs
);
447 /* Now start the termination of processes that are marked for delayed termn */
448 if (delayterm
== 0) {
452 /* drop the ref on initproc */
454 printf("continuing\n");
458 * Check whether the system has begun its shutdown sequence.
463 return shutting_down
;