linux关机过程流程

在正常情况下halt或者reboot会调用shutdown,shutdown又会调用init来关闭电脑或者重新启动,所谓的正常情况是run level不等于0或者6的时候。

/sbin/poweroff 相当于halt -p

当执行shutdown -h now时,调用init 0--》init.d/halt---->/sbin/halt

# the content of /etc/rc.d/init.d/halt
# halt          This file is executed by init when it goes into runlevel

#               0 (halt) or runlevel 6 (reboot). It kills all processes,
#               unmounts file systems and then either halts or reboots.

poweroff将会使halt调用reboot(BMAGIC_POWEROFF)函数,定义于<sys/reboot.h>

下面是man手册的节选内容:
DESCRIPTION of shutdown
       shutdown brings the system down in a secure way. All logged-in users are notified that the system is going down, and login(1) is
blocked. It is possible to shut the system down immediately or after a specified delay. All processes are first notified that the
       system is going down by the signal SIGTERM. This gives programs like vi(1) the time to save the file being edited, mail and news pro-
       cessing programs a chance to exit cleanly, etc. shutdown does its job by signalling the init process, asking it to change the run-
       level. Runlevel 0 is used to halt the system, runlevel 6 is used to reboot the system, and runlevel 1 is used to put to system into a
       state where administrative tasks can be performed; this is the default if neither the -h or -r flag is given to shutdown.   To see
       which actions are taken on halt or reboot see the appropriate entries for these runlevels in the file /etc/inittab.

Init can only capture CTRL-ALT-DEL and start shutdown in console mode. If the system is running the X window System, the X server
       processes all key strokes. Some X11 environments make it possible to capture CTRL-ALT-DEL, but what exactly is done with that event
       depends on that environment.

       Shutdown wasn’t designed to be run setuid. /etc/shutdown.allow is not used to find out who is executing shutdown, it ONLY checks who
       is currently logged in on (one of the) console(s).

DESCRIPTION of halt and reboot
       Halt notes that the system is being brought down in the file /var/log/wtmp, and then either tells the kernel to halt, reboot or
       poweroff the system.

       If halt or reboot is called when the system is not in runlevel 0 or 6, in other words when it’s running normally, shutdown will be
       invoked instead (with the -h or -r flag). For more info see the shutdown(8) manpage.

Under older sysvinit releases , reboot and halt should never be called directly. From release 2.74 on halt and reboot invoke shut-
       down(8) if the system is not in runlevel 0 or 6. This means that if halt or reboot cannot find out the current runlevel (for example,
       when /var/run/utmp hasn’t been initialized correctly) shutdown will be called, which might not be what you want. Use the -f flag if
       you want to do a hard halt or reboot.
============================================================

Linux关机命令详解

在linux下一些常用的关机/重启命令有shutdown、halt、reboot、及init,它们都可以达到重启系统的目的,但每个命令的内部工作过程是不同的。

   1.shutdown

shutdown命令安全地将系统关机。 有些用户会使用直接断掉电源的方式来关闭linux,这是十分危险的。因为linux与windows不同,其后台运行着许多进程,所以强制关机可能会导 致进程的数据丢失﹐使系统处于不稳定的状态﹐甚至在有的系统中会损坏硬件设备。

而在系统关机前使用shutdown命令﹐系统管理员会通知所有登录的用户系统将要关闭。并且login指令会被冻结﹐即新的用户不能再登录。直接 关机或者延迟一定的时间才关机都是可能的﹐还可能重启。这是由所有进程〔process〕都会收到系统所送达的信号〔signal〕决定的。这让像vi之 类的程序有时间储存目前正在编辑的文档﹐而像处理邮件〔mail〕和新闻〔news〕的程序则可以正常地离开等等。

shutdown执行它的工作是送信号〔signal〕给init程序﹐要求它改变runlevel。Runlevel 0被用来停机〔halt〕﹐runlevel 6是用来重新激活〔reboot〕系统﹐而runlevel 1则是被用来让系统进入管理工作可以进行的状态﹔这是预设的﹐假定没有-h也没有-r参数给shutdown。要想了解在停机〔halt〕或者重新开机 〔reboot〕过程中做了哪些动作﹐你可以在这个文件/etc/inittab里看到这些runlevels相关的资料。

   shutdown 参数说明:
[-t] 在改变到其它runlevel之前﹐告诉init多久以后关机。
[-r] 重启计算器。
[-k] 并不真正关机﹐只是送警告信号给每位登录者〔login〕。
[-h] 关机后关闭电源〔halt〕。
[-n] 不用init﹐而是自己来关机。不鼓励使用这个选项﹐而且该选项所产生的后果往往不总是你所预期得到的。
[-c] cancel current process取消目前正在执行的关机程序。所以这个选项当然没有时间参数﹐但是可以输入一个用来解释的讯息﹐而这信息将会送到每位使用者。
[-f] 在重启计算器〔reboot〕时忽略fsck。
[-F] 在重启计算器〔reboot〕时强迫fsck。
[-time] 设定关机〔shutdown〕前的时间。

