3 * Copyright (C) 1996, Onno Hovers, All rights reserved
5 * This software is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Library General Public License as
7 * published by the Free Software Foundation; either version 2 of the
8 * License, or (at your option) any later version.
10 * This software is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Library General Public License for more details.
15 * You should have received a copy of the GNU Library General Public
16 * License along with this software; see the file COPYING.LIB. If
17 * not, write to the Free Software Foundation, Inc., 675 Mass Ave,
18 * Cambridge, MA 02139, USA.
20 * Win32 heap functions (HeapXXX).
25 * Adapted for the ReactOS system libraries by David Welch (welch@mcmail.com)
26 * Put the type definitions of the heap in a seperate header. Boudewijn Dekker
29 #include <kernel32/kernel32.h>
30 #include <kernel32/heap.h>
31 #include <internal/string.h>
33 static HEAP_BUCKET __HeapDefaultBuckets
[]=
35 { NULL
, 16, 18, 504 },
36 { NULL
, 24, 30, 1016 },
37 { NULL
, 32, 24, 1016 },
38 { NULL
, 48, 17, 1016 },
39 { NULL
, 64, 27, 2040 },
40 { NULL
, 96, 19, 2040 },
41 { NULL
, 128, 29, 4088 },
42 { NULL
, 256, 15, 4088 },
47 static BOOL
__HeapCommit(PHEAP pheap
, LPVOID start
, LPVOID end
);
48 static BOOL
__HeapDecommit(PHEAP pheap
, LPVOID start
, LPVOID end
);
49 static LPVOID
__HeapAlloc(PHEAP pheap
, ULONG flags
, ULONG size
, ULONG tag
);
50 static VOID
__HeapFreeRest(PHEAP pheap
, PHEAP_BLOCK pfree
, ULONG allocsize
,
52 static LPVOID
__HeapReAlloc(PHEAP pheap
, ULONG flags
, LPVOID pold
, DWORD size
);
53 static BOOL
__HeapFree(PHEAP pheap
, ULONG flags
, LPVOID pmem
);
54 static PHEAP_SUBALLOC
__HeapAllocSub(PHEAP pheap
, PHEAP_BUCKET pbucket
);
55 static LPVOID
__HeapAllocFragment(PHEAP pheap
, ULONG flags
, ULONG size
);
56 static LPVOID
__HeapReAllocFragment(PHEAP pheap
, ULONG flags
,
57 LPVOID pold
, ULONG size
);
58 static BOOL
__HeapFreeFragment(PHEAP pheap
, ULONG flags
, LPVOID ptr
);
59 static PHEAP
__HeapPrepare(LPVOID base
, ULONG minsize
, ULONG maxsize
,
64 /*********************************************************************
67 * commits a range of memory in the heap *
68 *********************************************************************/
69 static BOOL
__HeapCommit(PHEAP pheap
, LPVOID start
, LPVOID end
)
71 dprintf("__HeapCommit( 0x%lX, 0x%lX, 0x%lX)\n",
72 (ULONG
) pheap
, (ULONG
) start
, (ULONG
) end
);
74 if(end
>= pheap
->LastBlock
)
76 if (VirtualAlloc(start
,end
-start
,MEM_COMMIT
,PAGE_READWRITE
)!=start
)
83 /*********************************************************************
86 * decommits a range of memory in the heap *
87 *********************************************************************/
88 static BOOL
__HeapDecommit(PHEAP pheap
, LPVOID start
, LPVOID end
)
90 dprintf("__HeapDecommit( 0x%lX, 0x%lX, 0x%lX)\n",
91 (ULONG
) pheap
, (ULONG
) start
, (ULONG
) end
);
95 if((end
>= pheap
->LastBlock
)&&(start
<= pheap
->LastBlock
))
96 pheap
->LastBlock
=start
;
98 return(VirtualFree(start
,end
-start
,MEM_RESERVE
));
101 /*********************************************************************
104 * allocates a range of memory from the heap *
105 *********************************************************************/
106 static LPVOID
__HeapAlloc(PHEAP pheap
, ULONG flags
, ULONG size
, ULONG tag
)
116 dprintf("__HeapAlloc(pheap %x, flags %x, size %d, tag %x)\n",
117 pheap
,flags
,size
,tag
);
119 pfree
=&(pheap
->Start
);
120 allocsize
=SIZE_ROUND(size
);
121 freesize
=HEAP_SIZE(pfree
);
122 /* look for a free region of memory: simple First Fit */
123 while( HEAP_ISALLOC(pfree
) || ( freesize
<allocsize
))
125 pfree
=HEAP_NEXT(pfree
);
126 if((LPVOID
) pfree
>=pheap
->End
)
127 return __ErrorReturnNull(ERROR_OUTOFMEMORY
);
128 freesize
=HEAP_SIZE(pfree
);
132 if(freesize
>allocsize
)
134 /* commit necessary memory */
135 commitstart
=(LPVOID
) ROUNDDOWN((ULONG
) palloc
+HEAP_ADMIN_SIZE
,PAGESIZE
);
136 commitend
=(LPVOID
) ROUNDUP ((ULONG
) palloc
+
137 allocsize
+2*HEAP_ADMIN_SIZE
, PAGESIZE
);
138 if(commitstart
<commitend
)
139 if(!__HeapCommit(pheap
, commitstart
, commitend
))
140 return __ErrorReturnNull(ERROR_OUTOFMEMORY
);
142 /* split this block in two */
143 pfree
= (LPVOID
) palloc
+ HEAP_ADMIN_SIZE
+ allocsize
;
146 pfree
->Size
=(freesize
-allocsize
-HEAP_ADMIN_SIZE
) | HEAP_FREE_TAG
;
147 pfree
->PrevSize
=(LPVOID
)pfree
-(LPVOID
)palloc
;
149 pnext
=HEAP_NEXT(pfree
);
150 if((LPVOID
) pnext
< pheap
->End
)
151 pnext
->PrevSize
=freesize
-allocsize
;
155 /* commit necessary memory */
156 commitstart
=(LPVOID
) ROUNDDOWN((ULONG
) palloc
+HEAP_ADMIN_SIZE
, PAGESIZE
);
157 commitend
=(LPVOID
) ROUNDUP((ULONG
) palloc
+HEAP_ADMIN_SIZE
+allocsize
,
159 if(commitstart
<commitend
)
160 if(!__HeapCommit(pheap
, commitstart
, commitend
))
161 return __ErrorReturnNull(ERROR_OUTOFMEMORY
);
163 /* update our administration */
164 palloc
->Size
= size
| tag
;
165 if((flags
| pheap
->Flags
)& HEAP_ZERO_MEMORY
)
166 FillMemory((LPVOID
)palloc
+HEAP_ADMIN_SIZE
, allocsize
, 0);
167 return (LPVOID
)palloc
+HEAP_ADMIN_SIZE
;
170 /*********************************************************************
173 * used by realloc to free a part of the heap *
174 *********************************************************************/
175 static VOID
__HeapFreeRest(PHEAP pheap
, PHEAP_BLOCK pfree
,
176 ULONG allocsize
, ULONG newsize
)
180 if(allocsize
==newsize
)
182 pfree
->PrevSize
=allocsize
+HEAP_ADMIN_SIZE
;
186 pfree
->Size
= (allocsize
-newsize
-HEAP_ADMIN_SIZE
) | HEAP_FREE_TAG
;
187 pfree
->PrevSize
= newsize
+HEAP_ADMIN_SIZE
;
189 pnext
=HEAP_NEXT(pfree
);
190 /* if there is a free region of memory after us, join it */
191 if(((LPVOID
) pnext
< pheap
->End
)&& HEAP_ISFREE(pnext
))
193 pfree
->Size
= (HEAP_SIZE(pfree
)+HEAP_SIZE(pnext
) + HEAP_ADMIN_SIZE
) |
200 pnext
=HEAP_NEXT(pfree
);
201 if((LPVOID
) pnext
< pheap
->End
)
202 pnext
->PrevSize
=(LPVOID
)pnext
-(LPVOID
)pfree
;
205 /*********************************************************************
208 * reallocates a range of memory from the heap *
209 *********************************************************************/
211 static LPVOID
__HeapReAlloc(PHEAP pheap
, ULONG flags
, LPVOID pold
, DWORD size
)
213 PHEAP_BLOCK prealloc
=(PHEAP_BLOCK
)((LPVOID
)pold
-HEAP_ADMIN_SIZE
);
222 /* check that this is a valid allocated block */
223 if(!HEAP_ISALLOC(prealloc
))
224 return __ErrorReturnNull(ERROR_INVALID_PARAMETER
);
226 allocsize
= HEAP_RSIZE(prealloc
);
227 newsize
= SIZE_ROUND(size
);
229 * cases: size=0 free memory
230 * [ size<HEAP_FRAGMENT_THRESHOLD realloc ]
231 * newsize<previous size free rest
232 * newsize=previous size nop
233 * newsize>previous size try to merge
238 dprintf("__HeapReAlloc: freeing memory\n");
239 __HeapFree(pheap
, flags
, pold
);
243 else if(size
< HEAP_FRAGMENT_THRESHOLD
)
245 /* alloc a new fragment */
246 pmem
=__HeapAllocFragment(pheap
, flags
, size
);
248 CopyMemory(pmem
, pold
, size
);
252 else if(newsize
< allocsize
)
254 dprintf("__HeapReAlloc: shrinking memory\n");
255 /* free remaining region of memory */
256 prealloc
->Size
=size
| HEAP_NORMAL_TAG
;
257 pnext
=HEAP_NEXT(prealloc
);
258 __HeapFreeRest(pheap
, pnext
, allocsize
, newsize
);
260 /* decommit unnecessary memory */
261 commitstart
=(LPVOID
) ROUNDUP((ULONG
) pnext
+HEAP_ADMIN_SIZE
,PAGESIZE
);
262 commitend
=(LPVOID
) ROUNDDOWN((ULONG
) pnext
+HEAP_ADMIN_SIZE
+
263 HEAP_SIZE(pnext
), PAGESIZE
);
264 if(commitstart
<commitend
)
265 __HeapDecommit(pheap
, commitstart
, commitend
);
268 else if(newsize
== allocsize
)
270 dprintf("__HeapReAlloc: no changes\n");
272 prealloc
->Size
= size
| HEAP_NORMAL_TAG
;
275 else if(newsize
> allocsize
)
278 pnext
=HEAP_NEXT(prealloc
);
280 if(((LPVOID
) pnext
< pheap
->End
)&& HEAP_ISFREE(pnext
) &&
281 (HEAP_SIZE(pnext
) + HEAP_ADMIN_SIZE
>=newsize
-allocsize
))
283 dprintf("__HeapReAlloc: joining memory\n");
284 oldsize
=HEAP_SIZE(prealloc
);
285 prealloc
->Size
=size
| HEAP_NORMAL_TAG
;
287 /* commit new memory if necessary */
288 commitstart
=(LPVOID
) ROUNDDOWN((ULONG
) pnext
+HEAP_ADMIN_SIZE
,
290 commitend
=(LPVOID
) ROUNDUP((ULONG
) pnext
+newsize
-allocsize
+
291 HEAP_ADMIN_SIZE
, PAGESIZE
);
292 if(commitstart
<commitend
)
293 if(!__HeapCommit(pheap
, commitstart
, commitend
))
294 return __ErrorReturnNull(ERROR_OUTOFMEMORY
);
296 __HeapFreeRest(pheap
, HEAP_NEXT(prealloc
),
297 allocsize
+HEAP_ADMIN_SIZE
+HEAP_SIZE(pnext
), newsize
);
299 if((flags
|pheap
->Flags
)&HEAP_ZERO_MEMORY
)
300 memset(pold
+oldsize
, 0, size
-oldsize
);
305 if((flags
&HEAP_REALLOC_IN_PLACE_ONLY
)==0)
307 dprintf("__HeapReAlloc: allocating new memory\n");
308 /* alloc a new piece of memory */
309 oldsize
=HEAP_SIZE(prealloc
);
310 pmem
=__HeapAlloc(pheap
, flags
, size
, HEAP_NORMAL_TAG
);
312 CopyMemory(pmem
, pold
, oldsize
);
313 if((flags
|pheap
->Flags
)&HEAP_ZERO_MEMORY
)
314 memset(pmem
+ oldsize
, 0, size
-oldsize
);
315 __HeapFree(pheap
, flags
, pold
);
319 return __ErrorReturnNull(ERROR_OUTOFMEMORY
);
325 /*********************************************************************
328 * frees a range of memory from the heap *
329 *********************************************************************/
331 static BOOL
__HeapFree(PHEAP pheap
, ULONG flags
, LPVOID ptr
)
333 PHEAP_BLOCK pfree
=(PHEAP_BLOCK
)((LPVOID
)ptr
-HEAP_ADMIN_SIZE
);
336 LPVOID decommitstart
;
339 /* check that this is a valid allocated block */
340 if(!HEAP_ISALLOC(pfree
))
343 pfree
->Size
= HEAP_RSIZE(pfree
) | HEAP_FREE_TAG
;
345 /* if there is a free region of memory before us, join it */
346 pprev
=HEAP_PREV(pfree
);
347 pnext
=HEAP_NEXT(pfree
);
348 if((pprev
!=pfree
) && HEAP_ISFREE(pprev
))
350 pprev
->Size
= (HEAP_SIZE(pprev
)+HEAP_SIZE(pfree
) + HEAP_ADMIN_SIZE
) |
352 if((LPVOID
) pnext
<pheap
->End
)
353 pnext
->PrevSize
=(LPVOID
)pnext
-(LPVOID
)pprev
;
359 /* if there is a free region of memory after us, join it */
360 if(((LPVOID
) pnext
< pheap
->End
)&& HEAP_ISFREE(pnext
))
362 pfree
->Size
= (HEAP_SIZE(pfree
)+HEAP_SIZE(pnext
) + HEAP_ADMIN_SIZE
) |
368 pnext
=HEAP_NEXT(pfree
);
369 if((LPVOID
) pnext
< pheap
->End
)
370 pnext
->PrevSize
=(LPVOID
)pnext
-(LPVOID
)pfree
;
373 /* decommit unnecessary memory */
374 decommitstart
=(LPVOID
) ROUNDUP((ULONG
) pfree
+HEAP_ADMIN_SIZE
,PAGESIZE
);
375 decommitend
=(LPVOID
) ROUNDDOWN((ULONG
) pfree
+HEAP_ADMIN_SIZE
+
376 HEAP_SIZE(pfree
), PAGESIZE
);
377 if(decommitstart
<decommitend
)
378 __HeapDecommit(pheap
, decommitstart
, decommitend
);
383 /*********************************************************************
386 * allocates a range of memory that is used to allocate small *
388 *********************************************************************/
389 PHEAP_SUBALLOC
__HeapAllocSub(PHEAP pheap
, PHEAP_BUCKET pbucket
)
394 PHEAP_FRAGMENT pprev
;
395 PHEAP_FRAGMENT pnext
;
396 PHEAP_FRAGMENT palloc
;
398 psub
=(PHEAP_SUBALLOC
) __HeapAlloc(pheap
, 0, pbucket
->TotalSize
,
401 return __ErrorReturnNull(ERROR_OUTOFMEMORY
);
403 /* initialize suballoc */
404 palloc
=(PHEAP_FRAGMENT
) ((LPVOID
)psub
+ sizeof(HEAP_SUBALLOC
));
405 psub
->FirstFree
=palloc
;
406 psub
->NumberFree
=pbucket
->Number
;
408 psub
->Next
=pbucket
->FirstFree
;
410 psub
->Bucket
=pbucket
;
411 pbucket
->FirstFree
=psub
;
413 /* initialize free fragments */
414 add
=pbucket
->Size
+HEAP_FRAG_ADMIN_SIZE
;
416 for(i
=0;i
<pbucket
->Number
;i
++)
418 pnext
=(PHEAP_FRAGMENT
)((LPVOID
)palloc
+add
);
419 palloc
->Magic
=HEAP_FRAG_MAGIC
;
421 palloc
->Size
=pbucket
->Size
;
423 palloc
->FreeNext
=pnext
;
424 palloc
->FreePrev
=pprev
;
428 pprev
->FreeNext
=NULL
;
432 /*********************************************************************
433 * __HeapAllocFragment *
435 * allocates a small fragment of memory from the heap *
436 *********************************************************************/
437 static LPVOID
__HeapAllocFragment(PHEAP pheap
, ULONG flags
, ULONG size
)
439 PHEAP_BUCKET pbucket
;
441 PHEAP_FRAGMENT palloc
;
444 /* get bucket size */
445 pbucket
=pheap
->Bucket
;
446 while(size
>pbucket
->Size
)
451 psub
= pbucket
->FirstFree
;
453 psub
= __HeapAllocSub(pheap
, pbucket
);
457 /* do our bookkeeping */
458 palloc
= psub
->FirstFree
;
459 psub
->FirstFree
= palloc
->FreeNext
;
460 nalloc
= palloc
->Number
;
462 psub
->Bitmap
|=(1<<nalloc
);
464 /* advance freelist */
465 if(!psub
->NumberFree
)
466 pbucket
->FirstFree
=psub
->Next
;
468 /* initialize allocated block */
469 palloc
->Magic
=HEAP_FRAG_MAGIC
;
472 if((flags
|pheap
->Flags
)&HEAP_ZERO_MEMORY
)
473 memset((LPVOID
)palloc
+HEAP_FRAG_ADMIN_SIZE
, 0, pbucket
->Size
);
474 return (LPVOID
) palloc
+HEAP_FRAG_ADMIN_SIZE
;
477 /*********************************************************************
478 * __HeapReAllocFragment *
480 * reallocates a small fragment of memory *
481 *********************************************************************/
482 static LPVOID
__HeapReAllocFragment(PHEAP pheap
, ULONG flags
,
483 LPVOID pold
, ULONG size
)
485 PHEAP_BUCKET pbucket
;
487 PHEAP_FRAGMENT pfrag
=(PHEAP_FRAGMENT
)
488 ((LPVOID
)pold
-HEAP_FRAG_ADMIN_SIZE
);
492 if(pfrag
->Magic
!=HEAP_FRAG_MAGIC
)
493 return __ErrorReturnNull(ERROR_INVALID_PARAMETER
);
495 /* get bucket size */
497 pbucket
=psub
->Bucket
;
498 if(size
<=pbucket
->Size
)
505 if((flags
&HEAP_REALLOC_IN_PLACE_ONLY
)==0)
507 /* alloc a new piece of memory */
508 if(size
>HEAP_FRAGMENT_THRESHOLD
)
509 pmem
=__HeapAlloc(pheap
, flags
, size
, HEAP_NORMAL_TAG
);
511 pmem
=__HeapAllocFragment(pheap
, flags
, size
);
514 CopyMemory(pmem
, pold
, size
);
515 if((flags
|pheap
->Flags
)&HEAP_ZERO_MEMORY
)
516 memset(pmem
+pfrag
->Size
, 0, size
-pfrag
->Size
);
518 __HeapFreeFragment(pheap
, flags
, pold
);
525 /*********************************************************************
526 * __HeapFreeFragment *
528 * frees a small fragment of memory *
529 *********************************************************************/
530 static BOOL
__HeapFreeFragment(PHEAP pheap
, ULONG flags
, LPVOID pfree
)
532 PHEAP_BUCKET pbucket
;
534 PHEAP_FRAGMENT pfrag
=(PHEAP_FRAGMENT
)
535 ((LPVOID
)pfree
-HEAP_FRAG_ADMIN_SIZE
);
539 if(pfrag
->Magic
!=HEAP_FRAG_MAGIC
)
540 return __ErrorReturnFalse(ERROR_INVALID_PARAMETER
);
542 /* get bucket size */
544 pbucket
=psub
->Bucket
;
546 nalloc
=pfrag
->Number
;
547 if((psub
->Bitmap
&(1<<nalloc
))==0)
548 return __ErrorReturnFalse(ERROR_INVALID_PARAMETER
);
550 if(psub
->NumberFree
==pbucket
->Number
)
553 if(psub
==pbucket
->FirstFree
)
554 pbucket
->FirstFree
=psub
->Next
;
556 psub
->Prev
->Next
=psub
->Next
;
558 psub
->Next
->Prev
=psub
->Prev
;
559 if(!__HeapFree(pheap
, flags
, psub
))
565 psub
->Bitmap
&= ~(1<<nalloc
);
569 pfrag
->FreeNext
= psub
->FirstFree
;
570 pfrag
->FreePrev
= NULL
;
571 psub
->FirstFree
->FreePrev
= pfrag
;
572 psub
->FirstFree
= pfrag
;
576 psub
->FirstFree
=pfrag
;
577 pfrag
->FreePrev
=NULL
;
578 pfrag
->FreeNext
=NULL
;
584 /*********************************************************************
587 * Fills in all the data structures of a heap *
588 *********************************************************************/
589 PHEAP
__HeapPrepare(LPVOID base
, ULONG minsize
, ULONG maxsize
, ULONG flags
)
591 PHEAP pheap
=(PHEAP
) base
;
593 dprintf("__HeapPrepare(base %x, minsize %d, maxsize %d, flags %x)\n",
594 base
,minsize
,maxsize
,flags
);
596 pheap
->Magic
=MAGIC_HEAP
;
597 pheap
->End
= ((LPVOID
)pheap
)+minsize
;
599 pheap
->LastBlock
=(LPVOID
)pheap
+ PAGESIZE
;
600 CopyMemory(pheap
->Bucket
,__HeapDefaultBuckets
,sizeof(__HeapDefaultBuckets
));
603 pheap
->NextHeap
=__ProcessHeap
->NextHeap
;
604 __ProcessHeap
->NextHeap
=pheap
;
611 InitializeCriticalSection(&(pheap
->Synchronize
));
612 pheap
->Start
.Size
= (minsize
-sizeof(HEAP
))|HEAP_FREE_TAG
;
613 pheap
->Start
.PrevSize
=0;
618 /*********************************************************************
621 * Called by __VirtualInit to initialize the default process heap *
622 *********************************************************************/
624 VOID WINAPI
__HeapInit(LPVOID base
, ULONG minsize
, ULONG maxsize
)
626 VirtualAlloc(base
,maxsize
,MEM_RESERVE
,PAGE_READWRITE
);
627 VirtualAlloc(base
,PAGESIZE
,MEM_COMMIT
,PAGE_READWRITE
);
629 __HeapPrepare(base
, minsize
, maxsize
, 0);
633 /*********************************************************************
634 * HeapCreate -- KERNEL32 *
635 *********************************************************************/
636 HANDLE STDCALL
HeapCreate(DWORD flags
, DWORD minsize
, DWORD maxsize
)
640 aprintf("HeapCreate( 0x%lX, 0x%lX, 0x%lX )\n", flags
, minsize
, maxsize
);
642 pheap
= VirtualAlloc(NULL
, minsize
, MEM_TOP_DOWN
, PAGE_READWRITE
);
643 VirtualAlloc(pheap
, PAGESIZE
, MEM_COMMIT
, PAGE_READWRITE
);
644 return (HANDLE
) __HeapPrepare(pheap
, minsize
, maxsize
, flags
);
647 /*********************************************************************
648 * HeapDestroy -- KERNEL32 *
649 *********************************************************************/
650 BOOL WINAPI
HeapDestroy(HANDLE hheap
)
652 PHEAP pheap
=(PHEAP
) hheap
;
654 aprintf("HeapDestroy( 0x%lX )\n", (ULONG
) hheap
);
656 if(pheap
->Magic
!=MAGIC_HEAP
)
657 return __ErrorReturnFalse(ERROR_INVALID_PARAMETER
);
659 DeleteCriticalSection(&(pheap
->Synchronize
));
660 VirtualFree(pheap
,0,MEM_RELEASE
);
665 /*********************************************************************
666 * HeapAlloc -- KERNEL32 *
667 *********************************************************************/
668 LPVOID STDCALL
HeapAlloc(HANDLE hheap
, DWORD flags
, DWORD size
)
673 aprintf("HeapAlloc( 0x%lX, 0x%lX, 0x%lX )\n",
674 (ULONG
) hheap
, flags
, (ULONG
) size
);
676 HeapValidate(hheap
, 0, 0);
678 if(( flags
| pheap
->Flags
) & HEAP_NO_SERIALIZE
)
679 EnterCriticalSection(&(pheap
->Synchronize
));
681 if(size
>HEAP_FRAGMENT_THRESHOLD
)
682 retval
=__HeapAlloc(pheap
, flags
, size
, HEAP_NORMAL_TAG
);
684 retval
=__HeapAllocFragment(pheap
, flags
, size
);
686 if( (flags
| pheap
->Flags
) & HEAP_NO_SERIALIZE
)
687 LeaveCriticalSection(&(pheap
->Synchronize
));
689 aprintf("HeapAlloc returns 0x%lX\n", (ULONG
) retval
);
694 /*********************************************************************
695 * HeapReAlloc -- KERNEL32 *
696 *********************************************************************/
697 LPVOID STDCALL
HeapReAlloc(HANDLE hheap
, DWORD flags
, LPVOID ptr
, DWORD size
)
700 PHEAP_BLOCK pfree
=((PHEAP_BLOCK
)ptr
-1);
703 aprintf("HeapReAlloc( 0x%lX, 0x%lX, 0x%lX, 0x%lX )\n",
704 (ULONG
) hheap
, flags
, (ULONG
) ptr
, size
);
706 HeapValidate(hheap
, 0, 0);
708 if(( flags
| pheap
->Flags
) & HEAP_NO_SERIALIZE
)
709 EnterCriticalSection(&(pheap
->Synchronize
));
711 if(HEAP_ISNORMAL(pfree
))
712 retval
=__HeapReAlloc(pheap
, flags
, ptr
, size
);
713 else if(HEAP_ISFRAG(pfree
))
714 retval
=__HeapReAllocFragment(pheap
, flags
, ptr
, size
);
716 retval
=__ErrorReturnNull(ERROR_INVALID_PARAMETER
);
718 if( (flags
| pheap
->Flags
) & HEAP_NO_SERIALIZE
)
719 LeaveCriticalSection(&(pheap
->Synchronize
));
724 /*********************************************************************
725 * HeapFree -- KERNEL32 *
726 *********************************************************************/
727 WINBOOL STDCALL
HeapFree(HANDLE hheap
, DWORD flags
, LPVOID ptr
)
730 PHEAP_BLOCK pfree
=(PHEAP_BLOCK
)((LPVOID
)ptr
-HEAP_ADMIN_SIZE
);
733 aprintf("HeapFree( 0x%lX, 0x%lX, 0x%lX )\n",
734 (ULONG
) hheap
, flags
, (ULONG
) ptr
);
736 HeapValidate(hheap
, 0, 0);
738 if(( flags
| pheap
->Flags
) & HEAP_NO_SERIALIZE
)
739 EnterCriticalSection(&(pheap
->Synchronize
));
741 if(HEAP_ISNORMAL(pfree
))
742 retval
=__HeapFree(pheap
, flags
, ptr
);
743 else if(HEAP_ISFRAG(pfree
))
744 retval
=__HeapFreeFragment(pheap
, flags
, ptr
);
746 retval
=__ErrorReturnFalse(ERROR_INVALID_PARAMETER
);
748 if( (flags
| pheap
->Flags
) & HEAP_NO_SERIALIZE
)
749 LeaveCriticalSection(&(pheap
->Synchronize
));
754 /*********************************************************************
755 * GetProcessHeap -- KERNEL32 *
756 *********************************************************************/
757 HANDLE WINAPI
GetProcessHeap(VOID
)
759 aprintf("GetProcessHeap()\n");
760 return (HANDLE
) __ProcessHeap
;
763 /********************************************************************
764 * GetProcessHeaps -- KERNEL32 *
766 * NOTE in Win95 this function is not implemented and just returns *
767 * ERROR_CALL_NOT_IMPLEMENTED *
768 ********************************************************************/
769 DWORD WINAPI
GetProcessHeaps(DWORD maxheaps
, PHANDLE phandles
)
774 aprintf("GetProcessHeaps( %u, 0x%lX )\n", maxheaps
, (ULONG
) phandles
);
778 while((pheap
)&&(maxheaps
))
784 pheap
=pheap
->NextHeap
;
789 pheap
=pheap
->NextHeap
;
796 /*********************************************************************
797 * HeapLock -- KERNEL32 *
798 *********************************************************************/
800 BOOL WINAPI
HeapLock(HANDLE hheap
)
804 aprintf("HeapLock( 0x%lX )\n", (ULONG
) hheap
);
806 EnterCriticalSection(&(pheap
->Synchronize
));
810 /*********************************************************************
811 * HeapUnlock -- KERNEL32 *
812 *********************************************************************/
814 BOOL WINAPI
HeapUnlock(HANDLE hheap
)
818 aprintf("HeapUnlock( 0x%lX )\n", (ULONG
) hheap
);
820 LeaveCriticalSection(&(pheap
->Synchronize
));
824 /*********************************************************************
825 * HeapCompact -- KERNEL32 *
827 * NT uses this function to compact moveable blocks and other things *
828 * Here it does not compact, but it finds the largest free region *
829 *********************************************************************/
831 UINT
HeapCompact(HANDLE hheap
, DWORD flags
)
838 if(( flags
| pheap
->Flags
) & HEAP_NO_SERIALIZE
)
839 EnterCriticalSection(&(pheap
->Synchronize
));
841 pfree
=&(pheap
->Start
);
842 /* look for the largest free region of memory */
846 freesize
=HEAP_SIZE(pfree
);
847 if(HEAP_ISFREE(pfree
) && freesize
>largestfree
)
848 largestfree
=freesize
;
850 pfree
=HEAP_NEXT(pfree
);
852 while( (LPVOID
)pfree
< pheap
->End
);
854 if( (flags
| pheap
->Flags
) & HEAP_NO_SERIALIZE
)
855 LeaveCriticalSection(&(pheap
->Synchronize
));
860 /*********************************************************************
861 * HeapSize -- KERNEL32 *
862 *********************************************************************/
863 DWORD WINAPI
HeapSize(HANDLE hheap
, DWORD flags
, LPCVOID pmem
)
865 PHEAP pheap
=(PHEAP
) hheap
;
866 PHEAP_BLOCK palloc
=((PHEAP_BLOCK
)pmem
-1);
869 aprintf("HeapSize( 0x%lX, 0x%lX, 0x%lX )\n",
870 (ULONG
) hheap
, flags
, (ULONG
) pmem
);
872 if(pheap
->Magic
!=MAGIC_HEAP
)
873 { SetLastError(ERROR_INVALID_PARAMETER
); return 0; }
875 if(( flags
| pheap
->Flags
) & HEAP_NO_SERIALIZE
)
876 EnterCriticalSection(&(pheap
->Synchronize
));
878 if((pmem
> (LPVOID
)pheap
)&&(pmem
< pheap
->End
))
880 if(HEAP_ISALLOC(palloc
))
881 retval
=HEAP_SIZE(palloc
); /* normal allocation */
882 else if(HEAP_ISFRAG(palloc
))
883 retval
=HEAP_FRAG_SIZE(palloc
); /* fragment */
885 { SetLastError(ERROR_INVALID_PARAMETER
); retval
= -1; }
888 if( (flags
| pheap
->Flags
) & HEAP_NO_SERIALIZE
)
889 LeaveCriticalSection(&(pheap
->Synchronize
));
894 /*********************************************************************
895 * HeapValidate -- KERNEL32 *
897 * NOTE: only implemented in NT *
898 *********************************************************************/
899 BOOL WINAPI
HeapValidate(HANDLE hheap
, DWORD flags
, LPCVOID pmem
)
901 PHEAP pheap
=(PHEAP
)hheap
;
906 PHEAP_FRAGMENT pfrag
;
907 PHEAP_FRAGMENT pnextfrag
;
908 PHEAP_FRAGMENT pprevfrag
;
909 PHEAP_BUCKET pbucket
;
914 if(( flags
| pheap
->Flags
) & HEAP_NO_SERIALIZE
)
915 EnterCriticalSection(&(pheap
->Synchronize
));
919 pcheck
=&(pheap
->Start
);
921 /* verify all blocks */
924 pnext
=HEAP_NEXT(pcheck
);
925 if((pprev
)&&(HEAP_PREV(pcheck
)!=pprev
))
927 dprintf("HeapValidate: linked list invalid, region 0x%lX,"
928 " previous region 0x%lX, list says 0x%lX\n",
929 (ULONG
)pcheck
, (ULONG
)pprev
, (ULONG
) HEAP_PREV(pcheck
));
932 if(HEAP_ISSUB(pcheck
))
935 /* check fragments */
936 psub
=(PHEAP_SUBALLOC
) ((PHEAP_BLOCK
)pcheck
+1);
937 pbucket
=psub
->Bucket
;
938 pfrag
=(PHEAP_FRAGMENT
) ((LPVOID
)psub
+ sizeof(HEAP_SUBALLOC
));
940 if(psub
->NumberFree
>pbucket
->Number
)
943 add
=pbucket
->Size
+HEAP_FRAG_ADMIN_SIZE
;
946 for(i
=0;i
<pbucket
->Number
;i
++)
948 pnextfrag
=(PHEAP_FRAGMENT
)((LPVOID
)pfrag
+add
);
949 if(pfrag
->Magic
!=HEAP_FRAG_MAGIC
)
951 dprintf("HeapValidate: fragment %d magic invalid, region 0x%lX,"
952 " previous region 0x%lX\n", i
, (ULONG
)pcheck
, (ULONG
)pprev
);
957 dprintf("HeapValidate: fragment %d number invalid, region 0x%lX,"
958 " previous region 0x%lX\n", i
, (ULONG
)pcheck
, (ULONG
)pprev
);
961 if((psub
->Bitmap
&(1<<i
))==0)
965 dprintf("HeapValidate: fragment %d suballoc invalid, region 0x%lX,"
966 " previous region 0x%lX\n", i
, (ULONG
)pcheck
, (ULONG
)pprev
);
972 if(number
!=psub
->NumberFree
)
974 dprintf("HeapValidate: invalid number of free fragments, region 0x%lX,"
975 " previous region 0x%lX\n", (ULONG
)pcheck
, (ULONG
)pprev
);
978 dprintf("HeapValidate: [0x%08lX-0x%08lX] suballocated,"
979 " bucket size=%d, bitmap=0x%08lX\n",
980 (ULONG
) pcheck
, (ULONG
) pnext
, pbucket
->Size
, psub
->Bitmap
);
982 else if(HEAP_ISFREE(pcheck
))
984 if(HEAP_RSIZE(pcheck
)!=HEAP_SIZE(pcheck
))
986 dprintf("HeapValidate: invalid size of free region 0x%lX,"
987 " previous region 0x%lX\n",
988 (ULONG
) pcheck
, (ULONG
) pprev
);
991 dprintf("HeapValidate: [0x%08lX-0x%08lX] free\n",
992 (ULONG
) pcheck
, (ULONG
) pnext
);
994 else if(HEAP_ISNORMAL(pcheck
))
996 dprintf("HeapValidate: [0x%08lX-0x%08lX] allocated\n",
997 (ULONG
) pcheck
, (ULONG
) pnext
);
1001 dprintf("HeapValidate: invalid tag %x, region 0x%lX,"
1002 " previous region 0x%lX\n", pcheck
->Size
>>28,
1003 (ULONG
)pcheck
, (ULONG
)pprev
);
1007 pcheck
=HEAP_NEXT(pcheck
);
1009 while( (LPVOID
)pcheck
< pheap
->End
);
1012 if( (flags
| pheap
->Flags
) & HEAP_NO_SERIALIZE
)
1013 LeaveCriticalSection(&(pheap
->Synchronize
));