best practice proposal: name locking and process exclusion

Colin Walters walters at verbum.org
Thu Apr 7 09:43:34 PDT 2011


So one of the things I've always said about DBus that it provides for
the operating system is a reliable means for loose binding between
components, in the form of well-known bus names like
org.freedesktop.NetworkManager.

Claiming a name serves multiple purposes:
* Acts as a "process exclusion" mechanism, to avoid multiple processes
in your component or app when not wanted (think in a classic GNOME 2
desktop, where Firefox has to go out of its way to make clicking on
the Firefox launcher multiple times work).
* Allows other components or apps to communicate with you

The tension between these two is simply that for the first property,
you want to claim the bus name *early*, before you start loading
resource files and the like.  For the latter, you really only want to
claim the bus name when your process is fully ready to respond to
requests.

See:
https://bugzilla.gnome.org/show_bug.cgi?id=640714
https://bugzilla.gnome.org/show_bug.cgi?id=645736

What I'd like to propose is simply a best practice for components and
apps acting as services: use two names:  org.example.Foo.Lock for the
first, and org.example.Foo for your well-known name.

So the pseudocode for this would look like:

main() {
  result = request_name (MYAPP_NAME ".Lock")
  if (result == -1)
    fatal ();
  if (!(result == PRIMARY_OWNER || result == ALREADY_OWNER))
    exit (0);

  if (check_name_has_owner (MYAPP_NAME))
    exit (0);

  /* Initialize application resources, create X windows, load SVGs,
open SQLite database, whatever */

  result = request_name (MYAPP_NAME);
  if (result == -1)
    fatal ();
  if (!(result == PRIMARY_OWNER || result == ALREADY_OWNER))
    exit (0);

  /* Not strictly necessary, but nice to avoid polluting d-feet etc. */
  release_name (MYAPP_NAME ".Lock");
}

This would require two additional round trips to the bus at startup,
but that's not a very large cost.

If you're using a mainloop, we could actually wrap this up (well, in
GLib), with a nice API like:

  g_dbus_acquire_exclusive_service_name (MYAPP_NAME);

Under the covers, this would do the first part, and then queue the
second part as a high-priority idle so it runs immediately after your
app is done initializing inside main().

Now there are other potential solutions to process exclusion - for
system services, you can also use a lockfile in /run say.  But this
solution avoids creating files, which is nice (we don't want to create
unnecessary writes - think relatime and flash devices).

Thoughts?


More information about the dbus mailing list