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...) Expand all 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(ptrdiff_t increment) { | 64 extern "C" PERFTOOLS_DLL_DECL void* __sbrk(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...) Expand 10 before | Expand all | Expand 10 after 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. | |
antonm
2011/06/02 13:37:35
may you elaborate why? e.g. does it require pthre
Alexander Potapenko
2011/06/09 09:35:24
The latter one, http://code.google.com/p/google-pe
| |
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 | |
222 SysAllocator* sys_alloc = NULL; | |
Alexander Potapenko
2011/06/09 09:35:24
These lines differ from the upstream version: we n
antonm
2011/06/14 14:15:35
Please, add a comment and consider backporting thi
Alexander Potapenko
2011/06/15 16:32:20
For some strange reason the trunk perftools do not
Alexander Potapenko
2011/06/16 14:49:47
Done.
I've also put system-alloc.cc back to the li
| |
223 | |
194 // This is mostly like MmapSysAllocator::Alloc, except it does these weird | 224 // 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. | 225 // 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, | 226 extern void* TCMalloc_SystemAlloc(size_t size, size_t *actual_size, |
197 size_t alignment) { | 227 size_t alignment) { |
198 // Align on the pagesize boundary | 228 // Align on the pagesize boundary |
199 const int pagesize = getpagesize(); | 229 const int pagesize = getpagesize(); |
200 if (alignment < pagesize) alignment = pagesize; | 230 if (alignment < pagesize) alignment = pagesize; |
201 size = ((size + alignment - 1) / alignment) * alignment; | 231 size = ((size + alignment - 1) / alignment) * alignment; |
202 | 232 |
203 // Report the total number of bytes the OS actually delivered. This might be | 233 // Report the total number of bytes the OS actually delivered. This might be |
(...skipping 93 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
297 if ((strlen(fname) >= prefix_length) && | 327 if ((strlen(fname) >= prefix_length) && |
298 (memcmp(fname, prefix, prefix_length) == 0)) { | 328 (memcmp(fname, prefix, prefix_length) == 0)) { |
299 RAW_VLOG(0, "Removing old heap profile %s\n", fname); | 329 RAW_VLOG(0, "Removing old heap profile %s\n", fname); |
300 // TODO(csilvers): we really need to unlink dirname + fname | 330 // TODO(csilvers): we really need to unlink dirname + fname |
301 _unlink(fname); | 331 _unlink(fname); |
302 } | 332 } |
303 } while (FindNextFileA(hFind, &found) != FALSE); // A is for Ansi | 333 } while (FindNextFileA(hFind, &found) != FALSE); // A is for Ansi |
304 FindClose(hFind); | 334 FindClose(hFind); |
305 } | 335 } |
306 } | 336 } |
OLD | NEW |