2.halt----最简单的关机命令
其实halt就是调用shutdown -h。halt执行时﹐杀死应用进程﹐执行sync系统调用﹐文件系统写操作完成后就会停止内核。
参数说明:
[-n] 防止sync系统调用﹐它用在用fsck修补根分区之后﹐以阻止内核用老版本的超级块〔superblock〕覆盖修补过的超级块。
[-w] 并不是真正的重启或关机﹐只是写wtmp〔/var/log/wtmp〕纪录。
[-d] 不写wtmp纪录〔已包含在选项[-n]中〕。
[-f] 没有调用shutdown而强制关机或重启。
[-i] 关机〔或重启〕前﹐关掉所有的网络接口。
[-p] 该选项为缺省选项。就是关机时调用poweroff。

3.reboot
reboot的工作过程差不多跟halt一样﹐不过它是引发主机重启﹐而halt是关机。它的参数与halt相差不多。

4.init
init是所有进程的祖先﹐它的进程号始终为1﹐所以发送TERM信号给init会终止所有的用户进程﹑守护进程等。shutdown 就是使用这种机制。init定义了7个运行级别(runlevel),init 0为关机﹐init 1为重启。关于init可以长篇大论﹐这里就不再叙述。另外还有telinit命令可以改变init的运行级别﹐比如﹐telinit -iS可使系统进入单用户模式﹐并且得不到使用shutdown时的信息和等待时间。

===========================================================

Linux 关机重启流程分析

developerWorks
<tr valign="top"><td width="8"><img alt="" height="1" width="8" src="//www.ibm.com/i/c.gif"/></td><td width="16"><img alt="" width="16" height="16" src="//www.ibm.com/i/c.gif"/></td><td class="small" width="122"><p><span class="ast">未显示需要 JavaScript 的文档选项</span></p></td></tr>

范晓炬 (xiaoju_f@263.net), 联想(北京)有限公司软件设计中心嵌入式研发处开发工程师, 联想(北京)有限公司软件设计中心

2003 年 8 月 11 日

linux下的关机和重启流程对于一般的桌面应用和网络服务器来说并不重要,但是在用户自己定义的嵌入式系统内核中就有一定的研究意义,通过了解Linux 关机重启的流程,我们对它可以修改和自定义,甚至以此为基础开发出全新的功能来。

1.概述

在linux下的关机和重启可能由两种行为引发,一是通过用户编程,一是系统自己产生的消息。用户和系统进行交互的方式也有两个,一个是系统调用:sys_reboot,另一个就是apm或则acpi的设备文件,通过对其操作也可以使系统关机或者重启。




回页首


2.通过系统调用sys_reboot的重启

这个系统调用定义了一系列的MAGIC_NUMBER,在调用的开始部分首先检查MAGIC_NUMBER是否正确,只有正确才继续向下运行。在重启的时候转向分支

case LINUX_REBOOT_CMD_RESTART:

首先使用notifier_call_chain向其它部分发出重启的消息,然后调用machine_restart函数完成重启。

machine_restart 函数的开始部分有一段SMP相关的代码,主要完成多CPU时由一个CPU完成重启操作,其它CPU处于等待状态。之后系统根据一个变量 reboot_thru_bios的内容判断重启方式,通过阅读reboot_setup我们可以得知,这个参数的内容是在系统启动时指定的,决定了是否 利用bios,事实上是系统复位后的入口(FFFF:0000)地址的程序进行重启。在不通过bios进行重启的情况下,系统首先设定了重启标志,然后向 端口0xfe写入数字0x64,这种重启的具体原理我还不大清楚,似乎是模拟了一次reset键的按下,希望大家和我讨论。在通过bios重启的情况下, 系统同样先设定了重启模式,然后切换到了实模式,通过一条ljmp $0xffff,$0x0完成了重启。




回页首


3.通过系统调用sys_reboot进行关机

在系统调用的处理分支上,我们可以看到,首先同样是检查MAGIC_NUMBER,然后在

case LINUX_REBOOT_CMD_POWER_OFF:

的执行流程里面,又是使用 notifier_call_chain发出了关闭计算机电源的消息,紧接着执行了machine_power_off函数。我们在 machine_power_off函数中可以看到,如果pm_power_off这个函数指针不为空,那么系统就会通过调用这个函数进行关机。在apm 已经加载的情况下(SMP除外),实际上pm_power_off函数实际上指向了apm.c中的apm_power_off,在这个函数里系统通过 apm_info结构里的值,使用切换到实模式关机,或者使用apm_bios_call_simple函数调用保护模式下的apm接口关机两种方法。




