blob: bdd03921dd0fdb33f1851d1410f71af31fb5a2c1 [file] [log] [blame]
Brian Silverman20350ac2021-11-17 18:19:55 -08001// -*- Mode: C++; c-basic-offset: 2; indent-tabs-mode: nil -*-
Austin Schuh745610d2015-09-06 18:19:50 -07002// Copyright (c) 2013, Google Inc.
3// All rights reserved.
Brian Silverman20350ac2021-11-17 18:19:55 -08004//
Austin Schuh745610d2015-09-06 18:19:50 -07005// Redistribution and use in source and binary forms, with or without
6// modification, are permitted provided that the following conditions are
7// met:
Brian Silverman20350ac2021-11-17 18:19:55 -08008//
Austin Schuh745610d2015-09-06 18:19:50 -07009// * 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.
Brian Silverman20350ac2021-11-17 18:19:55 -080018//
Austin Schuh745610d2015-09-06 18:19:50 -070019// 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: Petr Hosek
33
34#ifndef _WIN32
35# error You should only be including windows/system-alloc.cc in a windows environment!
36#endif
37
38#include <config.h>
39#include <windows.h>
40#include <algorithm> // std::min
41#include <gperftools/malloc_extension.h>
42#include "base/logging.h"
43#include "base/spinlock.h"
44#include "internal_logging.h"
45#include "system-alloc.h"
46
47static SpinLock spinlock(SpinLock::LINKER_INITIALIZED);
48
49// The current system allocator declaration
Brian Silverman20350ac2021-11-17 18:19:55 -080050SysAllocator* tcmalloc_sys_alloc = NULL;
Austin Schuh745610d2015-09-06 18:19:50 -070051// Number of bytes taken from system.
52size_t TCMalloc_SystemTaken = 0;
53
54class VirtualSysAllocator : public SysAllocator {
55public:
56 VirtualSysAllocator() : SysAllocator() {
57 }
58 void* Alloc(size_t size, size_t *actual_size, size_t alignment);
59};
60static char virtual_space[sizeof(VirtualSysAllocator)];
61
62// This is mostly like MmapSysAllocator::Alloc, except it does these weird
63// munmap's in the middle of the page, which is forbidden in windows.
64void* VirtualSysAllocator::Alloc(size_t size, size_t *actual_size,
65 size_t alignment) {
66 // Align on the pagesize boundary
67 const int pagesize = getpagesize();
68 if (alignment < pagesize) alignment = pagesize;
69 size = ((size + alignment - 1) / alignment) * alignment;
70
71 // Report the total number of bytes the OS actually delivered. This might be
72 // greater than |size| because of alignment concerns. The full size is
73 // necessary so that adjacent spans can be coalesced.
74 // TODO(antonm): proper processing of alignments
75 // in actual_size and decommitting.
76 if (actual_size) {
77 *actual_size = size;
78 }
79
80 // We currently do not support alignments larger than the pagesize or
81 // alignments that are not multiples of the pagesize after being floored.
82 // If this ability is needed it can be done by the caller (assuming it knows
83 // the page size).
84 assert(alignment <= pagesize);
85
86 void* result = VirtualAlloc(0, size,
87 MEM_COMMIT|MEM_RESERVE, PAGE_READWRITE);
88 if (result == NULL)
89 return NULL;
90
91 // If the result is not aligned memory fragmentation will result which can
92 // lead to pathological memory use.
93 assert((reinterpret_cast<uintptr_t>(result) & (alignment - 1)) == 0);
94
95 return result;
96}
97
98#ifdef _MSC_VER
99
100extern "C" SysAllocator* tc_get_sysalloc_override(SysAllocator *def);
101extern "C" SysAllocator* tc_get_sysalloc_default(SysAllocator *def)
102{
103 return def;
104}
105
106#if defined(_M_IX86)
107#pragma comment(linker, "/alternatename:_tc_get_sysalloc_override=_tc_get_sysalloc_default")
108#elif defined(_M_X64)
109#pragma comment(linker, "/alternatename:tc_get_sysalloc_override=tc_get_sysalloc_default")
110#endif
111
112#else // !_MSC_VER
113
114extern "C" ATTRIBUTE_NOINLINE
115SysAllocator* tc_get_sysalloc_override(SysAllocator *def)
116{
117 return def;
118}
119
120#endif
121
122static bool system_alloc_inited = false;
123void InitSystemAllocators(void) {
124 VirtualSysAllocator *alloc = new (virtual_space) VirtualSysAllocator();
Brian Silverman20350ac2021-11-17 18:19:55 -0800125 tcmalloc_sys_alloc = tc_get_sysalloc_override(alloc);
Austin Schuh745610d2015-09-06 18:19:50 -0700126}
127
128extern PERFTOOLS_DLL_DECL
129void* TCMalloc_SystemAlloc(size_t size, size_t *actual_size,
130 size_t alignment) {
131 SpinLockHolder lock_holder(&spinlock);
132
133 if (!system_alloc_inited) {
134 InitSystemAllocators();
135 system_alloc_inited = true;
136 }
137
Brian Silverman20350ac2021-11-17 18:19:55 -0800138 void* result = tcmalloc_sys_alloc->Alloc(size, actual_size, alignment);
Austin Schuh745610d2015-09-06 18:19:50 -0700139 if (result != NULL) {
140 if (actual_size) {
141 TCMalloc_SystemTaken += *actual_size;
142 } else {
143 TCMalloc_SystemTaken += size;
144 }
145 }
146 return result;
147}
148
149extern PERFTOOLS_DLL_DECL
150bool TCMalloc_SystemRelease(void* start, size_t length) {
151 if (VirtualFree(start, length, MEM_DECOMMIT))
152 return true;
153
154 // The decommit may fail if the memory region consists of allocations
155 // from more than one call to VirtualAlloc. In this case, fall back to
156 // using VirtualQuery to retrieve the allocation boundaries and decommit
157 // them each individually.
158
159 char* ptr = static_cast<char*>(start);
160 char* end = ptr + length;
161 MEMORY_BASIC_INFORMATION info;
162 while (ptr < end) {
163 size_t resultSize = VirtualQuery(ptr, &info, sizeof(info));
164 assert(resultSize == sizeof(info));
165 size_t decommitSize = std::min<size_t>(info.RegionSize, end - ptr);
166 BOOL success = VirtualFree(ptr, decommitSize, MEM_DECOMMIT);
167 assert(success == TRUE);
168 ptr += decommitSize;
169 }
170
171 return true;
172}
173
174extern PERFTOOLS_DLL_DECL
175void TCMalloc_SystemCommit(void* start, size_t length) {
176 if (VirtualAlloc(start, length, MEM_COMMIT, PAGE_READWRITE) == start)
177 return;
178
179 // The commit may fail if the memory region consists of allocations
180 // from more than one call to VirtualAlloc. In this case, fall back to
181 // using VirtualQuery to retrieve the allocation boundaries and commit them
182 // each individually.
183
184 char* ptr = static_cast<char*>(start);
185 char* end = ptr + length;
186 MEMORY_BASIC_INFORMATION info;
187 while (ptr < end) {
188 size_t resultSize = VirtualQuery(ptr, &info, sizeof(info));
189 assert(resultSize == sizeof(info));
190
191 size_t commitSize = std::min<size_t>(info.RegionSize, end - ptr);
192 void* newAddress = VirtualAlloc(ptr, commitSize, MEM_COMMIT,
193 PAGE_READWRITE);
194 assert(newAddress == ptr);
195 ptr += commitSize;
196 }
197}
198
199bool RegisterSystemAllocator(SysAllocator *allocator, int priority) {
200 return false; // we don't allow registration on windows, right now
201}
202
203void DumpSystemAllocatorStats(TCMalloc_Printer* printer) {
204 // We don't dump stats on windows, right now
205}