From: VMware, Inc <> Date: Wed, 18 Sep 2013 03:16:56 +0000 (-0700) Subject: Remove fake pthreads X-Git-Tag: 2013.09.16-1328054~103 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=227a637742a06ce2155ed14a60d2d31ce772bc90;p=thirdparty%2Fopen-vm-tools.git Remove fake pthreads A while ago, we decided to always compile with pthreads; optimizing for single-threaded programs no longer makes sense. Which means vthreadBase.c can get cleaned up. (Notice that this implements the "best thing to do" comment on lines 195-6). Signed-off-by: Dmitry Torokhov --- diff --git a/open-vm-tools/lib/misc/vthreadBase.c b/open-vm-tools/lib/misc/vthreadBase.c index c4c309769..84964a7e1 100644 --- a/open-vm-tools/lib/misc/vthreadBase.c +++ b/open-vm-tools/lib/misc/vthreadBase.c @@ -61,20 +61,10 @@ * threads. If lib/thread is used on top of this library, the lib/thread * NoID function may introduce a smaller limit. * - * On Windows and Mac, there is no way to compile single-threaded, - * so just make all the multi-threaded calls. - * - * On Linux, use some more complex logic to operate in two modes: - * - if _REENTRANT is defined (or implied by -pthread), link - * directly to all multithreaded symbols. - * - otherwise, compile in fake-pthread functions and choose at - * runtime whether to use them, depending on if pthreads are loaded. + * On Windows and Mac, native OS TLS support is available. + * On Linux, require pthreads. (Generally this implies -pthread and _REENTRANT) */ -#if defined __linux__ && !defined _REENTRANT -# define FAKE_PTHREADS -#endif - #if defined _WIN32 # include #else @@ -149,183 +139,6 @@ static struct { }; -#if defined FAKE_PTHREADS -/* - * glibc can either be used with pthreads or without. - * - * Nominally, glibc-without-pthreads is useful in cases like embedded systems - * where the overhead of libpthread (in terms of memory or CPU time) is not - * justified. Unfortunately for us, ESX userworlds are close enough to - * embedded systems that it's easier to navigate the pain than argue in favor - * of linking extraneous libraries. (Eventually, we should just link.) - * - * A quick run-through of all the different ways to run a Linux program: - * - * Compile with -pthread: (best, but uncommon) - * Compiler passes -pthread to gcc, which implicitly defines _REENTRANT. - * If this constant is defined, it is OK to link directly to all pthread - * symbols: the program is known multithreaded at compile-time. We will - * also accept somebody passing -D_REENTRANT as an indication they know - * what they are doing and want compile-time threading support. - * - * Compile without -pthread, link with -lpthread (common) - * Running multi-threaded, but this cannot be distinguised from running - * single-threaded without peeking into the dynamic linker. - * at run-time. - * - * Compile without -pthread, link without -lpthread, dlopen("libpthread.so") - * This is broken. libc starts using a simplified pthread implementation, - * then the dynamic load changes the implementation mid-stream. Any locks - * created before the dynamic open are thus unsafe. DO NOT DO THIS. - * - * Compile without -pthread, link without -lpthread, no dlopen() (common) - * Running single-threaded. - * - * - * After much experimentation, the only sane way to construct VThreadBase is - * with weak symbols, and require a ((sym != NULL) ? pthread_sym : fake_sym) - * construct for all pthread symbols used herein. This approach has two - * downsides: - * - extra branch on all TLS lookups (though easily predicted) - * - some compilers (gcc-4.1.0, gcc-4.1.1) have a buggy weak-symbol - * optimizer. - * Both of these downsides can be avoided by passing -D_REENTRANT to - * the compilation of this environment and supplying -lpthread at link time. - * - * Rejected approaches: - * - use dl_xxx to detect libpthread and link at runtime. This adds a libdl - * dependency that is as bad as the libpthread dependency in the first place. - * - use __libc_dlxxx@_GLIBC_PRIVATE symbols to detect libpthread and link - * at runtime. This works; however, 'rpm' refuses to package binaries - * with @_GLIBC_PRIVATE symbols and so builds break. - * - use a fake TLS backed by a locked hash table. Unfortunately, - * pthread_mutex_lock isn't async-signal-safe and we do read TLS within - * our signal handlers. (Oddly enough, pthread_getspecific is not marked - * as async-signal-safe either, but it happens to work fine.) - * - use a fake TLS backed by an atomic hash table. Alas, our atomic - * hash tables are insert-only, which causes a memory leak even if threads - * exit cleanly. - * - * If anything here ever breaks, the best thing to do is simply admit that - * this is the 21st century and always compile with -pthread. - */ - -#if defined __GNUC__ -/* gcc-4.1.0 and gcc-4.1.1 have buggy weak-symbol optimization. */ -# if __GNUC__ == 4 && __GNUC_MINOR__ == 1 && \ - (__GNUC_PATCHLEVEL__ == 0 || __GNUC_PATCHLEVEL__ == 1) -# error Cannot build VThreadBase with weak symbols: buggy gcc version -# endif -#endif - -extern int pthread_key_create(pthread_key_t *key, void (*destr_function)(void *)) - __attribute__ ((weak)); -extern int pthread_key_delete(pthread_key_t key) - __attribute__ ((weak)); -extern int pthread_setspecific(pthread_key_t key, const void *pointer) - __attribute__ ((weak)); -extern void * pthread_getspecific(pthread_key_t key) - __attribute__ ((weak)); -extern int pthread_sigmask(int how, const sigset_t *newmask, sigset_t *oldmask) - __attribute__ ((weak)); - - -static const pthread_key_t nothreadTLSKey = 0x12345; /* Chosen to be obvious */ -static void *nothreadTLSData; - -/* - *----------------------------------------------------------------------------- - * - * fake_key_create -- - * fake_key_delete -- - * fake_setspecific -- - * fake_getspecific -- - * fake_sigmask -- - * - * Trivial implementations of equivalent pthread functions, to be used - * when the weak pthread_xxx symbols are not defined (e.g. when - * libpthread.so is not loaded). - * - * These versions always succeed and are hard-coded to assume one thread. - * - * NOTE: These functions will not work if libpthread is dlopen()ed. - * That said, any pthread functions (like pthread_mutex_lock) also - * will not work, so we have lost nothing. - * - * Results: - * See pthread_xxx; these versions always succeed. - * - * Side effects: - * See pthread_xxx. - * - *----------------------------------------------------------------------------- - */ - -static int -fake_key_create(pthread_key_t *key, - void (*destr_function)(void *)) -{ - *key = nothreadTLSKey; - return 0; -} - -static int -fake_key_delete(pthread_key_t key) -{ - /* - * fake_key_delete will not be called if there are no threads because: - * - fake_key_create does not fail with no threads - * - single threads cannot race with themselves in VThreadBaseGetKey - * (a race requires deleting extra keys) - */ - NOT_REACHED(); -} - -static int -fake_setspecific(pthread_key_t key, - const void *pointer) -{ - ASSERT(key == nothreadTLSKey); - ASSERT(Atomic_Read(&vthreadBaseGlobals.numThreads) <= 1); - nothreadTLSData = (void *)pointer; - return 0; -} - -static void * -fake_getspecific(pthread_key_t key) -{ - ASSERT(key == nothreadTLSKey); - ASSERT(Atomic_Read(&vthreadBaseGlobals.numThreads) <= 1); - return nothreadTLSData; -} - -static int -fake_sigmask(int how, const sigset_t *newmask, sigset_t *oldmask) -{ - /* - * Verified against glibc sources: pthread_sigmask and sigprocmask - * use the same implementation for any kernel that supports - * the rt_sigprocmask syscall (and all kernels we support do). - */ - return sigprocmask(how, newmask, oldmask); -} - - -/* - * Replace all pthread_xxx calls with a runtime choice. This - * code is not quite optimal; if perfection is necessary, - * compile with -D_REENTRANT to link directly to pthreads. - */ -#define WRAP_WEAK(_fn) \ - ((pthread_##_fn != NULL) ? pthread_##_fn : fake_##_fn) -#define pthread_key_create WRAP_WEAK(key_create) -#define pthread_key_delete WRAP_WEAK(key_delete) -#define pthread_getspecific WRAP_WEAK(getspecific) -#define pthread_setspecific WRAP_WEAK(setspecific) -#define pthread_sigmask WRAP_WEAK(sigmask) - -#endif /* FAKE_PTHREADS */ - /* * Code to mask all asynchronous signals *