From 8931d9e5180830a5433d16ae6b3ad8dd9e629512 Mon Sep 17 00:00:00 2001 From: David Chisnall Date: Thu, 24 Nov 2011 17:17:26 +0000 Subject: 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. --- src/exception.cc | 58 +++++++++++++++++++++++++++++++++++++++++++++++++------- 1 file changed, 51 insertions(+), 7 deletions(-) (limited to 'src/exception.cc') 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) -- cgit v1.2.3