]> git.saurik.com Git - apple/xnu.git/blob - bsd/kern/kern_shutdown.c
xnu-124.7.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 * 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
60 int waittime = -1;
61
62 void
63 boot(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
73 static void proc_shutdown();
74
75 funnel_state = thread_funnel_set(kernel_flock, TRUE);
76
77 /* md_prepare_for_shutdown(paniced, howto, command); */
78
79 if ((howto&RB_NOSYNC)==0 && waittime < 0) {
80 int iter, nbusy;
81
82 waittime = 0;
83
84 printf("syncing disks... ");
85
86 /*
87 * Release vnodes held by texts before sync.
88 */
89
90 /* handle live procs (deallocate their root and current directories). */
91 proc_shutdown();
92
93 sync(p, (void *)NULL, (int *)NULL);
94
95 /* Release vnodes from the VM object cache */
96 ubc_unmountall();
97
98 IOSleep( 1 * 1000 );
99
100 /*
101 * Unmount filesystems
102 */
103 if (panicstr == 0)
104 vfs_unmountall();
105
106 /* Wait for the buffer cache to clean remaining dirty buffers */
107 for (iter = 0; iter < 20; iter++) {
108 nbusy = count_busy_buffers();
109 if (nbusy == 0)
110 break;
111 printf("%d ", nbusy);
112 IOSleep( 4 * nbusy );
113 }
114 if (nbusy)
115 printf("giving up\n");
116 else
117 printf("done\n");
118 }
119
120 /*
121 * Can't just use an splnet() here to disable the network
122 * because that will lock out softints which the disk
123 * drivers depend on to finish DMAs.
124 */
125 if_down_all();
126
127 if (howto & RB_POWERDOWN)
128 hostboot_option = HOST_REBOOT_HALT;
129 if (howto & RB_HALT)
130 hostboot_option = HOST_REBOOT_HALT;
131 if (paniced == RB_PANIC)
132 hostboot_option = HOST_REBOOT_HALT;
133
134 if (hostboot_option == HOST_REBOOT_HALT)
135 IOSleep( 1 * 1000 );
136
137 host_reboot(host_priv_self(), hostboot_option);
138
139 thread_funnel_set(kernel_flock, FALSE);
140 }
141
142 /*
143 * proc_shutdown()
144 *
145 * Shutdown down proc system (release references to current and root
146 * dirs for each process).
147 *
148 * POSIX modifications:
149 *
150 * For POSIX fcntl() file locking call vno_lockrelease() on
151 * the file to release all of its record locks, if any.
152 */
153
154 static void
155 proc_shutdown()
156 {
157 struct proc *p, *self;
158 struct vnode **cdirp, **rdirp, *vp;
159 int restart, i, TERM_catch;
160
161 /*
162 * Kill as many procs as we can. (Except ourself...)
163 */
164 self = (struct proc *)(get_bsdtask_info(current_task()));
165
166 /*
167 * Suspend /etc/init
168 */
169 p = pfind(1);
170 if (p && p != self)
171 task_suspend(p->task); /* stop init */
172
173 /*
174 * Suspend mach_init
175 */
176 p = pfind(2);
177 if (p && p != self)
178 task_suspend(p->task); /* stop mach_init */
179
180 printf("Killing all processes ");
181
182 /*
183 * send SIGTERM to those procs interested in catching one
184 */
185 for (p = allproc.lh_first; p; p = p->p_list.le_next) {
186 if (((p->p_flag&P_SYSTEM) == 0) && (p->p_pptr->p_pid != 0) && (p != self)) {
187 if (p->p_sigcatch & sigmask(SIGTERM))
188 psignal(p, SIGTERM);
189 }
190 }
191 /*
192 * now wait for up to 30 seconds to allow those procs catching SIGTERM
193 * to digest it
194 * as soon as these procs have exited, we'll continue on to the next step
195 */
196 for (i = 0; i < 300; i++) {
197 /*
198 * sleep for a tenth of a second
199 * and then check to see if the tasks that were sent a
200 * SIGTERM have exited
201 */
202 IOSleep(100);
203 TERM_catch = 0;
204
205 for (p = allproc.lh_first; p; p = p->p_list.le_next) {
206 if (((p->p_flag&P_SYSTEM) == 0) && (p->p_pptr->p_pid != 0) && (p != self)) {
207 if (p->p_sigcatch & sigmask(SIGTERM))
208 TERM_catch++;
209 }
210 }
211 if (TERM_catch == 0)
212 break;
213 }
214
215 /*
216 * send a SIGKILL to all the procs still hanging around
217 */
218 for (p = allproc.lh_first; p; p = p->p_list.le_next) {
219 if (((p->p_flag&P_SYSTEM) == 0) && (p->p_pptr->p_pid != 0) && (p != self))
220 psignal(p, SIGKILL);
221 }
222 /*
223 * wait for up to 60 seconds to allow these procs to exit normally
224 */
225 for (i = 0; i < 300; i++) {
226 IOSleep(200); /* double the time from 100 to 200 for NFS requests in particular */
227
228 for (p = allproc.lh_first; p; p = p->p_list.le_next) {
229 if (((p->p_flag&P_SYSTEM) == 0) && (p->p_pptr->p_pid != 0) && (p != self))
230 break;
231 }
232 if (!p)
233 break;
234 }
235
236 /*
237 * if we still have procs that haven't exited, then brute force 'em
238 */
239 p = allproc.lh_first;
240 while (p) {
241 if ((p->p_flag&P_SYSTEM) || (p->p_pptr->p_pid == 0) || (p == self)) {
242 p = p->p_list.le_next;
243 }
244 else {
245 /*
246 * NOTE: following code ignores sig_lock and plays
247 * with exit_thread correctly. This is OK unless we
248 * are a multiprocessor, in which case I do not
249 * understand the sig_lock. This needs to be fixed.
250 * XXX
251 */
252 if (p->exit_thread) { /* someone already doing it */
253 thread_block(0);/* give him a chance */
254 }
255 else {
256 p->exit_thread = current_thread();
257 printf(".");
258 exit1(p, 1);
259 }
260 p = allproc.lh_first;
261 }
262 }
263 printf("\n");
264 /*
265 * Forcibly free resources of what's left.
266 */
267 p = allproc.lh_first;
268 while (p) {
269 /*
270 * Close open files and release open-file table.
271 * This may block!
272 */
273 #ifdef notyet
274 /* panics on reboot due to "zfree: non-allocated memory in collectable zone" message */
275 fdfree(p);
276 #endif /* notyet */
277 p = p->p_list.le_next;
278 }
279 /* Wait for the reaper thread to run, and clean up what we have done
280 * before we proceed with the hardcore shutdown. This reduces the race
281 * between kill_tasks and the reaper thread.
282 */
283 /* thread_wakeup(&reaper_queue); */
284 /* IOSleep( 1 * 1000); */
285 printf("continuing\n");
286 }
287