15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Copyright (c) 2005, Google Inc.
25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// All rights reserved.
35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)//
45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Redistribution and use in source and binary forms, with or without
55821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// modification, are permitted provided that the following conditions are
65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// met:
75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)//
85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)//     * Redistributions of source code must retain the above copyright
95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// notice, this list of conditions and the following disclaimer.
105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)//     * Redistributions in binary form must reproduce the above
115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// copyright notice, this list of conditions and the following disclaimer
125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// in the documentation and/or other materials provided with the
135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// distribution.
145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)//     * Neither the name of Google Inc. nor the names of its
155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// contributors may be used to endorse or promote products derived from
165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// this software without specific prior written permission.
175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)//
185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// ---
315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Author: Paul Menage <opensource@google.com>
325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)//
335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Some wrappers for pthread functions so that we can be LD_PRELOADed
345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// against non-pthreads apps.
355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)//
365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// This module will behave very strangely if some pthreads functions
375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// exist and others don't.
385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "config.h"
405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <assert.h>
415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <string.h>    // for memcmp
425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <stdio.h>     // for __isthreaded on FreeBSD
435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// We don't actually need strings. But including this header seems to
445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// stop the compiler trying to short-circuit our pthreads existence
455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// tests and claiming that the address of a function is always
465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// non-zero. I have no idea why ...
475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include <string>
485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "maybe_threads.h"
495821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/basictypes.h"
505821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// __THROW is defined in glibc systems.  It means, counter-intuitively,
525821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// "This function will never throw an exception."  It's an optional
535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// optimization tool, but we may need to use it to match glibc prototypes.
545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#ifndef __THROW    // I guess we're not on a glibc system
555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)# define __THROW   // __THROW is just an optimization, so ok to make it ""
565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif
575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// These are the methods we're going to conditionally include.
595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)extern "C" {
605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int pthread_key_create (pthread_key_t*, void (*)(void*))
615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      __THROW ATTRIBUTE_WEAK;
625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  void *pthread_getspecific(pthread_key_t)
635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      __THROW ATTRIBUTE_WEAK;
645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int pthread_setspecific(pthread_key_t, const void*)
655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      __THROW ATTRIBUTE_WEAK;
665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  int pthread_once(pthread_once_t *, void (*)(void))
675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      ATTRIBUTE_WEAK;
685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
695821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
705821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#define MAX_PERTHREAD_VALS 16
715821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static void *perftools_pthread_specific_vals[MAX_PERTHREAD_VALS];
725821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static int next_key;
735821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
745821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)int perftools_pthread_key_create(pthread_key_t *key,
755821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                 void (*destr_function) (void *)) {
765821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (pthread_key_create) {
775821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return pthread_key_create(key, destr_function);
785821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } else {
795821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    assert(next_key < MAX_PERTHREAD_VALS);
805821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    *key = (pthread_key_t)(next_key++);
815821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return 0;
825821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void *perftools_pthread_getspecific(pthread_key_t key) {
865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (pthread_getspecific) {
875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return pthread_getspecific(key);
885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } else {
895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return perftools_pthread_specific_vals[(int)key];
905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)int perftools_pthread_setspecific(pthread_key_t key, void *val) {
945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (pthread_setspecific) {
955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return pthread_setspecific(key, val);
965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } else {
975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    perftools_pthread_specific_vals[(int)key] = val;
985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return 0;
995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)static pthread_once_t pthread_once_init = PTHREAD_ONCE_INIT;
1045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)int perftools_pthread_once(pthread_once_t *ctl,
1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                           void  (*init_routine) (void)) {
1065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#ifdef __FreeBSD__
1075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // On __FreeBSD__, calling pthread_once on a system that is not
1085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // linked with -pthread is silently a noop. :-( Luckily, we have a
1095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // workaround: FreeBSD exposes __isthreaded in <stdio.h>, which is
1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // set to 1 when the first thread is spawned.  So on those systems,
1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // we can use our own separate pthreads-once mechanism, which is
1125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // used until __isthreaded is 1 (which will never be true if the app
1135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // is not linked with -pthread).
1145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  static bool pthread_once_ran_before_threads = false;
1155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (pthread_once_ran_before_threads) {
1165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return 0;
1175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!__isthreaded) {
1195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    init_routine();
1205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    pthread_once_ran_before_threads = true;
1215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return 0;
1225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
12390dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)#elif defined(__ANDROID__)
12490dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  // Android >= 2.3 (GB) always implement pthread_once.
12590dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)  return pthread_once(ctl, init_routine);
12690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)#else
1275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (pthread_once) {
1285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return pthread_once(ctl, init_routine);
1295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  } else {
1305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    if (memcmp(ctl, &pthread_once_init, sizeof(*ctl)) == 0) {
1315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      init_routine();
1325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      ++*(char*)(ctl);        // make it so it's no longer equal to init
1335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
1345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return 0;
1355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
13690dce4d38c5ff5333bea97d859d4e484e27edf0cTorne (Richard Coles)#endif
1375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
138