Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(428)

Side by Side Diff: third_party/tcmalloc/port.cc

Issue 165275: Major changes to the Chrome allocator.... (Closed) Base URL: svn://chrome-svn/chrome/trunk/src/
Patch Set: '' Created 11 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « third_party/tcmalloc/page_heap.cc ('k') | third_party/tcmalloc/system-alloc.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 /* Copyright (c) 2007, Google Inc.
2 * All rights reserved.
3 *
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are
6 * met:
7 *
8 * * Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * * Redistributions in binary form must reproduce the above
11 * copyright notice, this list of conditions and the following disclaimer
12 * in the documentation and/or other materials provided with the
13 * distribution.
14 * * Neither the name of Google Inc. nor the names of its
15 * contributors may be used to endorse or promote products derived from
16 * this software without specific prior written permission.
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
21 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
22 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
23 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
24 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 *
30 * ---
31 * Author: Craig Silverstein
32 */
33
34 #ifndef _WIN32
35 # error You should only be including windows/port.cc in a windows environment!
36 #endif
37
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 <windows.h>
43 #include "port.h"
44 #include "base/logging.h"
45 #include "base/spinlock.h"
46 #include "system-alloc.h"
47
48 // -----------------------------------------------------------------------
49 // Basic libraries
50
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() {
70 static int pagesize = 0;
71 if (pagesize == 0) {
72 SYSTEM_INFO system_info;
73 GetSystemInfo(&system_info);
74 pagesize = system_info.dwPageSize;
75 }
76 return pagesize;
77 }
78
79 extern "C" PERFTOOLS_DLL_DECL void* __sbrk(ptrdiff_t increment) {
80 LOG(FATAL, "Windows doesn't implement sbrk!\n");
81 return NULL;
82 }
83
84 // -----------------------------------------------------------------------
85 // Threads code
86
87 bool CheckIfKernelSupportsTLS() {
88 // TODO(csilvers): return true (all win's since win95, at least, support this)
89 return false;
90 }
91
92 // Windows doesn't support pthread_key_create's destr_function, and in
93 // fact it's a bit tricky to get code to run when a thread exits. This
94 // is cargo-cult magic from http://www.codeproject.com/threads/tls.asp.
95 // This code is for VC++ 7.1 and later; VC++ 6.0 support is possible
96 // but more busy-work -- see the webpage for how to do it. If all
97 // this fails, we could use DllMain instead. The big problem with
98 // DllMain is it doesn't run if this code is statically linked into a
99 // binary (it also doesn't run if the thread is terminated via
100 // TerminateThread, which if we're lucky this routine does).
101
102 // This makes the linker create the TLS directory if it's not already
103 // there (that is, even if __declspec(thead) is not used).
104 #ifdef _MSC_VER
105 #pragma comment(linker, "/INCLUDE:__tls_used")
106 #endif
107
108 // When destr_fn eventually runs, it's supposed to take as its
109 // argument the tls-value associated with key that pthread_key_create
110 // creates. (Yeah, it sounds confusing but it's really not.) We
111 // store the destr_fn/key pair in this data structure. Because we
112 // store this in a single var, this implies we can only have one
113 // destr_fn in a program! That's enough in practice. If asserts
114 // trigger because we end up needing more, we'll have to turn this
115 // into an array.
116 struct DestrFnClosure {
117 void (*destr_fn)(void*);
118 pthread_key_t key_for_destr_fn_arg;
119 };
120
121 static DestrFnClosure destr_fn_info; // initted to all NULL/0.
122
123 static int on_process_term(void) {
124 if (destr_fn_info.destr_fn) {
125 void *ptr = TlsGetValue(destr_fn_info.key_for_destr_fn_arg);
126 // This shouldn't be necessary, but in Release mode, Windows
127 // sometimes trashes the pointer in the TLS slot, so we need to
128 // remove the pointer from the TLS slot before the thread dies.
129 TlsSetValue(destr_fn_info.key_for_destr_fn_arg, NULL);
130 if (ptr) // pthread semantics say not to call if ptr is NULL
131 (*destr_fn_info.destr_fn)(ptr);
132 }
133 return 0;
134 }
135
136 static void NTAPI on_tls_callback(HINSTANCE h, DWORD dwReason, PVOID pv) {
137 if (dwReason == DLL_THREAD_DETACH) { // thread is being destroyed!
138 on_process_term();
139 }
140 }
141
142 #ifdef _MSC_VER
143
144 // This tells the linker to run these functions.
145 #pragma data_seg(push, old_seg)
146 #pragma data_seg(".CRT$XLB")
147 static void (NTAPI *p_thread_callback)(HINSTANCE h, DWORD dwReason, PVOID pv)
148 = on_tls_callback;
149 #pragma data_seg(".CRT$XTU")
150 static int (*p_process_term)(void) = on_process_term;
151 #pragma data_seg(pop, old_seg)
152
153 #else // #ifdef _MSC_VER [probably msys/mingw]
154
155 // We have to try the DllMain solution here, because we can't use the
156 // msvc-specific pragmas.
157 BOOL WINAPI DllMain(HINSTANCE h, DWORD dwReason, PVOID pv) {
158 if (dwReason == DLL_THREAD_DETACH)
159 on_tls_callback(h, dwReason, pv);
160 else if (dwReason == DLL_PROCESS_DETACH)
161 on_process_term();
162 return TRUE;
163 }
164
165 #endif // #ifdef _MSC_VER
166
167 pthread_key_t PthreadKeyCreate(void (*destr_fn)(void*)) {
168 // Semantics are: we create a new key, and then promise to call
169 // destr_fn with TlsGetValue(key) when the thread is destroyed
170 // (as long as TlsGetValue(key) is not NULL).
171 pthread_key_t key = TlsAlloc();
172 if (destr_fn) { // register it
173 // If this assert fails, we'll need to support an array of destr_fn_infos
174 assert(destr_fn_info.destr_fn == NULL);
175 destr_fn_info.destr_fn = destr_fn;
176 destr_fn_info.key_for_destr_fn_arg = key;
177 }
178 return key;
179 }
180
181
182 // -----------------------------------------------------------------------
183 // These functions replace system-alloc.cc
184
185 static SpinLock alloc_lock(SpinLock::LINKER_INITIALIZED);
186
187 // This is mostly like MmapSysAllocator::Alloc, except it does these weird
188 // munmap's in the middle of the page, which is forbidden in windows.
189 extern void* TCMalloc_SystemAlloc(size_t size, size_t *actual_size,
190 size_t alignment) {
191 // Safest is to make actual_size same as input-size.
192 if (actual_size) {
193 *actual_size = size;
194 }
195
196 SpinLockHolder sh(&alloc_lock);
197 // Align on the pagesize boundary
198 const int pagesize = getpagesize();
199 if (alignment < pagesize) alignment = pagesize;
200 size = ((size + alignment - 1) / alignment) * alignment;
201
202 // Ask for extra memory if alignment > pagesize
203 size_t extra = 0;
204 if (alignment > pagesize) {
205 extra = alignment - pagesize;
206 }
207
208 void* result = VirtualAlloc(0, size + extra,
209 MEM_COMMIT|MEM_RESERVE, PAGE_READWRITE);
210 if (result == NULL)
211 return NULL;
212
213 // Adjust the return memory so it is aligned
214 uintptr_t ptr = reinterpret_cast<uintptr_t>(result);
215 size_t adjust = 0;
216 if ((ptr & (alignment - 1)) != 0) {
217 adjust = alignment - (ptr & (alignment - 1));
218 }
219
220 ptr += adjust;
221 return reinterpret_cast<void*>(ptr);
222 }
223
224 void TCMalloc_SystemRelease(void* start, size_t length) {
225 if (VirtualFree(start, length, MEM_DECOMMIT))
226 return;
227
228 // The decommit may fail if the memory region consists of allocations
229 // from more than one call to VirtualAlloc. In this case, fall back to
230 // using VirtualQuery to retrieve the allocation boundaries and decommit
231 // them each individually.
232
233 char* ptr = static_cast<char*>(start);
234 char* end = ptr + length;
235 MEMORY_BASIC_INFORMATION info;
236 while (ptr < end) {
237 size_t resultSize = VirtualQuery(ptr, &info, sizeof(info));
238 assert(resultSize == sizeof(info));
239 size_t decommitSize = std::min<size_t>(info.RegionSize, end - ptr);
240 BOOL success = VirtualFree(ptr, decommitSize, MEM_DECOMMIT);
241 assert(success == TRUE);
242 ptr += decommitSize;
243 }
244 }
245
246 void TCMalloc_SystemCommit(void* start, size_t length)
247 {
248 if (VirtualAlloc(start, length, MEM_COMMIT, PAGE_READWRITE) == start)
249 return;
250
251 // The commit may fail if the memory region consists of allocations
252 // from more than one call to VirtualAlloc. In this case, fall back to
253 // using VirtualQuery to retrieve the allocation boundaries and commit them
254 // each individually.
255
256 char* ptr = static_cast<char*>(start);
257 char* end = ptr + length;
258 MEMORY_BASIC_INFORMATION info;
259 while (ptr < end) {
260 size_t resultSize = VirtualQuery(ptr, &info, sizeof(info));
261 assert(resultSize == sizeof(info));
262
263 size_t commitSize = std::min<size_t>(info.RegionSize, end - ptr);
264 void* newAddress = VirtualAlloc(ptr, commitSize, MEM_COMMIT,
265 PAGE_READWRITE);
266 assert(newAddress == ptr);
267 ptr += commitSize;
268 }
269 }
270
271 bool RegisterSystemAllocator(SysAllocator *allocator, int priority) {
272 return false; // we don't allow registration on windows, right now
273 }
274
275 void DumpSystemAllocatorStats(TCMalloc_Printer* printer) {
276 // We don't dump stats on windows, right now
277 }
278
279
280 // -----------------------------------------------------------------------
281 // These functions rework existing functions of the same name in the
282 // Google codebase.
283
284 // A replacement for HeapProfiler::CleanupOldProfiles.
285 void DeleteMatchingFiles(const char* prefix, const char* full_glob) {
286 WIN32_FIND_DATAA found; // that final A is for Ansi (as opposed to Unicode)
287 HANDLE hFind = FindFirstFileA(full_glob, &found); // A is for Ansi
288 if (hFind != INVALID_HANDLE_VALUE) {
289 const int prefix_length = strlen(prefix);
290 do {
291 const char *fname = found.cFileName;
292 if ((strlen(fname) >= prefix_length) &&
293 (memcmp(fname, prefix, prefix_length) == 0)) {
294 RAW_VLOG(0, "Removing old heap profile %s\n", fname);
295 // TODO(csilvers): we really need to unlink dirname + fname
296 _unlink(fname);
297 }
298 } while (FindNextFileA(hFind, &found) != FALSE); // A is for Ansi
299 FindClose(hFind);
300 }
301 }
OLDNEW
« no previous file with comments | « third_party/tcmalloc/page_heap.cc ('k') | third_party/tcmalloc/system-alloc.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698