port.cc 8.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235
  1. // -*- Mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*-
  2. /* Copyright (c) 2007, 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. * ---
  32. * Author: Craig Silverstein
  33. */
  34. #ifndef _WIN32
  35. # error You should only be including windows/port.cc in a windows environment!
  36. #endif
  37. #define NOMINMAX // so std::max, below, compiles correctly
  38. #include <config.h>
  39. #include <string.h> // for strlen(), memset(), memcmp()
  40. #include <assert.h>
  41. #include <stdarg.h> // for va_list, va_start, va_end
  42. #include <algorithm> // for std:{min,max}
  43. #include <windows.h>
  44. #include "port.h"
  45. #include "base/logging.h"
  46. #include "base/spinlock.h"
  47. #include "internal_logging.h"
  48. // -----------------------------------------------------------------------
  49. // Basic libraries
  50. PERFTOOLS_DLL_DECL
  51. int getpagesize() {
  52. static int pagesize = 0;
  53. if (pagesize == 0) {
  54. SYSTEM_INFO system_info;
  55. GetSystemInfo(&system_info);
  56. pagesize = std::max(system_info.dwPageSize,
  57. system_info.dwAllocationGranularity);
  58. }
  59. return pagesize;
  60. }
  61. extern "C" PERFTOOLS_DLL_DECL void* __sbrk(ptrdiff_t increment) {
  62. LOG(FATAL, "Windows doesn't implement sbrk!\n");
  63. return NULL;
  64. }
  65. // We need to write to 'stderr' without having windows allocate memory.
  66. // The safest way is via a low-level call like WriteConsoleA(). But
  67. // even then we need to be sure to print in small bursts so as to not
  68. // require memory allocation.
  69. extern "C" PERFTOOLS_DLL_DECL void WriteToStderr(const char* buf, int len) {
  70. // Looks like windows allocates for writes of >80 bytes
  71. for (int i = 0; i < len; i += 80) {
  72. write(STDERR_FILENO, buf + i, std::min(80, len - i));
  73. }
  74. }
  75. // -----------------------------------------------------------------------
  76. // Threads code
  77. // Windows doesn't support pthread_key_create's destr_function, and in
  78. // fact it's a bit tricky to get code to run when a thread exits. This
  79. // is cargo-cult magic from http://www.codeproject.com/threads/tls.asp.
  80. // This code is for VC++ 7.1 and later; VC++ 6.0 support is possible
  81. // but more busy-work -- see the webpage for how to do it. If all
  82. // this fails, we could use DllMain instead. The big problem with
  83. // DllMain is it doesn't run if this code is statically linked into a
  84. // binary (it also doesn't run if the thread is terminated via
  85. // TerminateThread, which if we're lucky this routine does).
  86. // Force a reference to _tls_used to make the linker create the TLS directory
  87. // if it's not already there (that is, even if __declspec(thread) is not used).
  88. // Force a reference to p_thread_callback_tcmalloc and p_process_term_tcmalloc
  89. // to prevent whole program optimization from discarding the variables.
  90. #ifdef _MSC_VER
  91. #if defined(_M_IX86)
  92. #pragma comment(linker, "/INCLUDE:__tls_used")
  93. #pragma comment(linker, "/INCLUDE:_p_thread_callback_tcmalloc")
  94. #pragma comment(linker, "/INCLUDE:_p_process_term_tcmalloc")
  95. #elif defined(_M_X64)
  96. #pragma comment(linker, "/INCLUDE:_tls_used")
  97. #pragma comment(linker, "/INCLUDE:p_thread_callback_tcmalloc")
  98. #pragma comment(linker, "/INCLUDE:p_process_term_tcmalloc")
  99. #endif
  100. #endif
  101. // When destr_fn eventually runs, it's supposed to take as its
  102. // argument the tls-value associated with key that pthread_key_create
  103. // creates. (Yeah, it sounds confusing but it's really not.) We
  104. // store the destr_fn/key pair in this data structure. Because we
  105. // store this in a single var, this implies we can only have one
  106. // destr_fn in a program! That's enough in practice. If asserts
  107. // trigger because we end up needing more, we'll have to turn this
  108. // into an array.
  109. struct DestrFnClosure {
  110. void (*destr_fn)(void*);
  111. pthread_key_t key_for_destr_fn_arg;
  112. };
  113. static DestrFnClosure destr_fn_info; // initted to all NULL/0.
  114. static int on_process_term(void) {
  115. if (destr_fn_info.destr_fn) {
  116. void *ptr = TlsGetValue(destr_fn_info.key_for_destr_fn_arg);
  117. // This shouldn't be necessary, but in Release mode, Windows
  118. // sometimes trashes the pointer in the TLS slot, so we need to
  119. // remove the pointer from the TLS slot before the thread dies.
  120. TlsSetValue(destr_fn_info.key_for_destr_fn_arg, NULL);
  121. if (ptr) // pthread semantics say not to call if ptr is NULL
  122. (*destr_fn_info.destr_fn)(ptr);
  123. }
  124. return 0;
  125. }
  126. static void NTAPI on_tls_callback(HINSTANCE h, DWORD dwReason, PVOID pv) {
  127. if (dwReason == DLL_THREAD_DETACH) { // thread is being destroyed!
  128. on_process_term();
  129. }
  130. }
  131. #ifdef _MSC_VER
  132. // extern "C" suppresses C++ name mangling so we know the symbol names
  133. // for the linker /INCLUDE:symbol pragmas above.
  134. extern "C" {
  135. // This tells the linker to run these functions.
  136. #pragma data_seg(push, old_seg)
  137. #pragma data_seg(".CRT$XLB")
  138. void (NTAPI *p_thread_callback_tcmalloc)(
  139. HINSTANCE h, DWORD dwReason, PVOID pv) = on_tls_callback;
  140. #pragma data_seg(".CRT$XTU")
  141. int (*p_process_term_tcmalloc)(void) = on_process_term;
  142. #pragma data_seg(pop, old_seg)
  143. } // extern "C"
  144. #else // #ifdef _MSC_VER [probably msys/mingw]
  145. // We have to try the DllMain solution here, because we can't use the
  146. // msvc-specific pragmas.
  147. BOOL WINAPI DllMain(HINSTANCE h, DWORD dwReason, PVOID pv) {
  148. if (dwReason == DLL_THREAD_DETACH)
  149. on_tls_callback(h, dwReason, pv);
  150. else if (dwReason == DLL_PROCESS_DETACH)
  151. on_process_term();
  152. return TRUE;
  153. }
  154. #endif // #ifdef _MSC_VER
  155. extern "C" pthread_key_t PthreadKeyCreate(void (*destr_fn)(void*)) {
  156. // Semantics are: we create a new key, and then promise to call
  157. // destr_fn with TlsGetValue(key) when the thread is destroyed
  158. // (as long as TlsGetValue(key) is not NULL).
  159. pthread_key_t key = TlsAlloc();
  160. if (destr_fn) { // register it
  161. // If this assert fails, we'll need to support an array of destr_fn_infos
  162. assert(destr_fn_info.destr_fn == NULL);
  163. destr_fn_info.destr_fn = destr_fn;
  164. destr_fn_info.key_for_destr_fn_arg = key;
  165. }
  166. return key;
  167. }
  168. // NOTE: this is Win2K and later. For Win98 we could use a CRITICAL_SECTION...
  169. extern "C" int perftools_pthread_once(pthread_once_t *once_control,
  170. void (*init_routine)(void)) {
  171. // Try for a fast path first. Note: this should be an acquire semantics read.
  172. // It is on x86 and x64, where Windows runs.
  173. if (*once_control != 1) {
  174. while (true) {
  175. switch (InterlockedCompareExchange(once_control, 2, 0)) {
  176. case 0:
  177. init_routine();
  178. InterlockedExchange(once_control, 1);
  179. return 0;
  180. case 1:
  181. // The initializer has already been executed
  182. return 0;
  183. default:
  184. // The initializer is being processed by another thread
  185. SwitchToThread();
  186. }
  187. }
  188. }
  189. return 0;
  190. }
  191. // -----------------------------------------------------------------------
  192. // These functions rework existing functions of the same name in the
  193. // Google codebase.
  194. // A replacement for HeapProfiler::CleanupOldProfiles.
  195. void DeleteMatchingFiles(const char* prefix, const char* full_glob) {
  196. WIN32_FIND_DATAA found; // that final A is for Ansi (as opposed to Unicode)
  197. HANDLE hFind = FindFirstFileA(full_glob, &found); // A is for Ansi
  198. if (hFind != INVALID_HANDLE_VALUE) {
  199. const int prefix_length = strlen(prefix);
  200. do {
  201. const char *fname = found.cFileName;
  202. if ((strlen(fname) >= prefix_length) &&
  203. (memcmp(fname, prefix, prefix_length) == 0)) {
  204. RAW_VLOG(0, "Removing old heap profile %s\n", fname);
  205. // TODO(csilvers): we really need to unlink dirname + fname
  206. _unlink(fname);
  207. }
  208. } while (FindNextFileA(hFind, &found) != FALSE); // A is for Ansi
  209. FindClose(hFind);
  210. }
  211. }