Annotation of XNU/bsd/kern/kern_shutdown.c, revision 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.