]> git.saurik.com Git - apple/xnu.git/blame - bsd/kern/kern_shutdown.c
xnu-201.tar.gz
[apple/xnu.git] / bsd / kern / kern_shutdown.c
CommitLineData
1c79356b
A
1/*
2 * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * The contents of this file constitute Original Code as defined in and
7 * are subject to the Apple Public Source License Version 1.1 (the
8 * "License"). You may not use this file except in compliance with the
9 * License. Please obtain a copy of the License at
10 * http://www.apple.com/publicsource and read it before using this file.
11 *
12 * This Original Code and all software distributed under the License are
13 * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
14 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
15 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
17 * License for the specific language governing rights and limitations
18 * under the License.
19 *
20 * @APPLE_LICENSE_HEADER_END@
21 */
22/*
23 * File: bsd/kern/kern_shutdown.c
24 *
25 * Copyright (C) 1989, NeXT, Inc.
26 *
27 */
28
29#include <sys/param.h>
30#include <sys/systm.h>
31#include <sys/kernel.h>
32#include <sys/vm.h>
33#include <sys/proc.h>
34#include <sys/user.h>
35#include <sys/buf.h>
36#include <sys/reboot.h>
37#include <sys/conf.h>
38#include <sys/vnode.h>
39#include <sys/file.h>
40#include <sys/clist.h>
41#include <sys/callout.h>
42#include <sys/mbuf.h>
43#include <sys/msgbuf.h>
44#include <sys/ioctl.h>
45#include <sys/signal.h>
46#include <sys/tty.h>
47#include <kern/task.h>
48#include <ufs/ufs/quota.h>
49#include <ufs/ufs/inode.h>
50#if NCPUS > 1
51#include <kern/processor.h>
52#include <kern/thread.h>
53#include <sys/lock.h>
54#endif /* NCPUS > 1 */
55#include <vm/vm_kern.h>
56#include <mach/vm_param.h>
57#include <sys/filedesc.h>
58#include <mach/host_reboot.h>
59
60int waittime = -1;
61
62void
63boot(paniced, howto, command)
64 int paniced, howto;
65 char *command;
66{
67 register int i;
68 int s;
69 struct proc *p = current_proc(); /* XXX */
70 int hostboot_option=0;
71 int funnel_state;
72
0b4e3aa0
A
73 static void proc_shutdown();
74 extern void md_prepare_for_shutdown(int paniced, int howto, char * command);
1c79356b
A
75
76 funnel_state = thread_funnel_set(kernel_flock, TRUE);
77
0b4e3aa0 78 md_prepare_for_shutdown(paniced, howto, command);
1c79356b
A
79
80 if ((howto&RB_NOSYNC)==0 && waittime < 0) {
81 int iter, nbusy;
82
83 waittime = 0;
84
85 printf("syncing disks... ");
86
87 /*
88 * Release vnodes held by texts before sync.
89 */
90
91 /* handle live procs (deallocate their root and current directories). */
92 proc_shutdown();
93
94 sync(p, (void *)NULL, (int *)NULL);
95
96 /* Release vnodes from the VM object cache */
97 ubc_unmountall();
98
99 IOSleep( 1 * 1000 );
100
101 /*
102 * Unmount filesystems
103 */
104 if (panicstr == 0)
105 vfs_unmountall();
106
107 /* Wait for the buffer cache to clean remaining dirty buffers */
108 for (iter = 0; iter < 20; iter++) {
109 nbusy = count_busy_buffers();
110 if (nbusy == 0)
111 break;
112 printf("%d ", nbusy);
113 IOSleep( 4 * nbusy );
114 }
115 if (nbusy)
116 printf("giving up\n");
117 else
118 printf("done\n");
119 }
120
121 /*
122 * Can't just use an splnet() here to disable the network
123 * because that will lock out softints which the disk
124 * drivers depend on to finish DMAs.
125 */
126 if_down_all();
127
128 if (howto & RB_POWERDOWN)
129 hostboot_option = HOST_REBOOT_HALT;
130 if (howto & RB_HALT)
131 hostboot_option = HOST_REBOOT_HALT;
132 if (paniced == RB_PANIC)
133 hostboot_option = HOST_REBOOT_HALT;
134
135 if (hostboot_option == HOST_REBOOT_HALT)
136 IOSleep( 1 * 1000 );
137
138 host_reboot(host_priv_self(), hostboot_option);
139
140 thread_funnel_set(kernel_flock, FALSE);
141}
142
143/*
144 * proc_shutdown()
145 *
146 * Shutdown down proc system (release references to current and root
147 * dirs for each process).
148 *
149 * POSIX modifications:
150 *
151 * For POSIX fcntl() file locking call vno_lockrelease() on
152 * the file to release all of its record locks, if any.
153 */
154
155static void
156proc_shutdown()
157{
158 struct proc *p, *self;
159 struct vnode **cdirp, **rdirp, *vp;
160 int restart, i, TERM_catch;
161
162 /*
163 * Kill as many procs as we can. (Except ourself...)
164 */
0b4e3aa0 165 self = (struct proc *)current_proc();
1c79356b
A
166
167 /*
168 * Suspend /etc/init
169 */
170 p = pfind(1);
171 if (p && p != self)
172 task_suspend(p->task); /* stop init */
173
174 /*
175 * Suspend mach_init
176 */
177 p = pfind(2);
178 if (p && p != self)
179 task_suspend(p->task); /* stop mach_init */
180
181 printf("Killing all processes ");
182
183 /*
184 * send SIGTERM to those procs interested in catching one
185 */
186 for (p = allproc.lh_first; p; p = p->p_list.le_next) {
187 if (((p->p_flag&P_SYSTEM) == 0) && (p->p_pptr->p_pid != 0) && (p != self)) {
188 if (p->p_sigcatch & sigmask(SIGTERM))
189 psignal(p, SIGTERM);
190 }
191 }
192 /*
193 * now wait for up to 30 seconds to allow those procs catching SIGTERM
194 * to digest it
195 * as soon as these procs have exited, we'll continue on to the next step
196 */
197 for (i = 0; i < 300; i++) {
198 /*
199 * sleep for a tenth of a second
200 * and then check to see if the tasks that were sent a
201 * SIGTERM have exited
202 */
203 IOSleep(100);
204 TERM_catch = 0;
205
206 for (p = allproc.lh_first; p; p = p->p_list.le_next) {
207 if (((p->p_flag&P_SYSTEM) == 0) && (p->p_pptr->p_pid != 0) && (p != self)) {
208 if (p->p_sigcatch & sigmask(SIGTERM))
209 TERM_catch++;
210 }
211 }
212 if (TERM_catch == 0)
213 break;
214 }
215
216 /*
217 * send a SIGKILL to all the procs still hanging around
218 */
219 for (p = allproc.lh_first; p; p = p->p_list.le_next) {
220 if (((p->p_flag&P_SYSTEM) == 0) && (p->p_pptr->p_pid != 0) && (p != self))
221 psignal(p, SIGKILL);
222 }
223 /*
224 * wait for up to 60 seconds to allow these procs to exit normally
225 */
226 for (i = 0; i < 300; i++) {
227 IOSleep(200); /* double the time from 100 to 200 for NFS requests in particular */
228
229 for (p = allproc.lh_first; p; p = p->p_list.le_next) {
230 if (((p->p_flag&P_SYSTEM) == 0) && (p->p_pptr->p_pid != 0) && (p != self))
231 break;
232 }
233 if (!p)
234 break;
235 }
236
237 /*
238 * if we still have procs that haven't exited, then brute force 'em
239 */
240 p = allproc.lh_first;
241 while (p) {
242 if ((p->p_flag&P_SYSTEM) || (p->p_pptr->p_pid == 0) || (p == self)) {
243 p = p->p_list.le_next;
244 }
245 else {
246 /*
247 * NOTE: following code ignores sig_lock and plays
248 * with exit_thread correctly. This is OK unless we
249 * are a multiprocessor, in which case I do not
250 * understand the sig_lock. This needs to be fixed.
251 * XXX
252 */
253 if (p->exit_thread) { /* someone already doing it */
254 thread_block(0);/* give him a chance */
255 }
256 else {
257 p->exit_thread = current_thread();
258 printf(".");
0b4e3aa0 259 exit1(p, 1, (int *)NULL);
1c79356b
A
260 }
261 p = allproc.lh_first;
262 }
263 }
264 printf("\n");
265 /*
266 * Forcibly free resources of what's left.
267 */
268 p = allproc.lh_first;
269 while (p) {
270 /*
271 * Close open files and release open-file table.
272 * This may block!
273 */
274#ifdef notyet
275 /* panics on reboot due to "zfree: non-allocated memory in collectable zone" message */
276 fdfree(p);
277#endif /* notyet */
278 p = p->p_list.le_next;
279 }
280 /* Wait for the reaper thread to run, and clean up what we have done
281 * before we proceed with the hardcore shutdown. This reduces the race
282 * between kill_tasks and the reaper thread.
283 */
284 /* thread_wakeup(&reaper_queue); */
285 /* IOSleep( 1 * 1000); */
286 printf("continuing\n");
287}
288