[gnutls-dev] Re: living without global variables

Bryan Henderson bryanh at giraffe-data.com
Mon Dec 26 20:45:18 CET 2005


>The variables are used by code that has to parse X.509 certificates or
>other PKCS structures.

Now I'm starting to wonder just how constant this information is (I'm
talking about the information now, not the program variables that
represent it).  We know it's constant for the life of a program, but
is it constant for all programs?  I.e. could it conceivably be
generated at library build time and loaded whole by the
program/library loader?

>> There are only two methods I've seen to make a stateful library thread-safe:
>
>There is another popular approach:
>
>3) Declare functions thread-unsafe, 

I hate to be pedantic (well, not really), but (3) is not an _approach_
to making a library thread-safe; it's a _retreat_.

>4) Store the global variables in thread-local storage.  There is a
>   gnulib module that works with pthread, pth, solaris threads and
>   win32 threads to do this.

Thanks; I forgot that one.  I've only ever seen it in libc, probably
because of the portability difficulty.

>Here is another solution for removing the global variables without
>changing any APIs [1]: replace all uses of the global variable with a
>function call to a function that generate a local copy of the ASN.1
>structures.  This will be slower, but would work.

It _sounds_ impractically slow.  But then I don't know enough about the
code to know.

>Simply have all libraries using GnuTLS call gnutls_global_init() in a
>thread-unsafe initialization function, ultimately mutex synchronized
>by the application.

That initialization function (call it foo_global_init()) is more than
thread-unsafe.  Thread-unsafe means you can't call foo_global_init()
simultaneously from two threads.  But foo_global_init() not only can't
be called while another thread is calling it, but also not while
another thread is running at all.  Because that thread might be
calling gnutls_global_init() via something other than
foo_global_init().

But I guess this is probably the way to go, considering how much
easier it is to implement.  The paradigm is that the global
initialization/termination must propagate through all the libraries up
to the main program initialization code where the program is a single
thread.  The object oriented libraries are a little less object
oriented, since you can't just haul off and create an object whenever
you want (you have to think about the global state), but it's a whole
lot less coding.  And I guess the program can't dynamically load any
of these libraries.

I note that even removing global variables from GnuTLS and libgcrypt
just begins to solve my problem, because libcurl also uses 4 other
libraries, in various environments, that have the same global
initialization requirement.  But the single-threaded reference-counted
global init thing can work for all of them.

>[1] Changing APIs is really bad, that is why I'm having trouble with
>your proposed approach.

I thought I cleared this up before, but here it is again, so I guess
not.  Is it your opinion that changing an API by adding optional
functions to it is really bad?  That's what I proposed.  In contrast,
the "really bad" change to an API most people mean is doing something
that makes programs that use the existing API have to change.

-- 
Bryan Henderson                                    Phone 408-621-2000
San Jose, California



More information about the Gnutls-dev mailing list