Hi!

On Thu, 2011-05-19 at 12:26:56 +0300, Lasse Collin wrote:
> On 2011-05-19 Jonathan Nieder wrote:
> > (One reasonable answer might be "yes, such a person can
> > read the documentation and figure out what happened from the error
> > numbers, and at least they won't be worse off than they started."  If
> > it proves to be annoying, it's possible to introduce _r variants that
> > return the error message through a parameter later.)
> 
> It's possible that I will do something like this as the only method. 
> With functions that use lzma_stream, the message can be stored there. 
> For some other functions, a method to pass a pointer to a buffer to hold 
> the message may be needed.

Adding the _r (or _e for error or whatever) counterparts seems like the
most portable solution (with the C/POSIX restictions you mention), at
the cost of API bloat (as we discussed on IRC), and probably more code
churn? The normal functions could then be made to be tiny shims just
passing NULL as the error argument.

Passing just a pointer to a buffer might be problematic due to the
size being unknown to the caller, so ideally it should be a pointer to
pointer to buffer, and the function allocating the message or assigning
from a static string table, or a pointer to an int (or some other
integral type) to just assign an extended lzma_ret code.

> > C1X has[1] a _Thread_local keyword that might work well.  So in a
> > decade or so a person will be able to write
> > 
> >     _Thread_local const char *lzma_error_message;
> > 
> > and rely on compilers setting up the appropriate constructors and
> > destructors behind the scenes.  Today, GCC has[2] __thread and
> > Microsoft C has[3] __declspec(thread).
> > 
> > I haven't played around with it much, but maybe that can help.
> 
> It can help when the new standard has been out for a few years. Before 
> that, I cannot rely on GNU C extensions. Currently the code can be 
> compiled with several compilers, and that's how I want it to be in the 
> future too. The current portable method for thread-specific data is 
> pthread_key_create().

I'd add the TLS storage class specifier as an option, as it seems to be
suported by quite a few compilers, it obviously depends on which ones
you want to support currently. It seems (from [0] and [1]) at least
these compilers support something like __thread or __declspec(thread):

  * Borland C++ Builder
  * Digital Mars C/C++
  * GNU C/C++
  * HP Tru64 UNIX C/C++
  * IBM XL C/C++
  * Intel C/C++
  * Sun Studio C/C++
  * Visual C++

[0] <http://en.wikipedia.org/wiki/Thread-local_storage>
[1] <http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2006/n1966.html>

> My current understanding of the interactions of pthread_key_create() and 
> dlclose():
> 
>   - With C++ I could use a global object whose destructor is run
>     when the library is unloaded with dlclose(). The destructor
>     would free the thread-specific data and call pthread_key_delete().

Barring usage of TLS storage class specifier (and the C restriction),
this one seems pretty clean, and should not add a run-time dependency
on libstdc++ (or equivalent).

>   - Non-portable operating system, C compiler, or linker extensions
>     would make it possible to have a destructor function that is
>     called when the library is unloaded.

>   - I could require that developers call some initiazation and
>     destruction functions when they start and stop using the
>     library. This would be annoying and it's easy to forget to
>     call the destructor.

I agree this would be rather annoying and error prone.

>   - If the library is never unloaded with dlclose(), then there
>     is no problem with pthread_key_create(). This isn't an
>     acceptable limitation for liblzma.

Well, pthread_key_create() allows to provide a destructor function, so
as long as that function is not part of liblzma (free(3)), then it can
do proper cleanup once the thread terminates, ragardless of liblzma
having been unloaded. This still might leak, but then if liblzma would
allocate an int or a small struct with only integrals, then that “leak”
would be once per thread and rather small, say less than 24 bytes? And
only for things dlopening liblzma (supposedly through a plugin or
similar). So it does not seem unaccetable to me.

This would need a new extended lzma_ret error code enumeration, which
could map to error strings. It would have the disadvantage of maybe
being less flexlible when dealing with error strings, though.

> In short, if one wants to only use C code and functionality provided by 
> POSIX.1-2008, it's not possible to use thread-specific data in a shared 
> library without restricting or complicating the use of that library. I'm 
> happy if someone will show that I'm wrong.

While that's strictly true, I think it's more a matter of to what
extent you are willing to compromise. For example the solution that
could leak an int would seem pretty acceptable to me.

regards,
guillem

Reply via email to