]> git.saurik.com Git - apple/xnu.git/blob - bsd/kern/kern_shutdown.c
xnu-344.49.tar.gz
[apple/xnu.git] / bsd / kern / kern_shutdown.c
1 /*
2 * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * Copyright (c) 1999-2003 Apple Computer, Inc. All Rights Reserved.
7 *
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
13 * file.
14 *
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.
22 *
23 * @APPLE_LICENSE_HEADER_END@
24 */
25 /*
26 * File: bsd/kern/kern_shutdown.c
27 *
28 * Copyright (C) 1989, NeXT, Inc.
29 *
30 */
31
32 #include <sys/param.h>
33 #include <sys/systm.h>
34 #include <sys/kernel.h>
35 #include <sys/vm.h>
36 #include <sys/proc.h>
37 #include <sys/user.h>
38 #include <sys/buf.h>
39 #include <sys/reboot.h>
40 #include <sys/conf.h>
41 #include <sys/vnode.h>
42 #include <sys/file.h>
43 #include <sys/clist.h>
44 #include <sys/callout.h>
45 #include <sys/mbuf.h>
46 #include <sys/msgbuf.h>
47 #include <sys/ioctl.h>
48 #include <sys/signal.h>
49 #include <sys/tty.h>
50 #include <kern/task.h>
51 #include <sys/quota.h>
52 #include <ufs/ufs/inode.h>
53 #if NCPUS > 1
54 #include <kern/processor.h>
55 #include <kern/thread.h>
56 #include <sys/lock.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>
62
63 int waittime = -1;
64
65 void
66 boot(paniced, howto, command)
67 int paniced, howto;
68 char *command;
69 {
70 register int i;
71 int s;
72 struct proc *p = current_proc(); /* XXX */
73 int hostboot_option=0;
74 int funnel_state;
75
76 static void proc_shutdown();
77 extern void md_prepare_for_shutdown(int paniced, int howto, char * command);
78
79 funnel_state = thread_funnel_set(kernel_flock, TRUE);
80
81 md_prepare_for_shutdown(paniced, howto, command);
82
83 if ((howto&RB_NOSYNC)==0 && waittime < 0) {
84 int iter, nbusy;
85
86 waittime = 0;
87
88 printf("syncing disks... ");
89
90 /*
91 * Release vnodes held by texts before sync.
92 */
93
94 /* handle live procs (deallocate their root and current directories). */
95 proc_shutdown();
96
97 sync(p, (void *)NULL, (int *)NULL);
98
99 /* Release vnodes from the VM object cache */
100 ubc_unmountall();
101
102 IOSleep( 1 * 1000 );
103
104 /*
105 * Unmount filesystems
106 */
107 if (panicstr == 0)
108 vfs_unmountall();
109
110 /* Wait for the buffer cache to clean remaining dirty buffers */
111 for (iter = 0; iter < 20; iter++) {
112 nbusy = count_busy_buffers();
113 if (nbusy == 0)
114 break;
115 printf("%d ", nbusy);
116 IOSleep( 4 * nbusy );
117 }
118 if (nbusy)
119 printf("giving up\n");
120 else
121 printf("done\n");
122 }
123
124 /*
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.
128 */
129 if_down_all();
130
131 if (howto & RB_POWERDOWN)
132 hostboot_option = HOST_REBOOT_HALT;
133 if (howto & RB_HALT)
134 hostboot_option = HOST_REBOOT_HALT;
135 if (paniced == RB_PANIC)
136 hostboot_option = HOST_REBOOT_HALT;
137
138 if (hostboot_option == HOST_REBOOT_HALT)
139 IOSleep( 1 * 1000 );
140
141 host_reboot(host_priv_self(), hostboot_option);
142
143 thread_funnel_set(kernel_flock, FALSE);
144 }
145
146 /*
147 * proc_shutdown()
148 *
149 * Shutdown down proc system (release references to current and root
150 * dirs for each process).
151 *
152 * POSIX modifications:
153 *
154 * For POSIX fcntl() file locking call vno_lockrelease() on
155 * the file to release all of its record locks, if any.
156 */
157
158 static void
159 proc_shutdown()
160 {
161 struct proc *p, *self;
162 struct vnode **cdirp, **rdirp, *vp;
163 int restart, i, TERM_catch;
164
165 /*
166 * Kill as many procs as we can. (Except ourself...)
167 */
168 self = (struct proc *)current_proc();
169
170 /*
171 * Suspend /etc/init
172 */
173 p = pfind(1);
174 if (p && p != self)
175 task_suspend(p->task); /* stop init */
176
177 printf("Killing all processes ");
178
179 /*
180 * send SIGTERM to those procs interested in catching one
181 */
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))
185 psignal(p, SIGTERM);
186 }
187 }
188 /*
189 * now wait for up to 30 seconds to allow those procs catching SIGTERM
190 * to digest it
191 * as soon as these procs have exited, we'll continue on to the next step
192 */
193 for (i = 0; i < 300; i++) {
194 /*
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
198 */
199 IOSleep(100);
200 TERM_catch = 0;
201
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))
205 TERM_catch++;
206 }
207 }
208 if (TERM_catch == 0)
209 break;
210 }
211
212 /*
213 * send a SIGKILL to all the procs still hanging around
214 */
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))
217 psignal(p, SIGKILL);
218 }
219 /*
220 * wait for up to 60 seconds to allow these procs to exit normally
221 */
222 for (i = 0; i < 300; i++) {
223 IOSleep(200); /* double the time from 100 to 200 for NFS requests in particular */
224
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))
227 break;
228 }
229 if (!p)
230 break;
231 }
232
233 /*
234 * if we still have procs that haven't exited, then brute force 'em
235 */
236 p = allproc.lh_first;
237 while (p) {
238 if ((p->p_flag&P_SYSTEM) || (p->p_pptr->p_pid == 0) || (p == self)) {
239 p = p->p_list.le_next;
240 }
241 else {
242 /*
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.
247 * XXX
248 */
249 if (p->exit_thread) { /* someone already doing it */
250 /* give him a chance */
251 thread_block(THREAD_CONTINUE_NULL);
252 }
253 else {
254 p->exit_thread = current_thread();
255 printf(".");
256 exit1(p, 1, (int *)NULL);
257 }
258 p = allproc.lh_first;
259 }
260 }
261 printf("\n");
262 /*
263 * Forcibly free resources of what's left.
264 */
265 p = allproc.lh_first;
266 while (p) {
267 /*
268 * Close open files and release open-file table.
269 * This may block!
270 */
271 #ifdef notyet
272 /* panics on reboot due to "zfree: non-allocated memory in collectable zone" message */
273 fdfree(p);
274 #endif /* notyet */
275 p = p->p_list.le_next;
276 }
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.
280 */
281 /* thread_wakeup(&reaper_queue); */
282 /* IOSleep( 1 * 1000); */
283 printf("continuing\n");
284 }
285