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
30 #include <kernel32/kernel32.h>
32 #include <kernel32/proc.h>
33 #include <kernel32/heap.h>
34 #include <internal/string.h>
36 #include <ddk/ntddk.h>
39 static HEAP_BUCKET __HeapDefaultBuckets
[]=
41 { NULL
, 16, 18, 504 },
42 { NULL
, 24, 30, 1016 },
43 { NULL
, 32, 24, 1016 },
44 { NULL
, 48, 17, 1016 },
45 { NULL
, 64, 27, 2040 },
46 { NULL
, 96, 19, 2040 },
47 { NULL
, 128, 29, 4088 },
48 { NULL
, 256, 15, 4088 },
53 static BOOL
__HeapCommit(PHEAP pheap
, LPVOID start
, LPVOID end
);
54 static BOOL
__HeapDecommit(PHEAP pheap
, LPVOID start
, LPVOID end
);
55 static LPVOID
__HeapAlloc(PHEAP pheap
, ULONG flags
, ULONG size
, ULONG tag
);
56 static VOID
__HeapFreeRest(PHEAP pheap
, PHEAP_BLOCK pfree
, ULONG allocsize
,
58 static LPVOID
__HeapReAlloc(PHEAP pheap
, ULONG flags
, LPVOID pold
, DWORD size
);
59 static BOOL
__HeapFree(PHEAP pheap
, ULONG flags
, LPVOID pmem
);
60 static PHEAP_SUBALLOC
__HeapAllocSub(PHEAP pheap
, PHEAP_BUCKET pbucket
);
61 static LPVOID
__HeapAllocFragment(PHEAP pheap
, ULONG flags
, ULONG size
);
62 static LPVOID
__HeapReAllocFragment(PHEAP pheap
, ULONG flags
,
63 LPVOID pold
, ULONG size
);
64 static BOOL
__HeapFreeFragment(PHEAP pheap
, ULONG flags
, LPVOID ptr
);
65 static PHEAP
__HeapPrepare(LPVOID base
, ULONG minsize
, ULONG maxsize
,
70 /*********************************************************************
73 * commits a range of memory in the heap *
74 *********************************************************************/
75 static BOOL
__HeapCommit(PHEAP pheap
, LPVOID start
, LPVOID end
)
77 DPRINT("__HeapCommit( 0x%lX, 0x%lX, 0x%lX)\n",
78 (ULONG
) pheap
, (ULONG
) start
, (ULONG
) end
);
80 if(end
>= pheap
->LastBlock
)
82 if (VirtualAlloc(start
,end
-start
,MEM_COMMIT
,PAGE_READWRITE
)!=start
)
89 /*********************************************************************
92 * decommits a range of memory in the heap *
93 *********************************************************************/
94 static BOOL
__HeapDecommit(PHEAP pheap
, LPVOID start
, LPVOID end
)
96 DPRINT("__HeapDecommit( 0x%lX, 0x%lX, 0x%lX)\n",
97 (ULONG
) pheap
, (ULONG
) start
, (ULONG
) end
);
101 if((end
>= pheap
->LastBlock
)&&(start
<= pheap
->LastBlock
))
102 pheap
->LastBlock
=start
;
104 return(VirtualFree(start
,end
-start
,MEM_RESERVE
));
107 /*********************************************************************
110 * allocates a range of memory from the heap *
111 *********************************************************************/
112 static LPVOID
__HeapAlloc(PHEAP pheap
, ULONG flags
, ULONG size
, ULONG tag
)
122 DPRINT("__HeapAlloc(pheap %x, flags %x, size %d, tag %x)\n",
123 pheap
,flags
,size
,tag
);
125 pfree
=&(pheap
->Start
);
126 allocsize
=SIZE_ROUND(size
);
127 freesize
=HEAP_SIZE(pfree
);
128 /* look for a free region of memory: simple First Fit */
129 while( HEAP_ISALLOC(pfree
) || ( freesize
<allocsize
))
131 pfree
=HEAP_NEXT(pfree
);
132 if((LPVOID
) pfree
>=pheap
->End
)
133 return __ErrorReturnNull(ERROR_OUTOFMEMORY
);
134 freesize
=HEAP_SIZE(pfree
);
138 if(freesize
>allocsize
)
140 /* commit necessary memory */
141 commitstart
=(LPVOID
) ROUNDDOWN((ULONG
) palloc
+HEAP_ADMIN_SIZE
,PAGESIZE
);
142 commitend
=(LPVOID
) ROUNDUP ((ULONG
) palloc
+
143 allocsize
+2*HEAP_ADMIN_SIZE
, PAGESIZE
);
144 if(commitstart
<commitend
)
145 if(!__HeapCommit(pheap
, commitstart
, commitend
))
146 return __ErrorReturnNull(ERROR_OUTOFMEMORY
);
148 /* split this block in two */
149 pfree
= (LPVOID
) palloc
+ HEAP_ADMIN_SIZE
+ allocsize
;
152 pfree
->Size
=(freesize
-allocsize
-HEAP_ADMIN_SIZE
) | HEAP_FREE_TAG
;
153 pfree
->PrevSize
=(LPVOID
)pfree
-(LPVOID
)palloc
;
155 pnext
=HEAP_NEXT(pfree
);
156 if((LPVOID
) pnext
< pheap
->End
)
157 pnext
->PrevSize
=freesize
-allocsize
;
161 /* commit necessary memory */
162 commitstart
=(LPVOID
) ROUNDDOWN((ULONG
) palloc
+HEAP_ADMIN_SIZE
, PAGESIZE
);
163 commitend
=(LPVOID
) ROUNDUP((ULONG
) palloc
+HEAP_ADMIN_SIZE
+allocsize
,
165 if(commitstart
<commitend
)
166 if(!__HeapCommit(pheap
, commitstart
, commitend
))
167 return __ErrorReturnNull(ERROR_OUTOFMEMORY
);
169 /* update our administration */
170 palloc
->Size
= size
| tag
;
171 if((flags
| pheap
->Flags
)& HEAP_ZERO_MEMORY
)
172 FillMemory((LPVOID
)palloc
+HEAP_ADMIN_SIZE
, allocsize
, 0);
173 return (LPVOID
)palloc
+HEAP_ADMIN_SIZE
;
176 /*********************************************************************
179 * used by realloc to free a part of the heap *
180 *********************************************************************/
181 static VOID
__HeapFreeRest(PHEAP pheap
, PHEAP_BLOCK pfree
,
182 ULONG allocsize
, ULONG newsize
)
186 if(allocsize
==newsize
)
188 pfree
->PrevSize
=allocsize
+HEAP_ADMIN_SIZE
;
192 pfree
->Size
= (allocsize
-newsize
-HEAP_ADMIN_SIZE
) | HEAP_FREE_TAG
;
193 pfree
->PrevSize
= newsize
+HEAP_ADMIN_SIZE
;
195 pnext
=HEAP_NEXT(pfree
);
196 /* if there is a free region of memory after us, join it */
197 if(((LPVOID
) pnext
< pheap
->End
)&& HEAP_ISFREE(pnext
))
199 pfree
->Size
= (HEAP_SIZE(pfree
)+HEAP_SIZE(pnext
) + HEAP_ADMIN_SIZE
) |
206 pnext
=HEAP_NEXT(pfree
);
207 if((LPVOID
) pnext
< pheap
->End
)
208 pnext
->PrevSize
=(LPVOID
)pnext
-(LPVOID
)pfree
;
211 /*********************************************************************
214 * reallocates a range of memory from the heap *
215 *********************************************************************/
217 static LPVOID
__HeapReAlloc(PHEAP pheap
, ULONG flags
, LPVOID pold
, DWORD size
)
219 PHEAP_BLOCK prealloc
=(PHEAP_BLOCK
)((LPVOID
)pold
-HEAP_ADMIN_SIZE
);
228 /* check that this is a valid allocated block */
229 if(!HEAP_ISALLOC(prealloc
))
230 return __ErrorReturnNull(ERROR_INVALID_PARAMETER
);
232 allocsize
= HEAP_RSIZE(prealloc
);
233 newsize
= SIZE_ROUND(size
);
235 * cases: size=0 free memory
236 * [ size<HEAP_FRAGMENT_THRESHOLD realloc ]
237 * newsize<previous size free rest
238 * newsize=previous size nop
239 * newsize>previous size try to merge
244 DPRINT("__HeapReAlloc: freeing memory\n");
245 __HeapFree(pheap
, flags
, pold
);
249 else if(size
< HEAP_FRAGMENT_THRESHOLD
)
251 /* alloc a new fragment */
252 pmem
=__HeapAllocFragment(pheap
, flags
, size
);
254 CopyMemory(pmem
, pold
, size
);
258 else if(newsize
< allocsize
)
260 DPRINT("__HeapReAlloc: shrinking memory\n");
261 /* free remaining region of memory */
262 prealloc
->Size
=size
| HEAP_NORMAL_TAG
;
263 pnext
=HEAP_NEXT(prealloc
);
264 __HeapFreeRest(pheap
, pnext
, allocsize
, newsize
);
266 /* decommit unnecessary memory */
267 commitstart
=(LPVOID
) ROUNDUP((ULONG
) pnext
+HEAP_ADMIN_SIZE
,PAGESIZE
);
268 commitend
=(LPVOID
) ROUNDDOWN((ULONG
) pnext
+HEAP_ADMIN_SIZE
+
269 HEAP_SIZE(pnext
), PAGESIZE
);
270 if(commitstart
<commitend
)
271 __HeapDecommit(pheap
, commitstart
, commitend
);
274 else if(newsize
== allocsize
)
276 DPRINT("__HeapReAlloc: no changes\n");
278 prealloc
->Size
= size
| HEAP_NORMAL_TAG
;
281 else if(newsize
> allocsize
)
284 pnext
=HEAP_NEXT(prealloc
);
286 if(((LPVOID
) pnext
< pheap
->End
)&& HEAP_ISFREE(pnext
) &&
287 (HEAP_SIZE(pnext
) + HEAP_ADMIN_SIZE
>=newsize
-allocsize
))
289 DPRINT("__HeapReAlloc: joining memory\n");
290 oldsize
=HEAP_SIZE(prealloc
);
291 prealloc
->Size
=size
| HEAP_NORMAL_TAG
;
293 /* commit new memory if necessary */
294 commitstart
=(LPVOID
) ROUNDDOWN((ULONG
) pnext
+HEAP_ADMIN_SIZE
,
296 commitend
=(LPVOID
) ROUNDUP((ULONG
) pnext
+newsize
-allocsize
+
297 HEAP_ADMIN_SIZE
, PAGESIZE
);
298 if(commitstart
<commitend
)
299 if(!__HeapCommit(pheap
, commitstart
, commitend
))
300 return __ErrorReturnNull(ERROR_OUTOFMEMORY
);
302 __HeapFreeRest(pheap
, HEAP_NEXT(prealloc
),
303 allocsize
+HEAP_ADMIN_SIZE
+HEAP_SIZE(pnext
), newsize
);
305 if((flags
|pheap
->Flags
)&HEAP_ZERO_MEMORY
)
306 memset(pold
+oldsize
, 0, size
-oldsize
);
311 if((flags
&HEAP_REALLOC_IN_PLACE_ONLY
)==0)
313 DPRINT("__HeapReAlloc: allocating new memory\n");
314 /* alloc a new piece of memory */
315 oldsize
=HEAP_SIZE(prealloc
);
316 pmem
=__HeapAlloc(pheap
, flags
, size
, HEAP_NORMAL_TAG
);
318 CopyMemory(pmem
, pold
, oldsize
);
319 if((flags
|pheap
->Flags
)&HEAP_ZERO_MEMORY
)
320 memset(pmem
+ oldsize
, 0, size
-oldsize
);
321 __HeapFree(pheap
, flags
, pold
);
325 return __ErrorReturnNull(ERROR_OUTOFMEMORY
);
331 /*********************************************************************
334 * frees a range of memory from the heap *
335 *********************************************************************/
337 static BOOL
__HeapFree(PHEAP pheap
, ULONG flags
, LPVOID ptr
)
339 PHEAP_BLOCK pfree
=(PHEAP_BLOCK
)((LPVOID
)ptr
-HEAP_ADMIN_SIZE
);
342 LPVOID decommitstart
;
345 /* check that this is a valid allocated block */
346 if(!HEAP_ISALLOC(pfree
))
349 pfree
->Size
= HEAP_RSIZE(pfree
) | HEAP_FREE_TAG
;
351 /* if there is a free region of memory before us, join it */
352 pprev
=HEAP_PREV(pfree
);
353 pnext
=HEAP_NEXT(pfree
);
354 if((pprev
!=pfree
) && HEAP_ISFREE(pprev
))
356 pprev
->Size
= (HEAP_SIZE(pprev
)+HEAP_SIZE(pfree
) + HEAP_ADMIN_SIZE
) |
358 if((LPVOID
) pnext
<pheap
->End
)
359 pnext
->PrevSize
=(LPVOID
)pnext
-(LPVOID
)pprev
;
365 /* if there is a free region of memory after us, join it */
366 if(((LPVOID
) pnext
< pheap
->End
)&& HEAP_ISFREE(pnext
))
368 pfree
->Size
= (HEAP_SIZE(pfree
)+HEAP_SIZE(pnext
) + HEAP_ADMIN_SIZE
) |
374 pnext
=HEAP_NEXT(pfree
);
375 if((LPVOID
) pnext
< pheap
->End
)
376 pnext
->PrevSize
=(LPVOID
)pnext
-(LPVOID
)pfree
;
379 /* decommit unnecessary memory */
380 decommitstart
=(LPVOID
) ROUNDUP((ULONG
) pfree
+HEAP_ADMIN_SIZE
,PAGESIZE
);
381 decommitend
=(LPVOID
) ROUNDDOWN((ULONG
) pfree
+HEAP_ADMIN_SIZE
+
382 HEAP_SIZE(pfree
), PAGESIZE
);
383 if(decommitstart
<decommitend
)
384 __HeapDecommit(pheap
, decommitstart
, decommitend
);
389 /*********************************************************************
392 * allocates a range of memory that is used to allocate small *
394 *********************************************************************/
395 PHEAP_SUBALLOC
__HeapAllocSub(PHEAP pheap
, PHEAP_BUCKET pbucket
)
400 PHEAP_FRAGMENT pprev
;
401 PHEAP_FRAGMENT pnext
;
402 PHEAP_FRAGMENT palloc
;
404 psub
=(PHEAP_SUBALLOC
) __HeapAlloc(pheap
, 0, pbucket
->TotalSize
,
407 return __ErrorReturnNull(ERROR_OUTOFMEMORY
);
409 /* initialize suballoc */
410 palloc
=(PHEAP_FRAGMENT
) ((LPVOID
)psub
+ sizeof(HEAP_SUBALLOC
));
411 psub
->FirstFree
=palloc
;
412 psub
->NumberFree
=pbucket
->Number
;
414 psub
->Next
=pbucket
->FirstFree
;
416 psub
->Bucket
=pbucket
;
417 pbucket
->FirstFree
=psub
;
419 /* initialize free fragments */
420 add
=pbucket
->Size
+HEAP_FRAG_ADMIN_SIZE
;
422 for(i
=0;i
<pbucket
->Number
;i
++)
424 pnext
=(PHEAP_FRAGMENT
)((LPVOID
)palloc
+add
);
425 palloc
->Magic
=HEAP_FRAG_MAGIC
;
427 palloc
->Size
=pbucket
->Size
;
429 palloc
->FreeNext
=pnext
;
430 palloc
->FreePrev
=pprev
;
434 pprev
->FreeNext
=NULL
;
438 /*********************************************************************
439 * __HeapAllocFragment *
441 * allocates a small fragment of memory from the heap *
442 *********************************************************************/
443 static LPVOID
__HeapAllocFragment(PHEAP pheap
, ULONG flags
, ULONG size
)
445 PHEAP_BUCKET pbucket
;
447 PHEAP_FRAGMENT palloc
;
450 /* get bucket size */
451 pbucket
=pheap
->Bucket
;
452 while(size
>pbucket
->Size
)
457 psub
= pbucket
->FirstFree
;
459 psub
= __HeapAllocSub(pheap
, pbucket
);
463 /* do our bookkeeping */
464 palloc
= psub
->FirstFree
;
465 psub
->FirstFree
= palloc
->FreeNext
;
466 nalloc
= palloc
->Number
;
468 psub
->Bitmap
|=(1<<nalloc
);
470 /* advance freelist */
471 if(!psub
->NumberFree
)
472 pbucket
->FirstFree
=psub
->Next
;
474 /* initialize allocated block */
475 palloc
->Magic
=HEAP_FRAG_MAGIC
;
478 if((flags
|pheap
->Flags
)&HEAP_ZERO_MEMORY
)
479 memset((LPVOID
)palloc
+HEAP_FRAG_ADMIN_SIZE
, 0, pbucket
->Size
);
480 return (LPVOID
) palloc
+HEAP_FRAG_ADMIN_SIZE
;
483 /*********************************************************************
484 * __HeapReAllocFragment *
486 * reallocates a small fragment of memory *
487 *********************************************************************/
488 static LPVOID
__HeapReAllocFragment(PHEAP pheap
, ULONG flags
,
489 LPVOID pold
, ULONG size
)
491 PHEAP_BUCKET pbucket
;
493 PHEAP_FRAGMENT pfrag
=(PHEAP_FRAGMENT
)
494 ((LPVOID
)pold
-HEAP_FRAG_ADMIN_SIZE
);
498 if(pfrag
->Magic
!=HEAP_FRAG_MAGIC
)
499 return __ErrorReturnNull(ERROR_INVALID_PARAMETER
);
501 /* get bucket size */
503 pbucket
=psub
->Bucket
;
504 if(size
<=pbucket
->Size
)
511 if((flags
&HEAP_REALLOC_IN_PLACE_ONLY
)==0)
513 /* alloc a new piece of memory */
514 if(size
>HEAP_FRAGMENT_THRESHOLD
)
515 pmem
=__HeapAlloc(pheap
, flags
, size
, HEAP_NORMAL_TAG
);
517 pmem
=__HeapAllocFragment(pheap
, flags
, size
);
520 CopyMemory(pmem
, pold
, size
);
521 if((flags
|pheap
->Flags
)&HEAP_ZERO_MEMORY
)
522 memset(pmem
+pfrag
->Size
, 0, size
-pfrag
->Size
);
524 __HeapFreeFragment(pheap
, flags
, pold
);
531 /*********************************************************************
532 * __HeapFreeFragment *
534 * frees a small fragment of memory *
535 *********************************************************************/
536 static BOOL
__HeapFreeFragment(PHEAP pheap
, ULONG flags
, LPVOID pfree
)
538 PHEAP_BUCKET pbucket
;
540 PHEAP_FRAGMENT pfrag
=(PHEAP_FRAGMENT
)
541 ((DWORD
)pfree
- HEAP_FRAG_ADMIN_SIZE
);
545 if(pfrag
->Magic
!=HEAP_FRAG_MAGIC
)
546 return __ErrorReturnFalse(ERROR_INVALID_PARAMETER
);
548 /* get bucket size */
550 pbucket
=psub
->Bucket
;
552 nalloc
=pfrag
->Number
;
553 if((psub
->Bitmap
&(1<<nalloc
))==0)
554 return __ErrorReturnFalse(ERROR_INVALID_PARAMETER
);
556 if(psub
->NumberFree
==pbucket
->Number
)
559 if(psub
==pbucket
->FirstFree
)
560 pbucket
->FirstFree
=psub
->Next
;
562 psub
->Prev
->Next
=psub
->Next
;
564 psub
->Next
->Prev
=psub
->Prev
;
565 if(!__HeapFree(pheap
, flags
, psub
))
571 psub
->Bitmap
&= ~(1<<nalloc
);
575 pfrag
->FreeNext
= psub
->FirstFree
;
576 pfrag
->FreePrev
= NULL
;
577 psub
->FirstFree
->FreePrev
= pfrag
;
578 psub
->FirstFree
= pfrag
;
582 psub
->FirstFree
=pfrag
;
583 pfrag
->FreePrev
=NULL
;
584 pfrag
->FreeNext
=NULL
;
591 /*********************************************************************
594 * Fills in all the data structures of a heap *
595 *********************************************************************/
596 PHEAP
__HeapPrepare(LPVOID base
, ULONG minsize
, ULONG maxsize
, ULONG flags
)
598 PHEAP pheap
=(PHEAP
) base
;
600 DPRINT("__HeapPrepare(base %x, minsize %d, maxsize %d, flags %x)\n",
601 base
,minsize
,maxsize
,flags
);
603 pheap
->Magic
=MAGIC_HEAP
;
604 pheap
->End
= ((LPVOID
)pheap
)+minsize
;
606 pheap
->LastBlock
=(LPVOID
)pheap
+ PAGESIZE
;
607 CopyMemory(pheap
->Bucket
,__HeapDefaultBuckets
,sizeof(__HeapDefaultBuckets
));
610 pheap
->NextHeap
=__ProcessHeap
->NextHeap
;
611 __ProcessHeap
->NextHeap
=pheap
;
618 InitializeCriticalSection(&(pheap
->Synchronize
));
619 pheap
->Start
.Size
= (minsize
-sizeof(HEAP
))|HEAP_FREE_TAG
;
620 pheap
->Start
.PrevSize
=0;
625 /*********************************************************************
628 * Called by __VirtualInit to initialize the default process heap *
629 *********************************************************************/
631 VOID WINAPI
__HeapInit(LPVOID base
, ULONG minsize
, ULONG maxsize
)
634 NewHeap
= VirtualAlloc(base
, maxsize
, MEM_RESERVE
, PAGE_READWRITE
);
635 VirtualAlloc(NewHeap
, PAGESIZE
, MEM_COMMIT
, PAGE_READWRITE
);
636 __HeapPrepare(NewHeap
, minsize
, maxsize
, 0);
637 __ProcessHeap
= NewHeap
;
641 /*********************************************************************
642 * HeapCreate -- KERNEL32 *
643 *********************************************************************/
644 HANDLE STDCALL
HeapCreate(DWORD flags
, DWORD minsize
, DWORD maxsize
)
648 DPRINT("HeapCreate( 0x%lX, 0x%lX, 0x%lX )\n", flags
, minsize
, maxsize
);
650 pheap
= VirtualAlloc(NULL
, minsize
, MEM_TOP_DOWN
, PAGE_READWRITE
);
651 VirtualAlloc(pheap
, PAGESIZE
, MEM_COMMIT
, PAGE_READWRITE
);
652 return (HANDLE
) __HeapPrepare(pheap
, minsize
, maxsize
, flags
);
655 /*********************************************************************
656 * HeapDestroy -- KERNEL32 *
657 *********************************************************************/
658 BOOL WINAPI
HeapDestroy(HANDLE hheap
)
660 PHEAP pheap
=(PHEAP
) hheap
;
662 DPRINT("HeapDestroy( 0x%lX )\n", (ULONG
) hheap
);
664 if(pheap
->Magic
!=MAGIC_HEAP
)
665 return __ErrorReturnFalse(ERROR_INVALID_PARAMETER
);
667 DeleteCriticalSection(&(pheap
->Synchronize
));
668 VirtualFree(pheap
,0,MEM_RELEASE
);
673 /*********************************************************************
674 * HeapAlloc -- KERNEL32 *
675 *********************************************************************/
676 LPVOID STDCALL
HeapAlloc(HANDLE hheap
, DWORD flags
, DWORD size
)
682 DPRINT("HeapAlloc( 0x%lX, 0x%lX, 0x%lX )\n",
683 (ULONG
) hheap
, flags
, (ULONG
) size
);
685 HeapValidate(hheap
, 0, 0);
687 if(( flags
| pheap
->Flags
) & HEAP_NO_SERIALIZE
)
688 EnterCriticalSection(&(pheap
->Synchronize
));
690 if(size
>HEAP_FRAGMENT_THRESHOLD
)
691 retval
=__HeapAlloc(pheap
, flags
, size
, HEAP_NORMAL_TAG
);
693 retval
=__HeapAllocFragment(pheap
, flags
, size
);
695 if( (flags
| pheap
->Flags
) & HEAP_NO_SERIALIZE
)
696 LeaveCriticalSection(&(pheap
->Synchronize
));
698 DPRINT("HeapAlloc returns 0x%lX\n", (ULONG
) retval
);
704 /*********************************************************************
705 * HeapReAlloc -- KERNEL32 *
706 *********************************************************************/
707 LPVOID STDCALL
HeapReAlloc(HANDLE hheap
, DWORD flags
, LPVOID ptr
, DWORD size
)
711 PHEAP_BLOCK pfree
=((PHEAP_BLOCK
)ptr
-1);
714 DPRINT("HeapReAlloc( 0x%lX, 0x%lX, 0x%lX, 0x%lX )\n",
715 (ULONG
) hheap
, flags
, (ULONG
) ptr
, size
);
717 HeapValidate(hheap
, 0, 0);
719 if(( flags
| pheap
->Flags
) & HEAP_NO_SERIALIZE
)
720 EnterCriticalSection(&(pheap
->Synchronize
));
722 if(HEAP_ISNORMAL(pfree
))
723 retval
=__HeapReAlloc(pheap
, flags
, ptr
, size
);
724 else if(HEAP_ISFRAG(pfree
))
725 retval
=__HeapReAllocFragment(pheap
, flags
, ptr
, size
);
727 retval
=__ErrorReturnNull(ERROR_INVALID_PARAMETER
);
729 if( (flags
| pheap
->Flags
) & HEAP_NO_SERIALIZE
)
730 LeaveCriticalSection(&(pheap
->Synchronize
));
737 /*********************************************************************
738 * HeapFree -- KERNEL32 *
739 *********************************************************************/
740 WINBOOL STDCALL
HeapFree(HANDLE hheap
, DWORD flags
, LPVOID ptr
)
744 PHEAP_BLOCK pfree
=(PHEAP_BLOCK
)((DWORD
)ptr
-HEAP_ADMIN_SIZE
);
747 DPRINT("HeapFree( 0x%lX, 0x%lX, 0x%lX )\n",
748 (ULONG
) hheap
, flags
, (ULONG
) ptr
);
750 HeapValidate(hheap
, 0, 0);
752 if(( flags
| pheap
->Flags
) & HEAP_NO_SERIALIZE
)
753 EnterCriticalSection(&(pheap
->Synchronize
));
755 if(HEAP_ISNORMAL(pfree
))
757 retval
=__HeapFree(pheap
, flags
, ptr
);
759 else if(HEAP_ISFRAG(pfree
))
761 retval
=__HeapFreeFragment(pheap
, flags
, ptr
);
765 retval
=__ErrorReturnFalse(ERROR_INVALID_PARAMETER
);
768 if( (flags
| pheap
->Flags
) & HEAP_NO_SERIALIZE
)
769 LeaveCriticalSection(&(pheap
->Synchronize
));
775 /*********************************************************************
776 * GetProcessHeap -- KERNEL32 *
777 *********************************************************************/
778 HANDLE WINAPI
GetProcessHeap(VOID
)
780 DPRINT("GetProcessHeap()\n");
781 return (HANDLE
) __ProcessHeap
;
784 /********************************************************************
785 * GetProcessHeaps -- KERNEL32 *
787 * NOTE in Win95 this function is not implemented and just returns *
788 * ERROR_CALL_NOT_IMPLEMENTED *
789 ********************************************************************/
790 DWORD WINAPI
GetProcessHeaps(DWORD maxheaps
, PHANDLE phandles
)
795 DPRINT("GetProcessHeaps( %u, 0x%lX )\n", maxheaps
, (ULONG
) phandles
);
797 pheap
= __ProcessHeap
;
799 while((pheap
)&&(maxheaps
))
805 pheap
=pheap
->NextHeap
;
810 pheap
=pheap
->NextHeap
;
817 /*********************************************************************
818 * HeapLock -- KERNEL32 *
819 *********************************************************************/
821 BOOL WINAPI
HeapLock(HANDLE hheap
)
825 DPRINT("HeapLock( 0x%lX )\n", (ULONG
) hheap
);
827 EnterCriticalSection(&(pheap
->Synchronize
));
831 /*********************************************************************
832 * HeapUnlock -- KERNEL32 *
833 *********************************************************************/
835 BOOL WINAPI
HeapUnlock(HANDLE hheap
)
839 DPRINT("HeapUnlock( 0x%lX )\n", (ULONG
) hheap
);
841 LeaveCriticalSection(&(pheap
->Synchronize
));
845 /*********************************************************************
846 * HeapCompact -- KERNEL32 *
848 * NT uses this function to compact moveable blocks and other things *
849 * Here it does not compact, but it finds the largest free region *
850 *********************************************************************/
852 UINT
HeapCompact(HANDLE hheap
, DWORD flags
)
859 if(( flags
| pheap
->Flags
) & HEAP_NO_SERIALIZE
)
860 EnterCriticalSection(&(pheap
->Synchronize
));
862 pfree
=&(pheap
->Start
);
863 /* look for the largest free region of memory */
867 freesize
=HEAP_SIZE(pfree
);
868 if(HEAP_ISFREE(pfree
) && freesize
>largestfree
)
869 largestfree
=freesize
;
871 pfree
=HEAP_NEXT(pfree
);
873 while( (LPVOID
)pfree
< pheap
->End
);
875 if( (flags
| pheap
->Flags
) & HEAP_NO_SERIALIZE
)
876 LeaveCriticalSection(&(pheap
->Synchronize
));
881 /*********************************************************************
882 * HeapSize -- KERNEL32 *
883 *********************************************************************/
884 DWORD WINAPI
HeapSize(HANDLE hheap
, DWORD flags
, LPCVOID pmem
)
886 PHEAP pheap
=(PHEAP
) hheap
;
887 PHEAP_BLOCK palloc
=((PHEAP_BLOCK
)pmem
-1);
890 DPRINT("HeapSize( 0x%lX, 0x%lX, 0x%lX )\n",
891 (ULONG
) hheap
, flags
, (ULONG
) pmem
);
893 if(pheap
->Magic
!=MAGIC_HEAP
)
894 { SetLastError(ERROR_INVALID_PARAMETER
); return 0; }
896 if(( flags
| pheap
->Flags
) & HEAP_NO_SERIALIZE
)
897 EnterCriticalSection(&(pheap
->Synchronize
));
899 if((pmem
> (LPVOID
)pheap
)&&(pmem
< pheap
->End
))
901 if(HEAP_ISALLOC(palloc
))
902 retval
=HEAP_SIZE(palloc
); /* normal allocation */
903 else if(HEAP_ISFRAG(palloc
))
904 retval
=HEAP_FRAG_SIZE(palloc
); /* fragment */
906 { SetLastError(ERROR_INVALID_PARAMETER
); retval
= -1; }
909 if( (flags
| pheap
->Flags
) & HEAP_NO_SERIALIZE
)
910 LeaveCriticalSection(&(pheap
->Synchronize
));
915 /*********************************************************************
916 * HeapValidate -- KERNEL32 *
918 * NOTE: only implemented in NT *
919 *********************************************************************/
920 BOOL WINAPI
HeapValidate(HANDLE hheap
, DWORD flags
, LPCVOID pmem
)
922 PHEAP pheap
=(PHEAP
)hheap
;
927 PHEAP_FRAGMENT pfrag
;
928 PHEAP_FRAGMENT pnextfrag
;
929 PHEAP_FRAGMENT pprevfrag
;
930 PHEAP_BUCKET pbucket
;
935 if(( flags
| pheap
->Flags
) & HEAP_NO_SERIALIZE
)
936 EnterCriticalSection(&(pheap
->Synchronize
));
940 pcheck
=&(pheap
->Start
);
942 /* verify all blocks */
945 pnext
=HEAP_NEXT(pcheck
);
946 if((pprev
)&&(HEAP_PREV(pcheck
)!=pprev
))
948 DPRINT("HeapValidate: linked list invalid, region 0x%lX,"
949 " previous region 0x%lX, list says 0x%lX\n",
950 (ULONG
)pcheck
, (ULONG
)pprev
, (ULONG
) HEAP_PREV(pcheck
));
953 if(HEAP_ISSUB(pcheck
))
956 /* check fragments */
957 psub
=(PHEAP_SUBALLOC
) ((PHEAP_BLOCK
)pcheck
+1);
958 pbucket
=psub
->Bucket
;
959 pfrag
=(PHEAP_FRAGMENT
) ((LPVOID
)psub
+ sizeof(HEAP_SUBALLOC
));
961 if(psub
->NumberFree
>pbucket
->Number
)
964 add
=pbucket
->Size
+HEAP_FRAG_ADMIN_SIZE
;
967 for(i
=0;i
<pbucket
->Number
;i
++)
969 pnextfrag
=(PHEAP_FRAGMENT
)((LPVOID
)pfrag
+add
);
970 if(pfrag
->Magic
!=HEAP_FRAG_MAGIC
)
972 dprintf("HeapValidate: fragment %d magic invalid, region 0x%lX,"
973 " previous region 0x%lX\n", i
, (ULONG
)pcheck
, (ULONG
)pprev
);
978 dprintf("HeapValidate: fragment %d number invalid, region 0x%lX,"
979 " previous region 0x%lX\n", i
, (ULONG
)pcheck
, (ULONG
)pprev
);
982 if((psub
->Bitmap
&(1<<i
))==0)
986 dprintf("HeapValidate: fragment %d suballoc invalid, region 0x%lX,"
987 " previous region 0x%lX\n", i
, (ULONG
)pcheck
, (ULONG
)pprev
);
993 if(number
!=psub
->NumberFree
)
995 dprintf("HeapValidate: invalid number of free fragments, region 0x%lX,"
996 " previous region 0x%lX\n", (ULONG
)pcheck
, (ULONG
)pprev
);
999 dprintf("HeapValidate: [0x%08lX-0x%08lX] suballocated,"
1000 " bucket size=%d, bitmap=0x%08lX\n",
1001 (ULONG
) pcheck
, (ULONG
) pnext
, pbucket
->Size
, psub
->Bitmap
);
1003 else if(HEAP_ISFREE(pcheck
))
1005 if(HEAP_RSIZE(pcheck
)!=HEAP_SIZE(pcheck
))
1007 dprintf("HeapValidate: invalid size of free region 0x%lX,"
1008 " previous region 0x%lX\n",
1009 (ULONG
) pcheck
, (ULONG
) pprev
);
1012 dprintf("HeapValidate: [0x%08lX-0x%08lX] free\n",
1013 (ULONG
) pcheck
, (ULONG
) pnext
);
1015 else if(HEAP_ISNORMAL(pcheck
))
1017 dprintf("HeapValidate: [0x%08lX-0x%08lX] allocated\n",
1018 (ULONG
) pcheck
, (ULONG
) pnext
);
1022 dprintf("HeapValidate: invalid tag %x, region 0x%lX,"
1023 " previous region 0x%lX\n", pcheck
->Size
>>28,
1024 (ULONG
)pcheck
, (ULONG
)pprev
);
1028 pcheck
=HEAP_NEXT(pcheck
);
1030 while( (LPVOID
)pcheck
< pheap
->End
);
1033 if( (flags
| pheap
->Flags
) & HEAP_NO_SERIALIZE
)
1034 LeaveCriticalSection(&(pheap
->Synchronize
));