Take the 2-minute tour ×
Ask Ubuntu is a question and answer site for Ubuntu users and developers. It's 100% free, no registration required.

Is it possible to make Ubuntu go into Hibernate state from Suspend, aka "Suspend Sedation"?

For example, my laptop is set up to go into a Suspend once I close the lid. If then I don't use it for entire day, the battery goes flat, because even in suspend mode the hardware still consumes a small amount of power, and the battery eventually discharges. What I want is to be able to tell Ubuntu that even if it is suspended, it still needs to go into Hibernate after some hours of inactivity.

Windows can do that. Ubuntu can be programmed to go into Standby or Hibernate on timer, but not both.

Update:

I guess I need to be more specific. What I am looking for is this:
When I close the lid, the laptop is put into Suspend. Then, after a pre-determined time (even if the battery is going strong) if I still don't use it, it should put itself into a Hibernate to save battery power.

share|improve this question
    
In my research I found the same Linux Mint thread, but "Suspend Sedation" is not an official Microsoft term for that feature and as far as I can tell was invented by the Linux Mint forum user who mentioned it. –  ayan4m1 Nov 10 '10 at 20:43
    
Is there a better name for that feature? –  Sergey Stadnik Nov 11 '10 at 2:01
    
As far as I can tell, there is no universally accepted name for the feature. "Hybrid suspend" is used by some, "suspend sedation" is used by that one Linux Mint forum user, and I've heard "hibernate and suspend" used to refer to the process before. Microsoft officially refers to it as "hybrid sleep," for Windows 7 at least. –  ayan4m1 Nov 11 '10 at 13:16
1  
@ayan4m1 I realise this is an old question, but I think it is important to clarify this. Hyrbid sleep is not the same as "Sleep then hibernate after a specified time". Hybrid sleep simply becomes hibernate when power is lost, through battery running out. The behaviour described by the OP does not require Hybrid Sleep to be enabled. –  Paul Dec 9 '11 at 2:51

5 Answers 5

up vote 19 down vote accepted

The solution to this is simple. First, upon suspend and resume, the pm-suspend program executes a series of scripts in /etc/pm/sleep.d and /usr/lib/pm-utils/sleep.d. So my solution is to add a script that does the following:

  1. Upon suspend, record the current time and register a wakeup event using rtcwake.
  2. Upon resume,check the current time against the recorded time from above. If enough time has elapsed, then we probably woke up due to the rtc timer event. Otherwise we woke up early due to a user event (such as opening the laptop screen).
  3. If we woke up due to the rtc timer, then immediately issue a "pm-hibernate" command to go into hibernation.

Here is a script that does this. Name it 0000rtchibernate and place it in the /etc/pm/sleep.d directory (the 0000 is important, so that the script executes first on suspend, and last on resume).


#!/bin/bash
# Script name: /etc/pm/sleep.d/0000rtchibernate
# Purpose: Auto hibernates after a period of sleep
# Edit the "autohibernate" variable below to set the number of seconds to sleep.
curtime=$(date +%s)
autohibernate=7200
echo "$curtime $1" >>/tmp/autohibernate.log
if [ "$1" = "suspend" ]
then
    # Suspending.  Record current time, and set a wake up timer.
    echo "$curtime" >/var/run/pm-utils/locks/rtchibernate.lock
    rtcwake -m no -s $autohibernate
fi

if [ "$1" = "resume" ]
then
    # Coming out of sleep
    sustime=$(cat /var/run/pm-utils/locks/rtchibernate.lock)
    rm /var/run/pm-utils/locks/rtchibernate.lock
    # Did we wake up due to the rtc timer above?
    if [ $(($curtime - $sustime)) -ge $autohibernate ]
    then
        # Then hibernate
        rm /var/run/pm-utils/locks/pm-suspend.lock
        /usr/sbin/pm-hibernate
    else
        # Otherwise cancel the rtc timer and wake up normally.
        rtcwake -m no -s 1
    fi
fi

Hopefully this code comes through on this message board (this is my first post here).

