]>
git.saurik.com Git - apple/xnu.git/blob - bsd/kern/kern_shutdown.c
2 * Copyright (c) 2000-2004 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>
69 static void proc_shutdown();
72 boot(paniced
, howto
, command
)
78 struct proc
*p
= current_proc(); /* XXX */
79 int hostboot_option
=0;
81 struct proc
*launchd_proc
;
83 extern void md_prepare_for_shutdown(int paniced
, int howto
, char * command
);
85 funnel_state
= thread_funnel_set(kernel_flock
, TRUE
);
87 md_prepare_for_shutdown(paniced
, howto
, command
);
89 if ((howto
&RB_NOSYNC
)==0 && waittime
< 0) {
94 printf("syncing disks... ");
97 * Release vnodes held by texts before sync.
100 /* handle live procs (deallocate their root and current directories). */
105 sync(p
, (void *)NULL
, (int *)NULL
);
108 * Now that all processes have been termianted and system is sync'ed up,
112 launchd_proc
= pfind(1);
113 if (launchd_proc
&& p
!= launchd_proc
) {
114 task_suspend(launchd_proc
->task
);
118 * Unmount filesystems
122 /* Wait for the buffer cache to clean remaining dirty buffers */
123 for (iter
= 0; iter
< 100; iter
++) {
124 nbusy
= count_busy_buffers();
127 printf("%d ", nbusy
);
128 IOSleep( 1 * nbusy
);
131 printf("giving up\n");
137 * Can't just use an splnet() here to disable the network
138 * because that will lock out softints which the disk
139 * drivers depend on to finish DMAs.
143 if (howto
& RB_POWERDOWN
)
144 hostboot_option
= HOST_REBOOT_HALT
;
146 hostboot_option
= HOST_REBOOT_HALT
;
147 if (paniced
== RB_PANIC
)
148 hostboot_option
= HOST_REBOOT_HALT
;
150 if (howto
& RB_UPSDELAY
) {
151 hostboot_option
= HOST_REBOOT_UPSDELAY
;
155 * if we're going to power down due to a halt,
156 * give the disks a chance to finish getting
157 * the track cache flushed to the media...
158 * unfortunately, some of our earlier drives
159 * don't properly hold off on returning
160 * from the track flush command (issued by
161 * the unmounts) until it's actully fully
164 if (hostboot_option
== HOST_REBOOT_HALT
)
167 host_reboot(host_priv_self(), hostboot_option
);
169 thread_funnel_set(kernel_flock
, FALSE
);
175 * Shutdown down proc system (release references to current and root
176 * dirs for each process).
178 * POSIX modifications:
180 * For POSIX fcntl() file locking call vno_lockrelease() on
181 * the file to release all of its record locks, if any.
187 struct proc
*p
, *self
;
188 struct vnode
**cdirp
, **rdirp
, *vp
;
189 int restart
, i
, TERM_catch
;
193 * Kill as many procs as we can. (Except ourself...)
195 self
= (struct proc
*)current_proc();
198 * Signal the init with SIGTERM so that he does not launch
202 if (p
&& p
!= self
) {
206 printf("Killing all processes ");
209 * send SIGTERM to those procs interested in catching one
212 for (p
= allproc
.lh_first
; p
; p
= p
->p_list
.le_next
) {
213 if (((p
->p_flag
&P_SYSTEM
) == 0) && (p
->p_pptr
->p_pid
!= 0) && (p
!= self
) && (p
->p_stat
!= SZOMB
) && (p
->p_shutdownstate
== 0)) {
215 if ((delayterm
== 0) && ((p
->p_lflag
& P_LDELAYTERM
) == P_LDELAYTERM
)) {
218 if (p
->p_sigcatch
& sigmask(SIGTERM
)) {
219 p
->p_shutdownstate
= 1;
220 if (proc_refinternal(p
, 1) == p
) {
222 proc_dropinternal(p
, 1);
229 * now wait for up to 30 seconds to allow those procs catching SIGTERM
231 * as soon as these procs have exited, we'll continue on to the next step
233 for (i
= 0; i
< 300; i
++) {
235 * sleep for a tenth of a second
236 * and then check to see if the tasks that were sent a
237 * SIGTERM have exited
242 for (p
= allproc
.lh_first
; p
; p
= p
->p_list
.le_next
) {
243 if (p
->p_shutdownstate
== 1) {
252 * log the names of the unresponsive tasks
255 for (p
= allproc
.lh_first
; p
; p
= p
->p_list
.le_next
) {
256 if (p
->p_shutdownstate
== 1) {
257 printf("%s[%d]: didn't act on SIGTERM\n", p
->p_comm
, p
->p_pid
);
264 * send a SIGKILL to all the procs still hanging around
267 for (p
= allproc
.lh_first
; p
; p
= p
->p_list
.le_next
) {
268 if (((p
->p_flag
&P_SYSTEM
) == 0) && (p
->p_pptr
->p_pid
!= 0) && (p
!= self
) && (p
->p_stat
!= SZOMB
) && (p
->p_shutdownstate
!= 2)) {
270 if ((delayterm
== 0) && ((p
->p_lflag
& P_LDELAYTERM
) == P_LDELAYTERM
)) {
273 if (proc_refinternal(p
, 1) == p
) {
275 proc_dropinternal(p
, 1);
277 p
->p_shutdownstate
= 2;
282 * wait for up to 60 seconds to allow these procs to exit normally
284 for (i
= 0; i
< 300; i
++) {
285 IOSleep(200); /* double the time from 100 to 200 for NFS requests in particular */
287 for (p
= allproc
.lh_first
; p
; p
= p
->p_list
.le_next
) {
288 if (p
->p_shutdownstate
== 2)
296 * if we still have procs that haven't exited, then brute force 'em
298 p
= allproc
.lh_first
;
300 if ((p
->p_shutdownstate
== 3) || (p
->p_flag
&P_SYSTEM
) || (!delayterm
&& ((p
->p_lflag
& P_LDELAYTERM
)))
301 || (p
->p_pptr
->p_pid
== 0) || (p
== self
)) {
302 p
= p
->p_list
.le_next
;
305 p
->p_shutdownstate
= 3;
307 * NOTE: following code ignores sig_lock and plays
308 * with exit_thread correctly. This is OK unless we
309 * are a multiprocessor, in which case I do not
310 * understand the sig_lock. This needs to be fixed.
313 if (p
->exit_thread
) { /* someone already doing it */
314 /* give him a chance */
315 thread_block(THREAD_CONTINUE_NULL
);
317 p
->exit_thread
= current_thread();
319 if (proc_refinternal(p
, 1) == p
) {
320 exit1(p
, 1, (int *)NULL
);
321 proc_dropinternal(p
, 1);
324 p
= allproc
.lh_first
;
330 /* Now start the termination of processes that are marked for delayed termn */
331 if (delayterm
== 0) {
335 printf("continuing\n");