VirtualBox

source: vbox/trunk/src/VBox/Runtime/r3/posix/rtmempage-exec-mmap-heap-posix.cpp@ 43879

Last change on this file since 43879 was 43879, checked in by vboxsync, 12 years ago

Extended RTOnce with termination cleanups. (Changes existing structures and functions.)

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 23.1 KB
Line 
1/* $Id: rtmempage-exec-mmap-heap-posix.cpp 43879 2012-11-15 14:49:23Z vboxsync $ */
2/** @file
3 * IPRT - RTMemPage*, POSIX with heap.
4 */
5
6/*
7 * Copyright (C) 2006-2012 Oracle Corporation
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.virtualbox.org. This file is free software;
11 * you can redistribute it and/or modify it under the terms of the GNU
12 * General Public License (GPL) as published by the Free Software
13 * Foundation, in version 2 as it comes in the "COPYING" file of the
14 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
15 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
16 *
17 * The contents of this file may alternatively be used under the terms
18 * of the Common Development and Distribution License Version 1.0
19 * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
20 * VirtualBox OSE distribution, in which case the provisions of the
21 * CDDL are applicable instead of those of the GPL.
22 *
23 * You may elect to license modified versions of this file under the
24 * terms and conditions of either the GPL or the CDDL or both.
25 */
26
27
28/*******************************************************************************
29* Header Files *
30*******************************************************************************/
31#include "internal/iprt.h"
32#include <iprt/mem.h>
33
34#include <iprt/asm.h>
35#include <iprt/assert.h>
36#include <iprt/avl.h>
37#include <iprt/critsect.h>
38#include <iprt/err.h>
39#include <iprt/once.h>
40#include <iprt/param.h>
41#include <iprt/string.h>
42#include "internal/mem.h"
43
44#include <stdlib.h>
45#include <errno.h>
46#include <sys/mman.h>
47#if !defined(MAP_ANONYMOUS) && defined(MAP_ANON)
48# define MAP_ANONYMOUS MAP_ANON
49#endif
50
51
52/*******************************************************************************
53* Defined Constants And Macros *
54*******************************************************************************/
55/** Threshold at which to we switch to simply calling mmap. */
56#define RTMEMPAGEPOSIX_MMAP_THRESHOLD _128K
57/** The size of a heap block (power of two) - in bytes. */
58#define RTMEMPAGEPOSIX_BLOCK_SIZE _2M
59AssertCompile(RTMEMPAGEPOSIX_BLOCK_SIZE == (RTMEMPAGEPOSIX_BLOCK_SIZE / PAGE_SIZE) * PAGE_SIZE);
60/** The number of pages per heap block. */
61#define RTMEMPAGEPOSIX_BLOCK_PAGE_COUNT (RTMEMPAGEPOSIX_BLOCK_SIZE / PAGE_SIZE)
62
63
64/*******************************************************************************
65* Structures and Typedefs *
66*******************************************************************************/
67/** Pointer to a page heap block. */
68typedef struct RTHEAPPAGEBLOCK *PRTHEAPPAGEBLOCK;
69
70/**
71 * A simple page heap.
72 */
73typedef struct RTHEAPPAGE
74{
75 /** Magic number (RTHEAPPAGE_MAGIC). */
76 uint32_t u32Magic;
77 /** The number of pages in the heap (in BlockTree). */
78 uint32_t cHeapPages;
79 /** The number of currently free pages. */
80 uint32_t cFreePages;
81 /** Number of successful calls. */
82 uint32_t cAllocCalls;
83 /** Number of successful free calls. */
84 uint32_t cFreeCalls;
85 /** The free call number at which we last tried to minimize the heap. */
86 uint32_t uLastMinimizeCall;
87 /** Tree of heap blocks. */
88 AVLRPVTREE BlockTree;
89 /** Allocation hint no 1 (last freed). */
90 PRTHEAPPAGEBLOCK pHint1;
91 /** Allocation hint no 2 (last alloc). */
92 PRTHEAPPAGEBLOCK pHint2;
93 /** Critical section protecting the heap. */
94 RTCRITSECT CritSect;
95 /** Set if the memory must allocated with execute access. */
96 bool fExec;
97} RTHEAPPAGE;
98#define RTHEAPPAGE_MAGIC UINT32_C(0xfeedface)
99/** Pointer to a page heap. */
100typedef RTHEAPPAGE *PRTHEAPPAGE;
101
102
103/**
104 * Describes a page heap block.
105 */
106typedef struct RTHEAPPAGEBLOCK
107{
108 /** The AVL tree node core (void pointer range). */
109 AVLRPVNODECORE Core;
110 /** Allocation bitmap. Set bits marks allocated pages. */
111 uint32_t bmAlloc[RTMEMPAGEPOSIX_BLOCK_PAGE_COUNT / 32];
112 /** Allocation boundrary bitmap. Set bits marks the start of
113 * allocations. */
114 uint32_t bmFirst[RTMEMPAGEPOSIX_BLOCK_PAGE_COUNT / 32];
115 /** The number of free pages. */
116 uint32_t cFreePages;
117 /** Pointer back to the heap. */
118 PRTHEAPPAGE pHeap;
119} RTHEAPPAGEBLOCK;
120
121
122/**
123 * Argument package for rtHeapPageAllocCallback.
124 */
125typedef struct RTHEAPPAGEALLOCARGS
126{
127 /** The number of pages to allocate. */
128 size_t cPages;
129 /** Non-null on success. */
130 void *pvAlloc;
131 /** Whether the pages should be zeroed or not. */
132 bool fZero;
133} RTHEAPPAGEALLOCARGS;
134
135
136/*******************************************************************************
137* Global Variables *
138*******************************************************************************/
139/** Initialize once structure. */
140static RTONCE g_MemPagePosixInitOnce = RTONCE_INITIALIZER;
141/** The page heap. */
142static RTHEAPPAGE g_MemPagePosixHeap;
143/** The exec page heap. */
144static RTHEAPPAGE g_MemExecPosixHeap;
145
146
147#ifdef RT_OS_OS2
148/*
149 * A quick mmap/munmap mockup for avoid duplicating lots of good code.
150 */
151# define INCL_BASE
152# include <os2.h>
153# undef MAP_PRIVATE
154# define MAP_PRIVATE 0
155# undef MAP_ANONYMOUS
156# define MAP_ANONYMOUS 0
157# undef MAP_FAILED
158# define MAP_FAILED (void *)-1
159# undef mmap
160# define mmap iprt_mmap
161# undef munmap
162# define munmap iprt_munmap
163
164static void *mmap(void *pvWhere, size_t cb, int fProt, int fFlags, int fd, off_t off)
165{
166 NOREF(pvWhere); NOREF(fd); NOREF(off);
167 void *pv = NULL;
168 ULONG fAlloc = OBJ_ANY | PAG_COMMIT;
169 if (fProt & PROT_EXEC)
170 fAlloc |= PAG_EXECUTE;
171 if (fProt & PROT_READ)
172 fAlloc |= PAG_READ;
173 if (fProt & PROT_WRITE)
174 fAlloc |= PAG_WRITE;
175 APIRET rc = DosAllocMem(&pv, cb, fAlloc);
176 if (rc == NO_ERROR)
177 return pv;
178 errno = ENOMEM;
179 return MAP_FAILED;
180}
181
182static int munmap(void *pv, size_t cb)
183{
184 APIRET rc = DosFreeMem(pv);
185 if (rc == NO_ERROR)
186 return 0;
187 errno = EINVAL;
188 return -1;
189}
190
191#endif
192
193/**
194 * Initializes the heap.
195 *
196 * @returns IPRT status code.
197 * @param pHeap The page heap to initialize.
198 * @param fExec Whether the heap memory should be marked as
199 * executable or not.
200 */
201int RTHeapPageInit(PRTHEAPPAGE pHeap, bool fExec)
202{
203 int rc = RTCritSectInitEx(&pHeap->CritSect,
204 RTCRITSECT_FLAGS_NO_LOCK_VAL | RTCRITSECT_FLAGS_NO_NESTING | RTCRITSECT_FLAGS_BOOTSTRAP_HACK,
205 NIL_RTLOCKVALCLASS, RTLOCKVAL_SUB_CLASS_NONE, NULL);
206 if (RT_SUCCESS(rc))
207 {
208 pHeap->cHeapPages = 0;
209 pHeap->cFreePages = 0;
210 pHeap->cAllocCalls = 0;
211 pHeap->cFreeCalls = 0;
212 pHeap->uLastMinimizeCall = 0;
213 pHeap->BlockTree = NULL;
214 pHeap->fExec = fExec;
215 pHeap->u32Magic = RTHEAPPAGE_MAGIC;
216 }
217 return rc;
218}
219
220
221/**
222 * Deletes the heap and all the memory it tracks.
223 *
224 * @returns IPRT status code.
225 * @param pHeap The page heap to delete.
226 */
227int RTHeapPageDelete(PRTHEAPPAGE pHeap)
228{
229 NOREF(pHeap);
230 return VERR_NOT_IMPLEMENTED;
231}
232
233
234/**
235 * Avoids some gotos in rtHeapPageAllocFromBlock.
236 *
237 * @returns VINF_SUCCESS.
238 * @param pBlock The block.
239 * @param iPage The page to start allocating at.
240 * @param cPages The number of pages.
241 * @param fZero Whether to clear them.
242 * @param ppv Where to return the allocation address.
243 */
244DECLINLINE(int) rtHeapPageAllocFromBlockSuccess(PRTHEAPPAGEBLOCK pBlock, uint32_t iPage, size_t cPages, bool fZero, void **ppv)
245{
246 PRTHEAPPAGE pHeap = pBlock->pHeap;
247
248 ASMBitSet(&pBlock->bmFirst[0], iPage);
249 pBlock->cFreePages -= cPages;
250 pHeap->cFreePages -= cPages;
251 if (!pHeap->pHint2 || pHeap->pHint2->cFreePages < pBlock->cFreePages)
252 pHeap->pHint2 = pBlock;
253 pHeap->cAllocCalls++;
254
255 void *pv = (uint8_t *)pBlock->Core.Key + (iPage << PAGE_SHIFT);
256 *ppv = pv;
257 if (fZero)
258 RT_BZERO(pv, cPages << PAGE_SHIFT);
259
260 return VINF_SUCCESS;
261}
262
263
264/**
265 * Checks if a page range is free in the specified block.
266 *
267 * @returns @c true if the range is free, @c false if not.
268 * @param pBlock The block.
269 * @param iFirst The first page to check.
270 * @param cPages The number of pages to check.
271 */
272DECLINLINE(bool) rtHeapPageIsPageRangeFree(PRTHEAPPAGEBLOCK pBlock, uint32_t iFirst, uint32_t cPages)
273{
274 uint32_t i = iFirst + cPages;
275 while (i-- > iFirst)
276 {
277 if (ASMBitTest(&pBlock->bmAlloc[0], i))
278 return false;
279 Assert(!ASMBitTest(&pBlock->bmFirst[0], i));
280 }
281 return true;
282}
283
284
285/**
286 * Tries to allocate a chunk of pages from a heap block.
287 *
288 * @retval VINF_SUCCESS on success.
289 * @retval VERR_NO_MEMORY if the allocation failed.
290 * @param pBlock The block to allocate from.
291 * @param cPages The size of the allocation.
292 * @param fZero Whether it should be zeroed or not.
293 * @param ppv Where to return the allocation address on success.
294 */
295DECLINLINE(int) rtHeapPageAllocFromBlock(PRTHEAPPAGEBLOCK pBlock, size_t cPages, bool fZero, void **ppv)
296{
297 if (pBlock->cFreePages >= cPages)
298 {
299 int iPage = ASMBitFirstClear(&pBlock->bmAlloc[0], RTMEMPAGEPOSIX_BLOCK_PAGE_COUNT);
300 Assert(iPage >= 0);
301
302 /* special case: single page. */
303 if (cPages == 1)
304 {
305 ASMBitSet(&pBlock->bmAlloc[0], iPage);
306 return rtHeapPageAllocFromBlockSuccess(pBlock, iPage, cPages, fZero, ppv);
307 }
308
309 while ( iPage >= 0
310 && (unsigned)iPage <= RTMEMPAGEPOSIX_BLOCK_PAGE_COUNT - cPages)
311 {
312 if (rtHeapPageIsPageRangeFree(pBlock, iPage + 1, cPages - 1))
313 {
314 ASMBitSetRange(&pBlock->bmAlloc[0], iPage, iPage + cPages);
315 return rtHeapPageAllocFromBlockSuccess(pBlock, iPage, cPages, fZero, ppv);
316 }
317
318 /* next */
319 iPage = ASMBitNextSet(&pBlock->bmAlloc[0], RTMEMPAGEPOSIX_BLOCK_PAGE_COUNT, iPage);
320 if (iPage < 0 || iPage >= RTMEMPAGEPOSIX_BLOCK_PAGE_COUNT - 1)
321 break;
322 iPage = ASMBitNextClear(&pBlock->bmAlloc[0], RTMEMPAGEPOSIX_BLOCK_PAGE_COUNT, iPage);
323 }
324 }
325
326 return VERR_NO_MEMORY;
327}
328
329
330/**
331 * RTAvlrPVDoWithAll callback.
332 *
333 * @returns 0 to continue the enum, non-zero to quit it.
334 * @param pNode The node.
335 * @param pvUser The user argument.
336 */
337static DECLCALLBACK(int) rtHeapPageAllocCallback(PAVLRPVNODECORE pNode, void *pvUser)
338{
339 PRTHEAPPAGEBLOCK pBlock = RT_FROM_MEMBER(pNode, RTHEAPPAGEBLOCK, Core);
340 RTHEAPPAGEALLOCARGS *pArgs = (RTHEAPPAGEALLOCARGS *)pvUser;
341 int rc = rtHeapPageAllocFromBlock(pBlock, pArgs->cPages, pArgs->fZero, &pArgs->pvAlloc);
342 return RT_SUCCESS(rc) ? 1 : 0;
343}
344
345
346/**
347 * Worker for RTHeapPageAlloc.
348 *
349 * @returns IPRT status code
350 * @param pHeap The heap - locked.
351 * @param cPages The page count.
352 * @param pszTag The tag.
353 * @param fZero Whether to zero the memory.
354 * @param ppv Where to return the address of the allocation
355 * on success.
356 */
357static int rtHeapPageAllocLocked(PRTHEAPPAGE pHeap, size_t cPages, const char *pszTag, bool fZero, void **ppv)
358{
359 int rc;
360 NOREF(pszTag);
361
362 /*
363 * Use the hints first.
364 */
365 if (pHeap->pHint1)
366 {
367 rc = rtHeapPageAllocFromBlock(pHeap->pHint1, cPages, fZero, ppv);
368 if (rc != VERR_NO_MEMORY)
369 return rc;
370 }
371 if (pHeap->pHint2)
372 {
373 rc = rtHeapPageAllocFromBlock(pHeap->pHint2, cPages, fZero, ppv);
374 if (rc != VERR_NO_MEMORY)
375 return rc;
376 }
377
378 /*
379 * Search the heap for a block with enough free space.
380 *
381 * N.B. This search algorithm is not optimal at all. What (hopefully) saves
382 * it are the two hints above.
383 */
384 if (pHeap->cFreePages >= cPages)
385 {
386 RTHEAPPAGEALLOCARGS Args;
387 Args.cPages = cPages;
388 Args.pvAlloc = NULL;
389 Args.fZero = fZero;
390 RTAvlrPVDoWithAll(&pHeap->BlockTree, true /*fFromLeft*/, rtHeapPageAllocCallback, &Args);
391 if (Args.pvAlloc)
392 {
393 *ppv = Args.pvAlloc;
394 return VINF_SUCCESS;
395 }
396 }
397
398 /*
399 * Didn't find anytyhing, so expand the heap with a new block.
400 */
401 RTCritSectLeave(&pHeap->CritSect);
402 void *pvPages;
403 pvPages = mmap(NULL, RTMEMPAGEPOSIX_BLOCK_SIZE,
404 PROT_READ | PROT_WRITE | (pHeap->fExec ? PROT_EXEC : 0),
405 MAP_PRIVATE | MAP_ANONYMOUS,
406 -1, 0);
407 if (pvPages == MAP_FAILED)
408 {
409 RTCritSectEnter(&pHeap->CritSect);
410 return RTErrConvertFromErrno(errno);
411
412 }
413 /** @todo Eliminate this rtMemBaseAlloc dependency! */
414 PRTHEAPPAGEBLOCK pBlock = (PRTHEAPPAGEBLOCK)rtMemBaseAlloc(sizeof(*pBlock));
415 if (!pBlock)
416 {
417 munmap(pvPages, RTMEMPAGEPOSIX_BLOCK_SIZE);
418 RTCritSectEnter(&pHeap->CritSect);
419 return VERR_NO_MEMORY;
420 }
421
422 RT_ZERO(*pBlock);
423 pBlock->Core.Key = pvPages;
424 pBlock->Core.KeyLast = (uint8_t *)pvPages + RTMEMPAGEPOSIX_BLOCK_SIZE - 1;
425 pBlock->cFreePages = RTMEMPAGEPOSIX_BLOCK_PAGE_COUNT;
426 pBlock->pHeap = pHeap;
427
428 RTCritSectEnter(&pHeap->CritSect);
429
430 bool fRc = RTAvlrPVInsert(&pHeap->BlockTree, &pBlock->Core); Assert(fRc); NOREF(fRc);
431 pHeap->cFreePages += RTMEMPAGEPOSIX_BLOCK_PAGE_COUNT;
432 pHeap->cHeapPages += RTMEMPAGEPOSIX_BLOCK_PAGE_COUNT;
433
434 /*
435 * Grab memory from the new block (cannot fail).
436 */
437 rc = rtHeapPageAllocFromBlock(pBlock, cPages, fZero, ppv);
438 Assert(rc == VINF_SUCCESS);
439
440 return rc;
441}
442
443
444/**
445 * Allocates one or more pages off the heap.
446 *
447 * @returns IPRT status code.
448 * @param pHeap The page heap.
449 * @param cPages The number of pages to allocate.
450 * @param pszTag The allocation tag.
451 * @param fZero Set if the pages should be zeroed or not.
452 * @param ppv Where to return the pointer to the pages.
453 */
454int RTHeapPageAlloc(PRTHEAPPAGE pHeap, size_t cPages, const char *pszTag, bool fZero, void **ppv)
455{
456 /*
457 * Validate input.
458 */
459 AssertPtr(ppv);
460 *ppv = NULL;
461 AssertPtrReturn(pHeap, VERR_INVALID_HANDLE);
462 AssertReturn(pHeap->u32Magic == RTHEAPPAGE_MAGIC, VERR_INVALID_HANDLE);
463 AssertMsgReturn(cPages < RTMEMPAGEPOSIX_BLOCK_SIZE, ("%#zx\n", cPages), VERR_OUT_OF_RANGE);
464
465 /*
466 * Grab the lock and call a worker with many returns.
467 */
468 int rc = RTCritSectEnter(&pHeap->CritSect);
469 if (RT_SUCCESS(rc))
470 {
471 rc = rtHeapPageAllocLocked(pHeap, cPages, pszTag, fZero, ppv);
472 RTCritSectLeave(&pHeap->CritSect);
473 }
474
475 return rc;
476}
477
478
479/**
480 * RTAvlrPVDoWithAll callback.
481 *
482 * @returns 0 to continue the enum, non-zero to quit it.
483 * @param pNode The node.
484 * @param pvUser Pointer to a block pointer variable. For returning
485 * the address of the block to be freed.
486 */
487static DECLCALLBACK(int) rtHeapPageFindUnusedBlockCallback(PAVLRPVNODECORE pNode, void *pvUser)
488{
489 PRTHEAPPAGEBLOCK pBlock = RT_FROM_MEMBER(pNode, RTHEAPPAGEBLOCK, Core);
490 if (pBlock->cFreePages == RTMEMPAGEPOSIX_BLOCK_PAGE_COUNT)
491 {
492 *(PRTHEAPPAGEBLOCK *)pvUser = pBlock;
493 return 1;
494 }
495 return 0;
496}
497
498
499/**
500 * Allocates one or more pages off the heap.
501 *
502 * @returns IPRT status code.
503 * @param pHeap The page heap.
504 * @param pv Pointer to what RTHeapPageAlloc returned.
505 * @param cPages The number of pages that was allocated.
506 */
507int RTHeapPageFree(PRTHEAPPAGE pHeap, void *pv, size_t cPages)
508{
509 /*
510 * Validate input.
511 */
512 if (!pv)
513 return VINF_SUCCESS;
514 AssertPtrReturn(pHeap, VERR_INVALID_HANDLE);
515 AssertReturn(pHeap->u32Magic == RTHEAPPAGE_MAGIC, VERR_INVALID_HANDLE);
516
517 /*
518 * Grab the lock and look up the page.
519 */
520 int rc = RTCritSectEnter(&pHeap->CritSect);
521 if (RT_SUCCESS(rc))
522 {
523 PRTHEAPPAGEBLOCK pBlock = (PRTHEAPPAGEBLOCK)RTAvlrPVRangeGet(&pHeap->BlockTree, pv);
524 if (pBlock)
525 {
526 /*
527 * Validate the specified address range.
528 */
529 uint32_t const iPage = (uint32_t)(((uintptr_t)pv - (uintptr_t)pBlock->Core.Key) >> PAGE_SHIFT);
530 /* Check the range is within the block. */
531 bool fOk = iPage + cPages <= RTMEMPAGEPOSIX_BLOCK_PAGE_COUNT;
532 /* Check that it's the start of an allocation. */
533 fOk = fOk && ASMBitTest(&pBlock->bmFirst[0], iPage);
534 /* Check that the range ends at an allocation boundrary. */
535 fOk = fOk && ( iPage + cPages == RTMEMPAGEPOSIX_BLOCK_PAGE_COUNT
536 || ASMBitTest(&pBlock->bmFirst[0], iPage + cPages)
537 || !ASMBitTest(&pBlock->bmAlloc[0], iPage + cPages));
538 /* Check the other pages. */
539 uint32_t const iLastPage = iPage + cPages - 1;
540 for (uint32_t i = iPage + 1; i < iLastPage && fOk; i++)
541 fOk = ASMBitTest(&pBlock->bmAlloc[0], i)
542 && !ASMBitTest(&pBlock->bmFirst[0], i);
543 if (fOk)
544 {
545 /*
546 * Free the memory.
547 */
548 ASMBitClearRange(&pBlock->bmAlloc[0], iPage, iPage + cPages);
549 ASMBitClear(&pBlock->bmFirst[0], iPage);
550 pBlock->cFreePages += cPages;
551 pHeap->cFreePages += cPages;
552 pHeap->cFreeCalls++;
553 if (!pHeap->pHint1 || pHeap->pHint1->cFreePages < pBlock->cFreePages)
554 pHeap->pHint1 = pBlock;
555
556 /*
557 * Shrink the heap. Not very efficient because of the AVL tree.
558 */
559 if ( pHeap->cFreePages >= RTMEMPAGEPOSIX_BLOCK_PAGE_COUNT * 3
560 && pHeap->cFreePages >= pHeap->cHeapPages / 2 /* 50% free */
561 && pHeap->cFreeCalls - pHeap->uLastMinimizeCall > RTMEMPAGEPOSIX_BLOCK_PAGE_COUNT
562 )
563 {
564 uint32_t cFreePageTarget = pHeap->cHeapPages / 4; /* 25% free */
565 while (pHeap->cFreePages > cFreePageTarget)
566 {
567 pHeap->uLastMinimizeCall = pHeap->cFreeCalls;
568
569 pBlock = NULL;
570 RTAvlrPVDoWithAll(&pHeap->BlockTree, false /*fFromLeft*/,
571 rtHeapPageFindUnusedBlockCallback, &pBlock);
572 if (!pBlock)
573 break;
574
575 void *pv2 = RTAvlrPVRemove(&pHeap->BlockTree, pBlock->Core.Key); Assert(pv2); NOREF(pv2);
576 pHeap->cHeapPages -= RTMEMPAGEPOSIX_BLOCK_PAGE_COUNT;
577 pHeap->cFreePages -= RTMEMPAGEPOSIX_BLOCK_PAGE_COUNT;
578 pHeap->pHint1 = NULL;
579 pHeap->pHint2 = NULL;
580 RTCritSectLeave(&pHeap->CritSect);
581
582 munmap(pBlock->Core.Key, RTMEMPAGEPOSIX_BLOCK_SIZE);
583 pBlock->Core.Key = pBlock->Core.KeyLast = NULL;
584 pBlock->cFreePages = 0;
585 rtMemBaseFree(pBlock);
586
587 RTCritSectEnter(&pHeap->CritSect);
588 }
589 }
590 }
591 else
592 rc = VERR_INVALID_POINTER;
593 }
594 else
595 rc = VERR_INVALID_POINTER;
596
597 RTCritSectLeave(&pHeap->CritSect);
598 }
599
600 return rc;
601}
602
603
604/**
605 * Initializes the heap.
606 *
607 * @returns IPRT status code
608 * @param pvUser Unused.
609 */
610static DECLCALLBACK(int) rtMemPagePosixInitOnce(void *pvUser)
611{
612 NOREF(pvUser);
613 int rc = RTHeapPageInit(&g_MemPagePosixHeap, false /*fExec*/);
614 if (RT_SUCCESS(rc))
615 {
616 rc = RTHeapPageInit(&g_MemExecPosixHeap, true /*fExec*/);
617 if (RT_SUCCESS(rc))
618 return rc;
619 RTHeapPageDelete(&g_MemPagePosixHeap);
620 }
621 return rc;
622}
623
624
625/**
626 * Allocates memory from the specified heap.
627 *
628 * @returns Address of the allocated memory.
629 * @param cb The number of bytes to allocate.
630 * @param pszTag The tag.
631 * @param fZero Whether to zero the memory or not.
632 * @param pHeap The heap to use.
633 */
634static void *rtMemPagePosixAlloc(size_t cb, const char *pszTag, bool fZero, PRTHEAPPAGE pHeap)
635{
636 /*
637 * Validate & adjust the input.
638 */
639 Assert(cb > 0);
640 NOREF(pszTag);
641 cb = RT_ALIGN_Z(cb, PAGE_SIZE);
642
643 /*
644 * If the allocation is relatively large, we use mmap/munmap directly.
645 */
646 void *pv;
647 if (cb >= RTMEMPAGEPOSIX_MMAP_THRESHOLD)
648 {
649
650 pv = mmap(NULL, cb,
651 PROT_READ | PROT_WRITE | (pHeap == &g_MemExecPosixHeap ? PROT_EXEC : 0),
652 MAP_PRIVATE | MAP_ANONYMOUS,
653 -1, 0);
654 if (pv != MAP_FAILED)
655 {
656 AssertPtr(pv);
657 if (fZero)
658 RT_BZERO(pv, cb);
659 }
660 else
661 pv = NULL;
662 }
663 else
664 {
665 int rc = RTOnce(&g_MemPagePosixInitOnce, rtMemPagePosixInitOnce, NULL);
666 if (RT_SUCCESS(rc))
667 rc = RTHeapPageAlloc(pHeap, cb >> PAGE_SHIFT, pszTag, fZero, &pv);
668 if (RT_FAILURE(rc))
669 pv = NULL;
670 }
671
672 return pv;
673}
674
675
676/**
677 * Free memory allocated by rtMemPagePosixAlloc.
678 *
679 * @param pv The address of the memory to free.
680 * @param cb The size.
681 * @param pHeap The heap.
682 */
683static void rtMemPagePosixFree(void *pv, size_t cb, PRTHEAPPAGE pHeap)
684{
685 /*
686 * Validate & adjust the input.
687 */
688 if (!pv)
689 return;
690 AssertPtr(pv);
691 Assert(cb > 0);
692 Assert(!((uintptr_t)pv & PAGE_OFFSET_MASK));
693 cb = RT_ALIGN_Z(cb, PAGE_SIZE);
694
695 /*
696 * If the allocation is relatively large, we use mmap/munmap directly.
697 */
698 if (cb >= RTMEMPAGEPOSIX_MMAP_THRESHOLD)
699 {
700 int rc = munmap(pv, cb);
701 AssertMsg(rc == 0, ("rc=%d pv=%p cb=%#zx\n", rc, pv, cb)); NOREF(rc);
702 }
703 else
704 {
705 int rc = RTHeapPageFree(pHeap, pv, cb >> PAGE_SHIFT);
706 AssertRC(rc);
707 }
708}
709
710
711
712
713
714RTDECL(void *) RTMemPageAllocTag(size_t cb, const char *pszTag) RT_NO_THROW
715{
716 return rtMemPagePosixAlloc(cb, pszTag, false /*fZero*/, &g_MemPagePosixHeap);
717}
718
719
720RTDECL(void *) RTMemPageAllocZTag(size_t cb, const char *pszTag) RT_NO_THROW
721{
722 return rtMemPagePosixAlloc(cb, pszTag, true /*fZero*/, &g_MemPagePosixHeap);
723}
724
725
726RTDECL(void) RTMemPageFree(void *pv, size_t cb) RT_NO_THROW
727{
728 return rtMemPagePosixFree(pv, cb, &g_MemPagePosixHeap);
729}
730
731
732
733
734
735RTDECL(void *) RTMemExecAllocTag(size_t cb, const char *pszTag) RT_NO_THROW
736{
737 return rtMemPagePosixAlloc(cb, pszTag, false /*fZero*/, &g_MemExecPosixHeap);
738}
739
740
741RTDECL(void) RTMemExecFree(void *pv, size_t cb) RT_NO_THROW
742{
743 return rtMemPagePosixFree(pv, cb, &g_MemExecPosixHeap);
744}
745
Note: See TracBrowser for help on using the repository browser.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette