|
|
1.1 root 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: * History:
28: * Jan 29, 1992 [email protected]
29: * Created by munging machdep/m68k/shutdown.c and
30: * machdep/m68k/machdep.c into machine-independence.
31: *
32: */
33:
34: #import <mach_nbc.h>
35:
36: #import <sys/param.h>
37: #import <sys/systm.h>
38: #import <sys/kernel.h>
39: #import <sys/vm.h>
40: #import <sys/proc.h>
41: #import <sys/user.h>
42: #import <sys/buf.h>
43: #import <sys/reboot.h>
44: #import <sys/conf.h>
45: #import <sys/vnode.h>
46: #import <sys/file.h>
47: #import <sys/clist.h>
48: #import <sys/callout.h>
49: #import <sys/mbuf.h>
50: #import <sys/msgbuf.h>
51: #import <sys/ioctl.h>
52: #import <sys/signal.h>
53: #import <sys/tty.h>
54: #import <kern/task.h>
55: #import <ufs/ufs/quota.h>
56: #import <ufs/ufs/inode.h>
57: #if NCPUS > 1
58: #import <kern/processor.h>
59: #import <kern/thread.h>
60: #import <sys/lock.h>
61: #endif /* NCPUS > 1 */
62: #import <vm/vm_kern.h>
63: #import <mach/vm_param.h>
64: #import <sys/filedesc.h>
65: #import <mach/host_reboot.h>
66:
67: int waittime = -1;
68:
69: boot(paniced, howto, command)
70: int paniced, howto;
71: char *command;
72: {
73: register int i;
74: int s;
75: struct proc *p = current_proc(); /* XXX */
76: int hostboot_option=0;
77: /* md_prepare_for_shutdown(paniced, howto, command); */
78:
79: if ((howto&RB_NOSYNC)==0 && waittime < 0) {
80: register struct buf *bp;
81: int iter, nbusy;
82:
83: waittime = 0;
84:
85: (void) spl0();
86:
87: printf("syncing disks... ");
88:
89: /*
90: * Release vnodes held by texts before sync.
91: */
92:
93: proc_shutdown(); /* handle live procs (deallocate their
94: root and current directories). */
95: #if 0 /* [ */
96: /* NOT MY PROBLEM XXX */
97: kill_tasks(); /* get rid of all task memory */
98: #endif /* 0 ] */
99:
100: #if MACH_NBC
101: mapfs_cache_clear();
102: vm_object_cache_clear();
103: #endif /* MACH_NBC */
104: if (panicstr == 0)
105: vnode_pager_shutdown(); /* NO MORE PAGING - release vnodes */
106:
107: sync(p, (void *)NULL, (int *)NULL);
108:
109: /*
110: * Unmount filesystems
111: */
112: if (panicstr == 0)
113: vfs_unmountall();
114:
115: for (iter = 0; iter < 20; iter++) {
116: nbusy = 0;
117: for (bp = &buf[nbuf]; --bp >= buf; )
118: if ((bp->b_flags & (B_BUSY|B_INVAL)) == B_BUSY)
119: nbusy++;
120: if (nbusy == 0)
121: break;
122: printf("%d ", nbusy);
123: IOSleep( 4 * nbusy );
124: }
125: if (nbusy)
126: printf("giving up\n");
127: else
128: printf("done\n");
129:
130: /*
131: * If we've been adjusting the clock, the todr
132: * will be out of synch; adjust it now.
133: */
134: }
135:
136: /*
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.
140: */
141: if_down_all();
142: #define BSD_DUMMY_HOST 1
143: if (howto & RB_POWERDOWN)
144: hostboot_option = HOST_REBOOT_HALT;
145: if (howto & RB_HALT)
146: hostboot_option = HOST_REBOOT_HALT;
147: if (paniced == RB_PANIC)
148: hostboot_option = HOST_REBOOT_HALT;
149:
150: if (hostboot_option == HOST_REBOOT_HALT)
151: IOSleep( 1 * 1000 );
152:
153: host_reboot(BSD_DUMMY_HOST, hostboot_option);
154: }
155:
156: #if 0 /* [ */
157: kill_tasks()
158: {
159: processor_set_t pset;
160: task_t task;
161: vm_map_t map, empty_map;
162:
163: empty_map = vm_map_create(pmap_create(0), 0, 0, TRUE);
164:
165: /*
166: * Destroy all but the default processor_set.
167: */
168: simple_lock(&all_psets_lock);
169: pset = (processor_set_t) queue_first(&all_psets);
170: while (!queue_end(&all_psets, (queue_entry_t) pset)) {
171: if (pset == &default_pset) {
172: pset = (processor_set_t) queue_next(&pset->all_psets);
173: continue;
174: }
175: simple_unlock(&all_psets_lock);
176: processor_set_destroy(pset);
177: simple_lock(&all_psets_lock);
178: pset = (processor_set_t) queue_first(&all_psets);
179: }
180: simple_unlock(&all_psets_lock);
181:
182: /*
183: * Kill all the tasks in the default processor set.
184: */
185: pset = &default_pset;
186: pset_lock(pset);
187: task = (task_t) queue_first(&pset->tasks);
188: while (pset->task_count) {
189: pset_remove_task(pset, task);
190: map = task->map;
191: if ((map != kernel_map) && (map != empty_map)) {
192: task->map = empty_map;
193: vm_map_reference(empty_map);
194: pset_unlock(pset);
195: vm_map_remove(map, vm_map_min(map), vm_map_max(map));
196: pset_lock(pset);
197: }
198: task = (task_t) queue_first(&pset->tasks);
199: }
200: pset_unlock(pset);
201: }
202: #endif /* 0 ] */
203:
204: #if NeXT
205: extern int reaper_queue;
206: #endif
207: /*
208: * proc_shutdown()
209: *
210: * Shutdown down proc system (release references to current and root
211: * dirs for each process).
212: *
213: * POSIX modifications:
214: *
215: * For POSIX fcntl() file locking call vno_lockrelease() on
216: * the file to release all of its record locks, if any.
217: */
218:
219: proc_shutdown()
220: {
221: struct proc *p, *self;
222: struct vnode **cdirp, **rdirp, *vp;
223: int restart, i, TERM_catch;
224:
225: /*
226: * Kill as many procs as we can. (Except ourself...)
227: */
228: self = (struct proc *)(get_bsdtask_info(current_task()));
229:
230: /*
231: * Suspend /etc/init
232: */
233: p = pfind(1);
234: if (p && p != self)
235: task_suspend(p->task); /* stop init */
236:
237: /*
238: * Suspend mach_init
239: */
240: p = pfind(2);
241: if (p && p != self)
242: task_suspend(p->task); /* stop mach_init */
243:
244: printf("Killing all processes ");
245:
246: /*
247: * send SIGTERM to those procs interested in catching one
248: */
249: for (p = allproc.lh_first; p; p = p->p_list.le_next) {
250: if (((p->p_flag&P_SYSTEM) == 0) && (p->p_pptr->p_pid != 0) && (p != self)) {
251: if (p->p_sigcatch & sigmask(SIGTERM))
252: psignal(p, SIGTERM);
253: }
254: }
255: /*
256: * now wait for up to 5 seconds to allow those procs catching SIGTERM
257: * to digest it
258: * as soon as these procs have exited, we'll continue on to the next step
259: */
260: for (i = 0; i < 50; i++) {
261: /*
262: * sleep for a tenth of a second
263: * and then check to see if the tasks that were sent a
264: * SIGTERM have exited
265: */
266: IOSleep(100);
267: TERM_catch = 0;
268:
269: for (p = allproc.lh_first; p; p = p->p_list.le_next) {
270: if (((p->p_flag&P_SYSTEM) == 0) && (p->p_pptr->p_pid != 0) && (p != self)) {
271: if (p->p_sigcatch & sigmask(SIGTERM))
272: TERM_catch++;
273: }
274: }
275: if (TERM_catch == 0)
276: break;
277: }
278:
279: /*
280: * send a SIGKILL to all the procs still hanging around
281: */
282: for (p = allproc.lh_first; p; p = p->p_list.le_next) {
283: if (((p->p_flag&P_SYSTEM) == 0) && (p->p_pptr->p_pid != 0) && (p != self))
284: psignal(p, SIGKILL);
285: }
286: /*
287: * wait for up to 2 seconds to allow these procs to exit normally
288: */
289: for (i = 0; i < 20; i++) {
290: IOSleep(100);
291:
292: for (p = allproc.lh_first; p; p = p->p_list.le_next) {
293: if (((p->p_flag&P_SYSTEM) == 0) && (p->p_pptr->p_pid != 0) && (p != self))
294: break;
295: }
296: if (!p)
297: break;
298: }
299:
300: /*
301: * if we still have procs that haven't exited, then brute force 'em
302: */
303: p = allproc.lh_first;
304: while (p) {
305: if ((p->p_flag&P_SYSTEM) || (p->p_pptr->p_pid == 0) || (p == self)) {
306: p = p->p_list.le_next;
307: }
308: else {
309: /*
310: * NOTE: following code ignores sig_lock and plays
311: * with exit_thread correctly. This is OK unless we
312: * are a multiprocessor, in which case I do not
313: * understand the sig_lock. This needs to be fixed.
314: * XXX
315: */
316: if (p->exit_thread) { /* someone already doing it */
317: thread_block(0);/* give him a chance */
318: }
319: else {
320: p->exit_thread = current_thread();
321: printf(".");
322: exit1(p, 1);
323: }
324: p = allproc.lh_first;
325: }
326: }
327: printf("\n");
328: /*
329: * Forcibly free resources of what's left.
330: */
331: p = allproc.lh_first;
332: while (p) {
333: /*
334: * Close open files and release open-file table.
335: * This may block!
336: */
337: #ifdef notyet
338: /* panics on reboot due to "zfree: non-allocated memory in collectable zone" message */
339: fdfree(p);
340: #endif /* notyet */
341: p = p->p_list.le_next;
342: }
343: /* Wait for the reaper thread to run, and clean up what we have done
344: * before we proceed with the hardcore shutdown. This reduces the race
345: * between kill_tasks and the reaper thread.
346: */
347: /* thread_wakeup(&reaper_queue); */
348: /* IOSleep( 1 * 1000); */
349: printf("continuing\n");
350: }
351:
352: /*
353: * Close all file descriptors, called at shutdown time.
354: */
355: fd_shutdown()
356: {
357: register struct file *fp, *nextfp;
358:
359: for (fp = filehead.lh_first; fp != 0; fp = nextfp) {
360: nextfp = fp->f_list.le_next;
361: while (fp->f_count > 1)
362: closef(fp);
363: closef(fp);
364: }
365: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.