* 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 <windows.h>
#else
};
-#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
*