<> ||<
><>|| = Intro to what happens under the hood = This is an attempt to follow the process of hibernation all the way from the point at which you press the hibernate button till the power going off. It's based on Karmic. (So far it gets all the way through where the button comes from and how it lock screens and eventually calls the pm-hibernate command - more to come). = From the Gnome GUI to pm = On Karmic there is an icon on the panel with a menu with lock screen, set status, and shutdown and hibernate and similar; ''about'' shows this as being from ''indicator-applet-session'' (from package '''indicator-applet''') - that's just a wrapper that provides the glue on the panel. A ''ps'' shows that there are indicator-status-service, indicator-users-service and indicator-session-service processes - all from the '''indicator-session''' package, these populate the menu that ''indicator-applet-session'' provides. * The ''indicator-session-service'' in the '''indicator-session''' package provides the options for hibernation, shutdown etc. ''session-service.c:create_items'' creates the menu items using ''dbusmenu_menuitem_new'' (see '''libdbusmenu''' package) using the dbus object ''/org/ayatana/indicator/session/menu''. The menu item is bound to the 'sleep' callback with a data value of "Hibernate". That seems to be registered in indicator-session.c (still in the same package) which actually does gtk_menu_insert's. There is a also a 'dpk_changed_cb' (in session-service.c) that checks to see if hibernation and suspend are available. Via the ''hibernate_prop_cb'' they change the visibility of the hibernate menu option depending on the result of a dbus can-hibernate call on ''org.freedesktop.DeviceKit.Power'' (object ''/org/freedesktop/DeviceKit/Power.'') * The ''sleep'' function in session-service.c (still in '''indicator-session''') calls ''lock_screen'' * lock_screen exits if 'gdm_auto_login' is true but otherwise sends a ''Lock'' message on the session bus to ''org.gnome.ScreenSaver,"/","org.gnome.ScreenSaver"''. gdm_auto_login is read using gdm_get_autologin via a dbus call of GetValue on ''org.gnome.DisplayManager , /org/gnome/DisplayManager/Settings , org.gnome.DisplayManager.Settings'' (on the system bus) with the parameter of ''daemon/AutomaticLoginEnable'' On most systems that errors with no such key - but the ''gdm_auto_login'' variable is defaulted to false; it's only if you set this flag at some point that this returns. Reading gdm_auto_login is done at startup, a ValueChange signal is registered to detect it changing afterwards. * After the screen lock ''sleep'' then sends a message of ''Hibernate'' (from it's userdata field) via dbus to ''/org/freedesktop/DeviceKit/Power''. That's handled by ''/usr/lib/devicekit-power/devkit-power-daemon'' from the '''devicekit-power''' package. * In ''devicekit-power/src/dkp-daemon.c'' is the ''dkp_daemon_hibernate'' function where the ''Hibernate'' message is actioned.. It checks that: * the kernel can hibernate (having previously read from ''/sys/power/state'' and checking it contains the word '''disk''') * that there is enough swap (based on values previously read from ''/proc/meminfo'') * with polkit that you are allowed to hibernate (using ''polkit_authority_check_authorization_sync'' ) Finally it runs ''/usr/sbin/pm-hibernate'' which is from the '''pm-utils''' package. = pm-utils down to the kernel = ''pm-hibernate'' is a symlink to ''/usr/lib/pm-utils/bin/pm-action'' which is just a shell script. ''pm-action'' picks up a lot of helper functions from ''/usr/lib/pm-utils/pm-functions''; this stores a lot of config and log files based on a ''STASHNAME'' variable that pm-action sets to pm-suspend; this leads for example to the whole process being logged in ''/var/log/pm-suspend.log''. Other places ''pm-action'' looks are: * ''/usr/lib/pm-utils'' other scripts, script fragments (''hooks'') for individual sections of the hibernate/resume/etc process. * ''/etc/pm'' for configuration and extra script fragments to get run during the hibernation/resume/etc process. * ''/var/run/pm-utils'' for locks and temporary state files. ''pm-action'' sets up the ''STASHNAME'' variable and sources ''pm-functions''. * ''pm-functions'' sets up variables pointing to each of the directories it uses. It also pulls in ''/usr/lib/pm-utils/defaults'' and potentially ''/usr/lib/pm-utils/pm-suspend.defaults'' if it exists. It then sources each of the files in /etc/pm/config.d and ''/etc/pm/pm-suspend-config.d'' (that being from STASHNAME). As it works through these files it concatenates the SUSPEND_MODULES, HOOK_BLACKLIST, ADD_PARAMETERS and DROP_PARAMETERS variables - thus if any of the config files set them they accumulate rather than overriding earlier ones. * ''pm-functions'' then sources ''/usr/lib/pm-utils/functions'' which is a set of generic helper functions. * There are three different ways of dealing with hibernation; the kernel, tuxonice and uswsusp - the choice is made by the ''SLEEP_MODULE'' in ''pm-functions''. This is initially set as ''kernel'' but you can change that by setting the value in one of the config files - preferably ''/etc/pm/config.d/00sleep_module''. If it's set to ''auto'' ''pm_functions' will look for tuxonice and uswsusp. Given a particular settings for ''SLEEP_MODULE'' ''pm_functions'' sources file for that mechanism in ''/usr/lib/pm-utils/module.d''; the one for the ''kernel'' mode is pretty empty since ''pm_functions'' sets the defaults for that mode. In either case by the end of ''pm_functions'' the ''do_hibernate'' and ''do_suspend'' functions have been defined to invoke which ever sleep mechanism has been selected. * A list of ''parameters'' is maintained in ''/var/run/pm-utils/pm-suspend/storage/parameters'' - this is initially cleared and the parameters to ''pm_action'' are added to it as are flags later on. These flags indicate things like particular hardware specific ''quirks'' to use and avoid. * The ''load_hook_blacklist'' is used to take the ''HOOK_BLACKLIST'' variable and mark those hook scripts as being disabled. Similarly at this stage the ''ADD_PARAMETERS'' and ''DROP_PARAMETERS'' variables are merged with the existing set of parameters. * ''pm_action'' now uses ''run_hooks'' from ''pm_functions'' to run all the hook scripts; it must return true for the hibernate to actually happen. * ''run_hooks'': * first runs a ''before_hooks'' hook so you can execute any specials by setting the BEFORE_HOOKS variable. * Takes a list of all of the script fragments in ''/var/run/pm-utils/sleep.d'' and ''/etc/pm/sleep.d'' (sleep having been passed as a flag from pm-action). These are sorted into alphanumeric order and any duplicates removed - so it's probably a bad idea to have the same named script in both of these directories. * For each hook file the flags are checked to see if it was previously disabled by the ''HOOK_BLACKLIST'' mechanism and if not the hook is run. If the hook exits with an error the whole of the ''run_hooks'' exits stopping any further hooks running and the whole hibernate process is stopped. The running set of parameters is also updated between each one. * The individual sleep.d hooks: * '''000record''' - aborts the hibernate/sleep if the kernel has been upgraded (checks for /var/run/do-not-hibernate) * '''00auto-quirk''' - these are extracted from lshal by looking for lines with power_management.quirk.* = true, these then get turned into parameters of the form --quirk- - for example on my machine I have --quirk-vga-mode-3 which comes from a hal entry of power_management.quirk.vga_mode_3 = true (bool) * '''00logging''' - just add current modules, version number and free memory to the logs * '''00powersave''' - uses the pm-powersave to turn off powersaving features during the hibernate and restore them afterwards. This calls back into another run of ''run_hooks'' but this time with the argument of ''power'' rather than ''sleep'' - see below. pm-powersave is also called by ''acpi'' scripts (such as '''/etc/acpi/power.sh''') when events such as connecting an AC adapter happen. * Hooks in power.d - many appear to be the same as some of the files in sleep.d; it looks like some are moving to power.d as people find things that need to actually happens in power changes rather than just suspend/resume. * '''95hdparm-apm''' - Changes hard drive power settings based on whether we are on battery or not * '''anacron''' - as per the sleep.d equivalent script but used for changes in power. * '''laptop-mode''' - see sleep.d equivalent * '''sched-powersave''' - When on battery tune the scheduler for lower power usage in the way processes get scheduled accross multiple chips and threads. * '''01PulseAudio''' - For every pulseaudio daemon running (found from a ps) it mutes all the sinks and sources and then suspends the daemon * '''10_grub-common''' - Tell Grub the resume worked OK. * '''10_unattended-upgrades-hibernate''' - Waits for any unattended upgrades to finish before hibernating. This uses ''/usr/share/unattended-upgrades/unattended-upgrade-shutdown'' to do the bulk of the work. * '''49bluetooth''' - Suspend/resume bluetooth on some systems * '''55NetworkManager''' - Uses the dbus system bus to send a ''sleep'' or ''wake'' message to NetworkManager * '''75modules''' - unloads any modules set in the ''SUSPEND_MODULES'' variable and anything that depends on them, and loads them back on resume. * '''90clock''' - saves the current time to the hardware clock before hibernate and pulls it back during restore. * '''94cpufreq''' - sets the cpu frequency governers to performance during the hibernate cycle and restores it afterwards. This uses the ''savestate'' and ''restorestate'' functions to save the current state in ''/var/run/pm-utils/pm-suspend/storage/state\:cpu*_governor'' * '''95anacron''' - stop and start the ''anacron'' job scheduler. This seems to be on the basis that when you resume from hibernation there is a chance you are now on power and anacron doesn't run on battery. * '''95led''' - a trivial script to start the suspend LED blinking on some machines. * '''96laptop-mode''' - during resume turns laptop mode on if it's enabled * '''98smart-kernel-video''' - Removes a lot of the quirks that came from HAL if the kernel mode switching is in use, since they seem to be trusted to do the right thing most of the time. This file has rules for different vendors about which quirks can be ignored. * '''99video''' - This does the bulk of the video hibernation/resume work, guided by any remaining quirks. Some happen by default and are turned off by quirks (e.g. chvt and fb) others are turned on by quirks (e.g. vga_mode_3). Many use the VESA Bios extension (VBE) to get the video card bios to do things themselves. As noted above most of these are disabled in the case of KMS. The quirks are: * dpms-on - Use VBE to turn DPMS on during resume * dpms-suspend - Use VBE to suspend DPMS during hibernate/sleep * radeon-off - Radeon specific tweak using the '''radeontool''' package. * reset-brightness - Explicitly restore the brightness during resume. * s3-bios and s3-mode - Use the video bios to restore settings when coming back from sleep; see the Documentation/power/video.txt file in the kernel source for more details. * vbe-post - Use VBE to run the Video bios initialisation. * vbemode-restore and vbestate-restore - use VBE to save and restore some of the state of the video system. * no-fb - Refuse to suspend if framebuffer is in use * pci-save - Save and restore the PCI config space for the video card. (Appears to be broken by a thinko to me) * no-chvt - Don't flick to a spare virtual terminal and back during suspend/resume * '''action_wpa''' - Shut down interfaces used by wpa-roaming during suspend/resume. We've run all the hooks, assuming that none of them have failed we find ourselves back in pm-action. It's going to now run the ''do_hibernate'' function that was set up earlier to which ever hibernate system we're going to use. = From the kernel to sleep (using standard kernel hibernate) = * The ''do_hibernate'' function defined in pm-functions is pretty simple; it sets up the mode used to force the hardware into hibernate ( by writing it to /sys/power/disk ) and then just writes '''disk''' to /sys/power/state. * The write ends up calling ''state_store'' in kernel/power/main.c (via the sysfs_create_group call in the ''pm_init'' function and the rather sneaky ''power_attr'' macro that creates the data for each attribute/file). ''state_store'' itself checks to see if it was the word '''disk''' and if so calls the '''hibernate()''' function in kernel/power/hibernate.c To be continued.... * Must add where the quirks come from in hal * power.d - seem to have a lot of duplicates with sleep.d (asked about laptop-mode) --- ubuntu@treblig.org = External Links = http://www.ubuntu-forum.de/artikel/10046/gel%C3%B6st-standby-hibernate.html