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/heap.h>
31 static HEAP_BUCKET __HeapDefaultBuckets
[]=
33 { NULL
, 16, 18, 504 },
34 { NULL
, 24, 30, 1016 },
35 { NULL
, 32, 24, 1016 },
36 { NULL
, 48, 17, 1016 },
37 { NULL
, 64, 27, 2040 },
38 { NULL
, 96, 19, 2040 },
39 { NULL
, 128, 29, 4088 },
40 { NULL
, 256, 15, 4088 },
44 static BOOL
__HeapCommit(PHEAP pheap
, LPVOID start
, LPVOID end
);
45 static BOOL
__HeapDecommit(PHEAP pheap
, LPVOID start
, LPVOID end
);
46 static LPVOID
__HeapAlloc(PHEAP pheap
, ULONG flags
, ULONG size
, ULONG tag
);
47 static VOID
__HeapFreeRest(PHEAP pheap
, PHEAP_BLOCK pfree
, ULONG allocsize
,
49 static LPVOID
__HeapReAlloc(PHEAP pheap
, ULONG flags
, LPVOID pold
, ULONG size
);
50 static BOOL
__HeapFree(PHEAP pheap
, ULONG flags
, LPVOID pmem
);
51 static PHEAP_SUBALLOC
__HeapAllocSub(PHEAP pheap
, PHEAP_BUCKET pbucket
);
52 static LPVOID
__HeapAllocFragment(PHEAP pheap
, ULONG flags
, ULONG size
);
53 static LPVOID
__HeapReAllocFragment(PHEAP pheap
, ULONG flags
,
54 LPVOID pold
, ULONG size
);
55 static BOOL
__HeapFreeFragment(PHEAP pheap
, ULONG flags
, LPVOID ptr
);
56 static PHEAP
__HeapPrepare(LPVOID base
, ULONG minsize
, ULONG maxsize
,
61 /*********************************************************************
64 * commits a range of memory in the heap *
65 *********************************************************************/
66 static BOOL
__HeapCommit(PHEAP pheap
, LPVOID start
, LPVOID end
)
68 dprintf("__HeapCommit( 0x%lX, 0x%lX, 0x%lX)\n",
69 (ULONG
) pheap
, (ULONG
) start
, (ULONG
) end
);
73 if(end
>= pheap
->LastBlock
)
75 return __VirtualCommit(start
, end
-start
, PAGE_READWRITE
);
78 /*********************************************************************
81 * decommits a range of memory in the heap *
82 *********************************************************************/
83 static BOOL
__HeapDecommit(PHEAP pheap
, LPVOID start
, LPVOID end
)
85 dprintf("__HeapDecommit( 0x%lX, 0x%lX, 0x%lX)\n",
86 (ULONG
) pheap
, (ULONG
) start
, (ULONG
) end
);
90 if((end
>= pheap
->LastBlock
)&&(start
<= pheap
->LastBlock
))
91 pheap
->LastBlock
=start
;
92 return __VirtualDecommit(start
, end
-start
);
95 /*********************************************************************
98 * allocates a range of memory from the heap *
99 *********************************************************************/
100 static LPVOID
__HeapAlloc(PHEAP pheap
, ULONG flags
, ULONG size
, ULONG tag
)
110 pfree
=&(pheap
->Start
);
111 allocsize
=SIZE_ROUND(size
);
112 freesize
=HEAP_SIZE(pfree
);
113 /* look for a free region of memory: simple First Fit */
114 while( HEAP_ISALLOC(pfree
) || ( freesize
<allocsize
))
116 pfree
=HEAP_NEXT(pfree
);
117 if((LPVOID
) pfree
>=pheap
->End
)
118 return __ErrorReturnNull(ERROR_OUTOFMEMORY
);
119 freesize
=HEAP_SIZE(pfree
);
123 if(freesize
>allocsize
)
125 /* commit necessary memory */
126 commitstart
=(LPVOID
) ROUNDDOWN((ULONG
) palloc
+HEAP_ADMIN_SIZE
,PAGESIZE
);
127 commitend
=(LPVOID
) ROUNDUP ((ULONG
) palloc
+
128 allocsize
+2*HEAP_ADMIN_SIZE
, PAGESIZE
);
129 if(commitstart
<commitend
)
130 if(!__HeapCommit(pheap
, commitstart
, commitend
))
131 return __ErrorReturnNull(ERROR_OUTOFMEMORY
);
133 /* split this block in two */
134 pfree
= (LPVOID
) palloc
+ HEAP_ADMIN_SIZE
+ allocsize
;
137 pfree
->Size
=(freesize
-allocsize
-HEAP_ADMIN_SIZE
) | HEAP_FREE_TAG
;
138 pfree
->PrevSize
=(LPVOID
)pfree
-(LPVOID
)palloc
;
140 pnext
=HEAP_NEXT(pfree
);
141 if((LPVOID
) pnext
< pheap
->End
)
142 pnext
->PrevSize
=freesize
-allocsize
;
146 /* commit necessary memory */
147 commitstart
=(LPVOID
) ROUNDDOWN((ULONG
) palloc
+HEAP_ADMIN_SIZE
, PAGESIZE
);
148 commitend
=(LPVOID
) ROUNDUP((ULONG
) palloc
+HEAP_ADMIN_SIZE
+allocsize
,
150 if(commitstart
<commitend
)
151 if(!__HeapCommit(pheap
, commitstart
, commitend
))
152 return __ErrorReturnNull(ERROR_OUTOFMEMORY
);
154 /* update our administration */
155 palloc
->Size
= size
| tag
;
156 if((flags
| pheap
->Flags
)& HEAP_ZERO_MEMORY
)
157 memset((LPVOID
)palloc
+HEAP_ADMIN_SIZE
, 0, allocsize
);
158 return (LPVOID
)palloc
+HEAP_ADMIN_SIZE
;
161 /*********************************************************************
164 * used by realloc to free a part of the heap *
165 *********************************************************************/
166 static VOID
__HeapFreeRest(PHEAP pheap
, PHEAP_BLOCK pfree
,
167 ULONG allocsize
, ULONG newsize
)
171 if(allocsize
==newsize
)
173 pfree
->PrevSize
=allocsize
+HEAP_ADMIN_SIZE
;
177 pfree
->Size
= (allocsize
-newsize
-HEAP_ADMIN_SIZE
) | HEAP_FREE_TAG
;
178 pfree
->PrevSize
= newsize
+HEAP_ADMIN_SIZE
;
180 pnext
=HEAP_NEXT(pfree
);
181 /* if there is a free region of memory after us, join it */
182 if(((LPVOID
) pnext
< pheap
->End
)&& HEAP_ISFREE(pnext
))
184 pfree
->Size
= (HEAP_SIZE(pfree
)+HEAP_SIZE(pnext
) + HEAP_ADMIN_SIZE
) |
191 pnext
=HEAP_NEXT(pfree
);
192 if((LPVOID
) pnext
< pheap
->End
)
193 pnext
->PrevSize
=(LPVOID
)pnext
-(LPVOID
)pfree
;
196 /*********************************************************************
199 * reallocates a range of memory from the heap *
200 *********************************************************************/
202 static LPVOID
__HeapReAlloc(PHEAP pheap
, ULONG flags
, LPVOID pold
, DWORD size
)
204 PHEAP_BLOCK prealloc
=(PHEAP_BLOCK
)((LPVOID
)pold
-HEAP_ADMIN_SIZE
);
213 /* check that this is a valid allocated block */
214 if(!HEAP_ISALLOC(prealloc
))
215 return __ErrorReturnNull(ERROR_INVALID_PARAMETER
);
217 allocsize
= HEAP_RSIZE(prealloc
);
218 newsize
= SIZE_ROUND(size
);
220 * cases: size=0 free memory
221 * [ size<HEAP_FRAGMENT_THRESHOLD realloc ]
222 * newsize<previous size free rest
223 * newsize=previous size nop
224 * newsize>previous size try to merge
229 dprintf("__HeapReAlloc: freeing memory\n");
230 __HeapFree(pheap
, flags
, pold
);
234 else if(size
< HEAP_FRAGMENT_THRESHOLD
)
236 /* alloc a new fragment */
237 pmem
=__HeapAllocFragment(pheap
, flags
, size
);
239 memcpy(pmem
, pold
, size
);
243 else if(newsize
< allocsize
)
245 dprintf("__HeapReAlloc: shrinking memory\n");
246 /* free remaining region of memory */
247 prealloc
->Size
=size
| HEAP_NORMAL_TAG
;
248 pnext
=HEAP_NEXT(prealloc
);
249 __HeapFreeRest(pheap
, pnext
, allocsize
, newsize
);
251 /* decommit unnecessary memory */
252 commitstart
=(LPVOID
) ROUNDUP((ULONG
) pnext
+HEAP_ADMIN_SIZE
,PAGESIZE
);
253 commitend
=(LPVOID
) ROUNDDOWN((ULONG
) pnext
+HEAP_ADMIN_SIZE
+
254 HEAP_SIZE(pnext
), PAGESIZE
);
255 if(commitstart
<commitend
)
256 __HeapDecommit(pheap
, commitstart
, commitend
);
259 else if(newsize
== allocsize
)
261 dprintf("__HeapReAlloc: no changes\n");
263 prealloc
->Size
= size
| HEAP_NORMAL_TAG
;
266 else if(newsize
> allocsize
)
269 pnext
=HEAP_NEXT(prealloc
);
271 if(((LPVOID
) pnext
< pheap
->End
)&& HEAP_ISFREE(pnext
) &&
272 (HEAP_SIZE(pnext
) + HEAP_ADMIN_SIZE
>=newsize
-allocsize
))
274 dprintf("__HeapReAlloc: joining memory\n");
275 oldsize
=HEAP_SIZE(prealloc
);
276 prealloc
->Size
=size
| HEAP_NORMAL_TAG
;
278 /* commit new memory if necessary */
279 commitstart
=(LPVOID
) ROUNDDOWN((ULONG
) pnext
+HEAP_ADMIN_SIZE
,
281 commitend
=(LPVOID
) ROUNDUP((ULONG
) pnext
+newsize
-allocsize
+
282 HEAP_ADMIN_SIZE
, PAGESIZE
);
283 if(commitstart
<commitend
)
284 if(!__HeapCommit(pheap
, commitstart
, commitend
))
285 return __ErrorReturnNull(ERROR_OUTOFMEMORY
);
287 __HeapFreeRest(pheap
, HEAP_NEXT(prealloc
),
288 allocsize
+HEAP_ADMIN_SIZE
+HEAP_SIZE(pnext
), newsize
);
290 if((flags
|pheap
->Flags
)&HEAP_ZERO_MEMORY
)
291 memset(pold
+oldsize
, 0, size
-oldsize
);
296 if((flags
&HEAP_REALLOC_IN_PLACE_ONLY
)==0)
298 dprintf("__HeapReAlloc: allocating new memory\n");
299 /* alloc a new piece of memory */
300 oldsize
=HEAP_SIZE(prealloc
);
301 pmem
=__HeapAlloc(pheap
, flags
, size
, HEAP_NORMAL_TAG
);
303 memcpy(pmem
, pold
, oldsize
);
304 if((flags
|pheap
->Flags
)&HEAP_ZERO_MEMORY
)
305 memset(pmem
+ oldsize
, 0, size
-oldsize
);
306 __HeapFree(pheap
, flags
, pold
);
310 return __ErrorReturnNull(ERROR_OUTOFMEMORY
);
316 /*********************************************************************
319 * frees a range of memory from the heap *
320 *********************************************************************/
322 static BOOL
__HeapFree(PHEAP pheap
, ULONG flags
, LPVOID ptr
)
324 PHEAP_BLOCK pfree
=(PHEAP_BLOCK
)((LPVOID
)ptr
-HEAP_ADMIN_SIZE
);
327 LPVOID decommitstart
;
330 /* check that this is a valid allocated block */
331 if(!HEAP_ISALLOC(pfree
))
334 pfree
->Size
= HEAP_RSIZE(pfree
) | HEAP_FREE_TAG
;
336 /* if there is a free region of memory before us, join it */
337 pprev
=HEAP_PREV(pfree
);
338 pnext
=HEAP_NEXT(pfree
);
339 if((pprev
!=pfree
) && HEAP_ISFREE(pprev
))
341 pprev
->Size
= (HEAP_SIZE(pprev
)+HEAP_SIZE(pfree
) + HEAP_ADMIN_SIZE
) |
343 if((LPVOID
) pnext
<pheap
->End
)
344 pnext
->PrevSize
=(LPVOID
)pnext
-(LPVOID
)pprev
;
350 /* if there is a free region of memory after us, join it */
351 if(((LPVOID
) pnext
< pheap
->End
)&& HEAP_ISFREE(pnext
))
353 pfree
->Size
= (HEAP_SIZE(pfree
)+HEAP_SIZE(pnext
) + HEAP_ADMIN_SIZE
) |
359 pnext
=HEAP_NEXT(pfree
);
360 if((LPVOID
) pnext
< pheap
->End
)
361 pnext
->PrevSize
=(LPVOID
)pnext
-(LPVOID
)pfree
;
364 /* decommit unnecessary memory */
365 decommitstart
=(LPVOID
) ROUNDUP((ULONG
) pfree
+HEAP_ADMIN_SIZE
,PAGESIZE
);
366 decommitend
=(LPVOID
) ROUNDDOWN((ULONG
) pfree
+HEAP_ADMIN_SIZE
+
367 HEAP_SIZE(pfree
), PAGESIZE
);
368 if(decommitstart
<decommitend
)
369 __HeapDecommit(pheap
, decommitstart
, decommitend
);
374 /*********************************************************************
377 * allocates a range of memory that is used to allocate small *
379 *********************************************************************/
380 PHEAP_SUBALLOC
__HeapAllocSub(PHEAP pheap
, PHEAP_BUCKET pbucket
)
385 PHEAP_FRAGMENT pprev
;
386 PHEAP_FRAGMENT pnext
;
387 PHEAP_FRAGMENT palloc
;
389 psub
=(PHEAP_SUBALLOC
) __HeapAlloc(pheap
, 0, pbucket
->TotalSize
,
392 return __ErrorReturnNull(ERROR_OUTOFMEMORY
);
394 /* initialize suballoc */
395 palloc
=(PHEAP_FRAGMENT
) ((LPVOID
)psub
+ sizeof(HEAP_SUBALLOC
));
396 psub
->FirstFree
=palloc
;
397 psub
->NumberFree
=pbucket
->Number
;
399 psub
->Next
=pbucket
->FirstFree
;
401 psub
->Bucket
=pbucket
;
402 pbucket
->FirstFree
=psub
;
404 /* initialize free fragments */
405 add
=pbucket
->Size
+HEAP_FRAG_ADMIN_SIZE
;
407 for(i
=0;i
<pbucket
->Number
;i
++)
409 pnext
=(PHEAP_FRAGMENT
)((LPVOID
)palloc
+add
);
410 palloc
->Magic
=HEAP_FRAG_MAGIC
;
412 palloc
->Size
=pbucket
->Size
;
414 palloc
->FreeNext
=pnext
;
415 palloc
->FreePrev
=pprev
;
419 pprev
->FreeNext
=NULL
;
423 /*********************************************************************
424 * __HeapAllocFragment *
426 * allocates a small fragment of memory from the heap *
427 *********************************************************************/
428 static LPVOID
__HeapAllocFragment(PHEAP pheap
, ULONG flags
, ULONG size
)
430 PHEAP_BUCKET pbucket
;
432 PHEAP_FRAGMENT palloc
;
435 /* get bucket size */
436 pbucket
=pheap
->Bucket
;
437 while(size
>pbucket
->Size
)
442 psub
= pbucket
->FirstFree
;
444 psub
= __HeapAllocSub(pheap
, pbucket
);
448 /* do our bookkeeping */
449 palloc
= psub
->FirstFree
;
450 psub
->FirstFree
= palloc
->FreeNext
;
451 nalloc
= palloc
->Number
;
453 psub
->Bitmap
|=(1<<nalloc
);
455 /* advance freelist */
456 if(!psub
->NumberFree
)
457 pbucket
->FirstFree
=psub
->Next
;
459 /* initialize allocated block */
460 palloc
->Magic
=HEAP_FRAG_MAGIC
;
463 if((flags
|pheap
->Flags
)&HEAP_ZERO_MEMORY
)
464 memset((LPVOID
)palloc
+HEAP_FRAG_ADMIN_SIZE
, 0, pbucket
->Size
);
465 return (LPVOID
) palloc
+HEAP_FRAG_ADMIN_SIZE
;
468 /*********************************************************************
469 * __HeapReAllocFragment *
471 * reallocates a small fragment of memory *
472 *********************************************************************/
473 static LPVOID
__HeapReAllocFragment(PHEAP pheap
, ULONG flags
,
474 LPVOID pold
, ULONG size
)
476 PHEAP_BUCKET pbucket
;
478 PHEAP_FRAGMENT pfrag
=(PHEAP_FRAGMENT
)
479 ((LPVOID
)pold
-HEAP_FRAG_ADMIN_SIZE
);
483 if(pfrag
->Magic
!=HEAP_FRAG_MAGIC
)
484 return __ErrorReturnNull(ERROR_INVALID_PARAMETER
);
486 /* get bucket size */
488 pbucket
=psub
->Bucket
;
489 if(size
<=pbucket
->Size
)
496 if((flags
&HEAP_REALLOC_IN_PLACE_ONLY
)==0)
498 /* alloc a new piece of memory */
499 if(size
>HEAP_FRAGMENT_THRESHOLD
)
500 pmem
=__HeapAlloc(pheap
, flags
, size
, HEAP_NORMAL_TAG
);
502 pmem
=__HeapAllocFragment(pheap
, flags
, size
);
505 memcpy(pmem
, pold
, size
);
506 if((flags
|pheap
->Flags
)&HEAP_ZERO_MEMORY
)
507 memset(pmem
+pfrag
->Size
, 0, size
-pfrag
->Size
);
509 __HeapFreeFragment(pheap
, flags
, pold
);
516 /*********************************************************************
517 * __HeapFreeFragment *
519 * frees a small fragment of memory *
520 *********************************************************************/
521 static BOOL
__HeapFreeFragment(PHEAP pheap
, ULONG flags
, LPVOID pfree
)
523 PHEAP_BUCKET pbucket
;
525 PHEAP_FRAGMENT pfrag
=(PHEAP_FRAGMENT
)
526 ((LPVOID
)pfree
-HEAP_FRAG_ADMIN_SIZE
);
530 if(pfrag
->Magic
!=HEAP_FRAG_MAGIC
)
531 return __ErrorReturnFalse(ERROR_INVALID_PARAMETER
);
533 /* get bucket size */
535 pbucket
=psub
->Bucket
;
537 nalloc
=pfrag
->Number
;
538 if((psub
->Bitmap
&(1<<nalloc
))==0)
539 return __ErrorReturnFalse(ERROR_INVALID_PARAMETER
);
541 if(psub
->NumberFree
==pbucket
->Number
)
544 if(psub
==pbucket
->FirstFree
)
545 pbucket
->FirstFree
=psub
->Next
;
547 psub
->Prev
->Next
=psub
->Next
;
549 psub
->Next
->Prev
=psub
->Prev
;
550 if(!__HeapFree(pheap
, flags
, psub
))
556 psub
->Bitmap
&= ~(1<<nalloc
);
560 pfrag
->FreeNext
= psub
->FirstFree
;
561 pfrag
->FreePrev
= NULL
;
562 psub
->FirstFree
->FreePrev
= pfrag
;
563 psub
->FirstFree
= pfrag
;
567 psub
->FirstFree
=pfrag
;
568 pfrag
->FreePrev
=NULL
;
569 pfrag
->FreeNext
=NULL
;
575 /*********************************************************************
578 * Fills in all the data structures of a heap *
579 *********************************************************************/
580 PHEAP
__HeapPrepare(LPVOID base
, ULONG minsize
, ULONG maxsize
, ULONG flags
)
582 PHEAP pheap
=(PHEAP
) base
;
584 pheap
->Magic
=MAGIC_HEAP
;
585 pheap
->End
= ((LPVOID
)pheap
)+minsize
;
587 pheap
->LastBlock
=(LPVOID
)pheap
+ PAGESIZE
;
588 memcpy(pheap
->Bucket
,__HeapDefaultBuckets
,sizeof(__HeapDefaultBuckets
));
591 pheap
->NextHeap
=__ProcessHeap
->NextHeap
;
592 __ProcessHeap
->NextHeap
=pheap
;
599 InitializeCriticalSection(&(pheap
->Synchronize
));
600 pheap
->Start
.Size
= (minsize
-sizeof(HEAP
))|HEAP_FREE_TAG
;
601 pheap
->Start
.PrevSize
=0;
606 /*********************************************************************
609 * Called by __VirtualInit to initialize the default process heap *
610 *********************************************************************/
612 VOID WINAPI
__HeapInit(LPVOID base
, ULONG minsize
, ULONG maxsize
)
614 mmap(base
, PAGESIZE
, PROT_READ
| PROT_WRITE
, MAP_ANON
| MAP_PRIVATE
,
617 __HeapPrepare(base
, minsize
, maxsize
, 0);
621 /*********************************************************************
622 * HeapCreate -- KERNEL32 *
623 *********************************************************************/
625 HANDLE WINAPI
HeapCreate(ULONG flags
, ULONG minsize
, ULONG maxsize
)
629 aprintf("HeapCreate( 0x%lX, 0x%lX, 0x%lX )\n", flags
, minsize
, maxsize
);
631 pheap
= __VirtualReserve(NULL
, minsize
, PAGE_READWRITE
| MEM_TOP_DOWN
);
632 __VirtualCommit(pheap
, PAGESIZE
, PAGE_READWRITE
);
634 return (HANDLE
) __HeapPrepare(pheap
, minsize
, maxsize
, flags
);
637 /*********************************************************************
638 * HeapDestroy -- KERNEL32 *
639 *********************************************************************/
640 BOOL WINAPI
HeapDestroy(HANDLE hheap
)
642 PHEAP pheap
=(PHEAP
) hheap
;
644 aprintf("HeapDestroy( 0x%lX )\n", (ULONG
) hheap
);
646 if(pheap
->Magic
!=MAGIC_HEAP
)
647 return __ErrorReturnFalse(ERROR_INVALID_PARAMETER
);
649 DeleteCriticalSection(&(pheap
->Synchronize
));
650 __VirtualRelease(pheap
);
655 /*********************************************************************
656 * HeapAlloc -- KERNEL32 *
657 *********************************************************************/
658 LPVOID WINAPI
HeapAlloc(HANDLE hheap
, ULONG flags
, ULONG size
)
663 aprintf("HeapAlloc( 0x%lX, 0x%lX, 0x%lX )\n",
664 (ULONG
) hheap
, flags
, (ULONG
) size
);
666 HeapValidate(hheap
, 0, 0);
668 if(( flags
| pheap
->Flags
) & HEAP_NO_SERIALIZE
)
669 EnterCriticalSection(&(pheap
->Synchronize
));
671 if(size
>HEAP_FRAGMENT_THRESHOLD
)
672 retval
=__HeapAlloc(pheap
, flags
, size
, HEAP_NORMAL_TAG
);
674 retval
=__HeapAllocFragment(pheap
, flags
, size
);
676 if( (flags
| pheap
->Flags
) & HEAP_NO_SERIALIZE
)
677 LeaveCriticalSection(&(pheap
->Synchronize
));
679 aprintf("HeapAlloc returns 0x%lX\n", (ULONG
) retval
);
684 /*********************************************************************
685 * HeapReAlloc -- KERNEL32 *
686 *********************************************************************/
687 LPVOID WINAPI
HeapReAlloc(HANDLE hheap
, ULONG flags
, LPVOID ptr
, ULONG size
)
690 PHEAP_BLOCK pfree
=((PHEAP_BLOCK
)ptr
-1);
693 aprintf("HeapReAlloc( 0x%lX, 0x%lX, 0x%lX, 0x%lX )\n",
694 (ULONG
) hheap
, flags
, (ULONG
) ptr
, size
);
696 HeapValidate(hheap
, 0, 0);
698 if(( flags
| pheap
->Flags
) & HEAP_NO_SERIALIZE
)
699 EnterCriticalSection(&(pheap
->Synchronize
));
701 if(HEAP_ISNORMAL(pfree
))
702 retval
=__HeapReAlloc(pheap
, flags
, ptr
, size
);
703 else if(HEAP_ISFRAG(pfree
))
704 retval
=__HeapReAllocFragment(pheap
, flags
, ptr
, size
);
706 retval
=__ErrorReturnNull(ERROR_INVALID_PARAMETER
);
708 if( (flags
| pheap
->Flags
) & HEAP_NO_SERIALIZE
)
709 LeaveCriticalSection(&(pheap
->Synchronize
));
714 /*********************************************************************
715 * HeapFree -- KERNEL32 *
716 *********************************************************************/
717 BOOL WINAPI
HeapFree(HANDLE hheap
, ULONG flags
, LPVOID ptr
)
720 PHEAP_BLOCK pfree
=(PHEAP_BLOCK
)((LPVOID
)ptr
-HEAP_ADMIN_SIZE
);
723 aprintf("HeapFree( 0x%lX, 0x%lX, 0x%lX )\n",
724 (ULONG
) hheap
, flags
, (ULONG
) ptr
);
726 HeapValidate(hheap
, 0, 0);
728 if(( flags
| pheap
->Flags
) & HEAP_NO_SERIALIZE
)
729 EnterCriticalSection(&(pheap
->Synchronize
));
731 if(HEAP_ISNORMAL(pfree
))
732 retval
=__HeapFree(pheap
, flags
, ptr
);
733 else if(HEAP_ISFRAG(pfree
))
734 retval
=__HeapFreeFragment(pheap
, flags
, ptr
);
736 retval
=__ErrorReturnFalse(ERROR_INVALID_PARAMETER
);
738 if( (flags
| pheap
->Flags
) & HEAP_NO_SERIALIZE
)
739 LeaveCriticalSection(&(pheap
->Synchronize
));
744 /*********************************************************************
745 * GetProcessHeap -- KERNEL32 *
746 *********************************************************************/
747 HANDLE WINAPI
GetProcessHeap(VOID
)
749 aprintf("GetProcessHeap()\n");
750 return (HANDLE
) __ProcessHeap
;
753 /********************************************************************
754 * GetProcessHeaps -- KERNEL32 *
756 * NOTE in Win95 this function is not implemented and just returns *
757 * ERROR_CALL_NOT_IMPLEMENTED *
758 ********************************************************************/
759 DWORD WINAPI
GetProcessHeaps(DWORD maxheaps
, PHANDLE phandles
)
764 aprintf("GetProcessHeaps( %u, 0x%lX )\n", maxheaps
, (ULONG
) phandles
);
768 while((pheap
)&&(maxheaps
))
774 pheap
=pheap
->NextHeap
;
779 pheap
=pheap
->NextHeap
;
786 /*********************************************************************
787 * HeapLock -- KERNEL32 *
788 *********************************************************************/
790 BOOL WINAPI
HeapLock(HANDLE hheap
)
794 aprintf("HeapLock( 0x%lX )\n", (ULONG
) hheap
);
796 EnterCriticalSection(&(pheap
->Synchronize
));
800 /*********************************************************************
801 * HeapUnlock -- KERNEL32 *
802 *********************************************************************/
804 BOOL WINAPI
HeapUnlock(HANDLE hheap
)
808 aprintf("HeapUnlock( 0x%lX )\n", (ULONG
) hheap
);
810 LeaveCriticalSection(&(pheap
->Synchronize
));
814 /*********************************************************************
815 * HeapCompact -- KERNEL32 *
817 * NT uses this function to compact moveable blocks and other things *
818 * Here it does not compact, but it finds the largest free region *
819 *********************************************************************/
821 UINT
HeapCompact(HANDLE hheap
, DWORD flags
)
828 if(( flags
| pheap
->Flags
) & HEAP_NO_SERIALIZE
)
829 EnterCriticalSection(&(pheap
->Synchronize
));
831 pfree
=&(pheap
->Start
);
832 /* look for the largest free region of memory */
836 freesize
=HEAP_SIZE(pfree
);
837 if(HEAP_ISFREE(pfree
) && freesize
>largestfree
)
838 largestfree
=freesize
;
840 pfree
=HEAP_NEXT(pfree
);
842 while( (LPVOID
)pfree
< pheap
->End
);
844 if( (flags
| pheap
->Flags
) & HEAP_NO_SERIALIZE
)
845 LeaveCriticalSection(&(pheap
->Synchronize
));
850 /*********************************************************************
851 * HeapSize -- KERNEL32 *
852 *********************************************************************/
853 DWORD WINAPI
HeapSize(HANDLE hheap
, DWORD flags
, LPCVOID pmem
)
855 PHEAP pheap
=(PHEAP
) hheap
;
856 PHEAP_BLOCK palloc
=((PHEAP_BLOCK
)pmem
-1);
859 aprintf("HeapSize( 0x%lX, 0x%lX, 0x%lX )\n",
860 (ULONG
) hheap
, flags
, (ULONG
) pmem
);
862 if(pheap
->Magic
!=MAGIC_HEAP
)
863 { SetLastError(ERROR_INVALID_PARAMETER
); return 0; }
865 if(( flags
| pheap
->Flags
) & HEAP_NO_SERIALIZE
)
866 EnterCriticalSection(&(pheap
->Synchronize
));
868 if((pmem
> (LPVOID
)pheap
)&&(pmem
< pheap
->End
))
870 if(HEAP_ISALLOC(palloc
))
871 retval
=HEAP_SIZE(palloc
); /* normal allocation */
872 else if(HEAP_ISFRAG(palloc
))
873 retval
=HEAP_FRAG_SIZE(palloc
); /* fragment */
875 { SetLastError(ERROR_INVALID_PARAMETER
); retval
= -1; }
878 if( (flags
| pheap
->Flags
) & HEAP_NO_SERIALIZE
)
879 LeaveCriticalSection(&(pheap
->Synchronize
));
884 /*********************************************************************
885 * HeapValidate -- KERNEL32 *
887 * NOTE: only implemented in NT *
888 *********************************************************************/
889 BOOL WINAPI
HeapValidate(HANDLE hheap
, DWORD flags
, LPCVOID pmem
)
891 PHEAP pheap
=(PHEAP
)hheap
;
896 PHEAP_FRAGMENT pfrag
;
897 PHEAP_FRAGMENT pnextfrag
;
898 PHEAP_FRAGMENT pprevfrag
;
899 PHEAP_BUCKET pbucket
;
904 if(( flags
| pheap
->Flags
) & HEAP_NO_SERIALIZE
)
905 EnterCriticalSection(&(pheap
->Synchronize
));
909 pcheck
=&(pheap
->Start
);
911 /* verify all blocks */
914 pnext
=HEAP_NEXT(pcheck
);
915 if((pprev
)&&(HEAP_PREV(pcheck
)!=pprev
))
917 dprintf("HeapValidate: linked list invalid, region 0x%lX,"
918 " previous region 0x%lX, list says 0x%lX\n",
919 (ULONG
)pcheck
, (ULONG
)pprev
, (ULONG
) HEAP_PREV(pcheck
));
922 if(HEAP_ISSUB(pcheck
))
925 /* check fragments */
926 psub
=(PHEAP_SUBALLOC
) ((PHEAP_BLOCK
)pcheck
+1);
927 pbucket
=psub
->Bucket
;
928 pfrag
=(PHEAP_FRAGMENT
) ((LPVOID
)psub
+ sizeof(HEAP_SUBALLOC
));
930 if(psub
->NumberFree
>pbucket
->Number
)
933 add
=pbucket
->Size
+HEAP_FRAG_ADMIN_SIZE
;
936 for(i
=0;i
<pbucket
->Number
;i
++)
938 pnextfrag
=(PHEAP_FRAGMENT
)((LPVOID
)pfrag
+add
);
939 if(pfrag
->Magic
!=HEAP_FRAG_MAGIC
)
941 dprintf("HeapValidate: fragment %d magic invalid, region 0x%lX,"
942 " previous region 0x%lX\n", i
, (ULONG
)pcheck
, (ULONG
)pprev
);
947 dprintf("HeapValidate: fragment %d number invalid, region 0x%lX,"
948 " previous region 0x%lX\n", i
, (ULONG
)pcheck
, (ULONG
)pprev
);
951 if((psub
->Bitmap
&(1<<i
))==0)
955 dprintf("HeapValidate: fragment %d suballoc invalid, region 0x%lX,"
956 " previous region 0x%lX\n", i
, (ULONG
)pcheck
, (ULONG
)pprev
);
962 if(number
!=psub
->NumberFree
)
964 dprintf("HeapValidate: invalid number of free fragments, region 0x%lX,"
965 " previous region 0x%lX\n", (ULONG
)pcheck
, (ULONG
)pprev
);
968 dprintf("HeapValidate: [0x%08lX-0x%08lX] suballocated,"
969 " bucket size=%d, bitmap=0x%08lX\n",
970 (ULONG
) pcheck
, (ULONG
) pnext
, pbucket
->Size
, psub
->Bitmap
);
972 else if(HEAP_ISFREE(pcheck
))
974 if(HEAP_RSIZE(pcheck
)!=HEAP_SIZE(pcheck
))
976 dprintf("HeapValidate: invalid size of free region 0x%lX,"
977 " previous region 0x%lX\n",
978 (ULONG
) pcheck
, (ULONG
) pprev
);
981 dprintf("HeapValidate: [0x%08lX-0x%08lX] free\n",
982 (ULONG
) pcheck
, (ULONG
) pnext
);
984 else if(HEAP_ISNORMAL(pcheck
))
986 dprintf("HeapValidate: [0x%08lX-0x%08lX] allocated\n",
987 (ULONG
) pcheck
, (ULONG
) pnext
);
991 dprintf("HeapValidate: invalid tag %x, region 0x%lX,"
992 " previous region 0x%lX\n", pcheck
->Size
>>28,
993 (ULONG
)pcheck
, (ULONG
)pprev
);
997 pcheck
=HEAP_NEXT(pcheck
);
999 while( (LPVOID
)pcheck
< pheap
->End
);
1002 if( (flags
| pheap
->Flags
) & HEAP_NO_SERIALIZE
)
1003 LeaveCriticalSection(&(pheap
->Synchronize
));