When is a watch added/removed?

Simon McVittie smcv at collabora.com
Mon Jul 22 11:54:18 UTC 2019


On Sat, 20 Jul 2019 at 10:14:48 +0200, David Henningsson wrote:
> *dbus_connection_set_watch_functions* takes functions to add, remove and
> toggle watches. I understand toggling watches can happen if read/write
> buffers become full or empty, but are "add" and "remove" callbacks ever
> called from anything else than dbus_connection_set_watch_functions itself?

There is no API guarantee that libdbus will not add and remove watches
under other circumstances. If you rely on watches only being added and
removed from dbus_connection_set_watch_functions(), and your binding
breaks with a future libdbus release, then I don't think we would consider
that to be a bug in the future libdbus release.

(Implementation detail: all current transports use a single socket. There
is no API guarantee that there will not be a transport invented in future
that uses multiple sockets, or doesn't use sockets at all.)

> According to the documentation, a watch should not be added to the main loop
> at all if it is not enabled, but is this really true - would it not make
> sense to keep monitoring that fd for errors/hup/etc even though the watch is
> disabled (because of filled/empty buffers)?

If libdbus isn't in a suitable state to read in-band data from the socket,
it probably also isn't in a suitable state to read an error or a hangup
condition from the socket (which result in it synthesizing a message
representing end-of-stream). Those conditions should be delivered when
libdbus is ready for them, at which point it re-enables the watch.

The fact that libdbus is main-loop-agnostic is one of its design
problems, resulting from its triple role as the reference implementation,
the implementation used in production by the reference dbus-daemon,
and the implementation used in production by language bindings and
applications. If it used a specific main loop (for example GLib, libevent
or libuv) then we would be able to reason about the API guarantees of
that main loop. However, that would be a backwards-incompatible change
for language bindings and applications, so we're stuck with the current
situation, where all main loop providers have to tread carefully.

The design of libdbus' main loop abstraction also suffers from the fact
that it is portable to non-Unix OSs where sockets and fds work rather
differently (namely Windows), and portable to older Unix kernels where
we can't rely on recent kernel APIs (as opposed to targeting only Linux
with epoll, like sd-bus does, or targeting only Linux with epoll and
*BSD OSs with kqueue, or some similarly higher baseline).

You might find it more appealing to wrap systemd's sd-bus (Linux-specific,
low-level, each connection can only be used by a single thread,
has a simpler/lower-level main loop abstraction based on epoll) or GLib's
GDBus (portable, high- and low-level APIs available, designed to be
thread-safe, more elaborate/higher-level main loop abstraction, but has
heavier dependencies than sd-bus or libdbus).

    smcv


More information about the dbus mailing list