Edit the timeout value "autohibernate=7200" at the top, to however many seconds you which to sleep before going into hibernation. The current value above is 2 hours. Note, that you laptop WILL wake up at that time for a few seconds, while it is executing the hibernate function.

So if you plan on putting your laptop in a case, don't suspend, but hibernate instead. Otherwise your laptop could overheat in esp. if it is in a tight fitting slip case (although it will only be on for a few seconds to a minute).

I've been using this method for the past couple of days, so far it has been successful (and saved me from a dead battery this afternoon). Enjoy.

** Update ** For other Linux distributions that use systemd, this should still work if you place the script in /usr/lib/systemd/system-sleep instead of /etc/pm/sleep.d. Also, replace the "/usr/sbin/pm-hibernate" command with "systemctl hibernate".

share|improve this answer
    
Thank you! This is exactly what i was looking for. –  Sergey Stadnik Apr 6 '11 at 22:29
    
It has worked here, but only after I chmoded the file to add X to everyone. I am a huge newbie and it took me 2 days to figure out. Very good script and I hope this helps whoever might be having problems. Thank you. –  user52343 Mar 29 '12 at 17:27
    
This would make a useful Ubuntu/Debian package! –  Petr Pudlák Dec 10 '12 at 8:26
    
Just wondering: would this still be valid for Ubuntu 13.04? I need exactly this solution but I don't want to mess with wife's laptop if it turns out to break things on newer versions. –  Torben Gundtofte-Bruun Sep 17 '13 at 6:33
    
Thanks for the script. Works fine for me on Ubuntu 14.04! One improvement would be if when the laptop wakes up to hibernate, it could check to see if it is plugged into AC power. If so, I would want it to suspend again instead of hibernating. Restoring from hibernate takes longer and I don't really need it to hibernate when it is plugged in... –  maddentim Jun 6 at 14:19

To explain how this works (this is similar to Windows) in simple words: the machine doesn't wake up from standby when battery gets low to be able to save the machine state to the swap partition, it saves everything to the swap partition immediately on standby, and when the battery runs out, it will recover from that by loading the state from the swap partition (as it would do in case you hibernated).

AFAIK linux will/should use hybrid standby/hibernate instead of "normal" standby if it knows that it works for your hardware. It's also possible that this is disabled currently because of too many bugs or something... ;)

If you like experimenting, maybe you can see if you can get any good results with pm-suspend-hybrid.

If the following says you're lucky, then in theory hybrid suspend is supported on your system:

pm-is-supported --suspend-hybrid && echo "you're lucky"
share|improve this answer
    
The single apostrophe in your shell command could be misleading and confusing... please escape it. –  ayan4m1 Nov 11 '10 at 17:49
    
Bah, that's what happens when you edit a commandline embeded inside other text, without thinking about it as a commandline... Thanks & Fixed. –  JanC Nov 12 '10 at 3:44
    
No problem, yeah understood about the different headspaces for the two processes. –  ayan4m1 Nov 12 '10 at 5:40

You may be interested in s2both. It is provided by the package uswsusp in Ubuntu 10.10. It suspends to disk, but instead of shutting down the system instead puts it in S3, which is the power mode usually associated with the "Suspend" option in Ubuntu. pm-suspend-hybrid is another tool that purports to do the same thing.

To make this automated on lid close, take a look at the following guide which allows you to run an arbitrary script when a lid event is caught:

http://ubuntuforums.org/showthread.php?t=1076486

If you happen to have a ThinkPad, the manpage for tpctl makes reference to an argument, --pm-sedation-hibernate-from-suspend-timer, which seems to provide the feature you're looking for. I would caution you against trying this on non-ThinkPad hardware.

For reference, I looked through the manpage for hibernate.conf; it didn't seem to have any relevant options but might be worth a second reading.

share|improve this answer

Just in case something goes wrong during pm-hibernate i'd rather put the computer to suspend than let it run. So you can use:

   ...
/usr/sbin/pm-hibernate || /usr/sbin/pm-suspend
   ...
share|improve this answer

Don't forget to chmod +x that file, make it executable.

