VirtualBox

source: vbox/trunk/src/VBox/Additions/common/VBoxGuest/lib/VBoxGuestR0LibPhysHeap.cpp@ 97799

最後變更 在這個檔案從97799是 96407,由 vboxsync 提交於 3 年 前

scm copyright and license note update

  • 屬性 svn:eol-style 設為 native
  • 屬性 svn:keywords 設為 Author Date Id Revision
檔案大小: 19.7 KB
 
1/* $Id: VBoxGuestR0LibPhysHeap.cpp 96407 2022-08-22 17:43:14Z vboxsync $ */
2/** @file
3 * VBoxGuestLibR0 - Physical memory heap.
4 */
5
6/*
7 * Copyright (C) 2006-2022 Oracle and/or its affiliates.
8 *
9 * Permission is hereby granted, free of charge, to any person
10 * obtaining a copy of this software and associated documentation
11 * files (the "Software"), to deal in the Software without
12 * restriction, including without limitation the rights to use,
13 * copy, modify, merge, publish, distribute, sublicense, and/or sell
14 * copies of the Software, and to permit persons to whom the
15 * Software is furnished to do so, subject to the following
16 * conditions:
17 *
18 * The above copyright notice and this permission notice shall be
19 * included in all copies or substantial portions of the Software.
20 *
21 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
22 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
23 * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
24 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
25 * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
26 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
27 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
28 * OTHER DEALINGS IN THE SOFTWARE.
29 */
30
31
32/*********************************************************************************************************************************
33* Header Files *
34*********************************************************************************************************************************/
35#include "VBoxGuestR0LibInternal.h"
36
37#include <iprt/assert.h>
38#include <iprt/semaphore.h>
39#include <iprt/alloc.h>
40
41/* Physical memory heap consists of double linked list
42 * of chunks. Memory blocks are allocated inside these chunks
43 * and are members of Allocated and Free double linked lists.
44 *
45 * When allocating a block, we search in Free linked
46 * list for a suitable free block. If there is no such block,
47 * a new chunk is allocated and the new block is taken from
48 * the new chunk as the only chunk-sized free block.
49 * Allocated block is excluded from the Free list and goes to
50 * Alloc list.
51 *
52 * When freeing block, we check the pointer and then
53 * exclude block from Alloc list and move it to free list.
54 *
55 * For each chunk we maintain the allocated blocks counter.
56 * if 2 (or more) entire chunks are free they are immediately
57 * deallocated, so we always have at most 1 free chunk.
58 *
59 * When freeing blocks, two subsequent free blocks are always
60 * merged together. Current implementation merges blocks only
61 * when there is a block after the just freed one.
62 *
63 */
64
65#define VBGL_PH_ASSERT Assert
66#define VBGL_PH_ASSERTMsg AssertMsg
67
68// #define DUMPHEAP
69
70#ifdef DUMPHEAP
71# define VBGL_PH_dprintf(a) RTAssertMsg2Weak a
72#else
73# define VBGL_PH_dprintf(a)
74#endif
75
76/* Heap block signature */
77#define VBGL_PH_BLOCKSIGNATURE (0xADDBBBBB)
78
79
80/* Heap chunk signature */
81#define VBGL_PH_CHUNKSIGNATURE (0xADDCCCCC)
82/* Heap chunk allocation unit */
83#define VBGL_PH_CHUNKSIZE (0x10000)
84
85/* Heap block bit flags */
86#define VBGL_PH_BF_ALLOCATED (0x1)
87
88struct _VBGLPHYSHEAPBLOCK
89{
90 uint32_t u32Signature;
91
92 /* Size of user data in the block. Does not include the block header. */
93 uint32_t cbDataSize;
94
95 uint32_t fu32Flags;
96
97 struct _VBGLPHYSHEAPBLOCK *pNext;
98 struct _VBGLPHYSHEAPBLOCK *pPrev;
99
100 struct _VBGLPHYSHEAPCHUNK *pChunk;
101};
102
103struct _VBGLPHYSHEAPCHUNK
104{
105 uint32_t u32Signature;
106
107 /* Size of the chunk. Includes the chunk header. */
108 uint32_t cbSize;
109
110 /* Physical address of the chunk */
111 uint32_t physAddr;
112
113 /* Number of allocated blocks in the chunk */
114 int32_t cAllocatedBlocks;
115
116 struct _VBGLPHYSHEAPCHUNK *pNext;
117 struct _VBGLPHYSHEAPCHUNK *pPrev;
118};
119
120
121#ifndef DUMPHEAP
122#define dumpheap(a)
123#else
124void dumpheap (char *point)
125{
126 VBGL_PH_dprintf(("VBGL_PH dump at '%s'\n", point));
127
128 VBGL_PH_dprintf(("Chunks:\n"));
129
130 VBGLPHYSHEAPCHUNK *pChunk = g_vbgldata.pChunkHead;
131
132 while (pChunk)
133 {
134 VBGL_PH_dprintf(("%p: pNext = %p, pPrev = %p, sign = %08X, size = %8d, allocated = %8d, phys = %08X\n",
135 pChunk, pChunk->pNext, pChunk->pPrev, pChunk->u32Signature, pChunk->cbSize, pChunk->cAllocatedBlocks, pChunk->physAddr));
136
137 pChunk = pChunk->pNext;
138 }
139
140 VBGL_PH_dprintf(("Allocated blocks:\n"));
141
142 VBGLPHYSHEAPBLOCK *pBlock = g_vbgldata.pAllocBlocksHead;
143
144 while (pBlock)
145 {
146 VBGL_PH_dprintf(("%p: pNext = %p, pPrev = %p, sign = %08X, size = %8d, flags = %08X, pChunk = %p\n",
147 pBlock, pBlock->pNext, pBlock->pPrev, pBlock->u32Signature, pBlock->cbDataSize, pBlock->fu32Flags, pBlock->pChunk));
148
149 pBlock = pBlock->pNext;
150 }
151
152 VBGL_PH_dprintf(("Free blocks:\n"));
153
154 pBlock = g_vbgldata.pFreeBlocksHead;
155
156 while (pBlock)
157 {
158 VBGL_PH_dprintf(("%p: pNext = %p, pPrev = %p, sign = %08X, size = %8d, flags = %08X, pChunk = %p\n",
159 pBlock, pBlock->pNext, pBlock->pPrev, pBlock->u32Signature, pBlock->cbDataSize, pBlock->fu32Flags, pBlock->pChunk));
160
161 pBlock = pBlock->pNext;
162 }
163
164 VBGL_PH_dprintf(("VBGL_PH dump at '%s' done\n", point));
165}
166#endif
167
168
169DECLINLINE(void *) vbglPhysHeapBlock2Data (VBGLPHYSHEAPBLOCK *pBlock)
170{
171 return (void *)(pBlock? (char *)pBlock + sizeof (VBGLPHYSHEAPBLOCK): NULL);
172}
173
174DECLINLINE(VBGLPHYSHEAPBLOCK *) vbglPhysHeapData2Block (void *p)
175{
176 VBGLPHYSHEAPBLOCK *pBlock = (VBGLPHYSHEAPBLOCK *)(p? (char *)p - sizeof (VBGLPHYSHEAPBLOCK): NULL);
177
178 VBGL_PH_ASSERTMsg(pBlock == NULL || pBlock->u32Signature == VBGL_PH_BLOCKSIGNATURE,
179 ("pBlock->u32Signature = %08X\n", pBlock->u32Signature));
180
181 return pBlock;
182}
183
184DECLINLINE(int) vbglPhysHeapEnter (void)
185{
186 int rc = RTSemFastMutexRequest(g_vbgldata.mutexHeap);
187
188 VBGL_PH_ASSERTMsg(RT_SUCCESS(rc),
189 ("Failed to request heap mutex, rc = %Rrc\n", rc));
190
191 return rc;
192}
193
194DECLINLINE(void) vbglPhysHeapLeave (void)
195{
196 RTSemFastMutexRelease(g_vbgldata.mutexHeap);
197}
198
199
200static void vbglPhysHeapInitBlock (VBGLPHYSHEAPBLOCK *pBlock, VBGLPHYSHEAPCHUNK *pChunk, uint32_t cbDataSize)
201{
202 VBGL_PH_ASSERT(pBlock != NULL);
203 VBGL_PH_ASSERT(pChunk != NULL);
204
205 pBlock->u32Signature = VBGL_PH_BLOCKSIGNATURE;
206 pBlock->cbDataSize = cbDataSize;
207 pBlock->fu32Flags = 0;
208 pBlock->pNext = NULL;
209 pBlock->pPrev = NULL;
210 pBlock->pChunk = pChunk;
211}
212
213
214static void vbglPhysHeapInsertBlock (VBGLPHYSHEAPBLOCK *pInsertAfter, VBGLPHYSHEAPBLOCK *pBlock)
215{
216 VBGL_PH_ASSERTMsg(pBlock->pNext == NULL,
217 ("pBlock->pNext = %p\n", pBlock->pNext));
218 VBGL_PH_ASSERTMsg(pBlock->pPrev == NULL,
219 ("pBlock->pPrev = %p\n", pBlock->pPrev));
220
221 if (pInsertAfter)
222 {
223 pBlock->pNext = pInsertAfter->pNext;
224 pBlock->pPrev = pInsertAfter;
225
226 if (pInsertAfter->pNext)
227 {
228 pInsertAfter->pNext->pPrev = pBlock;
229 }
230
231 pInsertAfter->pNext = pBlock;
232 }
233 else
234 {
235 /* inserting to head of list */
236 pBlock->pPrev = NULL;
237
238 if (pBlock->fu32Flags & VBGL_PH_BF_ALLOCATED)
239 {
240 pBlock->pNext = g_vbgldata.pAllocBlocksHead;
241
242 if (g_vbgldata.pAllocBlocksHead)
243 {
244 g_vbgldata.pAllocBlocksHead->pPrev = pBlock;
245 }
246
247 g_vbgldata.pAllocBlocksHead = pBlock;
248 }
249 else
250 {
251 pBlock->pNext = g_vbgldata.pFreeBlocksHead;
252
253 if (g_vbgldata.pFreeBlocksHead)
254 {
255 g_vbgldata.pFreeBlocksHead->pPrev = pBlock;
256 }
257
258 g_vbgldata.pFreeBlocksHead = pBlock;
259 }
260 }
261}
262
263static void vbglPhysHeapExcludeBlock (VBGLPHYSHEAPBLOCK *pBlock)
264{
265 if (pBlock->pNext)
266 {
267 pBlock->pNext->pPrev = pBlock->pPrev;
268 }
269 else
270 {
271 /* this is tail of list but we do not maintain tails of block lists.
272 * so do nothing.
273 */
274 ;
275 }
276
277 if (pBlock->pPrev)
278 {
279 pBlock->pPrev->pNext = pBlock->pNext;
280 }
281 else
282 {
283 /* this is head of list but we do not maintain tails of block lists. */
284 if (pBlock->fu32Flags & VBGL_PH_BF_ALLOCATED)
285 {
286 g_vbgldata.pAllocBlocksHead = pBlock->pNext;
287 }
288 else
289 {
290 g_vbgldata.pFreeBlocksHead = pBlock->pNext;
291 }
292 }
293
294 pBlock->pNext = NULL;
295 pBlock->pPrev = NULL;
296}
297
298static VBGLPHYSHEAPBLOCK *vbglPhysHeapChunkAlloc(uint32_t cbMinBlock)
299{
300 RTCCPHYS PhysAddr = NIL_RTHCPHYS;
301 VBGLPHYSHEAPCHUNK *pChunk;
302 uint32_t cbChunk;
303 VBGL_PH_dprintf(("Allocating new chunk for %#x byte allocation\n", cbMinBlock));
304 AssertReturn(cbMinBlock < _128M, NULL); /* paranoia */
305
306 /* Compute the size of the new chunk, rounding up to next chunk size,
307 which must be power of 2. */
308 Assert(RT_IS_POWER_OF_TWO(VBGL_PH_CHUNKSIZE));
309 cbChunk = cbMinBlock + sizeof(VBGLPHYSHEAPCHUNK) + sizeof(VBGLPHYSHEAPBLOCK);
310 cbChunk = RT_ALIGN_32(cbChunk, VBGL_PH_CHUNKSIZE);
311
312 /* This function allocates physical contiguous memory below 4 GB. This 4GB
313 limitation stems from using a 32-bit OUT instruction to pass a block
314 physical address to the host. */
315 pChunk = (VBGLPHYSHEAPCHUNK *)RTMemContAlloc(&PhysAddr, cbChunk);
316 if (pChunk)
317 {
318 VBGLPHYSHEAPCHUNK *pOldHeadChunk;
319 VBGLPHYSHEAPBLOCK *pBlock;
320 AssertRelease(PhysAddr < _4G && PhysAddr + cbChunk <= _4G);
321
322 /* Init the new chunk. */
323 pChunk->u32Signature = VBGL_PH_CHUNKSIGNATURE;
324 pChunk->cbSize = cbChunk;
325 pChunk->physAddr = (uint32_t)PhysAddr;
326 pChunk->cAllocatedBlocks = 0;
327 pChunk->pNext = NULL;
328 pChunk->pPrev = NULL;
329
330 /* Initialize the free block, which now occupies entire chunk. */
331 pBlock = (VBGLPHYSHEAPBLOCK *)(pChunk + 1);
332 vbglPhysHeapInitBlock(pBlock, pChunk, cbChunk - sizeof(VBGLPHYSHEAPCHUNK) - sizeof(VBGLPHYSHEAPBLOCK));
333 vbglPhysHeapInsertBlock(NULL, pBlock);
334
335 /* Add the chunk to the list. */
336 pOldHeadChunk = g_vbgldata.pChunkHead;
337 pChunk->pNext = pOldHeadChunk;
338 if (pOldHeadChunk)
339 pOldHeadChunk->pPrev = pChunk;
340 g_vbgldata.pChunkHead = pChunk;
341
342 VBGL_PH_dprintf(("Allocated chunk %p LB %#x, block %p LB %#x\n", pChunk, cbChunk, pBlock, pBlock->cbDataSize));
343 return pBlock;
344 }
345 LogRel(("vbglPhysHeapChunkAlloc: failed to alloc %u (%#x) contiguous bytes.\n", cbChunk, cbChunk));
346 return NULL;
347}
348
349
350static void vbglPhysHeapChunkDelete (VBGLPHYSHEAPCHUNK *pChunk)
351{
352 char *p;
353 VBGL_PH_ASSERT(pChunk != NULL);
354 VBGL_PH_ASSERTMsg(pChunk->u32Signature == VBGL_PH_CHUNKSIGNATURE,
355 ("pChunk->u32Signature = %08X\n", pChunk->u32Signature));
356
357 VBGL_PH_dprintf(("Deleting chunk %p size %x\n", pChunk, pChunk->cbSize));
358
359 /* first scan the chunk and exclude all blocks from lists */
360
361 p = (char *)pChunk + sizeof (VBGLPHYSHEAPCHUNK);
362
363 while (p < (char *)pChunk + pChunk->cbSize)
364 {
365 VBGLPHYSHEAPBLOCK *pBlock = (VBGLPHYSHEAPBLOCK *)p;
366
367 p += pBlock->cbDataSize + sizeof (VBGLPHYSHEAPBLOCK);
368
369 vbglPhysHeapExcludeBlock (pBlock);
370 }
371
372 VBGL_PH_ASSERTMsg(p == (char *)pChunk + pChunk->cbSize,
373 ("p = %p, (char *)pChunk + pChunk->cbSize = %p, pChunk->cbSize = %08X\n",
374 p, (char *)pChunk + pChunk->cbSize, pChunk->cbSize));
375
376 /* Exclude chunk from the chunk list */
377 if (pChunk->pNext)
378 {
379 pChunk->pNext->pPrev = pChunk->pPrev;
380 }
381 else
382 {
383 /* we do not maintain tail */
384 ;
385 }
386
387 if (pChunk->pPrev)
388 {
389 pChunk->pPrev->pNext = pChunk->pNext;
390 }
391 else
392 {
393 /* the chunk was head */
394 g_vbgldata.pChunkHead = pChunk->pNext;
395 }
396
397 RTMemContFree (pChunk, pChunk->cbSize);
398}
399
400
401DECLR0VBGL(void *) VbglR0PhysHeapAlloc (uint32_t cbSize)
402{
403 VBGLPHYSHEAPBLOCK *pBlock, *pIter;
404 int rc;
405
406 /*
407 * Align the size to a pointer size to avoid getting misaligned header pointers and whatnot.
408 */
409 cbSize = RT_ALIGN_32(cbSize, sizeof(void *));
410
411 rc = vbglPhysHeapEnter ();
412 if (RT_FAILURE(rc))
413 return NULL;
414
415 dumpheap ("pre alloc");
416
417 /*
418 * Search the free list. We do this in linear fashion as we don't expect
419 * there to be many blocks in the heap.
420 */
421
422 pBlock = NULL;
423 if (cbSize <= PAGE_SIZE / 4 * 3)
424 {
425 /* Smaller than 3/4 page: Prefer a free block that can keep the request within a single page,
426 so HGCM processing in VMMDev can use page locks instead of several reads and writes. */
427
428 VBGLPHYSHEAPBLOCK *pFallback = NULL;
429 for (pIter = g_vbgldata.pFreeBlocksHead; pIter != NULL; pIter = pIter->pNext)
430 if (pIter->cbDataSize >= cbSize)
431 {
432 if (pIter->cbDataSize == cbSize)
433 {
434 if (PAGE_SIZE - ((uintptr_t)vbglPhysHeapBlock2Data(pIter) & PAGE_OFFSET_MASK) >= cbSize)
435 {
436 pBlock = pIter;
437 break;
438 }
439 pFallback = pIter;
440 }
441 else
442 {
443 if (!pFallback || pIter->cbDataSize < pFallback->cbDataSize)
444 pFallback = pIter;
445 if (PAGE_SIZE - ((uintptr_t)vbglPhysHeapBlock2Data(pIter) & PAGE_OFFSET_MASK) >= cbSize)
446 if (!pBlock || pIter->cbDataSize < pBlock->cbDataSize)
447 pBlock = pIter;
448 }
449 }
450
451 if (!pBlock)
452 pBlock = pFallback;
453 }
454 else
455 {
456 /* Large than 3/4 page: Find smallest free list match. */
457
458 for (pIter = g_vbgldata.pFreeBlocksHead; pIter != NULL; pIter = pIter->pNext)
459 if (pIter->cbDataSize >= cbSize)
460 {
461 if (pIter->cbDataSize == cbSize)
462 {
463 /* Exact match - we're done! */
464 pBlock = pIter;
465 break;
466 }
467
468 /* Looking for a free block with nearest size. */
469 if (!pBlock || pIter->cbDataSize < pBlock->cbDataSize)
470 pBlock = pIter;
471 }
472 }
473
474 if (!pBlock)
475 {
476 /* No free blocks, allocate a new chunk,
477 * the only free block of the chunk will
478 * be returned.
479 */
480 pBlock = vbglPhysHeapChunkAlloc (cbSize);
481 }
482
483 if (pBlock)
484 {
485 VBGL_PH_ASSERTMsg(pBlock->u32Signature == VBGL_PH_BLOCKSIGNATURE,
486 ("pBlock = %p, pBlock->u32Signature = %08X\n", pBlock, pBlock->u32Signature));
487 VBGL_PH_ASSERTMsg((pBlock->fu32Flags & VBGL_PH_BF_ALLOCATED) == 0,
488 ("pBlock = %p, pBlock->fu32Flags = %08X\n", pBlock, pBlock->fu32Flags));
489
490 /* We have a free block, either found or allocated. */
491
492 if (pBlock->cbDataSize > 2*(cbSize + sizeof (VBGLPHYSHEAPBLOCK)))
493 {
494 /* Data will occupy less than a half of the block,
495 * split off the tail end into a new free list entry.
496 */
497 pIter = (VBGLPHYSHEAPBLOCK *)((char *)pBlock + sizeof (VBGLPHYSHEAPBLOCK) + cbSize);
498
499 /* Init the new 'pIter' block, initialized blocks are always marked as free. */
500 vbglPhysHeapInitBlock (pIter, pBlock->pChunk, pBlock->cbDataSize - cbSize - sizeof (VBGLPHYSHEAPBLOCK));
501
502 pBlock->cbDataSize = cbSize;
503
504 /* Insert the new 'pIter' block after the 'pBlock' in the free list */
505 vbglPhysHeapInsertBlock (pBlock, pIter);
506 }
507
508 /* Exclude pBlock from free list */
509 vbglPhysHeapExcludeBlock (pBlock);
510
511 /* Mark as allocated */
512 pBlock->fu32Flags |= VBGL_PH_BF_ALLOCATED;
513
514 /* Insert to allocated list */
515 vbglPhysHeapInsertBlock (NULL, pBlock);
516
517 /* Adjust the chunk allocated blocks counter */
518 pBlock->pChunk->cAllocatedBlocks++;
519 }
520
521 dumpheap ("post alloc");
522
523 vbglPhysHeapLeave ();
524 VBGL_PH_dprintf(("VbglR0PhysHeapAlloc %x size %x\n", vbglPhysHeapBlock2Data (pBlock), pBlock->cbDataSize));
525
526 return vbglPhysHeapBlock2Data (pBlock);
527}
528
529DECLR0VBGL(uint32_t) VbglR0PhysHeapGetPhysAddr (void *p)
530{
531 uint32_t physAddr = 0;
532 VBGLPHYSHEAPBLOCK *pBlock = vbglPhysHeapData2Block (p);
533
534 if (pBlock)
535 {
536 VBGL_PH_ASSERTMsg((pBlock->fu32Flags & VBGL_PH_BF_ALLOCATED) != 0,
537 ("pBlock = %p, pBlock->fu32Flags = %08X\n", pBlock, pBlock->fu32Flags));
538
539 if (pBlock->fu32Flags & VBGL_PH_BF_ALLOCATED)
540 physAddr = pBlock->pChunk->physAddr + (uint32_t)((uintptr_t)p - (uintptr_t)pBlock->pChunk);
541 }
542
543 return physAddr;
544}
545
546DECLR0VBGL(void) VbglR0PhysHeapFree(void *p)
547{
548 VBGLPHYSHEAPBLOCK *pBlock;
549 VBGLPHYSHEAPBLOCK *pNeighbour;
550
551 int rc = vbglPhysHeapEnter ();
552 if (RT_FAILURE(rc))
553 return;
554
555 dumpheap ("pre free");
556
557 pBlock = vbglPhysHeapData2Block (p);
558
559 if (!pBlock)
560 {
561 vbglPhysHeapLeave ();
562 return;
563 }
564
565 VBGL_PH_ASSERTMsg((pBlock->fu32Flags & VBGL_PH_BF_ALLOCATED) != 0,
566 ("pBlock = %p, pBlock->fu32Flags = %08X\n", pBlock, pBlock->fu32Flags));
567
568 /* Exclude from allocated list */
569 vbglPhysHeapExcludeBlock (pBlock);
570
571 dumpheap ("post exclude");
572
573 VBGL_PH_dprintf(("VbglR0PhysHeapFree %x size %x\n", p, pBlock->cbDataSize));
574
575 /* Mark as free */
576 pBlock->fu32Flags &= ~VBGL_PH_BF_ALLOCATED;
577
578 /* Insert to free list */
579 vbglPhysHeapInsertBlock (NULL, pBlock);
580
581 dumpheap ("post insert");
582
583 /* Adjust the chunk allocated blocks counter */
584 pBlock->pChunk->cAllocatedBlocks--;
585
586 VBGL_PH_ASSERT(pBlock->pChunk->cAllocatedBlocks >= 0);
587
588 /* Check if we can merge 2 free blocks. To simplify heap maintenance,
589 * we will look at block after the just freed one.
590 * This will not prevent us from detecting free memory chunks.
591 * Also in most cases blocks are deallocated in reverse allocation order
592 * and in that case the merging will work.
593 */
594
595 pNeighbour = (VBGLPHYSHEAPBLOCK *)((char *)p + pBlock->cbDataSize);
596
597 if ((char *)pNeighbour < (char *)pBlock->pChunk + pBlock->pChunk->cbSize
598 && (pNeighbour->fu32Flags & VBGL_PH_BF_ALLOCATED) == 0)
599 {
600 /* The next block is free as well. */
601
602 /* Adjust size of current memory block */
603 pBlock->cbDataSize += pNeighbour->cbDataSize + sizeof (VBGLPHYSHEAPBLOCK);
604
605 /* Exclude the next neighbour */
606 vbglPhysHeapExcludeBlock (pNeighbour);
607 }
608
609 dumpheap ("post merge");
610
611 /* now check if there are 2 or more free chunks */
612 if (pBlock->pChunk->cAllocatedBlocks == 0)
613 {
614 VBGLPHYSHEAPCHUNK *pChunk = g_vbgldata.pChunkHead;
615
616 uint32_t u32FreeChunks = 0;
617
618 while (pChunk)
619 {
620 if (pChunk->cAllocatedBlocks == 0)
621 {
622 u32FreeChunks++;
623 }
624
625 pChunk = pChunk->pNext;
626 }
627
628 if (u32FreeChunks > 1)
629 {
630 /* Delete current chunk, it will also exclude all free blocks
631 * remaining in the chunk from the free list, so the pBlock
632 * will also be invalid after this.
633 */
634 vbglPhysHeapChunkDelete (pBlock->pChunk);
635 }
636 }
637
638 dumpheap ("post free");
639
640 vbglPhysHeapLeave ();
641}
642
643DECLR0VBGL(int) VbglR0PhysHeapInit (void)
644{
645 int rc = VINF_SUCCESS;
646
647 /* Allocate the first chunk of the heap. */
648 VBGLPHYSHEAPBLOCK *pBlock = vbglPhysHeapChunkAlloc (0);
649
650 if (!pBlock)
651 rc = VERR_NO_MEMORY;
652
653 RTSemFastMutexCreate(&g_vbgldata.mutexHeap);
654
655 return rc;
656}
657
658DECLR0VBGL(void) VbglR0PhysHeapTerminate (void)
659{
660 while (g_vbgldata.pChunkHead)
661 {
662 vbglPhysHeapChunkDelete (g_vbgldata.pChunkHead);
663 }
664
665 RTSemFastMutexDestroy(g_vbgldata.mutexHeap);
666}
667
注意: 瀏覽 TracBrowser 來幫助您使用儲存庫瀏覽器

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