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

Last change on this file since 3582 was 3578, checked in by bird, 18 years ago

kLdrRdr cleanup.

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