VirtualBox

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

Last change on this file since 34079 was 33279, checked in by vboxsync, 14 years ago

IPRT: Use the mmap+heap stuff on all posixy platforms.

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