|
|
1.1 root 1: /*
2: * Copyright (c) 1999 Apple Computer, Inc. All rights reserved.
3: *
4: * @APPLE_LICENSE_HEADER_START@
5: *
6: * Portions Copyright (c) 1999 Apple Computer, Inc. All Rights
7: * Reserved. This file contains Original Code and/or Modifications of
8: * Original Code as defined in and that are subject to the Apple Public
9: * Source License Version 1.1 (the "License"). You may not use this file
10: * except in compliance with the License. Please obtain a copy of the
11: * License at http://www.apple.com/publicsource and read it before using
12: * this file.
13: *
14: * The Original Code and all software distributed under the License are
15: * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
16: * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
17: * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
18: * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
19: * License for the specific language governing rights and limitations
20: * under the License.
21: *
22: * @APPLE_LICENSE_HEADER_END@
23: */
24:
25: /*
26: * File: bsd/kern/kern_shutdown.c
27: *
28: * Copyright (C) 1989, NeXT, Inc.
29: *
30: * History:
31: * Jan 29, 1992 [email protected]
32: * Created by munging machdep/m68k/shutdown.c and
33: * machdep/m68k/machdep.c into machine-independence.
34: *
35: */
36:
37: #import <cpus.h>
38: #import <quota.h>
39: #import <mach_nbc.h>
40:
41: #import <sys/param.h>
42: #import <sys/systm.h>
43: #import <sys/kernel.h>
44: // #import <sys/dnlc.h>
45: #import <sys/vm.h>
46: #import <sys/proc.h>
47: #import <sys/user.h>
48: #import <sys/buf.h>
49: #import <sys/reboot.h>
50: #import <sys/conf.h>
51: #import <sys/vnode.h>
52: #import <sys/file.h>
53: #import <sys/clist.h>
54: #import <sys/callout.h>
55: #import <sys/mbuf.h>
56: #import <sys/msgbuf.h>
57: #import <sys/ioctl.h>
58: #import <sys/signal.h>
59: #import <sys/tty.h>
60: #import <kern/task.h>
61: #import <ufs/ufs/quota.h>
62: #import <ufs/ufs/inode.h>
63: #if NCPUS > 1
64: #import <kern/processor.h>
65: #import <kern/thread.h>
66: #import <kern/lock.h>
67: #endif /* NCPUS > 1 */
68: #import <kern/xpr.h>
69: #import <vm/vm_kern.h>
70: #import <mach/vm_param.h>
71: #import <vm/vm_page.h>
72: #import <kernserv/ns_timer.h>
73: #import <bsd/sys/filedesc.h>
74:
75: int waittime = -1;
76:
77: boot(paniced, howto, command)
78: int paniced, howto;
79: char *command;
80: {
81: register int i;
82: int s;
83: struct proc *p = current_proc(); /* XXX */
84:
85: md_prepare_for_shutdown(paniced, howto, command);
86:
87: if ((howto&RB_NOSYNC)==0 && waittime < 0) {
88: register struct buf *bp;
89: int iter, nbusy;
90:
91: waittime = 0;
92:
93: (void) spl0();
94:
95: printf("syncing disks... ");
96:
97: /*
98: * Release vnodes held by texts before sync.
99: */
100:
101: proc_shutdown(); /* handle live procs (deallocate their
102: root and current directories). */
103: kill_tasks(); /* get rid of all task memory */
104:
105: #if MACH_NBC
106: mapfs_cache_clear();
107: vm_object_cache_clear();
108: #endif /* MACH_NBC */
109: if (panicstr == 0)
110: vnode_pager_shutdown(); /* NO MORE PAGING - release vnodes */
111:
112: sync(p, (void *)NULL, (int *)NULL);
113:
114: /*
115: * Unmount filesystems
116: */
117: if (panicstr == 0)
118: vfs_unmountall();
119:
120: for (iter = 0; iter < 20; iter++) {
121: nbusy = 0;
122: for (bp = &buf[nbuf]; --bp >= buf; )
123: if ((bp->b_flags & (B_BUSY|B_INVAL)) == B_BUSY)
124: nbusy++;
125: if (nbusy == 0)
126: break;
127: printf("%d ", nbusy);
128: DELAY(40000 * iter);
129: }
130: if (nbusy)
131: printf("giving up\n");
132: else
133: printf("done\n");
134:
135: /*
136: * If we've been adjusting the clock, the todr
137: * will be out of synch; adjust it now.
138: */
139: // resettodr();
140: }
141:
142: /*
143: * Can't just use an splnet() here to disable the network
144: * because that will lock out softints which the disk
145: * drivers depend on to finish DMAs.
146: */
147: if_down_all();
148:
149: md_shutdown_devices(paniced, howto, command);
150:
151: #if NCPUS > 1
152: #define LOOPCOUNT 1000
153: #define WAITCOUNT 1000
154:
155: for (i = 0; i < NCPUS; i++) {
156: processor_t thisprocessor;
157:
158: thisprocessor = cpu_to_processor(i);
159: if (thisprocessor->state != PROCESSOR_OFF_LINE &&
160: thisprocessor != current_processor()) {
161: register int j,k;
162:
163: processor_shutdown(thisprocessor);
164:
165: j = 0;
166: while ( machine_slot[i].running && j < LOOPCOUNT) {
167: for (k=0; k< WAITCOUNT; k++) DELAY(1);
168: j++;
169: }
170:
171: if (!machine_slot[i].running)
172: printf("Processor %d Halted.\n", i);
173: else
174: printf("Processor %d won't halt.\n", i);
175: }
176: }
177: #endif /* NCPUS > 1 */
178:
179: md_do_shutdown(paniced, howto, command);
180: }
181:
182: kill_tasks()
183: {
184: processor_set_t pset;
185: task_t task;
186: vm_map_t map, empty_map;
187:
188: empty_map = vm_map_create(pmap_create(0), 0, 0, TRUE);
189:
190: /*
191: * Destroy all but the default processor_set.
192: */
193: simple_lock(&all_psets_lock);
194: pset = (processor_set_t) queue_first(&all_psets);
195: while (!queue_end(&all_psets, (queue_entry_t) pset)) {
196: if (pset == &default_pset) {
197: pset = (processor_set_t) queue_next(&pset->all_psets);
198: continue;
199: }
200: simple_unlock(&all_psets_lock);
201: processor_set_destroy(pset);
202: simple_lock(&all_psets_lock);
203: pset = (processor_set_t) queue_first(&all_psets);
204: }
205: simple_unlock(&all_psets_lock);
206:
207: /*
208: * Kill all the tasks in the default processor set.
209: */
210: pset = &default_pset;
211: pset_lock(pset);
212: task = (task_t) queue_first(&pset->tasks);
213: while (pset->task_count) {
214: pset_remove_task(pset, task);
215: map = task->map;
216: if ((map != kernel_map) && (map != empty_map)) {
217: task->map = empty_map;
218: vm_map_reference(empty_map);
219: pset_unlock(pset);
220: vm_map_remove(map, vm_map_min(map), vm_map_max(map));
221: pset_lock(pset);
222: }
223: task = (task_t) queue_first(&pset->tasks);
224: }
225: pset_unlock(pset);
226: }
227:
228: #if NeXT
229: extern int reaper_queue;
230: #endif
231: /*
232: * proc_shutdown()
233: *
234: * Shutdown down proc system (release references to current and root
235: * dirs for each process).
236: *
237: * POSIX modifications:
238: *
239: * For POSIX fcntl() file locking call vno_lockrelease() on
240: * the file to release all of its record locks, if any.
241: */
242:
243: proc_shutdown()
244: {
245: struct proc *p, *self;
246: struct vnode **cdirp, **rdirp, *vp;
247: int restart, i;
248:
249: /*
250: * Kill as many procs as we can. (Except ourself...)
251: */
252: self = current_task()->proc;
253:
254: /*
255: * Suspend /etc/init
256: */
257: p = pfind(1);
258: if (p && p != self)
259: task_suspend(p->task); /* stop init */
260:
261: /*
262: * Suspend mach_init
263: */
264: p = pfind(2);
265: if (p && p != self)
266: task_suspend(p->task); /* stop mach_init */
267:
268: printf("Killing all processes ");
269: /* SIGTERM and ns_sleep to allow process to clean-up */
270: for (p = allproc.lh_first; p; p = p->p_list.le_next) {
271: if (((p->p_flag&P_SYSTEM) == 0) && (p->p_pptr->p_pid != 0) && (p != self))
272: psignal(p, SIGTERM);
273: }
274: ns_sleep(2 * 1000000000);
275: ns_sleep(2 * 1000000000);
276: /* SIGKILL in case the TERM wasn't heard */
277: for (p = allproc.lh_first; p; p = p->p_list.le_next) {
278: if (((p->p_flag&P_SYSTEM) == 0) && (p->p_pptr->p_pid != 0) && (p != self))
279: psignal(p, SIGKILL);
280: }
281: ns_sleep(1000000000);
282: /* Brute force 'em, if necessary */
283: p = allproc.lh_first;
284: while (p) {
285: if ((p->p_flag&P_SYSTEM) || (p->p_pptr->p_pid == 0) || (p == self)) {
286: p = p->p_list.le_next;
287: }
288: else {
289: /*
290: * NOTE: following code ignores sig_lock and plays
291: * with exit_thread correctly. This is OK unless we
292: * are a multiprocessor, in which case I do not
293: * understand the sig_lock. This needs to be fixed.
294: * XXX
295: */
296: if (p->exit_thread) { /* someone already doing it */
297: thread_block(); /* give him a chance */
298: }
299: else {
300: p->exit_thread = current_thread();
301: printf(".");
302: exit1(p, 1);
303: }
304: p = allproc.lh_first;
305: }
306: }
307: printf("\n");
308: /*
309: * Forcibly free resources of what's left.
310: */
311: p = allproc.lh_first;
312: while (p) {
313: /*
314: * Close open files and release open-file table.
315: * This may block!
316: */
317: fdfree(p);
318: p = p->p_list.le_next;
319: }
320: /* Wait for the reaper thread to run, and clean up what we have done
321: * before we proceed with the hardcore shutdown. This reduces the race
322: * between kill_tasks and the reaper thread.
323: */
324: thread_wakeup(&reaper_queue);
325: ns_sleep(2 * 1000000000);
326: printf("continuing\n");
327:
328: }
329:
330: /*
331: * Close all file descriptors, called at shutdown time.
332: */
333: fd_shutdown()
334: {
335: register struct file *fp, *nextfp;
336:
337: for (fp = filehead.lh_first; fp != 0; fp = nextfp) {
338: nextfp = fp->f_list.le_next;
339: while (fp->f_count > 1)
340: closef(fp);
341: closef(fp);
342: }
343: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.