diff options
author | David Chisnall <dchisnall@pathscale.com> | 2011-11-24 17:17:26 +0000 |
---|---|---|
committer | David Chisnall <dchisnall@pathscale.com> | 2011-11-24 17:17:26 +0000 |
commit | 8931d9e5180830a5433d16ae6b3ad8dd9e629512 (patch) | |
tree | df0c27b502ea5e999dd6aee617dfc9e2f78317fd | |
parent | c7d66e279e31c0523bcb8bc5b1dd5c98260f0848 (diff) | |
download | libcxxrt-8931d9e5180830a5433d16ae6b3ad8dd9e629512.tar.gz libcxxrt-8931d9e5180830a5433d16ae6b3ad8dd9e629512.tar.bz2 libcxxrt-8931d9e5180830a5433d16ae6b3ad8dd9e629512.tar.xz |
Make all pthread symbols weak and test before calling any of them. This should allow us to work on platforms like GNU/Linux that don't export pthread stubs in libc.
-rw-r--r-- | src/exception.cc | 58 |
1 files changed, 51 insertions, 7 deletions
diff --git a/src/exception.cc b/src/exception.cc index 0896354..2da7454 100644 --- a/src/exception.cc +++ b/src/exception.cc @@ -8,6 +8,17 @@ #include "dwarf_eh.h" #include "cxxabi.h" +#pragma weak pthread_key_create +#pragma weak pthread_setspecific +#pragma weak pthread_getspecific +#pragma weak pthread_once +#pragma weak pthread_once +#pragma weak pthread_cond_signal +#pragma weak pthread_cond_wait +#pragma weak pthread_mutex_lock +#pragma weak pthread_mutex_unlock + + using namespace ABI_NAMESPACE; /** @@ -303,6 +314,13 @@ static __cxa_thread_info singleThreadInfo; */ static void init_key(void) { + if ((0 == pthread_key_create) || + (0 == pthread_setspecific) || + (0 == pthread_getspecific)) + { + fakeTLS = true; + return; + } pthread_key_create(&eh_key, thread_cleanup); pthread_setspecific(eh_key, (void*)0x42); fakeTLS = (pthread_getspecific(eh_key) != (void*)0x42); @@ -314,7 +332,7 @@ static void init_key(void) */ static __cxa_thread_info *thread_info() { - if (pthread_once(&once_control, init_key)) + if ((0 == pthread_once) || pthread_once(&once_control, init_key)) { fakeTLS = true; } @@ -385,7 +403,10 @@ static char *emergency_malloc(size_t size) // Only 4 emergency buffers allowed per thread! if (info->emergencyBuffersHeld > 3) { return 0; } - pthread_mutex_lock(&emergency_malloc_lock); + if (pthread_mutex_lock) + { + pthread_mutex_lock(&emergency_malloc_lock); + } int buffer = -1; while (buffer < 0) { @@ -396,7 +417,10 @@ static char *emergency_malloc(size_t size) void *m = calloc(1, size); if (0 != m) { - pthread_mutex_unlock(&emergency_malloc_lock); + if (pthread_mutex_unlock) + { + pthread_mutex_unlock(&emergency_malloc_lock); + } return (char*)m; } for (int i=0 ; i<16 ; i++) @@ -413,10 +437,24 @@ static char *emergency_malloc(size_t size) // of the emergency buffers. if (buffer < 0) { + // If we don't have pthread_cond_wait, then there is only one + // thread and it's already used all of the emergency buffers, so we + // have no alternative but to die. Calling abort() instead of + // terminate, because terminate can throw exceptions, which can + // bring us back here and infinite loop. + if (!pthread_cond_wait) + { + fputs("Terminating while out of memory trying to throw an exception", + stderr); + abort(); + } pthread_cond_wait(&emergency_malloc_wait, &emergency_malloc_lock); } } - pthread_mutex_unlock(&emergency_malloc_lock); + if (pthread_mutex_unlock) + { + pthread_mutex_unlock(&emergency_malloc_lock); + } info->emergencyBuffersHeld++; return emergency_buffer + (1024 * buffer); } @@ -449,13 +487,19 @@ static void emergency_malloc_free(char *ptr) memset((void*)ptr, 0, 1024); // Signal the condition variable to wake up any threads that are blocking // waiting for some space in the emergency buffer - pthread_mutex_lock(&emergency_malloc_lock); + if (pthread_mutex_lock) + { + pthread_mutex_lock(&emergency_malloc_lock); + } // In theory, we don't need to do this with the lock held. In practice, // our array of bools will probably be updated using 32-bit or 64-bit // memory operations, so this update may clobber adjacent values. buffer_allocated[buffer] = false; - pthread_cond_signal(&emergency_malloc_wait); - pthread_mutex_unlock(&emergency_malloc_lock); + if (pthread_cond_signal && pthread_mutex_unlock) + { + pthread_cond_signal(&emergency_malloc_wait); + pthread_mutex_unlock(&emergency_malloc_lock); + } } static char *alloc_or_die(size_t size) |