source: trunk/kStuff/kHlp/Bare/kHlpBareHeap.c@ 3602

Last change on this file since 3602 was 3594, checked in by bird, 18 years ago

Made it build on darwin - leaving a couple of things for later...

  • Property svn:keywords set to Id
File size: 20.5 KB
Line 
1/* $Id: kHlpBareHeap.c 3594 2007-10-02 21:35:22Z bird $ */
2/** @file
3 * kHlpBare - Heap.
4 */
5
6/*
7 * Copyright (c) 2006-2007 knut st. osmundsen <bird-src-spam@anduin.net>
8 *
9 * This file is part of kStuff.
10 *
11 * kStuff is free software; you can redistribute it and/or
12 * modify it under the terms of the GNU Lesser General Public
13 * License as published by the Free Software Foundation; either
14 * version 2.1 of the License, or (at your option) any later version.
15 *
16 * kStuff is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
19 * Lesser General Public License for more details.
20 *
21 * You should have received a copy of the GNU Lesser General Public
22 * License along with kStuff; if not, write to the Free Software
23 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
24 *
25 */
26
27#define KHLPHEAP_STRICT
28
29/*******************************************************************************
30* Header Files *
31*******************************************************************************/
32#include <k/kHlpAlloc.h>
33#include <k/kHlpString.h>
34#include <k/kHlpAssert.h>
35
36#if K_OS == K_OS_OS2
37# define INCL_BASE
38# define INCL_ERRORS
39# include <os2.h>
40
41#elif K_OS == K_OS_WINDOWS
42# include <Windows.h>
43
44#else
45# include <k/kHlpAlloc.h>
46#endif
47
48
49/*******************************************************************************
50* Structures and Typedefs *
51*******************************************************************************/
52/**
53 * A heap block.
54 */
55typedef struct KHLPHEAPBLOCK
56{
57 /** Next block in the global list. */
58 struct KHLPHEAPBLOCK *pNext;
59 /** Previous block in the global list. */
60 struct KHLPHEAPBLOCK *pPrev;
61 /** The size of this block including this header. */
62 KSIZE cb;
63 /** The flags. */
64 KSIZE fFlags;
65} KHLPHEAPBLOCK, *PKHLPHEAPBLOCK;
66
67/** Indicates whether the block is free (set) or allocated (clear). */
68#define KHLPHEAPBLOCK_FLAG_FREE ((KSIZE)1)
69/** Valid flag mask. */
70#define KHLPHEAPBLOCK_FLAG_MASK ((KSIZE)1)
71
72/** Checks if the block is freed. */
73#define KHLPHEAPBLOCK_IS_FREE(pB) ( (pB)->fFlags & KHLPHEAPBLOCK_FLAG_FREE )
74/** Check if the block is allocated. */
75#define KHLPHEAPBLOCK_IS_ALLOCATED(pB) !KHLPHEAPBLOCK_IS_FREE(pB)
76/** Checks if the two blocks are adjacent.
77 * Assumes pB1 < pB2. */
78#define KHLPHEAPBLOCK_IS_ADJACENT(pB1, pB2) \
79 ( ((KUPTR)(pB1) + (pB1)->cb) == (KUPTR)(pB2) )
80
81/** The block alignment. */
82#define KHLPHEAPBLOCK_ALIGNMENT sizeof(KHLPHEAPBLOCK)
83
84/** @def KHLPHEAP_ASSERT
85 * Heap assertion. */
86/** @def KHLPHEAP_ASSERT_BLOCK
87 * Assert that a heap block is valid. */
88/** @def KHLPHEAP_ASSERT_FREE
89 * Assert that a heap free block is valid. */
90#ifdef KHLPHEAP_STRICT
91# define KHLPHEAP_ASSERT(expr) kHlpAssert(expr)
92
93# define KHLPHEAP_ASSERT_BLOCK(pHeap, pBlock) \
94 do { \
95 KHLPHEAP_ASSERT(!((pBlock)->fFlags & ~KHLPHEAPBLOCK_FLAG_MASK)); \
96 KHLPHEAP_ASSERT(!((pBlock)->cb & (KHLPHEAPBLOCK_ALIGNMENT - 1))); \
97 KHLPHEAP_ASSERT((KUPTR)(pBlock)->pPrev < (KUPTR)(pBlock)); \
98 KHLPHEAP_ASSERT((KUPTR)(pBlock)->pNext > (KUPTR)(pBlock) || !(pBlock)->pNext); \
99 } while (0)
100
101# define KHLPHEAP_ASSERT_FREE(pHeap, pFree) \
102 do { \
103 KHLPHEAP_ASSERT_BLOCK(pHeap, &(pFree)->Core); \
104 KHLPHEAP_ASSERT((KUPTR)(pFree)->pPrev < (KUPTR)(pFree)); \
105 KHLPHEAP_ASSERT((KUPTR)(pFree)->pNext > (KUPTR)(pFree) || !(pFree)->pNext); \
106 } while (0)
107
108#else
109# define KHLPHEAP_ASSERT(expr) do { } while (0)
110# define KHLPHEAP_ASSERT_BLOCK(pH, pB) do { } while (0)
111# define KHLPHEAP_ASSERT_FREE(pH, pF) do { } while (0)
112#endif
113
114
115/**
116 * A free heap block.
117 */
118typedef struct KHLPHEAPFREE
119{
120 /** The core bit which we have in common with used blocks. */
121 KHLPHEAPBLOCK Core;
122 /** The next free block. */
123 struct KHLPHEAPFREE *pNext;
124 /** The previous free block. */
125 struct KHLPHEAPFREE *pPrev;
126} KHLPHEAPFREE, *PKHLPHEAPFREE;
127
128
129/**
130 * A heap segment.
131 */
132typedef struct KHLPHEAPSEG
133{
134 /** The base address of the segment. */
135 void *pvBase;
136 /** The length of the segment (in bytes). */
137 KSIZE cb;
138} KHLPHEAPSEG, *PKHLPHEAPSEG;
139
140/**
141 * Bundle of heap segments.
142 */
143typedef struct KHLPHEAPSEGS
144{
145 /** Pointer to the next segment bundle. */
146 struct KHLPHEAPSEGS *pNext;
147 /** The number of segments used. */
148 KU32 cSegs;
149 /** Array of chunks. */
150 KHLPHEAPSEG aSegs[64];
151} KHLPHEAPSEGS, *PKHLPHEAPSEGS;
152
153
154/**
155 * Heap anchor block.
156 */
157typedef struct KHLPHEAPANCHOR
158{
159 /** Head of the block list. */
160 PKHLPHEAPBLOCK pHead;
161 /** Tail of the block list. */
162 PKHLPHEAPBLOCK pTail;
163 /** Head of the free list. */
164 PKHLPHEAPFREE pFreeHead;
165 /** Head segment bundle.
166 * The order of this list is important, but a bit peculiar.
167 * Logically, SegsHead::pNext is the tail pointer. */
168 KHLPHEAPSEGS SegsHead;
169} KHLPHEAPANCHOR, *PKHLPHEAPANCHOR;
170
171
172
173/*******************************************************************************
174* Global Variables *
175*******************************************************************************/
176/** The heap anchor block. */
177static KHLPHEAPANCHOR g_Heap;
178
179
180/*******************************************************************************
181* Internal Functions *
182*******************************************************************************/
183static int khlpHeapInit(PKHLPHEAPANCHOR pHeap);
184static void khlpHeapDelete(PKHLPHEAPANCHOR pHeap);
185static void * khlpHeapAlloc(PKHLPHEAPANCHOR pHeap, KSIZE cb);
186static void khlpHeapFree(PKHLPHEAPANCHOR pHeap, void *pv);
187static KSIZE khlpHeapBlockSize(PKHLPHEAPANCHOR pHeap, void *pv);
188static void khlpHeapDonate(PKHLPHEAPANCHOR pHeap, void *pv, KSIZE cb);
189static int khlpHeapSegAlloc(PKHLPHEAPSEG pSeg, KSIZE cb);
190static void khlpHeapSegFree(PKHLPHEAPSEG pSeg);
191
192
193/**
194 * Initializes the kLdr heap.
195 *
196 * @returns 0 on success, non-zero OS specific status code on failure.
197 */
198KHLP_DECL(int) kHlpHeapInit(void)
199{
200 return khlpHeapInit(&g_Heap);
201}
202
203
204/**
205 * Terminates the kLdr heap.
206 */
207KHLP_DECL(void) kHlpHeapTerm(void)
208{
209 khlpHeapDelete(&g_Heap);
210}
211
212
213KHLP_DECL(void *) kHlpAlloc(KSIZE cb)
214{
215 return khlpHeapAlloc(&g_Heap, cb);
216}
217
218
219KHLP_DECL(void *) kHlpAllocZ(KSIZE cb)
220{
221 void *pv = khlpHeapAlloc(&g_Heap, cb);
222 if (pv)
223 kHlpMemSet(pv, 0, cb);
224 return pv;
225}
226
227
228KHLP_DECL(void *) kHlpDup(const void *pv, KSIZE cb)
229{
230 void *pvNew = khlpHeapAlloc(&g_Heap, cb);
231 if (pvNew)
232 kHlpMemCopy(pvNew, pv, cb);
233 return pvNew;
234}
235
236
237KHLP_DECL(char *) kHlpStrDup(const char *psz)
238{
239 return (char *)kHlpDup(psz, kHlpStrLen(psz) + 1);
240}
241
242
243KHLP_DECL(void *) kHlpRealloc(void *pv, KSIZE cb)
244{
245 void *pvNew;
246 if (!cb)
247 {
248 kHlpFree(pv);
249 pvNew = NULL;
250 }
251 else if (!pv)
252 pvNew = khlpHeapAlloc(&g_Heap, cb);
253 else
254 {
255 KSIZE cbToCopy = khlpHeapBlockSize(&g_Heap, pv);
256 pvNew = khlpHeapAlloc(&g_Heap, cb);
257 if (pvNew)
258 {
259 kHlpMemCopy(pvNew, pv, cb);
260 kHlpFree(pv);
261 }
262 }
263 return pvNew;
264}
265
266
267KHLP_DECL(void) kHlpFree(void *pv)
268{
269 khlpHeapFree(&g_Heap, pv);
270}
271
272
273/**
274 * Donates memory to the heap.
275 *
276 * @param pv The address of the memory.
277 * @param cb The amount of memory.
278 */
279KHLP_DECL(void) kHlpHeapDonate(void *pv, KSIZE cb)
280{
281 khlpHeapDonate(&g_Heap, pv, cb);
282}
283
284
285
286/**
287 * Initializes the heap anchor.
288 *
289 * @returns 0 on success, non-zero on failure.
290 * @param pHeap The heap anchor to be initialized.
291 */
292static int khlpHeapInit(PKHLPHEAPANCHOR pHeap)
293{
294 pHeap->pHead = NULL;
295 pHeap->pTail = NULL;
296 pHeap->pFreeHead = NULL;
297 pHeap->SegsHead.pNext = NULL;
298 pHeap->SegsHead.cSegs = 0;
299 return 0;
300}
301
302
303/**
304 * Deletes a heap.
305 * This will free all resources (memory) associated with the heap.
306 *
307 * @param pHeap The heap to be deleted.
308 */
309static void khlpHeapDelete(PKHLPHEAPANCHOR pHeap)
310{
311 /*
312 * Free the segments, LIFO order.
313 * The head element is the last to be free, while the
314 * head.pNext is really the tail pointer - neat or what?
315 */
316 while ( pHeap->SegsHead.cSegs
317 || pHeap->SegsHead.pNext)
318 {
319 /* find the tail. */
320 KU32 iSeg;
321 PKHLPHEAPSEGS pSegs = pHeap->SegsHead.pNext;
322 if (!pSegs)
323 pSegs = &pHeap->SegsHead;
324 else
325 {
326 pHeap->SegsHead.pNext = pSegs->pNext;
327 pSegs->pNext = NULL;
328 }
329
330 /* free the segments */
331 iSeg = pSegs->cSegs;
332 while (iSeg-- > 0)
333 khlpHeapSegFree(&pSegs->aSegs[iSeg]);
334 pSegs->cSegs = 0;
335 }
336
337 /* Zap the anchor. */
338 pHeap->pHead = NULL;
339 pHeap->pTail = NULL;
340 pHeap->pFreeHead = NULL;
341 pHeap->SegsHead.pNext = NULL;
342 pHeap->SegsHead.cSegs = 0;
343}
344
345
346/**
347 * Internal heap block allocator.
348 */
349static void * kldrHeapAllocSub(PKHLPHEAPANCHOR pHeap, KSIZE cb)
350{
351 /*
352 * Find a fitting free block.
353 */
354 const KSIZE cbReq = K_ALIGN_Z(cb + sizeof(KHLPHEAPBLOCK), KHLPHEAPBLOCK_ALIGNMENT);
355 PKHLPHEAPFREE pCur = pHeap->pFreeHead;
356 while (pCur)
357 {
358 if (pCur->Core.cb >= cbReq)
359 {
360 if (pCur->Core.cb != cbReq)
361 {
362 /* check and see if there is a better match close by. */
363 PKHLPHEAPFREE pCur2 = pCur->pNext;
364 unsigned i = 16;
365 while (i-- > 0 && pCur2)
366 {
367 if (pCur2->Core.cb >= cbReq)
368 {
369 if (pCur2->Core.cb == cbReq)
370 {
371 pCur = pCur2;
372 break;
373 }
374 if (pCur2->Core.cb < pCur->Core.cb)
375 pCur = pCur2;
376 }
377
378 /* next */
379 KHLPHEAP_ASSERT_FREE(pHeap, pCur2);
380 pCur2 = pCur2->pNext;
381 }
382 }
383 break;
384 }
385
386 /* next */
387 KHLPHEAP_ASSERT_FREE(pHeap, pCur);
388 pCur = pCur->pNext;
389 }
390 if (!pCur)
391 return NULL;
392 KHLPHEAP_ASSERT_FREE(pHeap, pCur);
393
394 /*
395 * Do we need to split out a block?
396 */
397 if (pCur->Core.cb - cbReq >= KHLPHEAPBLOCK_ALIGNMENT * 2)
398 {
399 PKHLPHEAPBLOCK pNew;
400
401 pCur->Core.cb -= cbReq;
402
403 pNew = (PKHLPHEAPBLOCK)((KUPTR)pCur + pCur->Core.cb);
404 pNew->fFlags = 0;
405 pNew->cb = cbReq;
406 pNew->pNext = pCur->Core.pNext;
407 if (pNew->pNext)
408 pNew->pNext->pPrev = pNew;
409 else
410 pHeap->pTail = pNew;
411 pNew->pPrev = &pCur->Core;
412 pCur->Core.pNext = pNew;
413
414 KHLPHEAP_ASSERT_FREE(pHeap, pCur);
415 KHLPHEAP_ASSERT_BLOCK(pHeap, pNew);
416 return pNew + 1;
417 }
418
419 /*
420 * No, just unlink it from the free list and return.
421 */
422 if (pCur->pNext)
423 pCur->pNext->pPrev = pCur->pPrev;
424 if (pCur->pPrev)
425 pCur->pPrev->pNext = pCur->pNext;
426 else
427 pHeap->pFreeHead = pCur->pNext;
428 pCur->Core.fFlags &= ~KHLPHEAPBLOCK_FLAG_FREE;
429
430 KHLPHEAP_ASSERT_BLOCK(pHeap, &pCur->Core);
431 return &pCur->Core + 1;
432}
433
434
435/**
436 * Allocate a heap block.
437 *
438 * @returns Pointer to the allocated heap block on success. On failure NULL is returned.
439 * @param pHeap The heap.
440 * @param cb The requested heap block size.
441 */
442static void * khlpHeapAlloc(PKHLPHEAPANCHOR pHeap, KSIZE cb)
443{
444 void *pv;
445
446 /* adjust the requested block size. */
447 cb = K_ALIGN_Z(cb, KHLPHEAPBLOCK_ALIGNMENT);
448 if (!cb)
449 cb = KHLPHEAPBLOCK_ALIGNMENT;
450
451 /* try allocate the block. */
452 pv = kldrHeapAllocSub(pHeap, cb);
453 if (!pv)
454 {
455 /*
456 * Failed, add another segment and try again.
457 */
458 KHLPHEAPSEG Seg;
459 if (khlpHeapSegAlloc(&Seg, cb + sizeof(KHLPHEAPSEGS) + sizeof(KHLPHEAPBLOCK) * 16))
460 return NULL;
461
462 /* donate before insterting the segment, this makes sure we got heap to expand the segment list. */
463 khlpHeapDonate(pHeap, Seg.pvBase, Seg.cb);
464
465 /* insert the segment. */
466 if (pHeap->SegsHead.cSegs < sizeof(pHeap->SegsHead.aSegs) / sizeof(pHeap->SegsHead.aSegs[0]))
467 pHeap->SegsHead.aSegs[pHeap->SegsHead.cSegs++] = Seg;
468 else if ( pHeap->SegsHead.pNext
469 && pHeap->SegsHead.pNext->cSegs < sizeof(pHeap->SegsHead.aSegs) / sizeof(pHeap->SegsHead.aSegs[0]))
470 pHeap->SegsHead.pNext->aSegs[pHeap->SegsHead.pNext->cSegs++] = Seg;
471 else
472 {
473 PKHLPHEAPSEGS pSegs = (PKHLPHEAPSEGS)kldrHeapAllocSub(pHeap, sizeof(*pSegs));
474 KHLPHEAP_ASSERT(pSegs);
475 pSegs->pNext = pHeap->SegsHead.pNext;
476 pHeap->SegsHead.pNext = pSegs;
477 pSegs->aSegs[0] = Seg;
478 pSegs->cSegs = 1;
479 }
480
481 /* retry (should succeed) */
482 pv = kldrHeapAllocSub(pHeap, cb);
483 KHLPHEAP_ASSERT(pv);
484 }
485
486 return pv;
487}
488
489
490/**
491 * Frees a heap block.
492 *
493 * @param pHeap The heap.
494 * @param pv The pointer returned by khlpHeapAlloc().
495 */
496static void khlpHeapFree(PKHLPHEAPANCHOR pHeap, void *pv)
497{
498 PKHLPHEAPFREE pFree, pLeft, pRight;
499
500 /* ignore NULL pointers. */
501 if (!pv)
502 return;
503
504 pFree = (PKHLPHEAPFREE)((PKHLPHEAPBLOCK)pv - 1);
505 KHLPHEAP_ASSERT_BLOCK(pHeap, &pFree->Core);
506 KHLPHEAP_ASSERT(KHLPHEAPBLOCK_IS_ALLOCATED(&pFree->Core));
507
508 /*
509 * Merge or link with left node?
510 */
511 pLeft = (PKHLPHEAPFREE)pFree->Core.pPrev;
512 if ( pLeft
513 && KHLPHEAPBLOCK_IS_FREE(&pLeft->Core)
514 && KHLPHEAPBLOCK_IS_ADJACENT(&pLeft->Core, &pFree->Core)
515 )
516 {
517 /* merge left */
518 pLeft->Core.pNext = pFree->Core.pNext;
519 if (pFree->Core.pNext)
520 pFree->Core.pNext->pPrev = &pLeft->Core;
521 else
522 pHeap->pTail = &pLeft->Core;
523
524 pLeft->Core.cb += pFree->Core.cb;
525 pFree->Core.fFlags = ~0;
526 pFree = pLeft;
527 }
528 else
529 {
530 /* link left */
531 while (pLeft && !KHLPHEAPBLOCK_IS_FREE(&pLeft->Core))
532 pLeft = (PKHLPHEAPFREE)pLeft->Core.pPrev;
533 if (pLeft)
534 {
535 pFree->pPrev = pLeft;
536 pFree->pNext = pLeft->pNext;
537 if (pLeft->pNext)
538 pLeft->pNext->pPrev = pFree;
539 pLeft->pNext = pFree;
540 }
541 else
542 {
543 pFree->pPrev = NULL;
544 pFree->pNext = pHeap->pFreeHead;
545 if (pHeap->pFreeHead)
546 pHeap->pFreeHead->pPrev = pFree;
547 pHeap->pFreeHead = pFree;
548 }
549 pFree->Core.fFlags |= KHLPHEAPBLOCK_FLAG_FREE;
550 }
551 KHLPHEAP_ASSERT_FREE(pHeap, pFree);
552
553 /*
554 * Merge right?
555 */
556 pRight = (PKHLPHEAPFREE)pFree->Core.pNext;
557 if ( pRight
558 && KHLPHEAPBLOCK_IS_FREE(&pRight->Core)
559 && KHLPHEAPBLOCK_IS_ADJACENT(&pFree->Core, pRight)
560 )
561 {
562 /* unlink pRight from the global list. */
563 pFree->Core.pNext = pRight->Core.pNext;
564 if (pRight->Core.pNext)
565 pRight->Core.pNext->pPrev = &pFree->Core;
566 else
567 pHeap->pTail = &pFree->Core;
568
569 /* unlink pRight from the free list. */
570 pFree->pNext = pRight->pNext;
571 if (pRight->pNext)
572 pRight->pNext->pPrev = pFree;
573
574 /* update size and invalidate pRight. */
575 pFree->Core.cb += pRight->Core.cb;
576 pRight->Core.fFlags = ~0;
577 }
578}
579
580
581/**
582 * Calcs the size of a heap block.
583 *
584 * @returns The block size (in bytes).
585 * @param pHeap The heap.
586 * @param pv Pointer to an in-use heap block.
587 */
588static KSIZE khlpHeapBlockSize(PKHLPHEAPANCHOR pHeap, void *pv)
589{
590 PKHLPHEAPBLOCK pBlock = (PKHLPHEAPBLOCK)pv - 1;
591 KHLPHEAP_ASSERT_BLOCK(pHeap, pBlock);
592 KHLPHEAP_ASSERT(KHLPHEAPBLOCK_IS_ALLOCATED(pBlock));
593 return (KU8 *)pBlock->pNext - (KU8 *)pv;
594}
595
596
597/**
598 * Donates memory to the heap.
599 *
600 * The donated memory is returned to the donator when the heap is deleted.
601 *
602 * @param pHeap The heap
603 * @param pv The pointer to the donated memory.
604 * @param cb Size of the donated memory.
605 */
606static void khlpHeapDonate(PKHLPHEAPANCHOR pHeap, void *pv, KSIZE cb)
607{
608 PKHLPHEAPBLOCK pBlock;
609
610 /*
611 * Don't bother with small donations.
612 */
613 if (cb < KHLPHEAPBLOCK_ALIGNMENT * 4)
614 return;
615
616 /*
617 * Align the donation on a heap block boundrary.
618 */
619 if ((KUPTR)pv & (KHLPHEAPBLOCK_ALIGNMENT - 1))
620 {
621 cb -= (KUPTR)pv & 31;
622 pv = K_ALIGN_P(pv, KHLPHEAPBLOCK_ALIGNMENT);
623 }
624 cb &= ~(KSIZE)(KHLPHEAPBLOCK_ALIGNMENT - 1);
625
626 /*
627 * Create an allocated block, link it and free it.
628 */
629 pBlock = (PKHLPHEAPBLOCK)pv;
630 pBlock->pNext = NULL;
631 pBlock->pPrev = NULL;
632 pBlock->cb = cb;
633 pBlock->fFlags = 0;
634
635 /* insert */
636 if ((KUPTR)pBlock < (KUPTR)pHeap->pHead)
637 {
638 /* head */
639 pBlock->pNext = pHeap->pHead;
640 pHeap->pHead->pPrev = pBlock;
641 pHeap->pHead = pBlock;
642 }
643 else if ((KUPTR)pBlock > (KUPTR)pHeap->pTail)
644 {
645 if (pHeap->pTail)
646 {
647 /* tail */
648 pBlock->pPrev = pHeap->pTail;
649 pHeap->pTail->pNext = pBlock;
650 pHeap->pTail = pBlock;
651 }
652 else
653 {
654 /* first */
655 pHeap->pHead = pBlock;
656 pHeap->pTail = pBlock;
657 }
658 }
659 else
660 {
661 /* in list (unlikely) */
662 PKHLPHEAPBLOCK pPrev = pHeap->pHead;
663 PKHLPHEAPBLOCK pCur = pPrev->pNext;
664 for (;;)
665 {
666 KHLPHEAP_ASSERT_BLOCK(pHeap, pCur);
667 if ((KUPTR)pCur > (KUPTR)pBlock)
668 break;
669 pPrev = pCur;
670 pCur = pCur->pNext;
671 }
672
673 pBlock->pNext = pCur;
674 pBlock->pPrev = pPrev;
675 pPrev->pNext = pBlock;
676 pCur->pPrev = pBlock;
677 }
678 KHLPHEAP_ASSERT_BLOCK(pHeap, pBlock);
679
680 /* free it */
681 khlpHeapFree(pHeap, pBlock + 1);
682}
683
684
685
686/**
687 * Allocates a new segment.
688 *
689 * @returns 0 on success, non-zero OS status code on failure.
690 * @param pSeg Where to put the info about the allocated segment.
691 * @param cbMin The minimum segment size.
692 */
693static int khlpHeapSegAlloc(PKHLPHEAPSEG pSeg, KSIZE cbMin)
694{
695#if K_OS == K_OS_OS2
696 APIRET rc;
697
698 pSeg->cb = (cbMin + 0xffff) & ~(KSIZE)0xffff;
699 pSeg->pvBase = NULL;
700 rc = DosAllocMem(&pSeg->pvBase, pSeg->cb, PAG_COMMIT | PAG_READ | PAG_WRITE | OBJ_ANY);
701 if (rc == ERROR_INVALID_PARAMETER)
702 rc = DosAllocMem(&pSeg->pvBase, pSeg->cb, PAG_COMMIT | PAG_READ | PAG_WRITE);
703 if (rc)
704 {
705 pSeg->pvBase = NULL;
706 pSeg->cb = 0;
707 return rc;
708 }
709
710#elif K_OS == K_OS_WINDOWS
711 pSeg->cb = (cbMin + 0xffff) & ~(KSIZE)0xffff;
712 pSeg->pvBase = VirtualAlloc(NULL, pSeg->cb, MEM_COMMIT, PAGE_READWRITE);
713 if (!pSeg->pvBase)
714 {
715 pSeg->cb = 0;
716 return GetLastError();
717 }
718
719#else
720 int rc;
721
722 pSeg->cb = (cbMin + 0xffff) & ~(KSIZE)0xffff;
723 pSeg->pvBase = NULL;
724 rc = kHlpPageAlloc(&pSeg->pvBase, pSeg->cb, KPROT_READWRITE, K_FALSE);
725 if (rc)
726 {
727 pSeg->pvBase = NULL;
728 pSeg->cb = 0;
729 return rc;
730 }
731
732#endif
733
734 return 0;
735}
736
737
738/**
739 * Frees a segment.
740 *
741 * @param pSeg The segment to be freed.
742 */
743static void khlpHeapSegFree(PKHLPHEAPSEG pSeg)
744{
745#if K_OS == K_OS_OS2
746 APIRET rc = DosFreeMem(pSeg->pvBase);
747 KHLPHEAP_ASSERT(!rc); (void)rc;
748
749#elif K_OS == K_OS_WINDOWS
750 BOOL fRc = VirtualFree(pSeg->pvBase, 0 /*pSeg->cb*/, MEM_RELEASE);
751 KHLPHEAP_ASSERT(fRc); (void)fRc;
752
753#else
754 int rc = kHlpPageFree(pSeg->pvBase, pSeg->cb);
755 KHLPHEAP_ASSERT(!rc); (void)rc;
756
757#endif
758}
759
Note: See TracBrowser for help on using the repository browser.