Re: Design hole in nptl (and more general in POSIX threads)
Jim Blandy <[email protected]> 19 Dec 2003 21:45:37 -0500
| Newsgroups | gmane.comp.lib.phil |
|---|---|
| Message-ID | <[email protected]> |
DragiĹĄa DuriÄ <[email protected]> writes: > What bothers me now is... What procedures in pthread API are async > safe? Boehm GC uses pthread_self(), as probably you too are using. Is it > safe to use pthread_key_getspecific()? At the end of section 2.4 of the POSIX System Interfaces spec, it lists all the functions that are async-safe. Not a single pthread_* function is async-safe. Boehm does call pthread_self, which is thus not kosher. (But in some sense, the Boehm GC is all about taking advantage of non-guaranteed behavior, as carefully as possible, and getting surprising results.) It's my intent for my code uses only promised behavior of POSIX and ISO C facilities. Where I need things they don't give me, I try to use explicitly supplied compiler- or architecture-specific things, like mn__arch_memory_barrier and mn__arch_code_modified. Instead of calling pthread_self, I have a struct for each thread, declared with the __thread storage qualifier (which I'm calling mn__per_thread in my code). Using __thread variables is async-safe. I also have a pthreads thread-specific value that points to that struct. This sounds redundant, but here's the rationale: /* This is kind of dumb, but we need both 'thread_self' and 'thread_self_key': - We need to access our 'struct thread' from gc_pause_signal's handler. pthread_getspecific isn't async-safe, but mn__per_thread is. - We need to remove this thread from the global thread list when it dies. You can't define destructor functions for mn__per_thread objects, but you can for thread-specific values. Boehm has a hash table mapping pthread_t values onto his thread structures, and he knows the hash table isn't being modified while he's stopping threads, so his signal handler just calls pthread_self (which isn't officially async-signal-safe, but geez) and looks itself up. Maybe we should do that, too. */ /* A 'struct thread' instance for each thread. */ static mn__per_thread struct thread thread_self; /* A thread-specific value pointing to thread_self. */ static pthread_key_t thread_self_key;