GPGME CVS branched

Marcus Brinkmann marcus.brinkmann at ruhr-uni-bochum.de
Thu Dec 16 22:08:12 CET 2004


At Sun, 12 Dec 2004 18:44:14 +0100,
Simon Josefsson <jas at extundo.com> wrote:
> Marcus Brinkmann <marcus.brinkmann at ruhr-uni-bochum.de> writes:
> I find that requiring threaded applications to provide thread hooks
> into libraries is problematic.  The most common situation where a this
> causes problems is when a threaded application uses one library that
> in turn uses gcrypt/gpgme.

This is in fact exactly the situation that required us to take the
hook approach.

We have done extensive analysis of this problem, and we have seen what
happened to our other attempts at solving this.  And we have tried
everything we could think of: magic support via weak symbols,
different versions of the same library a la foo-threadpackage, and the
hooks.  We have also looked at how other projects solve this, and have
not seen anything better elsewhere.  There is no perfect approach for
this problem, it's impossible.  The goals are conflicting (support for
several thread libraries, portability to many platforms, supporting
mixed library environments).  So the best we can do is to be flexible
and make the problem obvious in whatever ways we can.

You can find an extensive defense of our approach in the gcrypt
mailing list:

http://lists.gnupg.org/pipermail/gcrypt-devel/2004-March/000566.html

> The middle-library does not need thread
> hooks, so it does not provide any functions for the application to set
> them, 

This is wrong, as gcrypt is not thread safe without setting the hooks.
Thus, by transfer, the middle-layer library is not thread safe either.
In this sense, gcrypt "infects" the middle layer with non-thread-safeness.

> and consequently does not set them any thread hooks in gcrypt.

It should export an interface to the user to do so (assuming that the
fact that gcrypt is used should be hidden).

> The application may use several libraries that look like this (e.g.,
> gnutls and gsasl), so gcrypt may end up being invoked in multiple
> threads with no thread hooks.

A good part of my analysis is dedicated to this situation.  It is
awkward, but solvable by allowing multiple initialization and error
out if different/incompatible thread configurations are selected.

> Requiring the application to be notice that gnutls/gsasl uses gcrypt,
> and have the application call the thread hooks in gcrypt, destroy
> abstraction layers.

I always found it a mistake by the gnutls developer to let the user of
gnutls call a gcrypt function directly.  I advised him to wrap the
interface.

Apart from that, the current design (using hooks) was suggested by the
gnutls maintainer itself, and agreed to.
 
> Forcing all libraries that use gcrypt to also provide thread hooks
> also does not look like a scalable solution to me.  In a big
> application, different parts may use different thread implementations.
> E.g., the top-level application might use Pth, but some lower-level
> library can be written for the specific platform, and could use POSIX
> threads, or even NPTL.

Have you actually tried mixing thread libraries?  I have never seen
such a configuration work.  You have a bunch of other problems (I mean
really severe problems) before you can even think about gcrypt.

Anybody trying to achieve such a configuration will have so much work
to do, that adapting gcrypt to such an environment will mean nothing
to them.  We are making reasonable assumptions here.

And then, how would such a mix of thread implementations work?  You
would _have_ to use interface hooks, and not only at the library
level, but at the per-object level (and allow only object interaction
among objects configured with the same hooks).  Really, we are way,
way beyond anything seemingly reasonable here (or even beyond anything
that people seem to want and actually do).

> I reviewed all uses of thread hooks in libgcrypt (a lot!), and to me
> all of the uses could be avoided by choosing a simpler design.
> Compare Nettle.  Perhaps the only exception I could find was
> randomness gathering, but then again I think that is such a critical
> function that the complexity of thread interaction should be avoided
> at all.

Well, once you have mutex support, it doesn't hurt to use it when it
comes in useful.  So, unless you can eliminate all uses, it doesn't
make sense to talk about eliminating some of them.

Of course there are alternative approaches possible.  But they come at
a cost, too, and it is always a trade-off.  Personally, I would have
designed some of the gcrypt interfaces differently myself, but that's
a different story.  I am not sure I would opt for a design that does
not require any mutual exclusion, but then, we have not even said
explicitely how such a design in the context of gcrypt may look, so
it's a moot point.

We constantly revise our design and look what we can do, with the
given limits (portability, backwards compatibility, feature
completeness, ease of use, etc).  And in fact I just did some work on
GPGME which got rid of some mutual exclusion, and I did not hesitate
to take advantage of that.  This is also an invitation to make
specific suggestions, patches preferred ;)

> I wish there were a paper that collected common wisdom about writing
> libraries that are used in multi-threaded applications, but I haven't
> seen any that discuss these issues in any detail.  I'm imagining
> something like Ulrich Drepper's excellent paper about writing and
> maintaining shared libraries.

Well, I'd love to just have pthread support in every single
application (ie, drop the distinction between single- and
multi-threadedness), and build on that.  However, the world does not
agree, and we have to compromise.  And considering that the semantics
of multi-threaded programs are not particularly clear (just check out
the POSIX signal semantics, or what happens at fork()), there is good
reason to be cautious.

Thanks,
Marcus




More information about the Gnupg-devel mailing list