]>
git.saurik.com Git - apple/xnu.git/blob - bsd/kern/kern_shutdown.c
2 * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
4 * @APPLE_LICENSE_HEADER_START@
6 * Copyright (c) 1999-2003 Apple Computer, Inc. All Rights Reserved.
8 * This file contains Original Code and/or Modifications of Original Code
9 * as defined in and that are subject to the Apple Public Source License
10 * Version 2.0 (the 'License'). You may not use this file except in
11 * compliance with the License. Please obtain a copy of the License at
12 * http://www.opensource.apple.com/apsl/ and read it before using this
15 * The Original Code and all software distributed under the License are
16 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
17 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
18 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
19 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
20 * Please see the License for the specific language governing rights and
21 * limitations under the License.
23 * @APPLE_LICENSE_HEADER_END@
26 * File: bsd/kern/kern_shutdown.c
28 * Copyright (C) 1989, NeXT, Inc.
32 #include <sys/param.h>
33 #include <sys/systm.h>
34 #include <sys/kernel.h>
39 #include <sys/reboot.h>
41 #include <sys/vnode.h>
43 #include <sys/clist.h>
44 #include <sys/callout.h>
46 #include <sys/msgbuf.h>
47 #include <sys/ioctl.h>
48 #include <sys/signal.h>
50 #include <kern/task.h>
51 #include <sys/quota.h>
52 #include <ufs/ufs/inode.h>
54 #include <kern/processor.h>
55 #include <kern/thread.h>
57 #endif /* NCPUS > 1 */
58 #include <vm/vm_kern.h>
59 #include <mach/vm_param.h>
60 #include <sys/filedesc.h>
61 #include <mach/host_reboot.h>
66 boot(paniced
, howto
, command
)
72 struct proc
*p
= current_proc(); /* XXX */
73 int hostboot_option
=0;
76 static void proc_shutdown();
77 extern void md_prepare_for_shutdown(int paniced
, int howto
, char * command
);
79 funnel_state
= thread_funnel_set(kernel_flock
, TRUE
);
81 md_prepare_for_shutdown(paniced
, howto
, command
);
83 if ((howto
&RB_NOSYNC
)==0 && waittime
< 0) {
88 printf("syncing disks... ");
91 * Release vnodes held by texts before sync.
94 /* handle live procs (deallocate their root and current directories). */
97 sync(p
, (void *)NULL
, (int *)NULL
);
99 /* Release vnodes from the VM object cache */
105 * Unmount filesystems
110 /* Wait for the buffer cache to clean remaining dirty buffers */
111 for (iter
= 0; iter
< 20; iter
++) {
112 nbusy
= count_busy_buffers();
115 printf("%d ", nbusy
);
116 IOSleep( 4 * nbusy
);
119 printf("giving up\n");
125 * Can't just use an splnet() here to disable the network
126 * because that will lock out softints which the disk
127 * drivers depend on to finish DMAs.
131 if (howto
& RB_POWERDOWN
)
132 hostboot_option
= HOST_REBOOT_HALT
;
134 hostboot_option
= HOST_REBOOT_HALT
;
135 if (paniced
== RB_PANIC
)
136 hostboot_option
= HOST_REBOOT_HALT
;
138 if (hostboot_option
== HOST_REBOOT_HALT
)
141 host_reboot(host_priv_self(), hostboot_option
);
143 thread_funnel_set(kernel_flock
, FALSE
);
149 * Shutdown down proc system (release references to current and root
150 * dirs for each process).
152 * POSIX modifications:
154 * For POSIX fcntl() file locking call vno_lockrelease() on
155 * the file to release all of its record locks, if any.
161 struct proc
*p
, *self
;
162 struct vnode
**cdirp
, **rdirp
, *vp
;
163 int restart
, i
, TERM_catch
;
166 * Kill as many procs as we can. (Except ourself...)
168 self
= (struct proc
*)current_proc();
175 task_suspend(p
->task
); /* stop init */
177 printf("Killing all processes ");
180 * send SIGTERM to those procs interested in catching one
182 for (p
= allproc
.lh_first
; p
; p
= p
->p_list
.le_next
) {
183 if (((p
->p_flag
&P_SYSTEM
) == 0) && (p
->p_pptr
->p_pid
!= 0) && (p
!= self
)) {
184 if (p
->p_sigcatch
& sigmask(SIGTERM
))
189 * now wait for up to 30 seconds to allow those procs catching SIGTERM
191 * as soon as these procs have exited, we'll continue on to the next step
193 for (i
= 0; i
< 300; i
++) {
195 * sleep for a tenth of a second
196 * and then check to see if the tasks that were sent a
197 * SIGTERM have exited
202 for (p
= allproc
.lh_first
; p
; p
= p
->p_list
.le_next
) {
203 if (((p
->p_flag
&P_SYSTEM
) == 0) && (p
->p_pptr
->p_pid
!= 0) && (p
!= self
)) {
204 if (p
->p_sigcatch
& sigmask(SIGTERM
))
213 * send a SIGKILL to all the procs still hanging around
215 for (p
= allproc
.lh_first
; p
; p
= p
->p_list
.le_next
) {
216 if (((p
->p_flag
&P_SYSTEM
) == 0) && (p
->p_pptr
->p_pid
!= 0) && (p
!= self
))
220 * wait for up to 60 seconds to allow these procs to exit normally
222 for (i
= 0; i
< 300; i
++) {
223 IOSleep(200); /* double the time from 100 to 200 for NFS requests in particular */
225 for (p
= allproc
.lh_first
; p
; p
= p
->p_list
.le_next
) {
226 if (((p
->p_flag
&P_SYSTEM
) == 0) && (p
->p_pptr
->p_pid
!= 0) && (p
!= self
))
234 * if we still have procs that haven't exited, then brute force 'em
236 p
= allproc
.lh_first
;
238 if ((p
->p_flag
&P_SYSTEM
) || (p
->p_pptr
->p_pid
== 0) || (p
== self
)) {
239 p
= p
->p_list
.le_next
;
243 * NOTE: following code ignores sig_lock and plays
244 * with exit_thread correctly. This is OK unless we
245 * are a multiprocessor, in which case I do not
246 * understand the sig_lock. This needs to be fixed.
249 if (p
->exit_thread
) { /* someone already doing it */
250 /* give him a chance */
251 thread_block(THREAD_CONTINUE_NULL
);
254 p
->exit_thread
= current_thread();
256 exit1(p
, 1, (int *)NULL
);
258 p
= allproc
.lh_first
;
263 * Forcibly free resources of what's left.
265 p
= allproc
.lh_first
;
268 * Close open files and release open-file table.
272 /* panics on reboot due to "zfree: non-allocated memory in collectable zone" message */
275 p
= p
->p_list
.le_next
;
277 /* Wait for the reaper thread to run, and clean up what we have done
278 * before we proceed with the hardcore shutdown. This reduces the race
279 * between kill_tasks and the reaper thread.
281 /* thread_wakeup(&reaper_queue); */
282 /* IOSleep( 1 * 1000); */
283 printf("continuing\n");