linux 定时休眠的实现思路
最近公司规定晚上走人后必须关闭电脑,但是像我们这样的人,经常会忘记了关闭电脑,而且关闭电脑之后再恢复工作环境也是件挺麻烦的事情,无奈之下只能折腾一下,让linux定时休眠了。
休眠的类型
目前大概由三种类型的休眠:
suspend(suspendtoRAM)
指的是除了内存以外的大部分机器部件都进入断电状态。这种休眠状态恢复速度特别快,但由于内存中的数据并没有被保存下来,因此这个状态的系统并没有进入真正意义上的休眠状态,还在持续耗电。
hibernate(suspendtodisk)
这种休眠会将内存中的系统状态写入交换空间内,当系统启动时就可以从交换空间内读回系统状态。这种情况下系统可以完全断电,但由于要保存/读取系统状态到/从交换空间,因此速度会比较慢,而且需要进行一些配置(下面会说到)
hybrid(suspendtoboth)
结合了上面两种休眠类型。它像hibernate一样将系统状态存入交换空间内,同时也像suspend一样并不关闭电源。这种,在电源未耗尽之前,它能很快的从休眠状态恢复。而若休眠期间电源耗尽,则它可以从交换空间中恢复系统状态。
suspend休眠
进入suspend特别简单,无需额外的配置,在systemd系统上直接执行systemctlsuspend就行了。\
systemctlsuspend
它的实际动作由systemd-suspend.service所定义,在archlinux上,它长成这样子的:
#SPDX-License-Identifier:LGPL-2.1+ ##Thisfileispartofsystemd. # #systemdisfreesoftware;youcanredistributeitand/ormodifyit #underthetermsoftheGNULesserGeneralPublicLicenseaspublishedby #theFreeSoftwareFoundation;eitherversion2.1oftheLicense,or #(atyouroption)anylaterversion. [Unit] Description=Suspend Documentation=man:systemd-suspend.service(8) DefaultDependencies=no Requires=sleep.target After=sleep.target [Service] Type=oneshot ExecStart=/usr/lib/systemd/systemd-sleepsuspend
Hibernation休眠
由于hibernation休眠要求将内存中的内容写入到交换空间中,因此你至少要有一个空间大于内存的交换分区或者交换文件。(其实若交换空间不够内存大也不是一定就无法进行hibernation休眠,可以尝试运行echo0|sudotee/sys/power/image_size,这会让系统在写入交换空间时尽可能的进行压缩,但这种方法也无法保证一定能够休眠成功)
若之前没有创建交换分区,那么可以临时创建一个交换文件来用。比如下面命令创建一个5G的交换文件
sudoddif=/dev/zeroof=/swapfilebs=10240count=524288 sudomkswap/swapfile sudochmod0600/swapfile sudoswapon/swapfile sudocp/etc/fstab/etc/fstab.bak echo"/swapfileswapswapdefault00"|tee-a/etc/fstab Settingupswapspaceversion1,size=5GiB(5368705024bytes) nolabel,UUID=d0f0c682-e1fa-416f-8fe2-b554b8ca363a /swapfileswapswapdefault00
除此创建交换分区之外,我们还需要修改kernel的启动参数,让系统在启动时先尝试从交换空间中恢复状态。具体操作如下:
1.如果使用交换分区来保存,则只需要为添加kernel的启动参数resume=交换分区即可
(1)查看那块分区是交换分区
swapon
NAMETYPESIZEUSEDPRIO /dev/sda2partition8G280K-2 /swapfilefile5G0B-3
可以看出交换分区为/dev/sda2
(2)修改/etc/default/grub,为GRUB_CMDLINE_LINUX_DEFAULT行添加参数resume=/dev/sda2
sudosed-i'/GRUB_CMDLINE_LINUX_DEFAULT/s!"$!resume=/dev/sda2"!'/etc/default/grub
2.如果是使用交换文件,则需要添加两个参数resume=交换文件所在磁盘以及resume_offset=交换文件在磁盘中的偏移位置:
(1)查看交换文件所在磁盘
df/swapfile
文件系统 1K-块 已用 可用已用%挂载点
/dev/sda3 552536962758222424834972 53%/
说明磁盘为/dev/sda3
(2)查看交换文件的偏移位置
sudofilefrag-v/swapfile|head-5 Filesystemtypeis:ef53 Filesizeof/swapfileis5368709120(1310720blocksof4096bytes) ext:logical_offset:physical_offset:length:expected:flags: 0:0..32767:4653056..4685823:32768: 1:32768..65535:4685824..4718591:32768:
这里可以看出物理偏移位置时4653056
(3)修改/etc/default/grub,为GRUB_CMDLINE_LINUX_DEFAULT行添加参数resume=/dev/sda3resume_offset=4653056
sudosed-i'/GRUB_CMDLINE_LINUX_DEFAULT/s!"$!resume=/dev/sda3resume_offset=4653056"!'/etc/default/grub
3.重新生成grub.cfg文件
sudogrub-mkconfig-o/boot/grub/grub.cfg
(1)配置initramfs添加resumehook修改/etc/mkinitcpio.conf文件,在HOOKS中添加resume
sudosed-i'/^HOOKS=/s/)/resume)/'/etc/mkinitcpio.conf
其中由两点需要注意:
- 由于分区的label和UUID都是udev分配的,因此resume必须放在udev之后
- 由于systemdhook已经有了resume的功能,因此若已经有了systemdhook,则无需再添加udevhook
(2)重新生成initramfs
sudomkinitcpio-g/boot/initramfs-linux-lily.img ==>Startingbuild:4.16.12-2-lily ->Runningbuildhook:[base] ->Runningbuildhook:[udev] ->Runningbuildhook:[autodetect] ->Runningbuildhook:[modconf] ->Runningbuildhook:[block] ->Runningbuildhook:[filesystems] ->Runningbuildhook:[keyboard] ->Runningbuildhook:[fsck] ->Runningbuildhook:[resume] ==>Generatingmoduledependencies ==>Creatinggzip-compressedinitcpioimage:/boot/initramfs-linux-lily.img ==>Imagegenerationsuccessful
(3)重启,让配置生效
经过上面复杂的配置后,hibernation休眠才能真正成功。与suspend休眠类似,我们也能使用systemctl来进行休眠
systemctlhibernate
类似的,它的实际动作由systemd-hibernte.service所定义,在archlinux上,它长成这样子的:
#SPDX-License-Identifier:LGPL-2.1+ # #Thisfileispartofsystemd. # #systemdisfreesoftware;youcanredistributeitand/ormodifyit #underthetermsoftheGNULesserGeneralPublicLicenseaspublishedby #theFreeSoftwareFoundation;eitherversion2.1oftheLicense,or #(atyouroption)anylaterversion. [Unit] Description=Hibernate Documentation=man:systemd-suspend.service(8) DefaultDependencies=no Requires=sleep.target After=sleep.target [Service] Type=oneshot ExecStart=/usr/lib/systemd/systemd-sleephibernate
hybrid休眠
在配置好hibernate休眠后,也就能正常进行hybrid休眠了,方法是执行
systemctlhybrid-sleep
类似的,它的实际动作由systemd-hybrid-sleep.service所定义,在archlinux上,它长成这样子的:
#SPDX-License-Identifier:LGPL-2.1+ # #Thisfileispartofsystemd. # #systemdisfreesoftware;youcanredistributeitand/ormodifyit #underthetermsoftheGNULesserGeneralPublicLicenseaspublishedby #theFreeSoftwareFoundation;eitherversion2.1oftheLicense,or #(atyouroption)anylaterversion. [Unit] Description=HybridSuspend+Hibernate Documentation=man:systemd-suspend.service(8) DefaultDependencies=no Requires=sleep.target After=sleep.target [Service] Type=oneshot ExecStart=/usr/lib/systemd/systemd-sleephybrid-sleep
SleepHooks
从上面的service文件中可以看出,不管是哪种类型的系统休眠,其内部实际调用的都是systemd-sleep.
mansystemd-sleep
SYSTEMD-SUSPEND.SERVICE(8)systemd-suspend.serviceSYSTEMD-SUSPEND.SERVICE(8) NAME systemd-suspend.service,systemd-hibernate.service,systemd-hybrid- sleep.service,systemd-sleep-Systemsleepstatelogic SYNOPSIS systemd-suspend.service systemd-hibernate.service systemd-hybrid-sleep.service /usr/lib/systemd/system-sleep DESCRIPTION systemd-suspend.serviceisasystemservicethatispulledinby suspend.targetandisresponsiblefortheactualsystemsuspend. Similarly,systemd-hibernate.serviceispulledinbyhibernate.target toexecutetheactualhibernation.Finally, systemd-hybrid-sleep.serviceispulledinbyhybrid-sleep.targetto executehybridhibernationwithsystemsuspend. Immediatelybeforeenteringsystemsuspendand/orhibernation systemd-suspend.service(andtheothermentionedunits,respectively) willrunallexecutablesin/usr/lib/systemd/system-sleep/andpasstwo argumentstothem.Thefirstargumentwillbe"pre",thesecondeither "suspend","hibernate",or"hybrid-sleep"dependingonthechosen action.Immediatelyafterleavingsystemsuspendand/orhibernationthe sameexecutablesarerun,butthefirstargumentisnow"post".All executablesinthisdirectoryareexecutedinparallel,andexecution oftheactionisnotcontinueduntilallexecutableshavefinished. Notethatscriptsorbinariesdroppedin/usr/lib/systemd/system-sleep/ areintendedforlocaluseonlyandshouldbeconsideredhacks.If applicationswanttoreacttosystemsuspend/hibernationandresume, theyshouldratherusetheInhibitorinterface[1]. Notethatsystemd-suspend.service,systemd-hibernate.service,and systemd-hybrid-sleep.serviceshouldneverbeexecuteddirectly. Instead,triggersystemsleepstateswithacommandsuchas"systemctl suspend"orsimilar. Internally,thisservicewillechoastringlike"mem"into /sys/power/state,totriggertheactualsystemsuspend.Whatexactlyis writtenwherecanbeconfiguredinthe"[Sleep]"sectionof /etc/systemd/sleep.conforasleep.conf.dfile.Seesystemd- sleep.conf(5). OPTIONS systemd-sleepunderstandsthefollowingcommands: -h,--help Printashorthelptextandexit. --version Printashortversionstringandexit. suspend,hibernate,hybrid-sleep Suspend,hibernate,orputthesystemtohybridsleep. SEEALSO systemd-sleep.conf(5),systemd(1),systemctl(1),systemd.special(7), systemd-halt.service(8) NOTES 1.Inhibitorinterface
https://www.freedesktop.org/wiki/Software/systemd/inhibit
systemd238 SYSTEMD-SUSPEND.SERVICE(8)
根据systemd-sleep的manualpages,可以看到在系统休眠之前以及从休眠状态恢复之后,都会并行地调用/usr/lib/systemd/system-sleep中的脚本,并传递两个参数。
第一个参数用来指定是开始休眠还是从休眠状态恢复,分别对应的字符串“pre”与“post”.
第二个参数用来指明休眠的类型,分别为字符串“suspend”,“hibernate”以及“hybrid-sleep”
定时执行休眠
systemd系统中的定时任务是由timer来实现的,而每个timer都与一个service相对应。
一般情况下,timer的名称与service一致,但必要时可以通过在.timer文件中的[Timer]部分指定Unit=选项来控制一个与timer不同名的service。
下面是一个timer的例子,每天21:30分开始自动hibernate休眠
[Unit] Description=Hibernateevery21:30:00 [Timer] OnCalendar=*-*-*21:30:00 Persistent=true Unit=systemd-hibernate.service [Install] WantedBy=timers.target
定时唤醒休眠的linux
使用rtcwake可以在给定的时间唤醒处于休眠状态的电脑
其主要用法为:
sudortcwake-m${mode}-t${time_t} #或者 sudortcwake-m${mode}-s${seconds}
其中,参数mode为待机模式,有以下几个选项:
standby
普通待机模式,为默认选项,对应ACPIstateS1
mem
suspend休眠,对应ACPIstateS3
disk
hibernation休眠,对应ACPIstateS4
off
通过调用系统的关机命令来休眠,对应ACPIstateS5
参数time_t为从1970-01-01,00:00UTC开始到现在的秒数,可以通过date命令来将时间字符串转换成这个秒数,比如
sudortcwake-mdisk-t$(date-d08:30+%s)
就是进行hibernation休眠,并于08:30分唤醒
参数seconds为秒数,表示从现在开始的多少秒后,系统唤醒。
总结
以上所述是小编给大家介绍的linux定时休眠的实现思路,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对毛票票网站的支持!