linux 定时休眠的实现思路

吾爱主题 阅读:134 2024-04-05 13:54:28 评论:0

最近公司规定晚上走人后必须关闭电脑,但是像我们这样的人,经常会忘记了关闭电脑,而且关闭电脑之后再恢复工作环境也是件挺麻烦的事情,无奈之下只能折腾一下,让linux定时休眠了。

休眠的类型

目前大概由三种类型的休眠:

suspend(suspend to RAM)

指的是除了内存以外的大部分机器部件都进入断电状态。 这种休眠状态恢复速度特别快,但由于内存中的数据并没有被保存下来,因此这个状态的系统并没有进入真正意义上的休眠状态,还在持续耗电。

hibernate(suspend to disk)

这种休眠会将内存中的系统状态写入交换空间内,当系统启动时就可以从交换空间内读回系统状态。 这种情况下系统可以完全断电,但由于要保存/读取系统状态到/从交换空间,因此速度会比较慢,而且需要进行一些配置(下面会说到)

hybrid(suspend to both)

结合了上面两种休眠类型。它像hibernate一样将系统状态存入交换空间内,同时也像suspend一样并不关闭电源。 这种,在电源未耗尽之前,它能很快的从休眠状态恢复。而若休眠期间电源耗尽,则它可以从交换空间中恢复系统状态。

suspend 休眠

进入 suspend 特别简单,无需额外的配置,在 systemd 系统上直接执行 systemctl suspend 就行了。\

systemctl suspend

它的实际动作由 systemd-suspend.service 所定义, 在 archlinux 上,它长成这样子的:

?
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 # SPDX-License-Identifier: LGPL-2.1+ ## This file is part of systemd. # # systemd is free software; you can redistribute it and/or modify it # under the terms of the GNU Lesser General Public License as published by # the Free Software Foundation; either version 2.1 of the License, or # (at your option) any later version. [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-sleep suspend

Hibernation 休眠

由于 hibernation 休眠要求将内存中的内容写入到交换空间中,因此你至少要有一个空间大于内存的交换分区或者交换文件。 (其实若交换空间不够内存大也不是一定就无法进行hibernation休眠,可以尝试运行 echo 0 |sudo tee /sys/power/image_size, 这会让系统在写入交换空间时尽可能的进行压缩,但这种方法也无法保证一定能够休眠成功)

若之前没有创建交换分区,那么可以临时创建一个交换文件来用。比如下面命令创建一个5G的交换文件

?
1 2 3 4 5 6 7 8 9 sudo dd if = /dev/zero of= /swapfile bs=10240 count=524288 sudo mkswap /swapfile sudo chmod 0600 /swapfile sudo swapon /swapfile sudo cp /etc/fstab /etc/fstab .bak echo "/swapfile swap swap default 0 0" | tee -a /etc/fstab Setting up swapspace version 1, size = 5 GiB (5368705024 bytes) no label, UUID=d0f0c682-e1fa-416f-8fe2-b554b8ca363a /swapfile swap swap default 0 0

除此创建交换分区之外,我们还需要修改kernel的启动参数,让系统在启动时先尝试从交换空间中恢复状态。 具体操作如下:

1. 如果使用交换分区来保存,则只需要为添加kernel的启动参数 resume=交换分区 即可

(1) 查看那块分区是交换分区

swapon

?
1 2 3 NAME  TYPE  SIZE USED PRIO /dev/sda2 partition 8G 280K -2 /swapfile file  5G 0B -3

可以看出交换分区为 /dev/sda2

(2) 修改 /etc/default/grub, 为 GRUB_CMDLINE_LINUX_DEFAULT 行添加参数 resume=/dev/sda2

?
1 sudo sed -i '/GRUB_CMDLINE_LINUX_DEFAULT/ s!"$! resume=/dev/sda2"!' /etc/default/grub

2. 如果是使用交换文件,则需要添加两个参数 resume=交换文件所在磁盘 以及 resume_offset=交换文件在磁盘中的偏移位置:

(1) 查看交换文件所在磁盘

df /swapfile

