歡迎光臨
每天分享高質量文章

Linux 定時休眠

來源:暗無天日

lujun9972.github.io/blog/2018/06/21/linux定時休眠/

最近公司規定晚上走人後必須關閉電腦,但是像我們這樣的人,經常會忘記了關閉電腦,而且關閉電腦之後再恢復工作環境也是件挺麻煩的事情,無奈之下只能折騰一下,讓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 上,它長成這樣子的:

#  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的交換檔案

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

 

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

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) 檢視交換檔案的偏移位置

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

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

sudo sed -i ‘/^HOOKS=/ s/)/ resume)/’ /etc/mkinitcpio.conf

其中由兩點需要註意:

由於分割槽的label和UUID都是 udev 分配的,因此 resume 必須放在 udev 之後

由於 systemd hook 已經有了 resume 的功能,因此若已經有了 systemd hook,則無需再新增 udev hook

(2) 重新生成initramfs

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 上,它長成這樣子的:

#  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 上,它長成這樣子的:

#  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

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休眠

[Unit]

Description=Hibernate every 21:30:00

 

[Timer]

OnCalendar=*-*-* 21:30:00

Persistent=true

Unit=systemd-hibernate.service

 

[Install]

WantedBy=timers.target

定時喚醒休眠的linux

使用 rtcwake 可以在給定的時間喚醒處於休眠狀態的電腦

其主要用法為:

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 為秒數,表示從現在開始的多少秒後,系統喚醒。


●編號555,輸入編號直達本文

●輸入m獲取文章目錄

推薦↓↓↓

 

運維

更多推薦18個技術類微信公眾號

涵蓋:程式人生、演演算法與資料結構、駭客技術與網路安全、大資料技術、前端開發、Java、Python、Web開發、安卓開發、iOS開發、C/C++、.NET、Linux、資料庫、運維等。

贊(0)

分享創造快樂