00001 // Copyright (c) 2005, Google Inc. 00002 // All rights reserved. 00003 // 00004 // Redistribution and use in source and binary forms, with or without 00005 // modification, are permitted provided that the following conditions are 00006 // met: 00007 // 00008 // * Redistributions of source code must retain the above copyright 00009 // notice, this list of conditions and the following disclaimer. 00010 // * Redistributions in binary form must reproduce the above 00011 // copyright notice, this list of conditions and the following disclaimer 00012 // in the documentation and/or other materials provided with the 00013 // distribution. 00014 // * Neither the name of Google Inc. nor the names of its 00015 // contributors may be used to endorse or promote products derived from 00016 // this software without specific prior written permission. 00017 // 00018 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 00019 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 00020 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 00021 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 00022 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 00023 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 00024 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 00025 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 00026 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 00027 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 00028 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 00029 00030 // --- 00031 // Author: Paul Menage <opensource@google.com> 00032 // 00033 // Some wrappers for pthread functions so that we can be LD_PRELOADed 00034 // against non-pthreads apps. 00035 // 00036 // This module will behave very strangely if some pthreads functions 00037 // exist and others don't. 00038 00039 #include "config.h" 00040 #include <assert.h> 00041 // We don't actually need strings. But including this header seems to 00042 // stop the compiler trying to short-circuit our pthreads existence 00043 // tests and claiming that the address of a function is always 00044 // non-zero. I have no idea why ... 00045 #include <string> 00046 #include <cstring> 00047 #include "maybe_threads.h" 00048 #include "base/basictypes.h" 00049 00050 // __THROW is defined in glibc systems. It means, counter-intuitively, 00051 // "This function will never throw an exception." It's an optional 00052 // optimization tool, but we may need to use it to match glibc prototypes. 00053 #ifndef __THROW // I guess we're not on a glibc system 00054 # define __THROW // __THROW is just an optimization, so ok to make it "" 00055 #endif 00056 00057 // These are the methods we're going to conditionally include. 00058 extern "C" { 00059 int pthread_key_create (pthread_key_t*, void (*)(void*)) 00060 __THROW ATTRIBUTE_WEAK; 00061 void *pthread_getspecific(pthread_key_t) 00062 __THROW ATTRIBUTE_WEAK; 00063 int pthread_setspecific(pthread_key_t, const void*) 00064 __THROW ATTRIBUTE_WEAK; 00065 int pthread_once(pthread_once_t *, void (*)(void)) 00066 __THROW ATTRIBUTE_WEAK; 00067 } 00068 00069 #define MAX_PERTHREAD_VALS 16 00070 static void *perftools_pthread_specific_vals[MAX_PERTHREAD_VALS]; 00071 static pthread_key_t next_key; 00072 00073 int perftools_pthread_key_create(pthread_key_t *key, 00074 void (*destr_function) (void *)) { 00075 if (pthread_key_create) { 00076 return pthread_key_create(key, destr_function); 00077 } else { 00078 assert(next_key < MAX_PERTHREAD_VALS); 00079 *key = next_key++; 00080 return 0; 00081 } 00082 } 00083 00084 void *perftools_pthread_getspecific(pthread_key_t key) { 00085 if (pthread_getspecific) { 00086 return pthread_getspecific(key); 00087 } else { 00088 return perftools_pthread_specific_vals[key]; 00089 } 00090 } 00091 00092 int perftools_pthread_setspecific(pthread_key_t key, void *val) { 00093 if (pthread_setspecific) { 00094 return pthread_setspecific(key, val); 00095 } else { 00096 perftools_pthread_specific_vals[key] = val; 00097 return 0; 00098 } 00099 } 00100 00101 static pthread_once_t pthread_once_init = PTHREAD_ONCE_INIT; 00102 int perftools_pthread_once(pthread_once_t *ctl, 00103 void (*init_routine) (void)) { 00104 if (pthread_once) { 00105 return pthread_once(ctl, init_routine); 00106 } else { 00107 if (memcmp(ctl, &pthread_once_init, sizeof(*ctl)) == 0) { 00108 init_routine(); 00109 ++*(char*)(ctl); // make it so it's no longer equal to init 00110 } 00111 return 0; 00112 } 00113 }