There's another solution without rtcwake, using wakealarm in /sys/class/rtc/rtc0. Make use obsolete code in pm-functions (/usr/lib/pm-utils) after the comments #since the kernel does not directly support ... , ('cos the current kernel (after 3.6 something) does directly support). Revert that code and put in do_suspend() part instead of do_suspend_hybrid().

Obsolete code (suspend then hibernate when suspend_hybrid is called):

# since the kernel does not directly support hybrid sleep, we do
# something else -- suspend and schedule an alarm to go into
# hibernate if we have slept long enough.
# Only do this if we do not need to do any special video hackery on resume
# from hibernate, though.
if [ -z "$SUSPEND_HYBRID_MODULE" -a -w "$PM_RTC/wakealarm" ] && \
    check_suspend && check_hibernate && ! is_set $HIBERNATE_RESUME_POST_VIDEO; \
    then
    SUSPEND_HYBRID_MODULE="kernel"
    do_suspend_hybrid() {
    WAKETIME=$(( $(cat "$PM_RTC/since_epoch") + PM_HIBERNATE_DELAY))
    echo >"$PM_RTC/wakealarm"
    echo $WAKETIME > "$PM_RTC/wakealarm"
    if do_suspend; then
        NOW=$(cat "$PM_RTC/since_epoch")
        if [ "$NOW" -ge "$WAKETIME" -a "$NOW" -lt $((WAKETIME + 30)) ]; then
        log "Woken by RTC alarm, hibernating."
        # if hibernate fails for any reason, go back to suspend.
        do_hibernate || do_suspend
        else
        echo > "$PM_RTC/wakealarm"
        fi
    else
        # if we cannot suspend, just try to hibernate.
        do_hibernate
    fi
    }
fi

Recommended. Even easier to use uswsusp while the same time maximize the benefit of s2both i.e. s2both when suspend. Put the reverted code in do_suspend() part of uswsusp module (/usr/lib/pm-utils/module.d).

Reverted code (suspend_hybrid when suspend is called):

WAKETIME=$(( $(cat "$PM_RTC/since_epoch") + PM_HIBERNATE_DELAY))
echo >"$PM_RTC/wakealarm"
echo $WAKETIME > "$PM_RTC/wakealarm"
if do_suspend_hybrid; then
    NOW=$(cat "$PM_RTC/since_epoch")
    if [ "$NOW" -ge "$WAKETIME" -a "$NOW" -lt $((WAKETIME + 30)) ];             then
    log "Woken by RTC alarm, hibernating."
    # if hibernate fails for any reason, go back to suspend_hybrid.
    do_hibernate || do_suspend_hybrid
    else
    echo > "$PM_RTC/wakealarm"
    fi
else
    # when do_suspend is being called, convert to suspend_hybrid.
    do_suspend_hybrid
fi      

With uswsusp, we can see the progress of suspend/hibernate and the reverse process displayed in text, even we can abort it by pressing backspace. Without uswsusp, suspend/hibernate just appear-disappear annoyingly, especially when wakealarm is triggered and execute hibernate (s2disk in uswsusp). Set the period of sleep before hibernate in the usual place on pm-functions file.

# variables to handle hibernate after suspend support
PM_HIBERNATE_DELAY=900  # 15 minutes
PM_RTC=/sys/class/rtc/rtc0

Here's the uswsusp mod: (remember, this module is called from pm-functions so the inserted variables are the same)

#!/bin/sh

# disable processing of 90chvt and 99video.
# s2ram and s2disk handle all this stuff internally.
uswsusp_hooks()
{
    disablehook 99video "disabled by uswsusp"
}

