vfs: check userland buffers before reading them.
[haiku.git] / src / system / libroot / posix / malloc / heap.cpp
blobe2cc553a17c67b38351e57872bb7c4ec22c2bac8
1 ///-*-C++-*-//////////////////////////////////////////////////////////////////
2 //
3 // Hoard: A Fast, Scalable, and Memory-Efficient Allocator
4 // for Shared-Memory Multiprocessors
5 // Contact author: Emery Berger, http://www.cs.utexas.edu/users/emery
6 //
7 // Copyright (c) 1998-2000, The University of Texas at Austin.
8 //
9 // This library is free software; you can redistribute it and/or modify
10 // it under the terms of the GNU Library General Public License as
11 // published by the Free Software Foundation, http://www.fsf.org.
13 // This library is distributed in the hope that it will be useful, but
14 // WITHOUT ANY WARRANTY; without even the implied warranty of
15 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 // Library General Public License for more details.
18 //////////////////////////////////////////////////////////////////////////////
20 #include "config.h"
22 #include "heap.h"
23 #include "processheap.h"
24 #include "superblock.h"
26 using namespace BPrivate;
28 // NB: Use maketable.cpp to update this
29 // if SIZE_CLASSES, ALIGNMENT, SIZE_CLASS_BASE, MAX_EMPTY_SUPERBLOCKS,
30 // or SUPERBLOCK_SIZE changes.
32 #if (MAX_INTERNAL_FRAGMENTATION == 2)
34 size_t hoardHeap::_sizeTable[hoardHeap::SIZE_CLASSES] = {
35 8UL, 16UL, 24UL, 32UL, 40UL, 48UL, 56UL, 72UL, 80UL, 96UL, 120UL, 144UL,
36 168UL, 200UL, 240UL, 288UL, 344UL, 416UL, 496UL, 592UL, 712UL, 856UL,
37 1024UL, 1232UL, 1472UL, 1768UL, 2120UL, 2544UL, 3048UL, 3664UL,
38 4392UL, 5272UL, 6320UL, 7584UL, 9104UL, 10928UL, 13112UL, 15728UL,
39 18872UL, 22648UL, 27176UL, 32616UL, 39136UL, 46960UL, 56352UL,
40 67624UL, 81144UL, 97376UL, 116848UL, 140216UL, 168256UL, 201904UL,
41 242288UL, 290744UL, 348896UL, 418672UL, 502408UL, 602888UL, 723464UL,
42 868152UL, 1041784UL, 1250136UL, 1500160UL, 1800192UL, 2160232UL,
43 2592280UL, 3110736UL, 3732880UL, 4479456UL, 5375344UL, 6450408UL,
44 7740496UL, 9288592UL, 11146312UL, 13375568UL, 16050680UL, 19260816UL,
45 23112984UL, 27735576UL, 33282688UL, 39939224UL, 47927072UL,
46 57512488UL, 69014984UL, 82817976UL, 99381576UL, 119257888UL,
47 143109472UL, 171731360UL, 206077632UL, 247293152UL, 296751776UL,
48 356102144UL, 427322560UL, 512787072UL, 615344512UL, 738413376UL,
49 886096064UL, 1063315264UL
52 size_t hoardHeap::_threshold[hoardHeap::SIZE_CLASSES] = {
53 4096UL, 2048UL, 1364UL, 1024UL, 816UL, 680UL, 584UL, 452UL, 408UL,
54 340UL, 272UL, 224UL, 192UL, 160UL, 136UL, 112UL, 92UL, 76UL, 64UL,
55 52UL, 44UL, 36UL, 32UL, 24UL, 20UL, 16UL, 12UL, 12UL, 8UL, 8UL, 4UL,
56 4UL, 4UL, 4UL, 4UL, 4UL, 4UL, 4UL, 4UL, 4UL, 4UL, 4UL, 4UL, 4UL, 4UL,
57 4UL, 4UL, 4UL, 4UL, 4UL, 4UL, 4UL, 4UL, 4UL, 4UL, 4UL, 4UL, 4UL, 4UL,
58 4UL, 4UL, 4UL, 4UL, 4UL, 4UL, 4UL, 4UL, 4UL, 4UL, 4UL, 4UL, 4UL, 4UL,
59 4UL, 4UL, 4UL, 4UL, 4UL, 4UL, 4UL, 4UL, 4UL, 4UL, 4UL, 4UL, 4UL, 4UL,
60 4UL, 4UL, 4UL, 4UL, 4UL, 4UL, 4UL, 4UL, 4UL, 4UL, 4UL, 4UL
63 #elif (MAX_INTERNAL_FRAGMENTATION == 6)
65 size_t hoardHeap::_sizeTable[hoardHeap::SIZE_CLASSES] = {
66 8UL, 16UL, 24UL, 32UL, 48UL, 72UL, 112UL, 176UL, 288UL, 456UL, 728UL,
67 1160UL, 1848UL, 2952UL, 4728UL, 7560UL, 12096UL, 19344UL, 30952UL,
68 49520UL, 79232UL, 126768UL, 202832UL, 324520UL, 519232UL, 830768UL,
69 1329232UL, 2126768UL, 3402824UL, 5444520UL, 8711232UL, 13937968UL,
70 22300752UL, 35681200UL, 57089912UL, 91343856UL, 146150176UL,
71 233840256UL, 374144416UL, 598631040UL, 957809728UL, 1532495488UL
74 size_t hoardHeap::_threshold[hoardHeap::SIZE_CLASSES] = {
75 4096UL, 2048UL, 1364UL, 1024UL, 680UL, 452UL, 292UL, 184UL, 112UL, 68UL,
76 44UL, 28UL, 16UL, 8UL, 4UL, 4UL, 4UL, 4UL, 4UL, 4UL, 4UL, 4UL, 4UL,
77 4UL, 4UL, 4UL, 4UL, 4UL, 4UL, 4UL, 4UL, 4UL, 4UL, 4UL, 4UL, 4UL, 4UL,
78 4UL, 4UL, 4UL, 4UL, 4UL
81 #elif (MAX_INTERNAL_FRAGMENTATION == 10)
83 size_t hoardHeap::_sizeTable[hoardHeap::SIZE_CLASSES] = {
84 8UL, 16UL, 32UL, 64UL, 128UL, 256UL, 512UL, 1024UL, 2048UL, 4096UL,
85 8192UL, 16384UL, 32768UL, 65536UL, 131072UL, 262144UL, 524288UL,
86 1048576UL, 2097152UL, 4194304UL, 8388608UL, 16777216UL, 33554432UL,
87 67108864UL, 134217728UL, 268435456UL, 536870912UL, 1073741824UL,
88 2147483648UL
91 size_t hoardHeap::_threshold[hoardHeap::SIZE_CLASSES] = {
92 4096UL, 2048UL, 1024UL, 512UL, 256UL, 128UL, 64UL, 32UL, 16UL, 8UL, 4UL,
93 4UL, 4UL, 4UL, 4UL, 4UL, 4UL, 4UL, 4UL, 4UL, 4UL, 4UL, 4UL, 4UL, 4UL,
94 4UL, 4UL, 4UL, 4UL
97 #else
98 # error "Undefined size class base."
99 #endif
102 int hoardHeap::fMaxThreadHeaps = 1;
103 int hoardHeap::_numProcessors;
104 int hoardHeap::_numProcessorsMask;
107 // Return ceil(log_2(num)).
108 // num must be positive.
110 static int
111 lg(int num)
113 assert(num > 0);
114 int power = 0;
115 int n = 1;
116 // Invariant: 2^power == n.
117 while (n < num) {
118 n <<= 1;
119 power++;
121 return power;
125 // #pragma mark -
128 hoardHeap::hoardHeap(void)
130 _index(0), _reusableSuperblocks(NULL), _reusableSuperblocksCount(0)
131 #if HEAP_DEBUG
132 , _magic(HEAP_MAGIC)
133 #endif
135 initLock();
137 for (int i = 0; i < SUPERBLOCK_FULLNESS_GROUP; i++) {
138 for (int j = 0; j < SIZE_CLASSES; j++) {
139 // Initialize all superblocks lists to empty.
140 _superblocks[i][j] = NULL;
144 for (int k = 0; k < SIZE_CLASSES; k++) {
145 _leastEmptyBin[k] = 0;
150 void
151 hoardHeap::insertSuperblock(int sizeclass,
152 superblock *sb, processHeap *pHeap)
154 assert(sb->isValid());
155 assert(sb->getBlockSizeClass() == sizeclass);
156 assert(sb->getPrev() == NULL);
157 assert(sb->getNext() == NULL);
158 assert(_magic == HEAP_MAGIC);
160 // Now it's ours.
161 sb->setOwner(this);
163 // How full is this superblock? We'll use this information to put
164 // it into the right 'bin'.
165 sb->computeFullness();
166 int fullness = sb->getFullness();
168 // Update the stats.
169 incStats(sizeclass, sb->getNumBlocks() - sb->getNumAvailable(),
170 sb->getNumBlocks());
172 if (fullness == 0
173 && sb->getNumBlocks() > 1
174 && sb->getNumBlocks() == sb->getNumAvailable()) {
175 // Recycle this superblock.
176 #if 0
177 removeSuperblock(sb, sizeclass);
178 // Update the stats.
179 decStats(sizeclass,
180 sb->getNumBlocks() - sb->getNumAvailable(), sb->getNumBlocks());
181 // Free it immediately.
182 const size_t s = sizeFromClass(sizeclass);
183 const int blksize = align(sizeof(block) + s);
184 #if HEAP_LOG
185 // Record the memory deallocation.
186 MemoryRequest m;
187 m.deallocate((int)sb->getNumBlocks() *
188 (int)sizeFromClass(sb->getBlockSizeClass()));
189 pHeap->getLog(getIndex()).append(m);
190 #endif
191 #if HEAP_FRAG_STATS
193 pHeap->setDeallocated(0, sb->getNumBlocks() * sizeFromClass(sb->getBlockSizeClass()));
194 #endif
196 hoardUnsbrk(sb, align(sizeof(superblock) + blksize));
197 #else
198 recycle(sb);
199 #endif
200 } else {
201 // Insert it into the appropriate list.
202 superblock *&head = _superblocks[fullness][sizeclass];
203 sb->insertBefore(head);
204 head = sb;
205 assert(head->isValid());
207 // Reset the least-empty bin counter.
208 _leastEmptyBin[sizeclass] = RESET_LEAST_EMPTY_BIN;
213 superblock *
214 hoardHeap::removeMaxSuperblock(int sizeclass)
216 assert(_magic == HEAP_MAGIC);
218 superblock *head = NULL;
220 // First check the reusable superblocks list.
222 head = reuse(sizeclass);
223 if (head) {
224 // We found one. Since we're removing this superblock, update the
225 // stats accordingly.
226 decStats(sizeclass,
227 head->getNumBlocks() - head->getNumAvailable(),
228 head->getNumBlocks());
230 return head;
233 // Instead of finding the superblock with the most available space
234 // (something that would either involve a linear scan through the
235 // superblocks or maintaining the superblocks in sorted order), we
236 // just pick one that is no more than
237 // 1/(SUPERBLOCK_FULLNESS_GROUP-1) more full than the superblock
238 // with the most available space. We start with the emptiest group.
240 int i = 0;
242 // Note: the last group (SUPERBLOCK_FULLNESS_GROUP - 1) is full, so
243 // we never need to check it. But for robustness, we leave it in.
244 while (i < SUPERBLOCK_FULLNESS_GROUP) {
245 head = _superblocks[i][sizeclass];
246 if (head)
247 break;
249 i++;
252 if (!head)
253 return NULL;
255 // Make sure that this superblock is at least 1/EMPTY_FRACTION
256 // empty.
257 assert(head->getNumAvailable() * EMPTY_FRACTION >= head->getNumBlocks());
259 removeSuperblock(head, sizeclass);
261 assert(head->isValid());
262 assert(head->getPrev() == NULL);
263 assert(head->getNext() == NULL);
264 return head;
268 void
269 hoardHeap::removeSuperblock(superblock *sb, int sizeclass)
271 assert(_magic == HEAP_MAGIC);
273 assert(sb->isValid());
274 assert(sb->getOwner() == this);
275 assert(sb->getBlockSizeClass() == sizeclass);
277 for (int i = 0; i < SUPERBLOCK_FULLNESS_GROUP; i++) {
278 if (sb == _superblocks[i][sizeclass]) {
279 _superblocks[i][sizeclass] = sb->getNext();
280 if (_superblocks[i][sizeclass] != NULL) {
281 assert(_superblocks[i][sizeclass]->isValid());
283 break;
287 sb->remove();
288 decStats(sizeclass, sb->getNumBlocks() - sb->getNumAvailable(),
289 sb->getNumBlocks());
293 void
294 hoardHeap::moveSuperblock(superblock *sb,
295 int sizeclass, int fromBin, int toBin)
297 assert(_magic == HEAP_MAGIC);
298 assert(sb->isValid());
299 assert(sb->getOwner() == this);
300 assert(sb->getBlockSizeClass() == sizeclass);
301 assert(sb->getFullness() == toBin);
303 // Remove the superblock from the old bin.
305 superblock *&oldHead = _superblocks[fromBin][sizeclass];
306 if (sb == oldHead) {
307 oldHead = sb->getNext();
308 if (oldHead != NULL) {
309 assert(oldHead->isValid());
313 sb->remove();
315 // Insert the superblock into the new bin.
317 superblock *&newHead = _superblocks[toBin][sizeclass];
318 sb->insertBefore(newHead);
319 newHead = sb;
320 assert(newHead->isValid());
322 // Reset the least-empty bin counter.
323 _leastEmptyBin[sizeclass] = RESET_LEAST_EMPTY_BIN;
327 // The heap lock must be held when this procedure is called.
330 hoardHeap::freeBlock(block * &b, superblock * &sb,
331 int sizeclass, processHeap *pHeap)
333 assert(sb->isValid());
334 assert(b->isValid());
335 assert(this == sb->getOwner());
337 const int oldFullness = sb->getFullness();
338 sb->putBlock(b);
339 decUStats(sizeclass);
340 const int newFullness = sb->getFullness();
342 // Free big superblocks.
343 if (sb->getNumBlocks() == 1) {
344 removeSuperblock(sb, sizeclass);
345 const size_t s = sizeFromClass(sizeclass);
346 const int blksize = align(sizeof(block) + s);
347 #if HEAP_LOG
348 // Record the memory deallocation.
349 MemoryRequest m;
350 m.deallocate((int)sb->getNumBlocks()
351 * (int)sizeFromClass(sb->getBlockSizeClass()));
352 pHeap->getLog(getIndex()).append(m);
353 #endif
354 #if HEAP_FRAG_STATS
355 pHeap->setDeallocated(0,
356 sb->getNumBlocks() * sizeFromClass(sb->getBlockSizeClass()));
357 #endif
358 hoardUnsbrk(sb, align(sizeof(superblock) + blksize));
359 return 1;
362 // If the fullness value has changed, move the superblock.
363 if (newFullness != oldFullness) {
364 moveSuperblock(sb, sizeclass, oldFullness, newFullness);
365 } else {
366 // Move the superblock to the front of its list (to reduce
367 // paging).
368 superblock *&head = _superblocks[newFullness][sizeclass];
369 if (sb != head) {
370 sb->remove();
371 sb->insertBefore(head);
372 head = sb;
376 // If the superblock is now empty, recycle it.
378 if ((newFullness == 0) && (sb->getNumBlocks() == sb->getNumAvailable())) {
379 removeSuperblock(sb, sizeclass);
380 #if 0
381 // Free it immediately.
382 const size_t s = sizeFromClass(sizeclass);
383 const int blksize = align(sizeof(block) + s);
384 #if HEAP_LOG
385 // Record the memory deallocation.
386 MemoryRequest m;
387 m.deallocate((int)sb->getNumBlocks()
388 * (int)sizeFromClass(sb->getBlockSizeClass()));
389 pHeap->getLog(getIndex()).append(m);
390 #endif
391 #if HEAP_FRAG_STATS
392 pHeap->setDeallocated(0,
393 sb->getNumBlocks() * sizeFromClass(sb->getBlockSizeClass()));
394 #endif
396 hoardUnsbrk(sb, align(sizeof(superblock) + blksize));
397 return 1;
398 #else
399 recycle(sb);
400 // Update the stats. This restores the stats to their state
401 // before the call to removeSuperblock, above.
402 incStats(sizeclass,
403 sb->getNumBlocks() - sb->getNumAvailable(), sb->getNumBlocks());
404 #endif
407 // If this is the process heap, then we're done.
408 if (this == (hoardHeap *)pHeap)
409 return 0;
412 // Release a superblock, if necessary.
416 // Check to see if the amount free exceeds the release threshold
417 // (two superblocks worth of blocks for a given sizeclass) and if
418 // the heap is sufficiently empty.
421 // We never move anything to the process heap if we're on a
422 // uniprocessor.
423 if (_numProcessors > 1) {
424 int inUse, allocated;
425 getStats(sizeclass, inUse, allocated);
426 if ((inUse < allocated - getReleaseThreshold(sizeclass))
427 && (EMPTY_FRACTION * inUse <
428 EMPTY_FRACTION * allocated - allocated)) {
430 // We've crossed the magical threshold. Find the superblock with
431 // the most free blocks and give it to the process heap.
432 superblock *const maxSb = removeMaxSuperblock(sizeclass);
433 assert(maxSb != NULL);
435 // Update the statistics.
437 assert(maxSb->getNumBlocks() >= maxSb->getNumAvailable());
439 // Give the superblock back to the process heap.
440 pHeap->release(maxSb);
444 return 0;
448 void
449 hoardHeap::initNumProcs(void)
451 system_info info;
452 if (get_system_info(&info) != B_OK)
453 hoardHeap::_numProcessors = 1;
454 else
455 hoardHeap::_numProcessors = info.cpu_count;
457 fMaxThreadHeaps = 1 << (lg(_numProcessors) + 1);
458 _numProcessorsMask = fMaxThreadHeaps - 1;