race-condition using AddMatch
David Zeuthen
david at fubar.dk
Tue Jun 21 11:43:38 PDT 2005
Hi,
So, one very common pattern using D-BUS is that some service manages a
number of object and normally there's an object with a well-known path
where you can query for other objects. Specifically (cause it's much
more simple to explain the problem in concrete terms), HAL uses this
pattern; we export
/org/freedesktop/Hal/Manager
with an interface org.freedesktop.Hal.Manager. This interface offers
methods for finding other objects as well as asynchronous signals for
DeviceAdded(), DeviceRemoved() etc. Each object has a path
/org/freedesktop/Hal/devices/<some_unique_id>
and implements (at least) the org.freedesktop.Hal.Device interface. Now,
this interface emits signals that users care about so they normally
write code like this (pseudo-code)
void hal_manager_handle_device_added (String newobj_path)
{
bus.AddMatch (interface="org.freedesktop.Hal.Device",
path=newobj_path,
signal="*",
callback=hal_device_handle_signal)
}
void main()
{
bus.AddMatch (interface="org.freedesktop.Hal.Manager",
path="/org/freedesktop/Hal/Manager",
signal="DeviceAdded",
callback=hal_manager_handle_device_added)
...
}
Now, the call sequence sort of looks like this
o.fd.Hal system-bus client
| DeviceAdded | |
|- - - - - - - - - - >| DeviceAdded |
| |- - - - - - - - - >|
| | |--> hal_manager_handle_device_added
| | |
| | |
|signal A on obj_path | |
|- - - - - - - - - - >| |
| |AddMatch(obj_path) |
| |<------------------|
| | |
| | AddMatch OK |
| |------------------>|
|signal B on obj_path | |
|- - - - - - - - - - >| |
| |- - - - - - - - - >|
| | |--> hal_device_handle_signal
| | |
where we evidently lose signal A because we haven't yet subscribed to
any signals. Is this the intended behavior of the bus?
It's not exactly bad behavior as mostly all signals on HAL represent a
state change (e.g. disk mount/umount) and the _device_added signal
handler should query that state (e.g. is disk mounted) after AddMatch()
succeeds.
However. We do have signals in HAL where it doesn't make sense to
provide the corresponding getState() method, e.g. we send a signal when
the user presses e.g. the Power Button on the laptop.
But there are more interesting examples of where this fails.
Consider a service streaming video through signals. We could argue (and
frankly, I'm all for that) that this is not what D-BUS is for (indeed,
the service should just offer direct sessions to the users instead) but
I think this is something that should go in the FAQ / developers guide.
Mostly because lots of people are going to make this mistake and assume
they get all signals when they don't (e.g. we lose signal A above).
Here's another approach: Should we queue all signals until we the bus
gets a receipt that the signal handler for a service has run? That's one
possible solution to this problem.
David
More information about the dbus
mailing list