summaryrefslogtreecommitdiff
path: root/doc/spec/hal-spec-locking.xml
blob: 7306dbb5c858c13849841c5bf7e466d41d68a427 (plain)
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
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE chapter PUBLIC "-//OASIS//DTD DocBook XML V4.1.2//EN" "http://www.oasis-open.org/docbook/xml/4.1.2/docbookx.dtd">

<chapter id="locking">
  <title>Locking</title>

  <para>
    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.
  </para>

  <para>
    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.
  </para>

  <sect1 id="locking-overview">
    <title>Overview</title>
    <para>
      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. 
    </para>
    <para>
      The former is achieved by using
      the <literal>AcquireInterfaceLock()</literal>
      and <literal>ReleaseInterfaceLock()</literal> methods on
      the <literal>org.freedesktop.Hal.Device</literal> interface that
      every device object implements (see
      <xref linkend="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 <literal>org.freedesktop.Hal.Device.InterfaceLocked</literal>
      exception if they attempt to invoke a method on the given
      interface on the given device. The locker can specify whether
      the lock is <emphasis>exclusive</emphasis> 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 <literal>org.freedesktop.Hal.PermissionDenied</literal>
      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 <literal>InterfaceLockReleased</literal>
      signal.
    </para>

    <para>
      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.
    </para>

    <para>
      If another client already holds a lock exclusively, attempts
      from other clients to acquire the lock will fail with
      the <literal>org.freedesktop.Hal.Device.InterfaceAlreadyLocked</literal>
      exception even if they have access to the device.
    </para>
    
    <para>
      In addition, a client may opt to lock all devices that he got
      access to by using
      the <literal>AcquireGlobalInterfaceLock()</literal>
      and <literal>ReleaseGlobalInterfaceLock()</literal> methods on
      the <literal>org.freedesktop.Hal.Manager</literal> interface on
      the <literal>/org/freedesktop/Hal/Manager</literal> object (see
      <xref linkend="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.
    </para>

    <para>
      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,
    </para>

    <orderedlist>
      <listitem> 
	<para>
          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
        </para>
      </listitem>
      <listitem>
        <para>
          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.
        </para>
      </listitem>
    </orderedlist>

    <para>
      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.
    </para>

    <para>
      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 <xref linkend="interfaces"/>.
    </para>

    <para>
      If a process holding locks disconnects from the system bus, the
      locks being held by that process will be released.
    </para>
  </sect1>

  <sect1 id="locking-guidelines">
    <title>Guidelines</title>
    <para>
      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.
    </para>

    <itemizedlist>
      <listitem><para>
          <emphasis>Disk Management / Partitioning</emphasis>
        </para>
        <para>
          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 <literal>org.freedesktop.Hal.Device.Storage</literal>
          lock on each drive being processed; or b) obtaintaing the
          global
          <literal>org.freedesktop.Hal.Device.Storage</literal>
          lock. This includes programs like fdisk, gparted, parted and
          operating system installers. See also
          <xref linkend="interface-device-volume"/> and
          the <literal>hal-lock</literal>(1) program and manual page.
        </para>
      </listitem>

      <listitem><para>
          <emphasis>Power Management</emphasis>
        </para>
        <para>
          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.
        </para>

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

        <para>
          In addition, any power management session daemon instance
        </para>

        <itemizedlist>
          <listitem>
            <para>
              ... MUST hold the <literal>org.freedesktop.Hal.Device.SystemPowerManagement</literal> 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 <literal>org.freedesktop.Hal.Device.SystemPowerManagement</literal>
              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 <literal>org.freedesktop.Hal.Device.SystemPowerManagement</literal> 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.
            </para>
          </listitem>

          <listitem>
            <para>
              ... 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 <literal>org.freedesktop.PowerManagement</literal>
              D-Bus session bus interface of the PM daemon.
            </para>
          </listitem>

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

        </itemizedlist>
        <para>
          However, any Power management daemon instance
        </para>
        <itemizedlist>

          <listitem>
            <para>
              ... MAY prompt the user, if applicable, to ask if she
              still wants to perform the requested action (e.g. call
              into
              the <literal>org.freedesktop.Hal.Device.SystemPowerManagement</literal>
              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 <literal>org.freedesktop.Hal.Device.SystemPowerManagement</literal>
              interface. Typically, it's only useful to prompt the
              user with such questions if the request to call into
              the <literal>org.freedesktop.Hal.Device.SystemPowerManagement</literal>
              interface originates from user input, e.g. either a
              hotkey, the user clicking a suspend button in the UI or
              an application invoking the <literal>Suspend()</literal> method on the 
              <literal>org.freedesktop.PowerManagement</literal> D-Bus
              session interface of the PM daemon.
            </para>
          </listitem>

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

          <listitem>
            <para>
              ... MAY still call <literal>SetPowerSave()</literal> on
              the <literal>org.freedesktop.Hal.Device.SystemPowerManagement</literal>
              interface even if other processes are holding the lock.
            </para>
          </listitem>
        </itemizedlist>
      </listitem>
      
    </itemizedlist>

  </sect1>

</chapter>