123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203 |
- // -*- Mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*-
- // Copyright (c) 2005, Google Inc.
- // All rights reserved.
- //
- // Redistribution and use in source and binary forms, with or without
- // modification, are permitted provided that the following conditions are
- // met:
- //
- // * Redistributions of source code must retain the above copyright
- // notice, this list of conditions and the following disclaimer.
- // * Redistributions in binary form must reproduce the above
- // copyright notice, this list of conditions and the following disclaimer
- // in the documentation and/or other materials provided with the
- // distribution.
- // * Neither the name of Google Inc. nor the names of its
- // contributors may be used to endorse or promote products derived from
- // this software without specific prior written permission.
- //
- // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- // ---
- // Author: Paul Menage <opensource@google.com>
- //
- // Some wrappers for pthread functions so that we can be LD_PRELOADed
- // against non-pthreads apps.
- //
- // This module will behave very strangely if some pthreads functions
- // exist and others don't.
- #include "config.h"
- #include <assert.h>
- #include <string.h> // for memcmp
- #include <stdio.h> // for __isthreaded on FreeBSD
- // We don't actually need strings. But including this header seems to
- // stop the compiler trying to short-circuit our pthreads existence
- // tests and claiming that the address of a function is always
- // non-zero. I have no idea why ...
- #include <string>
- #include "maybe_threads.h"
- #include "base/basictypes.h"
- #include "base/logging.h"
- // __THROW is defined in glibc systems. It means, counter-intuitively,
- // "This function will never throw an exception." It's an optional
- // optimization tool, but we may need to use it to match glibc prototypes.
- #ifndef __THROW // I guess we're not on a glibc system
- # define __THROW // __THROW is just an optimization, so ok to make it ""
- #endif
- /*SGX doesn't support pthread*/
- #ifndef TCMALLOC_SGX
- // These are the methods we're going to conditionally include.
- extern "C" {
- int pthread_key_create (pthread_key_t*, void (*)(void*))
- __THROW ATTRIBUTE_WEAK;
- int pthread_key_delete (pthread_key_t)
- __THROW ATTRIBUTE_WEAK;
- void *pthread_getspecific(pthread_key_t)
- __THROW ATTRIBUTE_WEAK;
- int pthread_setspecific(pthread_key_t, const void*)
- __THROW ATTRIBUTE_WEAK;
- int pthread_once(pthread_once_t *, void (*)(void))
- ATTRIBUTE_WEAK;
- int pthread_atfork(void (*__prepare) (void),
- void (*__parent) (void),
- void (*__child) (void))
- __THROW ATTRIBUTE_WEAK;
- }
- #endif
- #define MAX_PERTHREAD_VALS 16
- static void *perftools_pthread_specific_vals[MAX_PERTHREAD_VALS];
- static int next_key;
- // NOTE: it's similar to bitcast defined in basic_types.h with
- // exception of ignoring sizes mismatch
- template <typename T1, typename T2>
- static T2 memcpy_cast(const T1 &input) {
- T2 output;
- size_t s = sizeof(input);
- if (sizeof(output) < s) {
- s = sizeof(output);
- }
- memcpy(&output, &input, s);
- return output;
- }
- int perftools_pthread_key_create(pthread_key_t *key,
- void (*destr_function) (void *)) {
- #ifndef TCMALLOC_SGX
- if (pthread_key_create) {
- return pthread_key_create(key, destr_function);
- }else
- #endif
- {
- assert(next_key < MAX_PERTHREAD_VALS);
- *key = memcpy_cast<int, pthread_key_t>(next_key++);
- return 0;
- }
- }
- int perftools_pthread_key_delete(pthread_key_t key) {
- #ifndef TCMALLOC_SGX
- if (pthread_key_delete) {
- return pthread_key_delete(key);
- } else
- #endif
- {
- return 0;
- }
- }
- void *perftools_pthread_getspecific(pthread_key_t key) {
- #ifndef TCMALLOC_SGX
- if (pthread_getspecific) {
- return pthread_getspecific(key);
- } else
- #endif
- {
- return perftools_pthread_specific_vals[memcpy_cast<pthread_key_t, int>(key)];
- }
- }
- int perftools_pthread_setspecific(pthread_key_t key, void *val) {
- #ifndef TCMALLOC_SGX
- if (pthread_setspecific) {
- return pthread_setspecific(key, val);
- } else
- #endif
- {
- perftools_pthread_specific_vals[memcpy_cast<pthread_key_t, int>(key)] = val;
- return 0;
- }
- }
- #ifdef TCMALLOC_SGX
- static sgx_spinlock_t g_once_lock = SGX_SPINLOCK_INITIALIZER;
- #endif
- static pthread_once_t pthread_once_init = PTHREAD_ONCE_INIT;
- int perftools_pthread_once(pthread_once_t *ctl,
- void (*init_routine) (void)) {
- #ifdef TCMALLOC_SGX
- sgx_spin_lock(&g_once_lock);
- if (memcmp(ctl, &pthread_once_init, sizeof(*ctl)) == 0) {
- init_routine();
- ++*(char*)(ctl); // make it so it's no longer equal to init
- }
- sgx_spin_unlock(&g_once_lock);
- return 0;
- #else
- #ifdef __FreeBSD__
- // On __FreeBSD__, calling pthread_once on a system that is not
- // linked with -pthread is silently a noop. :-( Luckily, we have a
- // workaround: FreeBSD exposes __isthreaded in <stdio.h>, which is
- // set to 1 when the first thread is spawned. So on those systems,
- // we can use our own separate pthreads-once mechanism, which is
- // used until __isthreaded is 1 (which will never be true if the app
- // is not linked with -pthread).
- static bool pthread_once_ran_before_threads = false;
- if (pthread_once_ran_before_threads) {
- return 0;
- }
- if (!__isthreaded) {
- init_routine();
- pthread_once_ran_before_threads = true;
- return 0;
- }
- #endif
- if (pthread_once) {
- return pthread_once(ctl, init_routine);
- } else {
- if (memcmp(ctl, &pthread_once_init, sizeof(*ctl)) == 0) {
- init_routine();
- ++*(char*)(ctl); // make it so it's no longer equal to init
- }
- return 0;
- }
- #endif
- }
- void perftools_pthread_atfork(void (*before)(),
- void (*parent_after)(),
- void (*child_after)()) {
- #ifdef TCMALLOC_SGX
- /*no pthread inside SGX, so abort it when be called */
- abort();
- #else
- if (pthread_atfork) {
- int rv = pthread_atfork(before, parent_after, child_after);
- CHECK(rv == 0);
- }
- #endif
- }
|