文件系统          1K-块     已用     可用 已用% 挂载点
/dev/sda3      55253696 27582224 24834972   53% /

说明磁盘为 /dev/sda3

(2) 查看交换文件的偏移位置

?
1 2 3 4 5 6 sudo filefrag - v /swapfile | head -5 Filesystem type is: ef53 File size of /swapfile is 5368709120 (1310720 blocks of 4096 bytes)   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/sda3 resume_offset=4653056

?
1 sudo sed -i '/GRUB_CMDLINE_LINUX_DEFAULT/ s!"$! resume=/dev/sda3 resume_offset=4653056"!' /etc/default/grub

3. 重新生成 grub.cfg 文件

sudo grub-mkconfig -o /boot/grub/grub.cfg

(1) 配置initramfs添加 resume hook 修改 /etc/mkinitcpio.conf 文件,在 HOOKS 中添加 resume

?
1 sudo sed -i '/^HOOKS=/ s/)/ resume)/' /etc/mkinitcpio .conf

其中由两点需要注意:

  • 由于分区的label和UUID都是 udev 分配的,因此 resume 必须放在 udev 之后
  • 由于 systemd hook 已经有了 resume 的功能,因此若已经有了 systemd hook,则无需再添加 udev hook

(2) 重新生成initramfs

?
1 2 3 4 5 6 7 8 9 10 11 12 13 14 sudo mkinitcpio -g /boot/initramfs-linux-lily .img ==> Starting build: 4.16.12-2-lily   -> Running build hook: [base]   -> Running build hook: [udev]   -> Running build hook: [autodetect]   -> Running build hook: [modconf]   -> Running build hook: [block]   -> Running build hook: [filesystems]   -> Running build hook: [keyboard]   -> Running build hook: [ fsck ]   -> Running build hook: [resume] ==> Generating module dependencies ==> Creating gzip -compressed initcpio image: /boot/initramfs-linux-lily .img ==> Image generation successful

(3) 重启,让配置生效

经过上面复杂的配置后,hibernation 休眠才能真正成功。与 suspend 休眠类似,我们也能使用 systemctl 来进行休眠

systemctl hibernate

类似的,它的实际动作由 systemd-hibernte.service 所定义, 在 archlinux 上,它长成这样子的:

?
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 # SPDX-License-Identifier: LGPL-2.1+ # # This file is part of systemd. # # systemd is free software; you can redistribute it and/or modify it # under the terms of the GNU Lesser General Public License as published by # the Free Software Foundation; either version 2.1 of the License, or # (at your option) any later version. [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-sleep hibernate

hybrid 休眠

在配置好 hibernate 休眠后,也就能正常进行 hybrid 休眠了,方法是执行

systemctl hybrid-sleep

类似的,它的实际动作由 systemd-hybrid-sleep.service 所定义, 在 archlinux 上,它长成这样子的:

?
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 # SPDX-License-Identifier: LGPL-2.1+ # # This file is part of systemd. # # systemd is free software; you can redistribute it and/or modify it # under the terms of the GNU Lesser General Public License as published by # the Free Software Foundation; either version 2.1 of the License, or # (at your option) any later version. [Unit] Description=Hybrid Suspend+Hibernate Documentation= man :systemd-suspend.service(8) DefaultDependencies=no Requires= sleep .target After= sleep .target [Service] Type=oneshot ExecStart= /usr/lib/systemd/systemd-sleep hybrid- sleep

Sleep Hooks

从上面的service文件中可以看出,不管是哪种类型的系统休眠,其内部实际调用的都是 systemd-sleep.

man systemd-sleep

