maybe_threads.cc 6.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203
  1. // -*- Mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*-
  2. // Copyright (c) 2005, Google Inc.
  3. // All rights reserved.
  4. //
  5. // Redistribution and use in source and binary forms, with or without
  6. // modification, are permitted provided that the following conditions are
  7. // met:
  8. //
  9. // * Redistributions of source code must retain the above copyright
  10. // notice, this list of conditions and the following disclaimer.
  11. // * Redistributions in binary form must reproduce the above
  12. // copyright notice, this list of conditions and the following disclaimer
  13. // in the documentation and/or other materials provided with the
  14. // distribution.
  15. // * Neither the name of Google Inc. nor the names of its
  16. // contributors may be used to endorse or promote products derived from
  17. // this software without specific prior written permission.
  18. //
  19. // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
  20. // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
  21. // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
  22. // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
  23. // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
  24. // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
  25. // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
  26. // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
  27. // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  28. // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
  29. // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  30. // ---
  31. // Author: Paul Menage <opensource@google.com>
  32. //
  33. // Some wrappers for pthread functions so that we can be LD_PRELOADed
  34. // against non-pthreads apps.
  35. //
  36. // This module will behave very strangely if some pthreads functions
  37. // exist and others don't.
  38. #include "config.h"
  39. #include <assert.h>
  40. #include <string.h> // for memcmp
  41. #include <stdio.h> // for __isthreaded on FreeBSD
  42. // We don't actually need strings. But including this header seems to
  43. // stop the compiler trying to short-circuit our pthreads existence
  44. // tests and claiming that the address of a function is always
  45. // non-zero. I have no idea why ...
  46. #include <string>
  47. #include "maybe_threads.h"
  48. #include "base/basictypes.h"
  49. #include "base/logging.h"
  50. // __THROW is defined in glibc systems. It means, counter-intuitively,
  51. // "This function will never throw an exception." It's an optional
  52. // optimization tool, but we may need to use it to match glibc prototypes.
  53. #ifndef __THROW // I guess we're not on a glibc system
  54. # define __THROW // __THROW is just an optimization, so ok to make it ""
  55. #endif
  56. /*SGX doesn't support pthread*/
  57. #ifndef TCMALLOC_SGX
  58. // These are the methods we're going to conditionally include.
  59. extern "C" {
  60. int pthread_key_create (pthread_key_t*, void (*)(void*))
  61. __THROW ATTRIBUTE_WEAK;
  62. int pthread_key_delete (pthread_key_t)
  63. __THROW ATTRIBUTE_WEAK;
  64. void *pthread_getspecific(pthread_key_t)
  65. __THROW ATTRIBUTE_WEAK;
  66. int pthread_setspecific(pthread_key_t, const void*)
  67. __THROW ATTRIBUTE_WEAK;
  68. int pthread_once(pthread_once_t *, void (*)(void))
  69. ATTRIBUTE_WEAK;
  70. int pthread_atfork(void (*__prepare) (void),
  71. void (*__parent) (void),
  72. void (*__child) (void))
  73. __THROW ATTRIBUTE_WEAK;
  74. }
  75. #endif
  76. #define MAX_PERTHREAD_VALS 16
  77. static void *perftools_pthread_specific_vals[MAX_PERTHREAD_VALS];
  78. static int next_key;
  79. // NOTE: it's similar to bitcast defined in basic_types.h with
  80. // exception of ignoring sizes mismatch
  81. template <typename T1, typename T2>
  82. static T2 memcpy_cast(const T1 &input) {
  83. T2 output;
  84. size_t s = sizeof(input);
  85. if (sizeof(output) < s) {
  86. s = sizeof(output);
  87. }
  88. memcpy(&output, &input, s);
  89. return output;
  90. }
  91. int perftools_pthread_key_create(pthread_key_t *key,
  92. void (*destr_function) (void *)) {
  93. #ifndef TCMALLOC_SGX
  94. if (pthread_key_create) {
  95. return pthread_key_create(key, destr_function);
  96. }else
  97. #endif
  98. {
  99. assert(next_key < MAX_PERTHREAD_VALS);
  100. *key = memcpy_cast<int, pthread_key_t>(next_key++);
  101. return 0;
  102. }
  103. }
  104. int perftools_pthread_key_delete(pthread_key_t key) {
  105. #ifndef TCMALLOC_SGX
  106. if (pthread_key_delete) {
  107. return pthread_key_delete(key);
  108. } else
  109. #endif
  110. {
  111. return 0;
  112. }
  113. }
  114. void *perftools_pthread_getspecific(pthread_key_t key) {
  115. #ifndef TCMALLOC_SGX
  116. if (pthread_getspecific) {
  117. return pthread_getspecific(key);
  118. } else
  119. #endif
  120. {
  121. return perftools_pthread_specific_vals[memcpy_cast<pthread_key_t, int>(key)];
  122. }
  123. }
  124. int perftools_pthread_setspecific(pthread_key_t key, void *val) {
  125. #ifndef TCMALLOC_SGX
  126. if (pthread_setspecific) {
  127. return pthread_setspecific(key, val);
  128. } else
  129. #endif
  130. {
  131. perftools_pthread_specific_vals[memcpy_cast<pthread_key_t, int>(key)] = val;
  132. return 0;
  133. }
  134. }
  135. #ifdef TCMALLOC_SGX
  136. static sgx_spinlock_t g_once_lock = SGX_SPINLOCK_INITIALIZER;
  137. #endif
  138. static pthread_once_t pthread_once_init = PTHREAD_ONCE_INIT;
  139. int perftools_pthread_once(pthread_once_t *ctl,
  140. void (*init_routine) (void)) {
  141. #ifdef TCMALLOC_SGX
  142. sgx_spin_lock(&g_once_lock);
  143. if (memcmp(ctl, &pthread_once_init, sizeof(*ctl)) == 0) {
  144. init_routine();
  145. ++*(char*)(ctl); // make it so it's no longer equal to init
  146. }
  147. sgx_spin_unlock(&g_once_lock);
  148. return 0;
  149. #else
  150. #ifdef __FreeBSD__
  151. // On __FreeBSD__, calling pthread_once on a system that is not
  152. // linked with -pthread is silently a noop. :-( Luckily, we have a
  153. // workaround: FreeBSD exposes __isthreaded in <stdio.h>, which is
  154. // set to 1 when the first thread is spawned. So on those systems,
  155. // we can use our own separate pthreads-once mechanism, which is
  156. // used until __isthreaded is 1 (which will never be true if the app
  157. // is not linked with -pthread).
  158. static bool pthread_once_ran_before_threads = false;
  159. if (pthread_once_ran_before_threads) {
  160. return 0;
  161. }
  162. if (!__isthreaded) {
  163. init_routine();
  164. pthread_once_ran_before_threads = true;
  165. return 0;
  166. }
  167. #endif
  168. if (pthread_once) {
  169. return pthread_once(ctl, init_routine);
  170. } else {
  171. if (memcmp(ctl, &pthread_once_init, sizeof(*ctl)) == 0) {
  172. init_routine();
  173. ++*(char*)(ctl); // make it so it's no longer equal to init
  174. }
  175. return 0;
  176. }
  177. #endif
  178. }
  179. void perftools_pthread_atfork(void (*before)(),
  180. void (*parent_after)(),
  181. void (*child_after)()) {
  182. #ifdef TCMALLOC_SGX
  183. /*no pthread inside SGX, so abort it when be called */
  184. abort();
  185. #else
  186. if (pthread_atfork) {
  187. int rv = pthread_atfork(before, parent_after, child_after);
  188. CHECK(rv == 0);
  189. }
  190. #endif
  191. }