# Locking

As HAL is a mechanism that enables programs in a desktop session to enforce the policy of the users choice, unexpected things can happen. For example, if the user is in the middle of partitioning a disk drive, it is desirable to keep the desktop from mounting partitions that have not yet been prepared with a suitable file system. In fact, in such a situation data loss may be the result if a volume have an old file system signature indicating it's mountable and, simultenously, another tool is writing to the raw block device. The mechanism that automounters use, HAL, provides locking primitives to avoid this.

Further, for multi-user systems, several desktop sessions may run on a system each on their own display. Suppose that one session becomes idle and the power management daemon in that session decides to suspend the system according to user preferences in the idle session. The result is that users at other seats will see the system suspend and this is not desirable. The power management daemons in all sessions need to cooperate to ensure that the system only suspends when e.g. all sessions are idle or not at all. The mechanism that each power management daemon uses, HAL, provides locking primitives that can be used to achieve this.

## Overview

HAL provides a mechanism to lock a specific D-Bus interface either for a specific device or for all the devices the caller have access to.

The former is achieved by using the `AcquireInterfaceLock()` and `ReleaseInterfaceLock()` methods on the `org.freedesktop.Hal.Device` interface that every device object implements (see interface-device). By using this API, a caller can prevent any other caller from invoking methods on the given interface for the given device object - other callers will simply see the `org.freedesktop.Hal.Device.InterfaceLocked` exception if they attempt to invoke a method on the given interface on the given device. The locker can specify whether the lock is exclusive meaning if multiple clients clients can hold the lock or if only one client can hold the lock at one time. If a client don't have access to the interface of the device, attempts to lock will fail with a `org.freedesktop.Hal.PermissionDenied` exception. If a client loses access to a device (say, if his session is switched away from using fast user switching) while holding a lock, he will lose the lock; this can be tracked by listening to the `InterfaceLockReleased` signal.

All local clients, whether they are active or not, can always lock interfaces on the root computer device object (this doesn't mean that they are privileged to use the interfaces though) - the rationale is that this device object represents shared infrastructure, e.g. power management, and even inactive sessions needs to participate in managing this.

If another client already holds a lock exclusively, attempts from other clients to acquire the lock will fail with the `org.freedesktop.Hal.Device.InterfaceAlreadyLocked` exception even if they have access to the device.

In addition, a client may opt to lock all devices that he got access to by using the `AcquireGlobalInterfaceLock()` and `ReleaseGlobalInterfaceLock()` methods on the `org.freedesktop.Hal.Manager` interface on the `/org/freedesktop/Hal/Manager` object (see interface-manager). Global interface locks can also be obtained exclusively if the caller so desires. Unlike per-device interface locking, it is not checked at locking time whether the locker have access to a given device; instead checking is done when callers attempt to access the interface.

The algorithm used for determining if a caller is locked out is shown below. A caller A is locked out of an interface IFACE on a device object DEVICE if, and only if,

1. Another caller B is holding a lock on the interface IFACE on DEVICE and A don't have either a global lock on IFACE or a lock on IFACE on DEVICE; or

2. Another caller B is holding the global lock on the interface IFACE and B has access to DEVICE and and A don't have either a global lock on IFACE or a lock on IFACE on DEVICE.

In other words, a caller A can grab a global lock, but that doesn't mean A can lock other clients out of devices that A doesn't have access to. Specifically a caller is never locked out if he has locked an interface either globally or on the device in question. However, if two clients have a lock on a device, then both can access it. To ensure that everyone is locked out, a caller needs to use an exclusive lock.

Note that certain interfaces will also check whether other locks are being held on other device objects. This is specified on a per-interface basis in interfaces.

If a process holding locks disconnects from the system bus, the locks being held by that process will be released.

## Guidelines

Locking is only useful if applications requiring exclusive access actually use the locking primitives to cooperate with other applications. Here is a list of guidelines.

- Disk Management / Partitioning

  In order to prevent HAL-based automounters from mounting partitions that are being prepared, applications that access block devices directly (and pokes the kernel to reload the partitioning table) should lock out automounters by either a) obtaining the `org.freedesktop.Hal.Device.Storage` lock on each drive being processed; or b) obtaintaing the global `org.freedesktop.Hal.Device.Storage` lock. This includes programs like fdisk, gparted, parted and operating system installers. See also interface-device-volume and the `hal-lock`(1) program and manual page.