# Since we disabled 99video, we need to take responsibility for proper
# quirk handling.  s2ram handles all common video quirks internally,
# so all we have to do is translate the HAL standard options to s2ram options.
uswsusp_get_quirks()
{
    OPTS=""
    ACPI_SLEEP=0
    for opt in $PM_CMDLINE; do
        case "${opt##--quirk-}" in # just quirks, please
            dpms-on)       ;; # no-op
            dpms-suspend)      ;; # no-op
            radeon-off)        OPTS="$OPTS --radeontool" ;;
            reset-brightness)  ;; # no-op
            s3-bios)       ACPI_SLEEP=$(($ACPI_SLEEP + 1)) ;;
            s3-mode)       ACPI_SLEEP=$(($ACPI_SLEEP + 2)) ;;
            vbe-post)      OPTS="$OPTS --vbe_post" ;;
            vbemode-restore)   OPTS="$OPTS --vbe_mode" ;;
            vbestate-restore)  OPTS="$OPTS --vbe_save" ;;
            vga-mode-3)        ;; # no-op
            save-pci)          OPTS="$OPTS --pci_save" ;;
            none)          QUIRK_NONE="true" ;;
            *) continue ;;
        esac
    done
    [ $ACPI_SLEEP -ne 0 ] && OPTS="$OPTS --acpi_sleep $ACPI_SLEEP"
    # if we were told to ignore quirks, do so.
    # This is arguably not the best way to do things, but...
    [ "$QUIRK_NONE" = "true" ] && OPTS=""
}

# Since we disabled 99video, we also need to handle displaying
# help info for the quirks we handle.
uswsusp_help()
{
    echo  # first echo makes it look nicer.
    echo "s2ram video quirk handler options:"
    echo
    echo "  --quirk-radeon-off"
    echo "  --quirk-s3-bios"
    echo "  --quirk-s3-mode"
    echo "  --quirk-vbe-post"
    echo "  --quirk-vbemode-restore"
    echo "  --quirk-vbestate-restore"
    echo "  --quirk-save-pci"
    echo "  --quirk-none"
}

# This idiom is used for all sleep methods.  Only declare the actual
# do_ method if:
# 1: some other sleep module has not already done so, and
# 2: this sleep method can actually work on this system.
#
# For suspend, if SUSPEND_MODULE is set then something else has already
# implemented do_suspend.  We could just check to see of do_suspend was
# already declared using command_exists, but using a dedicated environment
# variable makes it easier to debug when we have to know what sleep module
# ended up claiming ownership of a given sleep method.
if [ -z "$SUSPEND_MODULE" ] && command_exists s2ram && \
    ( grep -q mem /sys/power/state || \
        ( [ -c /dev/pmu ] && check_suspend_pmu; ); ); then
    SUSPEND_MODULE="uswsusp"
    do_suspend()
    {
        WAKETIME=$(( $(cat "$PM_RTC/since_epoch") + PM_HIBERNATE_DELAY))
        echo >"$PM_RTC/wakealarm"
        echo $WAKETIME > "$PM_RTC/wakealarm"
        if do_suspend_hybrid; then
            NOW=$(cat "$PM_RTC/since_epoch")
            if [ "$NOW" -ge "$WAKETIME" -a "$NOW" -lt $((WAKETIME + 30)) ];             then
            log "Woken by RTC alarm, hibernating."
            # if hibernate fails for any reason, go back to suspend_hybrid.
            do_hibernate || do_suspend_hybrid
            else
            echo > "$PM_RTC/wakealarm"
            fi
        else
            # when do_suspend is being called, convert to suspend_hybrid.
            do_suspend_hybrid
        fi      
    }
fi

if [ -z "$HIBERNATE_MODULE" ] && \
    [ -f /sys/power/disk ] && \
    grep -q disk /sys/power/state && \
    [ -c /dev/snapshot ] &&
    command_exists s2disk; then
    HIBERNATE_MODULE="uswsusp"
    do_hibernate()
    {
        s2disk
    }
fi

if [ -z "$SUSPEND_HYBRID_MODULE" ] && 
    grep -q mem /sys/power/state && \
    command_exists s2both && \
    check_hibernate; then
    SUSPEND_HYBRID_MODULE="uswsusp"
    do_suspend_hybrid()
    {   
        uswsusp_get_quirks
        s2both --force $OPTS 
    }
    if [ "$METHOD" = "suspend_hybrid" ]; then
        add_before_hooks uswsusp_hooks
        add_module_help uswsusp_help
    fi
fi  
share|improve this answer

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.