VirtualBox

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

Last change on this file since 73531 was 69111, checked in by vboxsync, 7 years ago

(C) year

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 24.0 KB
Line 
1/* $Id: rtmempage-exec-mmap-heap-posix.cpp 69111 2017-10-17 14:26:02Z vboxsync $ */
2/** @file
3 * IPRT - RTMemPage*, POSIX with heap.
4 */
5
6/*
7 * Copyright (C) 2006-2017 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#include "../alloc-ef.h"
44
45#include <stdlib.h>
46#include <errno.h>
47#include <sys/mman.h>
48#if !defined(MAP_ANONYMOUS) && defined(MAP_ANON)
49# define MAP_ANONYMOUS MAP_ANON
50#endif
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#ifdef RT_OS_OS2
149/*
150 * A quick mmap/munmap mockup for avoid duplicating lots of good code.
151 */
152# define INCL_BASE
153# include <os2.h>
154# undef MAP_PRIVATE
155# define MAP_PRIVATE 0
156# undef MAP_ANONYMOUS
157# define MAP_ANONYMOUS 0
158# undef MAP_FAILED
159# define MAP_FAILED (void *)-1
160# undef mmap
161# define mmap iprt_mmap
162# undef munmap
163# define munmap iprt_munmap
164
165static void *mmap(void *pvWhere, size_t cb, int fProt, int fFlags, int fd, off_t off)
166{
167 NOREF(pvWhere); NOREF(fd); NOREF(off);
168 void *pv = NULL;
169 ULONG fAlloc = OBJ_ANY | PAG_COMMIT;
170 if (fProt & PROT_EXEC)
171 fAlloc |= PAG_EXECUTE;
172 if (fProt & PROT_READ)
173 fAlloc |= PAG_READ;
174 if (fProt & PROT_WRITE)
175 fAlloc |= PAG_WRITE;
176 APIRET rc = DosAllocMem(&pv, cb, fAlloc);
177 if (rc == NO_ERROR)
178 return pv;
179 errno = ENOMEM;
180 return MAP_FAILED;
181}
182
183static int munmap(void *pv, size_t cb)
184{
185 APIRET rc = DosFreeMem(pv);
186 if (rc == NO_ERROR)
187 return 0;
188 errno = EINVAL;
189 return -1;
190}
191
192#endif
193
194/**
195 * Initializes the heap.
196 *
197 * @returns IPRT status code.
198 * @param pHeap The page heap to initialize.
199 * @param fExec Whether the heap memory should be marked as
200 * executable or not.
201 */
202int RTHeapPageInit(PRTHEAPPAGE pHeap, bool fExec)
203{
204 int rc = RTCritSectInitEx(&pHeap->CritSect,
205 RTCRITSECT_FLAGS_NO_LOCK_VAL | RTCRITSECT_FLAGS_NO_NESTING | RTCRITSECT_FLAGS_BOOTSTRAP_HACK,
206 NIL_RTLOCKVALCLASS, RTLOCKVAL_SUB_CLASS_NONE, NULL);
207 if (RT_SUCCESS(rc))
208 {
209 pHeap->cHeapPages = 0;
210 pHeap->cFreePages = 0;
211 pHeap->cAllocCalls = 0;
212 pHeap->cFreeCalls = 0;
213 pHeap->uLastMinimizeCall = 0;
214 pHeap->BlockTree = NULL;
215 pHeap->fExec = fExec;
216 pHeap->u32Magic = RTHEAPPAGE_MAGIC;
217 }
218 return rc;
219}
220
221
222/**
223 * Deletes the heap and all the memory it tracks.
224 *
225 * @returns IPRT status code.
226 * @param pHeap The page heap to delete.
227 */
228int RTHeapPageDelete(PRTHEAPPAGE pHeap)
229{
230 NOREF(pHeap);
231 return VERR_NOT_IMPLEMENTED;
232}
233
234
235/**
236 * Avoids some gotos in rtHeapPageAllocFromBlock.
237 *
238 * @returns VINF_SUCCESS.
239 * @param pBlock The block.
240 * @param iPage The page to start allocating at.
241 * @param cPages The number of pages.
242 * @param fZero Whether to clear them.
243 * @param ppv Where to return the allocation address.
244 */
245DECLINLINE(int) rtHeapPageAllocFromBlockSuccess(PRTHEAPPAGEBLOCK pBlock, uint32_t iPage, size_t cPages, bool fZero, void **ppv)
246{
247 PRTHEAPPAGE pHeap = pBlock->pHeap;
248
249 ASMBitSet(&pBlock->bmFirst[0], iPage);
250 pBlock->cFreePages -= cPages;
251 pHeap->cFreePages -= cPages;
252 if (!pHeap->pHint2 || pHeap->pHint2->cFreePages < pBlock->cFreePages)
253 pHeap->pHint2 = pBlock;
254 pHeap->cAllocCalls++;
255
256 void *pv = (uint8_t *)pBlock->Core.Key + (iPage << PAGE_SHIFT);
257 *ppv = pv;
258 if (fZero)
259 RT_BZERO(pv, cPages << PAGE_SHIFT);
260
261 return VINF_SUCCESS;
262}
263
264
265/**
266 * Checks if a page range is free in the specified block.
267 *
268 * @returns @c true if the range is free, @c false if not.
269 * @param pBlock The block.
270 * @param iFirst The first page to check.
271 * @param cPages The number of pages to check.
272 */
273DECLINLINE(bool) rtHeapPageIsPageRangeFree(PRTHEAPPAGEBLOCK pBlock, uint32_t iFirst, uint32_t cPages)
274{
275 uint32_t i = iFirst + cPages;
276 while (i-- > iFirst)
277 {
278 if (ASMBitTest(&pBlock->bmAlloc[0], i))
279 return false;
280 Assert(!ASMBitTest(&pBlock->bmFirst[0], i));
281 }
282 return true;
283}
284
285
286/**
287 * Tries to allocate a chunk of pages from a heap block.
288 *
289 * @retval VINF_SUCCESS on success.
290 * @retval VERR_NO_MEMORY if the allocation failed.
291 * @param pBlock The block to allocate from.
292 * @param cPages The size of the allocation.
293 * @param fZero Whether it should be zeroed or not.
294 * @param ppv Where to return the allocation address on success.
295 */
296DECLINLINE(int) rtHeapPageAllocFromBlock(PRTHEAPPAGEBLOCK pBlock, size_t cPages, bool fZero, void **ppv)
297{
298 if (pBlock->cFreePages >= cPages)
299 {
300 int iPage = ASMBitFirstClear(&pBlock->bmAlloc[0], RTMEMPAGEPOSIX_BLOCK_PAGE_COUNT);
301 Assert(iPage >= 0);
302
303 /* special case: single page. */
304 if (cPages == 1)
305 {
306 ASMBitSet(&pBlock->bmAlloc[0], iPage);
307 return rtHeapPageAllocFromBlockSuccess(pBlock, iPage, cPages, fZero, ppv);
308 }
309
310 while ( iPage >= 0
311 && (unsigned)iPage <= RTMEMPAGEPOSIX_BLOCK_PAGE_COUNT - cPages)
312 {
313 if (rtHeapPageIsPageRangeFree(pBlock, iPage + 1, cPages - 1))
314 {
315 ASMBitSetRange(&pBlock->bmAlloc[0], iPage, iPage + cPages);
316 return rtHeapPageAllocFromBlockSuccess(pBlock, iPage, cPages, fZero, ppv);
317 }
318
319 /* next */
320 iPage = ASMBitNextSet(&pBlock->bmAlloc[0], RTMEMPAGEPOSIX_BLOCK_PAGE_COUNT, iPage);
321 if (iPage < 0 || iPage >= RTMEMPAGEPOSIX_BLOCK_PAGE_COUNT - 1)
322 break;
323 iPage = ASMBitNextClear(&pBlock->bmAlloc[0], RTMEMPAGEPOSIX_BLOCK_PAGE_COUNT, iPage);
324 }
325 }
326
327 return VERR_NO_MEMORY;
328}
329
330
331/**
332 * RTAvlrPVDoWithAll callback.
333 *
334 * @returns 0 to continue the enum, non-zero to quit it.
335 * @param pNode The node.
336 * @param pvUser The user argument.
337 */
338static DECLCALLBACK(int) rtHeapPageAllocCallback(PAVLRPVNODECORE pNode, void *pvUser)
339{
340 PRTHEAPPAGEBLOCK pBlock = RT_FROM_MEMBER(pNode, RTHEAPPAGEBLOCK, Core);
341 RTHEAPPAGEALLOCARGS *pArgs = (RTHEAPPAGEALLOCARGS *)pvUser;
342 int rc = rtHeapPageAllocFromBlock(pBlock, pArgs->cPages, pArgs->fZero, &pArgs->pvAlloc);
343 return RT_SUCCESS(rc) ? 1 : 0;
344}
345
346
347/**
348 * Worker for RTHeapPageAlloc.
349 *
350 * @returns IPRT status code
351 * @param pHeap The heap - locked.
352 * @param cPages The page count.
353 * @param pszTag The tag.
354 * @param fZero Whether to zero the memory.
355 * @param ppv Where to return the address of the allocation
356 * on success.
357 */
358static int rtHeapPageAllocLocked(PRTHEAPPAGE pHeap, size_t cPages, const char *pszTag, bool fZero, void **ppv)
359{
360 int rc;
361 NOREF(pszTag);
362
363 /*
364 * Use the hints first.
365 */
366 if (pHeap->pHint1)
367 {
368 rc = rtHeapPageAllocFromBlock(pHeap->pHint1, cPages, fZero, ppv);
369 if (rc != VERR_NO_MEMORY)
370 return rc;
371 }
372 if (pHeap->pHint2)
373 {
374 rc = rtHeapPageAllocFromBlock(pHeap->pHint2, cPages, fZero, ppv);
375 if (rc != VERR_NO_MEMORY)
376 return rc;
377 }
378
379 /*
380 * Search the heap for a block with enough free space.
381 *
382 * N.B. This search algorithm is not optimal at all. What (hopefully) saves
383 * it are the two hints above.
384 */
385 if (pHeap->cFreePages >= cPages)
386 {
387 RTHEAPPAGEALLOCARGS Args;
388 Args.cPages = cPages;
389 Args.pvAlloc = NULL;
390 Args.fZero = fZero;
391 RTAvlrPVDoWithAll(&pHeap->BlockTree, true /*fFromLeft*/, rtHeapPageAllocCallback, &Args);
392 if (Args.pvAlloc)
393 {
394 *ppv = Args.pvAlloc;
395 return VINF_SUCCESS;
396 }
397 }
398
399 /*
400 * Didn't find anytyhing, so expand the heap with a new block.
401 */
402 RTCritSectLeave(&pHeap->CritSect);
403 void *pvPages;
404 pvPages = mmap(NULL, RTMEMPAGEPOSIX_BLOCK_SIZE,
405 PROT_READ | PROT_WRITE | (pHeap->fExec ? PROT_EXEC : 0),
406 MAP_PRIVATE | MAP_ANONYMOUS,
407 -1, 0);
408 if (pvPages == MAP_FAILED)
409 {
410 RTCritSectEnter(&pHeap->CritSect);
411 return RTErrConvertFromErrno(errno);
412
413 }
414 /** @todo Eliminate this rtMemBaseAlloc dependency! */
415 PRTHEAPPAGEBLOCK pBlock;
416#ifdef RTALLOC_REPLACE_MALLOC
417 if (g_pfnOrgMalloc)
418 pBlock = (PRTHEAPPAGEBLOCK)g_pfnOrgMalloc(sizeof(*pBlock));
419 else
420#endif
421 pBlock = (PRTHEAPPAGEBLOCK)rtMemBaseAlloc(sizeof(*pBlock));
422 if (!pBlock)
423 {
424 munmap(pvPages, RTMEMPAGEPOSIX_BLOCK_SIZE);
425 RTCritSectEnter(&pHeap->CritSect);
426 return VERR_NO_MEMORY;
427 }
428
429 RT_ZERO(*pBlock);
430 pBlock->Core.Key = pvPages;
431 pBlock->Core.KeyLast = (uint8_t *)pvPages + RTMEMPAGEPOSIX_BLOCK_SIZE - 1;
432 pBlock->cFreePages = RTMEMPAGEPOSIX_BLOCK_PAGE_COUNT;
433 pBlock->pHeap = pHeap;
434
435 RTCritSectEnter(&pHeap->CritSect);
436
437 bool fRc = RTAvlrPVInsert(&pHeap->BlockTree, &pBlock->Core); Assert(fRc); NOREF(fRc);
438 pHeap->cFreePages += RTMEMPAGEPOSIX_BLOCK_PAGE_COUNT;
439 pHeap->cHeapPages += RTMEMPAGEPOSIX_BLOCK_PAGE_COUNT;
440
441 /*
442 * Grab memory from the new block (cannot fail).
443 */
444 rc = rtHeapPageAllocFromBlock(pBlock, cPages, fZero, ppv);
445 Assert(rc == VINF_SUCCESS);
446
447 return rc;
448}
449
450
451/**
452 * Allocates one or more pages off the heap.
453 *
454 * @returns IPRT status code.
455 * @param pHeap The page heap.
456 * @param cPages The number of pages to allocate.
457 * @param pszTag The allocation tag.
458 * @param fZero Set if the pages should be zeroed or not.
459 * @param ppv Where to return the pointer to the pages.
460 */
461int RTHeapPageAlloc(PRTHEAPPAGE pHeap, size_t cPages, const char *pszTag, bool fZero, void **ppv)
462{
463 /*
464 * Validate input.
465 */
466 AssertPtr(ppv);
467 *ppv = NULL;
468 AssertPtrReturn(pHeap, VERR_INVALID_HANDLE);
469 AssertReturn(pHeap->u32Magic == RTHEAPPAGE_MAGIC, VERR_INVALID_HANDLE);
470 AssertMsgReturn(cPages < RTMEMPAGEPOSIX_BLOCK_SIZE, ("%#zx\n", cPages), VERR_OUT_OF_RANGE);
471
472 /*
473 * Grab the lock and call a worker with many returns.
474 */
475 int rc = RTCritSectEnter(&pHeap->CritSect);
476 if (RT_SUCCESS(rc))
477 {
478 rc = rtHeapPageAllocLocked(pHeap, cPages, pszTag, fZero, ppv);
479 RTCritSectLeave(&pHeap->CritSect);
480 }
481
482 return rc;
483}
484
485
486/**
487 * RTAvlrPVDoWithAll callback.
488 *
489 * @returns 0 to continue the enum, non-zero to quit it.
490 * @param pNode The node.
491 * @param pvUser Pointer to a block pointer variable. For returning
492 * the address of the block to be freed.
493 */
494static DECLCALLBACK(int) rtHeapPageFindUnusedBlockCallback(PAVLRPVNODECORE pNode, void *pvUser)
495{
496 PRTHEAPPAGEBLOCK pBlock = RT_FROM_MEMBER(pNode, RTHEAPPAGEBLOCK, Core);
497 if (pBlock->cFreePages == RTMEMPAGEPOSIX_BLOCK_PAGE_COUNT)
498 {
499 *(PRTHEAPPAGEBLOCK *)pvUser = pBlock;
500 return 1;
501 }
502 return 0;
503}
504
505
506/**
507 * Allocates one or more pages off the heap.
508 *
509 * @returns IPRT status code.
510 * @param pHeap The page heap.
511 * @param pv Pointer to what RTHeapPageAlloc returned.
512 * @param cPages The number of pages that was allocated.
513 */
514int RTHeapPageFree(PRTHEAPPAGE pHeap, void *pv, size_t cPages)
515{
516 /*
517 * Validate input.
518 */
519 if (!pv)
520 return VINF_SUCCESS;
521 AssertPtrReturn(pHeap, VERR_INVALID_HANDLE);
522 AssertReturn(pHeap->u32Magic == RTHEAPPAGE_MAGIC, VERR_INVALID_HANDLE);
523
524 /*
525 * Grab the lock and look up the page.
526 */
527 int rc = RTCritSectEnter(&pHeap->CritSect);
528 if (RT_SUCCESS(rc))
529 {
530 PRTHEAPPAGEBLOCK pBlock = (PRTHEAPPAGEBLOCK)RTAvlrPVRangeGet(&pHeap->BlockTree, pv);
531 if (pBlock)
532 {
533 /*
534 * Validate the specified address range.
535 */
536 uint32_t const iPage = (uint32_t)(((uintptr_t)pv - (uintptr_t)pBlock->Core.Key) >> PAGE_SHIFT);
537 /* Check the range is within the block. */
538 bool fOk = iPage + cPages <= RTMEMPAGEPOSIX_BLOCK_PAGE_COUNT;
539 /* Check that it's the start of an allocation. */
540 fOk = fOk && ASMBitTest(&pBlock->bmFirst[0], iPage);
541 /* Check that the range ends at an allocation boundrary. */
542 fOk = fOk && ( iPage + cPages == RTMEMPAGEPOSIX_BLOCK_PAGE_COUNT
543 || ASMBitTest(&pBlock->bmFirst[0], iPage + cPages)
544 || !ASMBitTest(&pBlock->bmAlloc[0], iPage + cPages));
545 /* Check the other pages. */
546 uint32_t const iLastPage = iPage + cPages - 1;
547 for (uint32_t i = iPage + 1; i < iLastPage && fOk; i++)
548 fOk = ASMBitTest(&pBlock->bmAlloc[0], i)
549 && !ASMBitTest(&pBlock->bmFirst[0], i);
550 if (fOk)
551 {
552 /*
553 * Free the memory.
554 */
555 ASMBitClearRange(&pBlock->bmAlloc[0], iPage, iPage + cPages);
556 ASMBitClear(&pBlock->bmFirst[0], iPage);
557 pBlock->cFreePages += cPages;
558 pHeap->cFreePages += cPages;
559 pHeap->cFreeCalls++;
560 if (!pHeap->pHint1 || pHeap->pHint1->cFreePages < pBlock->cFreePages)
561 pHeap->pHint1 = pBlock;
562
563 /*
564 * Shrink the heap. Not very efficient because of the AVL tree.
565 */
566 if ( pHeap->cFreePages >= RTMEMPAGEPOSIX_BLOCK_PAGE_COUNT * 3
567 && pHeap->cFreePages >= pHeap->cHeapPages / 2 /* 50% free */
568 && pHeap->cFreeCalls - pHeap->uLastMinimizeCall > RTMEMPAGEPOSIX_BLOCK_PAGE_COUNT
569 )
570 {
571 uint32_t cFreePageTarget = pHeap->cHeapPages / 4; /* 25% free */
572 while (pHeap->cFreePages > cFreePageTarget)
573 {
574 pHeap->uLastMinimizeCall = pHeap->cFreeCalls;
575
576 pBlock = NULL;
577 RTAvlrPVDoWithAll(&pHeap->BlockTree, false /*fFromLeft*/,
578 rtHeapPageFindUnusedBlockCallback, &pBlock);
579 if (!pBlock)
580 break;
581
582 void *pv2 = RTAvlrPVRemove(&pHeap->BlockTree, pBlock->Core.Key); Assert(pv2); NOREF(pv2);
583 pHeap->cHeapPages -= RTMEMPAGEPOSIX_BLOCK_PAGE_COUNT;
584 pHeap->cFreePages -= RTMEMPAGEPOSIX_BLOCK_PAGE_COUNT;
585 pHeap->pHint1 = NULL;
586 pHeap->pHint2 = NULL;
587 RTCritSectLeave(&pHeap->CritSect);
588
589 munmap(pBlock->Core.Key, RTMEMPAGEPOSIX_BLOCK_SIZE);
590 pBlock->Core.Key = pBlock->Core.KeyLast = NULL;
591 pBlock->cFreePages = 0;
592#ifdef RTALLOC_REPLACE_MALLOC
593 if (g_pfnOrgFree)
594 g_pfnOrgFree(pBlock);
595 else
596#endif
597 rtMemBaseFree(pBlock);
598
599 RTCritSectEnter(&pHeap->CritSect);
600 }
601 }
602 }
603 else
604 rc = VERR_INVALID_POINTER;
605 }
606 else
607 rc = VERR_INVALID_POINTER;
608
609 RTCritSectLeave(&pHeap->CritSect);
610 }
611
612 return rc;
613}
614
615
616/**
617 * Initializes the heap.
618 *
619 * @returns IPRT status code
620 * @param pvUser Unused.
621 */
622static DECLCALLBACK(int) rtMemPagePosixInitOnce(void *pvUser)
623{
624 NOREF(pvUser);
625 int rc = RTHeapPageInit(&g_MemPagePosixHeap, false /*fExec*/);
626 if (RT_SUCCESS(rc))
627 {
628 rc = RTHeapPageInit(&g_MemExecPosixHeap, true /*fExec*/);
629 if (RT_SUCCESS(rc))
630 return rc;
631 RTHeapPageDelete(&g_MemPagePosixHeap);
632 }
633 return rc;
634}
635
636
637/**
638 * Allocates memory from the specified heap.
639 *
640 * @returns Address of the allocated memory.
641 * @param cb The number of bytes to allocate.
642 * @param pszTag The tag.
643 * @param fZero Whether to zero the memory or not.
644 * @param pHeap The heap to use.
645 */
646static void *rtMemPagePosixAlloc(size_t cb, const char *pszTag, bool fZero, PRTHEAPPAGE pHeap)
647{
648 /*
649 * Validate & adjust the input.
650 */
651 Assert(cb > 0);
652 NOREF(pszTag);
653 cb = RT_ALIGN_Z(cb, PAGE_SIZE);
654
655 /*
656 * If the allocation is relatively large, we use mmap/munmap directly.
657 */
658 void *pv;
659 if (cb >= RTMEMPAGEPOSIX_MMAP_THRESHOLD)
660 {
661
662 pv = mmap(NULL, cb,
663 PROT_READ | PROT_WRITE | (pHeap == &g_MemExecPosixHeap ? PROT_EXEC : 0),
664 MAP_PRIVATE | MAP_ANONYMOUS,
665 -1, 0);
666 if (pv != MAP_FAILED)
667 {
668 AssertPtr(pv);
669 if (fZero)
670 RT_BZERO(pv, cb);
671 }
672 else
673 pv = NULL;
674 }
675 else
676 {
677 int rc = RTOnce(&g_MemPagePosixInitOnce, rtMemPagePosixInitOnce, NULL);
678 if (RT_SUCCESS(rc))
679 rc = RTHeapPageAlloc(pHeap, cb >> PAGE_SHIFT, pszTag, fZero, &pv);
680 if (RT_FAILURE(rc))
681 pv = NULL;
682 }
683
684 return pv;
685}
686
687
688/**
689 * Free memory allocated by rtMemPagePosixAlloc.
690 *
691 * @param pv The address of the memory to free.
692 * @param cb The size.
693 * @param pHeap The heap.
694 */
695static void rtMemPagePosixFree(void *pv, size_t cb, PRTHEAPPAGE pHeap)
696{
697 /*
698 * Validate & adjust the input.
699 */
700 if (!pv)
701 return;
702 AssertPtr(pv);
703 Assert(cb > 0);
704 Assert(!((uintptr_t)pv & PAGE_OFFSET_MASK));
705 cb = RT_ALIGN_Z(cb, PAGE_SIZE);
706
707 /*
708 * If the allocation is relatively large, we use mmap/munmap directly.
709 */
710 if (cb >= RTMEMPAGEPOSIX_MMAP_THRESHOLD)
711 {
712 int rc = munmap(pv, cb);
713 AssertMsg(rc == 0, ("rc=%d pv=%p cb=%#zx\n", rc, pv, cb)); NOREF(rc);
714 }
715 else
716 {
717 int rc = RTHeapPageFree(pHeap, pv, cb >> PAGE_SHIFT);
718 AssertRC(rc);
719 }
720}
721
722
723
724
725
726RTDECL(void *) RTMemPageAllocTag(size_t cb, const char *pszTag) RT_NO_THROW_DEF
727{
728 return rtMemPagePosixAlloc(cb, pszTag, false /*fZero*/, &g_MemPagePosixHeap);
729}
730
731
732RTDECL(void *) RTMemPageAllocZTag(size_t cb, const char *pszTag) RT_NO_THROW_DEF
733{
734 return rtMemPagePosixAlloc(cb, pszTag, true /*fZero*/, &g_MemPagePosixHeap);
735}
736
737
738RTDECL(void) RTMemPageFree(void *pv, size_t cb) RT_NO_THROW_DEF
739{
740 return rtMemPagePosixFree(pv, cb, &g_MemPagePosixHeap);
741}
742
743
744
745
746
747RTDECL(void *) RTMemExecAllocTag(size_t cb, const char *pszTag) RT_NO_THROW_DEF
748{
749 return rtMemPagePosixAlloc(cb, pszTag, false /*fZero*/, &g_MemExecPosixHeap);
750}
751
752
753RTDECL(void) RTMemExecFree(void *pv, size_t cb) RT_NO_THROW_DEF
754{
755 return rtMemPagePosixFree(pv, cb, &g_MemExecPosixHeap);
756}
757
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