回页首


4.apm驱动本身的关机过程

apm使用其注册的设备的ioctl接口完成apm的操作,在apm.c的do_ioctl函数中可以看见处理的分支。这里只有suspend和standby的代码,所以我们不能通过ioctl这种方法使用apm关机。

当 用户按下POWER开关的时候,如果有apm模块,那么关机流程是由apm来处理的。apm驱动在初始化的时候启动了一个apm内核线程: apm_mainloop,系统会在这里检测到POWEROFF按键消息并且将其命名为APM_SYS_SUSPEND,以区别apm -s设置的APM_USER_SUSPEND模式。紧接着进入了apm_event_handler函数,又从apm_event_handler函数进 入了check_events函数,处理函数对应的case分支上。系统同样使用了suspend函数进行关机,不过由于其它参数的原因,suspend 最后调用的是关机的流程。




回页首


5.解决问题实例

1)按POWER键时某些主板死机

经 查只有某些特定的驱动装载之后才会出现这样的情况,并且当使用关机系统调用sys_reboot的时候没有这样的问题。分析apm的处理流程,怀疑是在关 机前驱动程序没有正确处理apm发出的询问消息造成的。由于部分驱动程序没有源代码,决定hack掉apm.c的关机部分,让两种方式的关机走同样的流 程。于是把apm.c的check_events函数中对APM_SYS_SUSPEND部分改写为如下代码:

ret = exec_usermodehelper(poweroff_helper_path, argv, envp);
 if (ret) {
  printk(KERN_ERR
   "apm.c: failed to exec %s , errno = %d\\n",
   poweroff_helper_path, errno);
 }
 break;

定义了一个用户态应用程序poweroff_helper_path,当POWEROFF键按下的时候系统运行这个kernel_helper程序。我们再写一个通过sys_reboot系统调用关机的程序,放在指定的位置下。死机的问题就解决了。

2)快速返回实模式重启

主要可以参考了process.c中的返回实模式的代码,比如我把real_mode_switch换成如下代码:

// For fast reboot support
static unsigned char fast_reboot_switch [] =
{
 0x66, 0x0f, 0x20, 0xc0,                 /*    movl  %cr0,%eax        */ 
 0x66, 0x25, 0x10, 0x11, 0x11, 0x11, /*    andl  $0x11111110,%eax */
 0x66, 0x0f, 0x22, 0xc0,                 /*    movl  %eax,%cr0        */
 0xea, 0x00, 0x00, 0x00, 0x70  /*    ljmp  $0x7000,$0x0000  */
};

系统就可以切换到实模式中,然后跳转到7000H:0位置开始执行。




回页首


6.ACPI概述

在2.4.20 内核中ACPI模块被注明为试验和未完成,里面有一部分功能也许没有实现。如果APM和APCI两个模块同时编译进内核,APM在ACPI前被加载, APM起作用使ACPI退出。对于系统电量、电源实践一类的支持(主要是在笔记本上有用),靠的是acpid这个daemon程序。

没有一个功能类似apm的应用程序切换状态,acpi的程序仅仅完成了对acpi状态的查询。用户实现S0-S4的功能可以直接向/proc/acpi/sleep文件中写入数字来实现。通过读出(cat)其中的内容可以知道系统到底支持那些模式。

acpi 模块的源代码主程序在linux/drivers/acpi/driver.c中,如果向sleep文件写东西,就转到了 linux/drivers/acpi/ospm/system/sm_osl.c文件的sm_osl_proc_write_sleep函数中,这个函 数后来调用了sm_osl_suspend函数。在这个函数里完成了各种功能,包括保护各种状态。最后真正的sleep是通过对 acpi_enter_sleep_state的调用完成的,这个函数在linux/drivers/acpi/hardware/hwsleep.c文 件中,这里写了acpi的寄存器使系统进入sleep状态。写寄存器的指令在这个目录下面的hwregs.c中。




回页首


7.总结

本文对acpi的介绍非常简略,实际上ACPI必定会成为将来linux内核中首选的电源管理方式。由于目前官方代码中ACPI版本较低,所以没有太详细的论述,希望将来的内核能有所改变。



参考资料

  • linux-2.4.20源代码

关于作者

范晓炬,联想(北京)有限公司软件设计中心嵌入式研发处开发工程师,研究兴趣为 Linux 内核,网络安全,XWindow 系统,Linux 桌面应用,人工智能系统。你可以通过 xiaoju_f@263.net联系他

========================================


参考资料:
www.ibm.com/developerworks/cn/linux/embed/l-rb/index.html
blog.chinaunix.net/u/7356/showart.php
if.ustc.edu.cn/~jbhuang/blog/archives/000265.html
www.ahinc.com/linux101/boot.htm
  • 1
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值