Annotation of XNU/bsd/kern/kern_shutdown.c, revision 1.1.1.1

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: }

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.