- Power Management

  Typically, a desktop session includes a session-wide power management daemon that enforces the policy of the users choice, e.g. whether the system should suspend to ram on lid close, whether to hibernate the system after the user being idle for 30 minutes and so on. In a multi-user setup (both fast user switching and multi-seat), this can break in various interesting ways unless the power management daemons cooperate. Also, there may be software running at the system level who will want to inhibit a desktop session power management daemon from suspending / shutting down.

  - System-level software that do not wish to be interrupted by the effect of someone calling into the `org.freedesktop.Hal.Device.SystemPowerManagement` interface MUST hold the `org.freedesktop.Hal.Device.SystemPowerManagement` lock non-exclusively on the root computer device object. For example, the YUM software updater should hold the lock when doing an RPM transaction.

  In addition, any power management session daemon instance

  - ... MUST hold the `org.freedesktop.Hal.Device.SystemPowerManagement` lock non-exclusively on the root computer device object unless it is prepared to call into this interface itself. This typically means that the PM daemon instance simply acquires the lock on start up and releases it just before it calls into the `org.freedesktop.Hal.Device.SystemPowerManagement` interface. In other words, the PM daemon instance needs to hold the lock exactly when it doesn't want other PM daemon instances to call into the `org.freedesktop.Hal.Device.SystemPowerManagement` interface. This means that if the user have configured the PM daemon instance to go to sleep after 30 minutes of inactivity, the lock should be released then.

  - ... MUST not hold the lock when the session is inactive (fast user switching) UNLESS an application in the session have explicitly called Inhibit() on the `org.freedesktop.PowerManagement` D-Bus session bus interface of the PM daemon.

  - ... MUST check that no other process is holding the lock (using the `IsLockedByOthers` method on the standard `org.freedesktop.Hal.Device` interface) before calling into the `org.freedesktop.Hal.Device.SystemPowerManagement` interface. If another process is holding the lock, it means that either 1) another session is not prepared to call into the `org.freedesktop.Hal.Device.SystemPowerManagement` interface; OR 2) some system-level software is holding the lock. The PM daemon instance MUST respect this by not calling into the `org.freedesktop.Hal.Device.SystemPowerManagement` interface itself.

  However, any Power management daemon instance

  - ... MAY prompt the user, if applicable, to ask if she still wants to perform the requested action (e.g. call into the `org.freedesktop.Hal.Device.SystemPowerManagement` interface) despite the fact that another process (possibly from another user) is indicating that it does not want the system to e.g. suspend. Only if the user agrees, the power management instance should call into the `org.freedesktop.Hal.Device.SystemPowerManagement` interface. Typically, it's only useful to prompt the user with such questions if the request to call into the `org.freedesktop.Hal.Device.SystemPowerManagement` interface originates from user input, e.g. either a hotkey, the user clicking a suspend button in the UI or an application invoking the `Suspend()` method on the `org.freedesktop.PowerManagement` D-Bus session interface of the PM daemon.

  - ... MAY ignore that other processes are holding the lock and call into the `org.freedesktop.Hal.Device.SystemPowerManagement` interface anyway, but ONLY if if the request to call into the `org.freedesktop.Hal.Device.SystemPowerManagement` interface originated from e.g. lid close, critically low battery or other similar conditions.

  - ... MAY still call `SetPowerSave()` on the `org.freedesktop.Hal.Device.SystemPowerManagement` interface even if other processes are holding the lock.