]>
git.saurik.com Git - apple/xnu.git/blob - bsd/kern/kern_shutdown.c
   2  * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. 
   4  * @APPLE_LICENSE_HEADER_START@ 
   6  * Copyright (c) 1999-2003 Apple Computer, Inc.  All Rights Reserved. 
   8  * This file contains Original Code and/or Modifications of Original Code 
   9  * as defined in and that are subject to the Apple Public Source License 
  10  * Version 2.0 (the 'License'). You may not use this file except in 
  11  * compliance with the License. Please obtain a copy of the License at 
  12  * http://www.opensource.apple.com/apsl/ and read it before using this 
  15  * The Original Code and all software distributed under the License are 
  16  * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER 
  17  * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, 
  18  * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, 
  19  * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. 
  20  * Please see the License for the specific language governing rights and 
  21  * limitations under the License. 
  23  * @APPLE_LICENSE_HEADER_END@ 
  26  *      File:   bsd/kern/kern_shutdown.c 
  28  *      Copyright (C) 1989, NeXT, Inc. 
  32 #include <sys/param.h> 
  33 #include <sys/systm.h> 
  34 #include <sys/kernel.h> 
  39 #include <sys/reboot.h> 
  41 #include <sys/vnode.h> 
  43 #include <sys/clist.h> 
  44 #include <sys/callout.h> 
  46 #include <sys/msgbuf.h> 
  47 #include <sys/ioctl.h> 
  48 #include <sys/signal.h> 
  50 #include <kern/task.h> 
  51 #include <sys/quota.h> 
  52 #include <ufs/ufs/inode.h> 
  54 #include <kern/processor.h> 
  55 #include <kern/thread.h> 
  57 #endif  /* NCPUS > 1 */ 
  58 #include <vm/vm_kern.h> 
  59 #include <mach/vm_param.h> 
  60 #include <sys/filedesc.h> 
  61 #include <mach/host_reboot.h> 
  66 boot(paniced
, howto
, command
) 
  72         struct proc 
*p 
= current_proc();        /* XXX */ 
  73         int hostboot_option
=0; 
  76         static void proc_shutdown(); 
  77     extern void md_prepare_for_shutdown(int paniced
, int howto
, char * command
); 
  79         funnel_state 
