OLD | NEW |
1 /* Copyright (c) 2007, Google Inc. | 1 /* Copyright (c) 2007, Google Inc. |
2 * All rights reserved. | 2 * All rights reserved. |
3 * | 3 * |
4 * Redistribution and use in source and binary forms, with or without | 4 * Redistribution and use in source and binary forms, with or without |
5 * modification, are permitted provided that the following conditions are | 5 * modification, are permitted provided that the following conditions are |
6 * met: | 6 * met: |
7 * | 7 * |
8 * * Redistributions of source code must retain the above copyright | 8 * * Redistributions of source code must retain the above copyright |
9 * notice, this list of conditions and the following disclaimer. | 9 * notice, this list of conditions and the following disclaimer. |
10 * * Redistributions in binary form must reproduce the above | 10 * * Redistributions in binary form must reproduce the above |
(...skipping 17 matching lines...) Loading... |
28 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | 28 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
29 * | 29 * |
30 * --- | 30 * --- |
31 * Author: Craig Silverstein | 31 * Author: Craig Silverstein |
32 */ | 32 */ |
33 | 33 |
34 #ifndef _WIN32 | 34 #ifndef _WIN32 |
35 # error You should only be including windows/port.cc in a windows environment! | 35 # error You should only be including windows/port.cc in a windows environment! |
36 #endif | 36 #endif |
37 | 37 |
| 38 #define NOMINMAX // so std::max, below, compiles correctly |
38 #include <config.h> | 39 #include <config.h> |
39 #include <string.h> // for strlen(), memset(), memcmp() | 40 #include <string.h> // for strlen(), memset(), memcmp() |
40 #include <assert.h> | 41 #include <assert.h> |
41 #include <stdarg.h> // for va_list, va_start, va_end | 42 #include <stdarg.h> // for va_list, va_start, va_end |
42 #include <windows.h> | 43 #include <windows.h> |
43 #include "port.h" | 44 #include "port.h" |
44 #include "base/logging.h" | 45 #include "base/logging.h" |
45 #include "base/spinlock.h" | 46 #include "base/spinlock.h" |
| 47 #include "internal_logging.h" |
46 #include "system-alloc.h" | 48 #include "system-alloc.h" |
47 | 49 |
48 // ----------------------------------------------------------------------- | 50 // ----------------------------------------------------------------------- |
49 // Basic libraries | 51 // Basic libraries |
50 | 52 |
51 // These call the windows _vsnprintf, but always NUL-terminate. | |
52 int safe_vsnprintf(char *str, size_t size, const char *format, va_list ap) { | |
53 if (size == 0) // not even room for a \0? | |
54 return -1; // not what C99 says to do, but what windows does | |
55 str[size-1] = '\0'; | |
56 return _vsnprintf(str, size-1, format, ap); | |
57 } | |
58 | |
59 #ifndef HAVE_SNPRINTF | |
60 int snprintf(char *str, size_t size, const char *format, ...) { | |
61 va_list ap; | |
62 va_start(ap, format); | |
63 const int r = vsnprintf(str, size, format, ap); | |
64 va_end(ap); | |
65 return r; | |
66 } | |
67 #endif | |
68 | |
69 int getpagesize() { | 53 int getpagesize() { |
70 static int pagesize = 0; | 54 static int pagesize = 0; |
71 if (pagesize == 0) { | 55 if (pagesize == 0) { |
72 SYSTEM_INFO system_info; | 56 SYSTEM_INFO system_info; |
73 GetSystemInfo(&system_info); | 57 GetSystemInfo(&system_info); |
74 pagesize = std::max(system_info.dwPageSize, | 58 pagesize = std::max(system_info.dwPageSize, |
75 system_info.dwAllocationGranularity); | 59 system_info.dwAllocationGranularity); |
76 } | 60 } |
77 return pagesize; | 61 return pagesize; |
78 } | 62 } |
79 | 63 |
80 extern "C" PERFTOOLS_DLL_DECL void* __sbrk(std::ptrdiff_t increment) { | 64 extern "C" PERFTOOLS_DLL_DECL void* __sbrk(std::ptrdiff_t increment) { |
81 LOG(FATAL, "Windows doesn't implement sbrk!\n"); | 65 LOG(FATAL, "Windows doesn't implement sbrk!\n"); |
82 return NULL; | 66 return NULL; |
83 } | 67 } |
84 | 68 |
| 69 // We need to write to 'stderr' without having windows allocate memory. |
| 70 // The safest way is via a low-level call like WriteConsoleA(). But |
| 71 // even then we need to be sure to print in small bursts so as to not |
| 72 // require memory allocation. |
| 73 extern "C" PERFTOOLS_DLL_DECL void WriteToStderr(const char* buf, int len) { |
| 74 // Looks like windows allocates for writes of >80 bytes |
| 75 for (int i = 0; i < len; i += 80) { |
| 76 write(STDERR_FILENO, buf + i, std::min(80, len - i)); |
| 77 } |
| 78 } |
| 79 |
| 80 |
85 // ----------------------------------------------------------------------- | 81 // ----------------------------------------------------------------------- |
86 // Threads code | 82 // Threads code |
87 | 83 |
| 84 // Declared (not extern "C") in thread_cache.h |
88 bool CheckIfKernelSupportsTLS() { | 85 bool CheckIfKernelSupportsTLS() { |
89 // TODO(csilvers): return true (all win's since win95, at least, support this) | 86 // TODO(csilvers): return true (all win's since win95, at least, support this) |
90 return false; | 87 return false; |
91 } | 88 } |
92 | 89 |
93 // Windows doesn't support pthread_key_create's destr_function, and in | 90 // Windows doesn't support pthread_key_create's destr_function, and in |
94 // fact it's a bit tricky to get code to run when a thread exits. This | 91 // fact it's a bit tricky to get code to run when a thread exits. This |
95 // is cargo-cult magic from http://www.codeproject.com/threads/tls.asp. | 92 // is cargo-cult magic from http://www.codeproject.com/threads/tls.asp. |
96 // This code is for VC++ 7.1 and later; VC++ 6.0 support is possible | 93 // This code is for VC++ 7.1 and later; VC++ 6.0 support is possible |
97 // but more busy-work -- see the webpage for how to do it. If all | 94 // but more busy-work -- see the webpage for how to do it. If all |
98 // this fails, we could use DllMain instead. The big problem with | 95 // this fails, we could use DllMain instead. The big problem with |
99 // DllMain is it doesn't run if this code is statically linked into a | 96 // DllMain is it doesn't run if this code is statically linked into a |
100 // binary (it also doesn't run if the thread is terminated via | 97 // binary (it also doesn't run if the thread is terminated via |
101 // TerminateThread, which if we're lucky this routine does). | 98 // TerminateThread, which if we're lucky this routine does). |
102 | 99 |
103 // Force a reference to _tls_used to make the linker create the TLS directory | 100 // Force a reference to _tls_used to make the linker create the TLS directory |
104 // if it's not already there (that is, even if __declspec(thread) is not used). | 101 // if it's not already there (that is, even if __declspec(thread) is not used). |
105 // Force a reference to p_thread_callback_tcmalloc and p_process_term_tcmalloc | 102 // Force a reference to p_thread_callback_tcmalloc and p_process_term_tcmalloc |
106 // to prevent whole program optimization from discarding the variables. | 103 // to prevent whole program optimization from discarding the variables. |
107 #ifdef _MSC_VER | 104 #ifdef _MSC_VER |
| 105 #if defined(_M_IX86) |
108 #pragma comment(linker, "/INCLUDE:__tls_used") | 106 #pragma comment(linker, "/INCLUDE:__tls_used") |
109 #pragma comment(linker, "/INCLUDE:_p_thread_callback_tcmalloc") | 107 #pragma comment(linker, "/INCLUDE:_p_thread_callback_tcmalloc") |
110 #pragma comment(linker, "/INCLUDE:_p_process_term_tcmalloc") | 108 #pragma comment(linker, "/INCLUDE:_p_process_term_tcmalloc") |
| 109 #elif defined(_M_X64) |
| 110 #pragma comment(linker, "/INCLUDE:_tls_used") |
| 111 #pragma comment(linker, "/INCLUDE:p_thread_callback_tcmalloc") |
| 112 #pragma comment(linker, "/INCLUDE:p_process_term_tcmalloc") |
| 113 #endif |
111 #endif | 114 #endif |
112 | 115 |
113 // When destr_fn eventually runs, it's supposed to take as its | 116 // When destr_fn eventually runs, it's supposed to take as its |
114 // argument the tls-value associated with key that pthread_key_create | 117 // argument the tls-value associated with key that pthread_key_create |
115 // creates. (Yeah, it sounds confusing but it's really not.) We | 118 // creates. (Yeah, it sounds confusing but it's really not.) We |
116 // store the destr_fn/key pair in this data structure. Because we | 119 // store the destr_fn/key pair in this data structure. Because we |
117 // store this in a single var, this implies we can only have one | 120 // store this in a single var, this implies we can only have one |
118 // destr_fn in a program! That's enough in practice. If asserts | 121 // destr_fn in a program! That's enough in practice. If asserts |
119 // trigger because we end up needing more, we'll have to turn this | 122 // trigger because we end up needing more, we'll have to turn this |
120 // into an array. | 123 // into an array. |
(...skipping 45 matching lines...) Loading... |
166 BOOL WINAPI DllMain(HINSTANCE h, DWORD dwReason, PVOID pv) { | 169 BOOL WINAPI DllMain(HINSTANCE h, DWORD dwReason, PVOID pv) { |
167 if (dwReason == DLL_THREAD_DETACH) | 170 if (dwReason == DLL_THREAD_DETACH) |
168 on_tls_callback(h, dwReason, pv); | 171 on_tls_callback(h, dwReason, pv); |
169 else if (dwReason == DLL_PROCESS_DETACH) | 172 else if (dwReason == DLL_PROCESS_DETACH) |
170 on_process_term(); | 173 on_process_term(); |
171 return TRUE; | 174 return TRUE; |
172 } | 175 } |
173 | 176 |
174 #endif // #ifdef _MSC_VER | 177 #endif // #ifdef _MSC_VER |
175 | 178 |
176 pthread_key_t PthreadKeyCreate(void (*destr_fn)(void*)) { | 179 extern "C" pthread_key_t PthreadKeyCreate(void (*destr_fn)(void*)) { |
177 // Semantics are: we create a new key, and then promise to call | 180 // Semantics are: we create a new key, and then promise to call |
178 // destr_fn with TlsGetValue(key) when the thread is destroyed | 181 // destr_fn with TlsGetValue(key) when the thread is destroyed |
179 // (as long as TlsGetValue(key) is not NULL). | 182 // (as long as TlsGetValue(key) is not NULL). |
180 pthread_key_t key = TlsAlloc(); | 183 pthread_key_t key = TlsAlloc(); |
181 if (destr_fn) { // register it | 184 if (destr_fn) { // register it |
182 // If this assert fails, we'll need to support an array of destr_fn_infos | 185 // If this assert fails, we'll need to support an array of destr_fn_infos |
183 assert(destr_fn_info.destr_fn == NULL); | 186 assert(destr_fn_info.destr_fn == NULL); |
184 destr_fn_info.destr_fn = destr_fn; | 187 destr_fn_info.destr_fn = destr_fn; |
185 destr_fn_info.key_for_destr_fn_arg = key; | 188 destr_fn_info.key_for_destr_fn_arg = key; |
186 } | 189 } |
187 return key; | 190 return key; |
188 } | 191 } |
189 | 192 |
| 193 // NOTE: this is Win2K and later. For Win98 we could use a CRITICAL_SECTION... |
| 194 extern "C" int perftools_pthread_once(pthread_once_t *once_control, |
| 195 void (*init_routine)(void)) { |
| 196 // Try for a fast path first. Note: this should be an acquire semantics read. |
| 197 // It is on x86 and x64, where Windows runs. |
| 198 if (*once_control != 1) { |
| 199 while (true) { |
| 200 switch (InterlockedCompareExchange(once_control, 2, 0)) { |
| 201 case 0: |
| 202 init_routine(); |
| 203 InterlockedExchange(once_control, 1); |
| 204 return 0; |
| 205 case 1: |
| 206 // The initializer has already been executed |
| 207 return 0; |
| 208 default: |
| 209 // The initializer is being processed by another thread |
| 210 SwitchToThread(); |
| 211 } |
| 212 } |
| 213 } |
| 214 return 0; |
| 215 } |
| 216 |
190 | 217 |
191 // ----------------------------------------------------------------------- | 218 // ----------------------------------------------------------------------- |
192 // These functions replace system-alloc.cc | 219 // These functions replace system-alloc.cc |
193 | 220 |
| 221 // The current system allocator. Because we don't link with system-alloc.cc, |
| 222 // we need to define our own. |
| 223 SysAllocator* sys_alloc = NULL; |
| 224 |
194 // This is mostly like MmapSysAllocator::Alloc, except it does these weird | 225 // This is mostly like MmapSysAllocator::Alloc, except it does these weird |
195 // munmap's in the middle of the page, which is forbidden in windows. | 226 // munmap's in the middle of the page, which is forbidden in windows. |
196 extern void* TCMalloc_SystemAlloc(size_t size, size_t *actual_size, | 227 extern void* TCMalloc_SystemAlloc(size_t size, size_t *actual_size, |
197 size_t alignment) { | 228 size_t alignment) { |
198 // Align on the pagesize boundary | 229 // Align on the pagesize boundary |
199 const int pagesize = getpagesize(); | 230 const int pagesize = getpagesize(); |
200 if (alignment < pagesize) alignment = pagesize; | 231 if (alignment < pagesize) alignment = pagesize; |
201 size = ((size + alignment - 1) / alignment) * alignment; | 232 size = ((size + alignment - 1) / alignment) * alignment; |
202 | 233 |
203 // Report the total number of bytes the OS actually delivered. This might be | 234 // Report the total number of bytes the OS actually delivered. This might be |
(...skipping 93 matching lines...) Loading... |
297 if ((strlen(fname) >= prefix_length) && | 328 if ((strlen(fname) >= prefix_length) && |
298 (memcmp(fname, prefix, prefix_length) == 0)) { | 329 (memcmp(fname, prefix, prefix_length) == 0)) { |
299 RAW_VLOG(0, "Removing old heap profile %s\n", fname); | 330 RAW_VLOG(0, "Removing old heap profile %s\n", fname); |
300 // TODO(csilvers): we really need to unlink dirname + fname | 331 // TODO(csilvers): we really need to unlink dirname + fname |
301 _unlink(fname); | 332 _unlink(fname); |
302 } | 333 } |
303 } while (FindNextFileA(hFind, &found) != FALSE); // A is for Ansi | 334 } while (FindNextFileA(hFind, &found) != FALSE); // A is for Ansi |
304 FindClose(hFind); | 335 FindClose(hFind); |
305 } | 336 } |
306 } | 337 } |
OLD | NEW |