?
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 SYSTEMD-SUSPEND.SERVICE(8) systemd-suspend.service SYSTEMD-SUSPEND.SERVICE(8) NAME    systemd-suspend.service, systemd-hibernate.service, systemd-hybrid-    sleep .service, systemd- sleep - System sleep state logic SYNOPSIS    systemd-suspend.service    systemd-hibernate.service    systemd-hybrid- sleep .service    /usr/lib/systemd/system-sleep DESCRIPTION    systemd-suspend.service is a system service that is pulled in by    suspend.target and is responsible for the actual system suspend.    Similarly, systemd-hibernate.service is pulled in by hibernate.target    to execute the actual hibernation. Finally,    systemd-hybrid- sleep .service is pulled in by hybrid- sleep .target to    execute hybrid hibernation with system suspend.    Immediately before entering system suspend and /or hibernation    systemd-suspend.service (and the other mentioned units , respectively)    will run all executables in /usr/lib/systemd/system-sleep/ and pass two    arguments to them. The first argument will be "pre" , the second either    "suspend" , "hibernate" , or "hybrid-sleep" depending on the chosen    action. Immediately after leaving system suspend and /or hibernation the    same executables are run, but the first argument is now "post" . All    executables in this directory are executed in parallel, and execution    of the action is not continued until all executables have finished.    Note that scripts or binaries dropped in /usr/lib/systemd/system-sleep/    are intended for local use only and should be considered hacks. If    applications want to react to system suspend /hibernation and resume,    they should rather use the Inhibitor interface[1].    Note that systemd-suspend.service, systemd-hibernate.service, and    systemd-hybrid- sleep .service should never be executed directly.    Instead, trigger system sleep states with a command such as "systemctl    suspend" or similar.    Internally, this service will echo a string like "mem" into    /sys/power/state , to trigger the actual system suspend. What exactly is    written where can be configured in the "[Sleep]" section of    /etc/systemd/sleep .conf or a sleep .conf.d file . See systemd-    sleep .conf(5). OPTIONS    systemd- sleep understands the following commands:    -h, --help     Print a short help text and exit .    --version     Print a short version string and exit .    suspend, hibernate, hybrid- sleep     Suspend, hibernate, or put the system to hybrid sleep . SEE ALSO    systemd- sleep .conf(5), systemd(1), systemctl(1), systemd.special(7),    systemd-halt.service(8) NOTES    1. Inhibitor interface

https://www.freedesktop.org/wiki/Software/systemd/inhibit

systemd 238                                         SYSTEMD-SUSPEND.SERVICE(8)
根据 systemd-sleep 的manual pages,可以看到在系统休眠之前以及从休眠状态恢复之后,都会并行地调用 /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休眠

?
1 2 3 4 5 6 7 8 [Unit] Description=Hibernate every 21:30:00 [Timer] OnCalendar=*-*-* 21:30:00 Persistent= true Unit=systemd-hibernate.service [Install] WantedBy=timers.target

定时唤醒休眠的linux

使用 rtcwake 可以在给定的时间唤醒处于休眠状态的电脑

其主要用法为:

?
1 2 3 sudo rtcwake -m ${mode} -t ${time_t} # 或者 sudo rtcwake -m ${mode} -s ${seconds}

其中,参数mode为待机模式,有以下几个选项:

standby

普通待机模式,为默认选项,对应 ACPI state S1

mem

suspend休眠,对应 ACPI state S3

disk

hibernation 休眠,对应 ACPI state S4

off

通过调用系统的关机命令来休眠,对应 ACPI state S5

参数 time_t 为从 1970-01-01, 00:00 UTC 开始到现在的秒数,可以通过 date 命令来将时间字符串转换成这个秒数,比如

sudo rtcwake -m disk -t $(date -d 08:30 +%s)

就是进行 hibernation 休眠,并于08:30分唤醒

参数 seconds 为秒数,表示从现在开始的多少秒后,系统唤醒。

总结

以上所述是小编给大家介绍的linux 定时休眠的实现思路,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对服务器之家网站的支持!

原文链接:http://www.importnew.com/29158.html

可以去百度分享获取分享代码输入这里。
声明

1.本站遵循行业规范,任何转载的稿件都会明确标注作者和来源;2.本站的原创文章,请转载时务必注明文章作者和来源,不尊重原创的行为我们将追究责任;3.作者投稿可能会经我们编辑修改或补充。

【腾讯云】云服务器产品特惠热卖中
搜索
标签列表
    关注我们

    了解等多精彩内容