= thread_funnel_set(kernel_flock
, TRUE
); 
  81         md_prepare_for_shutdown(paniced
, howto
, command
); 
  83         if ((howto
&RB_NOSYNC
)==0 && waittime 
< 0) { 
  88                 printf("syncing disks... "); 
  91                  * Release vnodes held by texts before sync. 
  94                 /* handle live procs (deallocate their root and current directories). */                 
  97                 sync(p
, (void *)NULL
, (int *)NULL
); 
  99                 /* Release vnodes from the VM object cache */     
 105                  * Unmount filesystems 
 110                 /* Wait for the buffer cache to clean remaining dirty buffers */ 
 111                 for (iter 
= 0; iter 
< 20; iter
++) { 
 112                         nbusy 
= count_busy_buffers(); 
 115                         printf("%d ", nbusy
); 
 116                         IOSleep( 4 * nbusy 
); 
 119                         printf("giving up\n"); 
 125          * Can't just use an splnet() here to disable the network 
 126          * because that will lock out softints which the disk 
 127          * drivers depend on to finish DMAs. 
 131         if (howto 
& RB_POWERDOWN
) 
 132                 hostboot_option 
= HOST_REBOOT_HALT
; 
 134                 hostboot_option 
= HOST_REBOOT_HALT
; 
 135         if (paniced 
== RB_PANIC
) 
 136                 hostboot_option 
= HOST_REBOOT_HALT
; 
 138         if (hostboot_option 
== HOST_REBOOT_HALT
) 
 141         host_reboot(host_priv_self(), hostboot_option
); 
 143         thread_funnel_set(kernel_flock
, FALSE
); 
 149  *      Shutdown down proc system (release references to current and root 
 150  *      dirs for each process). 
 152  * POSIX modifications: 
 154  *      For POSIX fcntl() file locking call vno_lockrelease() on  
 155  *      the file to release all of its record locks, if any. 
 161         struct proc     
*p
, *self
; 
 162         struct vnode    
**cdirp
, **rdirp
, *vp
; 
 163         int             restart
, i
, TERM_catch
; 
 166          *      Kill as many procs as we can.  (Except ourself...) 
 168         self 
= (struct proc 
*)current_proc(); 
 175                 task_suspend(p
->task
);          /* stop init */ 
 177         printf("Killing all processes "); 
 180          * send SIGTERM to those procs interested in catching one 
 182         for (p 
= allproc
.lh_first
; p
; p 
= p
->p_list
.le_next
) { 
 183                 if (((p
->p_flag
&P_SYSTEM
) == 0) && (p
->p_pptr
->p_pid 
!= 0) && (p 
!= self
)) { 
 184                         if (p
->p_sigcatch 
& sigmask(SIGTERM
)) 
 189          * now wait for up to 30 seconds to allow those procs catching SIGTERM 
 191          * as soon as these procs have exited, we'll continue on to the next step 
 193         for (i 
= 0; i 
< 300; i
++) { 
 195                  * sleep for a tenth of a second 
 196                  * and then check to see if the tasks that were sent a 
 197                  * SIGTERM have exited 
 202                 for (p 
= allproc
.lh_first
; p
; p 
= p
->p_list
.le_next
) { 
 203                         if (((p
->p_flag
&P_SYSTEM
) == 0) && (p
->p_pptr
->p_pid 
!= 0) && (p 
!= self
)) { 
 204                                 if (p
->p_sigcatch 
& sigmask(SIGTERM
)) 
 213          * send a SIGKILL to all the procs still hanging around 
 215         for (p 
= allproc
.lh_first
; p
; p 
= p
->p_list
.le_next
) { 
 216                 if (((p
->p_flag
&P_SYSTEM
) == 0) && (p
->p_pptr
->p_pid 
!= 0) && (p 
!= self
)) 
 220          * wait for up to 60 seconds to allow these procs to exit normally 
 222         for (i 
= 0; i 
< 300; i
++) { 
 223                 IOSleep(200);  /* double the time from 100 to 200 for NFS requests in particular */ 
 225                 for (p 
= allproc
.lh_first
; p
; p 
= p
->p_list
.le_next
) { 
 226                         if (((p
->p_flag
&P_SYSTEM
) == 0) && (p
->p_pptr
->p_pid 
!= 0) && (p 
!= self
)) 
 234          * if we still have procs that haven't exited, then brute force 'em 
 236         p 
= allproc
.lh_first
; 
 238                 if ((p
->p_flag
&P_SYSTEM
) || (p
->p_pptr
->p_pid 
== 0) || (p 
== self
)) { 
 239                         p 
= p
->p_list
.le_next
; 
 243                          * NOTE: following code ignores sig_lock and plays 
 244                          * with exit_thread correctly.  This is OK unless we 
 245                          * are a multiprocessor, in which case I do not 
 246                          * understand the sig_lock.  This needs to be fixed. 
 249                         if (p
->exit_thread
) {   /* someone already doing it */ 
 250                                                 /* give him a chance */ 
 251                                 thread_block(THREAD_CONTINUE_NULL
); 
 254                                 p
->exit_thread 
= current_thread(); 
 256                                 exit1(p
, 1, (int *)NULL
); 
 258                         p 
= allproc
.lh_first
; 
 263          *      Forcibly free resources of what's left. 
 265         p 
= allproc
.lh_first
; 
 268          * Close open files and release open-file table. 
 272         /* panics on reboot due to "zfree: non-allocated memory in collectable zone" message */ 
 275         p 
= p
->p_list
.le_next
; 
 277         /* Wait for the reaper thread to run, and clean up what we have done  
 278          * before we proceed with the hardcore shutdown. This reduces the race 
 279          * between kill_tasks and the reaper thread. 
 281         /* thread_wakeup(&reaper_queue); */ 
 282         /*      IOSleep( 1 * 1000);      */ 
 283         printf("continuing\n");