fixed a bug in K32 heap init
[reactos.git] / reactos / lib / kernel32 / mem / heap.c
1 /*
2 * kernel/heap.c
3 * Copyright (C) 1996, Onno Hovers, All rights reserved
4 *
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.
9 *
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.
14 *
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.
19 *
20 * Win32 heap functions (HeapXXX).
21 *
22 */
23
24 /*
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
27 */
28
29 #define NDEBUG
30 #include <kernel32/kernel32.h>
31
32 #include <kernel32/proc.h>
33 #include <kernel32/heap.h>
34 #include <internal/string.h>
35
36 #include <ddk/ntddk.h>
37
38
39 static HEAP_BUCKET __HeapDefaultBuckets[]=
40 {
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 },
49 };
50
51 PHEAP __ProcessHeap;
52
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,
57 ULONG newsize);
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,
66 ULONG flags);
67
68
69
70 /*********************************************************************
71 * __HeapCommit *
72 * *
73 * commits a range of memory in the heap *
74 *********************************************************************/
75 static BOOL __HeapCommit(PHEAP pheap, LPVOID start, LPVOID end)
76 {
77 DPRINT("__HeapCommit( 0x%lX, 0x%lX, 0x%lX)\n",
78 (ULONG) pheap, (ULONG) start, (ULONG) end);
79
80 if(end >= pheap->LastBlock)
81 pheap->LastBlock=end;
82 if (VirtualAlloc(start,end-start,MEM_COMMIT,PAGE_READWRITE)!=start)
83 {
84 return(FALSE);
85 }
86 return(TRUE);
87 }
88
89 /*********************************************************************
90 * __HeapDecommit *
91 * *
92 * decommits a range of memory in the heap *
93 *********************************************************************/
94 static BOOL __HeapDecommit(PHEAP pheap, LPVOID start, LPVOID end)
95 {
96 DPRINT("__HeapDecommit( 0x%lX, 0x%lX, 0x%lX)\n",
97 (ULONG) pheap, (ULONG) start, (ULONG) end);
98 #ifdef NOT
99 __VirtualDump();
100 #endif
101 if((end >= pheap->LastBlock)&&(start<= pheap->LastBlock))
102 pheap->LastBlock=start;
103
104 return(VirtualFree(start,end-start,MEM_RESERVE));
105 }
106
107 /*********************************************************************
108 * __HeapAlloc *
109 * *
110 * allocates a range of memory from the heap *
111 *********************************************************************/
112 static LPVOID __HeapAlloc(PHEAP pheap, ULONG flags, ULONG size, ULONG tag)
113 {
114 PHEAP_BLOCK pfree;
115 PHEAP_BLOCK palloc;
116 PHEAP_BLOCK pnext;
117 LPVOID commitstart;
118 LPVOID commitend;
119 ULONG freesize;
120 ULONG allocsize;
121
122 DPRINT("__HeapAlloc(pheap %x, flags %x, size %d, tag %x)\n",
123 pheap,flags,size,tag);
124
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 ))
130 {
131 pfree=HEAP_NEXT(pfree);
132 if((LPVOID) pfree>=pheap->End)
133 return __ErrorReturnNull(ERROR_OUTOFMEMORY);
134 freesize=HEAP_SIZE(pfree);
135 }
136 palloc=pfree;
137
138 if(freesize>allocsize)
139 {
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);
147
148 /* split this block in two */
149 pfree= (LPVOID) palloc+ HEAP_ADMIN_SIZE + allocsize;
150
151 /* update admin */
152 pfree->Size =(freesize-allocsize-HEAP_ADMIN_SIZE) | HEAP_FREE_TAG;
153 pfree->PrevSize=(LPVOID)pfree-(LPVOID)palloc;
154
155 pnext=HEAP_NEXT(pfree);
156 if((LPVOID) pnext < pheap->End )
157 pnext->PrevSize=freesize-allocsize;
158 }
159 else
160 {
161 /* commit necessary memory */
162 commitstart=(LPVOID) ROUNDDOWN((ULONG) palloc+HEAP_ADMIN_SIZE, PAGESIZE);
163 commitend =(LPVOID) ROUNDUP((ULONG) palloc+HEAP_ADMIN_SIZE +allocsize,
164 PAGESIZE);
165 if(commitstart<commitend)
166 if(!__HeapCommit(pheap, commitstart, commitend))
167 return __ErrorReturnNull(ERROR_OUTOFMEMORY);
168 }
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;
174 }
175
176 /*********************************************************************
177 * __HeapFreeRest *
178 * *
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)
183 {
184 PHEAP_BLOCK pnext;
185
186 if(allocsize==newsize)
187 {
188 pfree->PrevSize=allocsize+HEAP_ADMIN_SIZE;
189 return;
190 }
191
192 pfree->Size = (allocsize-newsize-HEAP_ADMIN_SIZE) | HEAP_FREE_TAG;
193 pfree->PrevSize = newsize+HEAP_ADMIN_SIZE;
194
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))
198 {
199 pfree->Size = (HEAP_SIZE(pfree)+HEAP_SIZE(pnext) + HEAP_ADMIN_SIZE) |
200 HEAP_FREE_TAG;
201
202 pnext->Size=0;
203 pnext->PrevSize=0;
204 }
205
206 pnext=HEAP_NEXT(pfree);
207 if((LPVOID) pnext< pheap->End)
208 pnext->PrevSize=(LPVOID)pnext-(LPVOID)pfree;
209 }
210
211 /*********************************************************************
212 * __HeapReAlloc *
213 * *
214 * reallocates a range of memory from the heap *
215 *********************************************************************/
216
217 static LPVOID __HeapReAlloc(PHEAP pheap, ULONG flags, LPVOID pold, DWORD size)
218 {
219 PHEAP_BLOCK prealloc=(PHEAP_BLOCK)((LPVOID)pold-HEAP_ADMIN_SIZE);
220 PHEAP_BLOCK pnext;
221 LPVOID pmem;
222 LPVOID commitstart;
223 LPVOID commitend;
224 ULONG allocsize;
225 ULONG newsize;
226 ULONG oldsize;
227
228 /* check that this is a valid allocated block */
229 if(!HEAP_ISALLOC(prealloc))
230 return __ErrorReturnNull(ERROR_INVALID_PARAMETER);
231
232 allocsize = HEAP_RSIZE(prealloc);
233 newsize = SIZE_ROUND(size);
234 /*
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
240 * else realloc
241 */
242 if(size==0)
243 {
244 DPRINT("__HeapReAlloc: freeing memory\n");
245 __HeapFree(pheap, flags, pold);
246 return NULL;
247 }
248 #ifdef NOT
249 else if(size < HEAP_FRAGMENT_THRESHOLD)
250 {
251 /* alloc a new fragment */
252 pmem=__HeapAllocFragment(pheap, flags, size);
253 if(pmem)
254 CopyMemory(pmem, pold, size);
255 return pmem;
256 }
257 #endif
258 else if(newsize < allocsize )
259 {
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);
265
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);
272 return pold;
273 }
274 else if(newsize == allocsize )
275 {
276 DPRINT("__HeapReAlloc: no changes\n");
277 /* nothing to do */
278 prealloc->Size= size | HEAP_NORMAL_TAG;
279 return pold;
280 }
281 else if(newsize > allocsize)
282 {
283 /* try to merge */
284 pnext=HEAP_NEXT(prealloc);
285
286 if(((LPVOID) pnext< pheap->End)&& HEAP_ISFREE(pnext) &&
287 (HEAP_SIZE(pnext) + HEAP_ADMIN_SIZE >=newsize-allocsize))
288 {
289 DPRINT("__HeapReAlloc: joining memory\n");
290 oldsize=HEAP_SIZE(prealloc);
291 prealloc->Size=size | HEAP_NORMAL_TAG;
292
293 /* commit new memory if necessary */
294 commitstart=(LPVOID) ROUNDDOWN((ULONG) pnext+HEAP_ADMIN_SIZE,
295 PAGESIZE);
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);
301
302 __HeapFreeRest(pheap, HEAP_NEXT(prealloc),
303 allocsize+HEAP_ADMIN_SIZE+HEAP_SIZE(pnext), newsize);
304
305 if((flags|pheap->Flags)&HEAP_ZERO_MEMORY)
306 memset(pold+oldsize, 0, size-oldsize);
307 return pold;
308 }
309 else
310 {
311 if((flags&HEAP_REALLOC_IN_PLACE_ONLY)==0)
312 {
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);
317 if(pmem)
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);
322 return pmem;
323 }
324 else
325 return __ErrorReturnNull(ERROR_OUTOFMEMORY);
326 }
327 }
328 return NULL;
329 }
330
331 /*********************************************************************
332 * __HeapFree *
333 * *
334 * frees a range of memory from the heap *
335 *********************************************************************/
336
337 static BOOL __HeapFree(PHEAP pheap, ULONG flags, LPVOID ptr)
338 {
339 PHEAP_BLOCK pfree=(PHEAP_BLOCK)((LPVOID)ptr-HEAP_ADMIN_SIZE);
340 PHEAP_BLOCK pprev;
341 PHEAP_BLOCK pnext;
342 LPVOID decommitstart;
343 LPVOID decommitend;
344
345 /* check that this is a valid allocated block */
346 if(!HEAP_ISALLOC(pfree))
347 return FALSE;
348
349 pfree->Size = HEAP_RSIZE(pfree) | HEAP_FREE_TAG;
350
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))
355 {
356 pprev->Size = (HEAP_SIZE(pprev)+HEAP_SIZE(pfree) + HEAP_ADMIN_SIZE) |
357 HEAP_FREE_TAG;
358 if((LPVOID) pnext<pheap->End)
359 pnext->PrevSize=(LPVOID)pnext-(LPVOID)pprev;
360
361 pfree->Size=0;
362 pfree->PrevSize=0;
363 pfree=pprev;
364 }
365 /* if there is a free region of memory after us, join it */
366 if(((LPVOID) pnext< pheap->End)&& HEAP_ISFREE(pnext))
367 {
368 pfree->Size = (HEAP_SIZE(pfree)+HEAP_SIZE(pnext) + HEAP_ADMIN_SIZE) |
369 HEAP_FREE_TAG;
370
371 pnext->Size=0;
372 pnext->PrevSize=0;
373
374 pnext=HEAP_NEXT(pfree);
375 if((LPVOID) pnext< pheap->End)
376 pnext->PrevSize=(LPVOID)pnext-(LPVOID)pfree;
377 }
378
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);
385
386 return TRUE;
387 }
388
389 /*********************************************************************
390 * __HeapAllocSub *
391 * *
392 * allocates a range of memory that is used to allocate small *
393 * fragments *
394 *********************************************************************/
395 PHEAP_SUBALLOC __HeapAllocSub(PHEAP pheap, PHEAP_BUCKET pbucket)
396 {
397 INT i;
398 INT add;
399 PHEAP_SUBALLOC psub;
400 PHEAP_FRAGMENT pprev;
401 PHEAP_FRAGMENT pnext;
402 PHEAP_FRAGMENT palloc;
403
404 psub=(PHEAP_SUBALLOC) __HeapAlloc(pheap, 0, pbucket->TotalSize,
405 HEAP_SUB_TAG);
406 if(!psub)
407 return __ErrorReturnNull(ERROR_OUTOFMEMORY);
408
409 /* initialize suballoc */
410 palloc=(PHEAP_FRAGMENT) ((LPVOID)psub + sizeof(HEAP_SUBALLOC));
411 psub->FirstFree=palloc;
412 psub->NumberFree=pbucket->Number;
413 psub->Bitmap=0;
414 psub->Next=pbucket->FirstFree;
415 psub->Prev=NULL;
416 psub->Bucket=pbucket;
417 pbucket->FirstFree=psub;
418
419 /* initialize free fragments */
420 add=pbucket->Size+HEAP_FRAG_ADMIN_SIZE;
421 pprev=NULL;
422 for(i=0;i<pbucket->Number;i++)
423 {
424 pnext=(PHEAP_FRAGMENT)((LPVOID)palloc+add);
425 palloc->Magic=HEAP_FRAG_MAGIC;
426 palloc->Number=i;
427 palloc->Size=pbucket->Size;
428 palloc->Sub=psub;
429 palloc->FreeNext=pnext;
430 palloc->FreePrev=pprev;
431 pprev=palloc;
432 palloc=pnext;
433 }
434 pprev->FreeNext=NULL;
435 return psub;
436 }
437
438 /*********************************************************************
439 * __HeapAllocFragment *
440 * *
441 * allocates a small fragment of memory from the heap *
442 *********************************************************************/
443 static LPVOID __HeapAllocFragment(PHEAP pheap, ULONG flags, ULONG size )
444 {
445 PHEAP_BUCKET pbucket;
446 PHEAP_SUBALLOC psub;
447 PHEAP_FRAGMENT palloc;
448 INT nalloc;
449
450 /* get bucket size */
451 pbucket=pheap->Bucket;
452 while(size>pbucket->Size)
453 {
454 pbucket++;
455 }
456 /* get suballoc */
457 psub = pbucket->FirstFree;
458 if(!psub)
459 psub = __HeapAllocSub(pheap, pbucket);
460 if(!psub)
461 return NULL;
462
463 /* do our bookkeeping */
464 palloc = psub->FirstFree;
465 psub->FirstFree = palloc->FreeNext;
466 nalloc = palloc->Number;
467 psub->NumberFree--;
468 psub->Bitmap|=(1<<nalloc);
469
470 /* advance freelist */
471 if(!psub->NumberFree)
472 pbucket->FirstFree=psub->Next;
473
474 /* initialize allocated block */
475 palloc->Magic=HEAP_FRAG_MAGIC;
476 palloc->Size=size;
477
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;
481 }
482
483 /*********************************************************************
484 * __HeapReAllocFragment *
485 * *
486 * reallocates a small fragment of memory *
487 *********************************************************************/
488 static LPVOID __HeapReAllocFragment(PHEAP pheap, ULONG flags,
489 LPVOID pold, ULONG size )
490 {
491 PHEAP_BUCKET pbucket;
492 PHEAP_SUBALLOC psub;
493 PHEAP_FRAGMENT pfrag=(PHEAP_FRAGMENT)
494 ((LPVOID)pold-HEAP_FRAG_ADMIN_SIZE);
495 LPVOID pmem;
496
497 /* sanity checks */
498 if(pfrag->Magic!=HEAP_FRAG_MAGIC)
499 return __ErrorReturnNull(ERROR_INVALID_PARAMETER);
500
501 /* get bucket size */
502 psub=pfrag->Sub;
503 pbucket=psub->Bucket;
504 if(size<=pbucket->Size)
505 {
506 pfrag->Size=size;
507 return pold;
508 }
509 else
510 {
511 if((flags&HEAP_REALLOC_IN_PLACE_ONLY)==0)
512 {
513 /* alloc a new piece of memory */
514 if(size>HEAP_FRAGMENT_THRESHOLD)
515 pmem=__HeapAlloc(pheap, flags, size, HEAP_NORMAL_TAG);
516 else
517 pmem=__HeapAllocFragment(pheap, flags, size);
518
519 if(pmem)
520 CopyMemory(pmem, pold, size);
521 if((flags|pheap->Flags)&HEAP_ZERO_MEMORY)
522 memset(pmem+pfrag->Size, 0, size-pfrag->Size);
523
524 __HeapFreeFragment(pheap, flags, pold);
525 return pmem;
526 }
527 }
528 return NULL;
529 }
530
531 /*********************************************************************
532 * __HeapFreeFragment *
533 * *
534 * frees a small fragment of memory *
535 *********************************************************************/
536 static BOOL __HeapFreeFragment(PHEAP pheap, ULONG flags, LPVOID pfree )
537 {
538 PHEAP_BUCKET pbucket;
539 PHEAP_SUBALLOC psub;
540 PHEAP_FRAGMENT pfrag=(PHEAP_FRAGMENT)
541 ((DWORD)pfree - HEAP_FRAG_ADMIN_SIZE);
542 INT nalloc;
543
544 /* sanity checks */
545 if(pfrag->Magic!=HEAP_FRAG_MAGIC)
546 return __ErrorReturnFalse(ERROR_INVALID_PARAMETER);
547
548 /* get bucket size */
549 psub=pfrag->Sub;
550 pbucket=psub->Bucket;
551
552 nalloc=pfrag->Number;
553 if((psub->Bitmap&(1<<nalloc))==0)
554 return __ErrorReturnFalse(ERROR_INVALID_PARAMETER);
555 psub->NumberFree++;
556 if(psub->NumberFree==pbucket->Number)
557 {
558 /* free suballoc */
559 if(psub==pbucket->FirstFree)
560 pbucket->FirstFree=psub->Next;
561 if(psub->Prev)
562 psub->Prev->Next=psub->Next;
563 if(psub->Next)
564 psub->Next->Prev=psub->Prev;
565 if(!__HeapFree(pheap, flags, psub))
566 return FALSE;
567 }
568 else
569 {
570 /* free fragment */
571 psub->Bitmap&= ~(1<<nalloc);
572
573 if(psub->FirstFree)
574 {
575 pfrag->FreeNext = psub->FirstFree;
576 pfrag->FreePrev = NULL;
577 psub->FirstFree->FreePrev = pfrag;
578 psub->FirstFree = pfrag;
579 }
580 else
581 {
582 psub->FirstFree=pfrag;
583 pfrag->FreePrev=NULL;
584 pfrag->FreeNext=NULL;
585 }
586 }
587
588 return TRUE;
589 }
590
591 /*********************************************************************
592 * __HeapPrepare *
593 * *
594 * Fills in all the data structures of a heap *
595 *********************************************************************/
596 PHEAP __HeapPrepare(LPVOID base, ULONG minsize, ULONG maxsize, ULONG flags)
597 {
598 PHEAP pheap=(PHEAP) base;
599
600 DPRINT("__HeapPrepare(base %x, minsize %d, maxsize %d, flags %x)\n",
601 base,minsize,maxsize,flags);
602
603 pheap->Magic=MAGIC_HEAP;
604 pheap->End= ((LPVOID)pheap)+minsize;
605 pheap->Flags=flags;
606 pheap->LastBlock=(LPVOID)pheap + PAGESIZE;
607 CopyMemory(pheap->Bucket,__HeapDefaultBuckets,sizeof(__HeapDefaultBuckets));
608 if(__ProcessHeap)
609 {
610 pheap->NextHeap=__ProcessHeap->NextHeap;
611 __ProcessHeap->NextHeap=pheap;
612 }
613 else
614 {
615 pheap->NextHeap=0;
616 __ProcessHeap=pheap;
617 }
618 InitializeCriticalSection(&(pheap->Synchronize));
619 pheap->Start.Size= (minsize-sizeof(HEAP))|HEAP_FREE_TAG;
620 pheap->Start.PrevSize =0;
621
622 return pheap;
623 }
624
625 /*********************************************************************
626 * __HeapInit *
627 * *
628 * Called by __VirtualInit to initialize the default process heap *
629 *********************************************************************/
630
631 VOID WINAPI __HeapInit(LPVOID base, ULONG minsize, ULONG maxsize)
632 {
633 PHEAP NewHeap;
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;
638 }
639
640
641 /*********************************************************************
642 * HeapCreate -- KERNEL32 *
643 *********************************************************************/
644 HANDLE STDCALL HeapCreate(DWORD flags, DWORD minsize, DWORD maxsize)
645 {
646 PHEAP pheap;
647
648 DPRINT("HeapCreate( 0x%lX, 0x%lX, 0x%lX )\n", flags, minsize, maxsize);
649
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);
653 }
654
655 /*********************************************************************
656 * HeapDestroy -- KERNEL32 *
657 *********************************************************************/
658 BOOL WINAPI HeapDestroy(HANDLE hheap)
659 {
660 PHEAP pheap=(PHEAP) hheap;
661
662 DPRINT("HeapDestroy( 0x%lX )\n", (ULONG) hheap );
663
664 if(pheap->Magic!=MAGIC_HEAP)
665 return __ErrorReturnFalse(ERROR_INVALID_PARAMETER);
666
667 DeleteCriticalSection(&(pheap->Synchronize));
668 VirtualFree(pheap,0,MEM_RELEASE);
669
670 return TRUE;
671 }
672
673 /*********************************************************************
674 * HeapAlloc -- KERNEL32 *
675 *********************************************************************/
676 LPVOID STDCALL HeapAlloc(HANDLE hheap, DWORD flags, DWORD size)
677 {
678
679 PHEAP pheap=hheap;
680 LPVOID retval;
681
682 DPRINT("HeapAlloc( 0x%lX, 0x%lX, 0x%lX )\n",
683 (ULONG) hheap, flags, (ULONG) size );
684 #ifdef NOT
685 HeapValidate(hheap, 0, 0);
686 #endif
687 if(( flags | pheap->Flags) & HEAP_NO_SERIALIZE )
688 EnterCriticalSection(&(pheap->Synchronize));
689
690 if(size>HEAP_FRAGMENT_THRESHOLD)
691 retval=__HeapAlloc(pheap, flags, size, HEAP_NORMAL_TAG);
692 else
693 retval=__HeapAllocFragment(pheap, flags, size);
694
695 if( (flags | pheap->Flags) & HEAP_NO_SERIALIZE )
696 LeaveCriticalSection(&(pheap->Synchronize));
697
698 DPRINT("HeapAlloc returns 0x%lX\n", (ULONG) retval);
699 return retval;
700
701
702 }
703
704 /*********************************************************************
705 * HeapReAlloc -- KERNEL32 *
706 *********************************************************************/
707 LPVOID STDCALL HeapReAlloc(HANDLE hheap, DWORD flags, LPVOID ptr, DWORD size)
708 {
709
710 PHEAP pheap=hheap;
711 PHEAP_BLOCK pfree=((PHEAP_BLOCK)ptr-1);
712 LPVOID retval;
713
714 DPRINT("HeapReAlloc( 0x%lX, 0x%lX, 0x%lX, 0x%lX )\n",
715 (ULONG) hheap, flags, (ULONG) ptr, size );
716 #ifdef NOT
717 HeapValidate(hheap, 0, 0);
718 #endif
719 if(( flags | pheap->Flags) & HEAP_NO_SERIALIZE )
720 EnterCriticalSection(&(pheap->Synchronize));
721
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);
726 else
727 retval=__ErrorReturnNull(ERROR_INVALID_PARAMETER);
728
729 if( (flags| pheap->Flags) & HEAP_NO_SERIALIZE )
730 LeaveCriticalSection(&(pheap->Synchronize));
731
732 return retval;
733
734
735 }
736
737 /*********************************************************************
738 * HeapFree -- KERNEL32 *
739 *********************************************************************/
740 WINBOOL STDCALL HeapFree(HANDLE hheap, DWORD flags, LPVOID ptr)
741 {
742
743 PHEAP pheap=hheap;
744 PHEAP_BLOCK pfree=(PHEAP_BLOCK)((DWORD)ptr-HEAP_ADMIN_SIZE);
745 BOOL retval;
746
747 DPRINT("HeapFree( 0x%lX, 0x%lX, 0x%lX )\n",
748 (ULONG) hheap, flags, (ULONG) ptr );
749 #ifdef NOT
750 HeapValidate(hheap, 0, 0);
751 #endif
752 if(( flags | pheap->Flags) & HEAP_NO_SERIALIZE )
753 EnterCriticalSection(&(pheap->Synchronize));
754
755 if(HEAP_ISNORMAL(pfree))
756 {
757 retval=__HeapFree(pheap, flags, ptr);
758 }
759 else if(HEAP_ISFRAG(pfree))
760 {
761 retval=__HeapFreeFragment(pheap, flags, ptr);
762 }
763 else
764 {
765 retval=__ErrorReturnFalse(ERROR_INVALID_PARAMETER);
766 }
767
768 if( (flags| pheap->Flags) & HEAP_NO_SERIALIZE )
769 LeaveCriticalSection(&(pheap->Synchronize));
770
771 return retval;
772
773 }
774
775 /*********************************************************************
776 * GetProcessHeap -- KERNEL32 *
777 *********************************************************************/
778 HANDLE WINAPI GetProcessHeap(VOID)
779 {
780 DPRINT("GetProcessHeap()\n");
781 return (HANDLE) __ProcessHeap;
782 }
783
784 /********************************************************************
785 * GetProcessHeaps -- KERNEL32 *
786 * *
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 )
791 {
792 DWORD retval;
793 PHEAP pheap;
794
795 DPRINT("GetProcessHeaps( %u, 0x%lX )\n", maxheaps, (ULONG) phandles );
796
797 pheap= __ProcessHeap;
798 retval=0;
799 while((pheap)&&(maxheaps))
800 {
801 *phandles=pheap;
802 phandles++;
803 maxheaps--;
804 retval++;
805 pheap=pheap->NextHeap;
806 }
807 while(pheap)
808 {
809 retval++;
810 pheap=pheap->NextHeap;
811 }
812
813
814 return retval;
815 }
816
817 /*********************************************************************
818 * HeapLock -- KERNEL32 *
819 *********************************************************************/
820
821 BOOL WINAPI HeapLock(HANDLE hheap)
822 {
823 PHEAP pheap=hheap;
824
825 DPRINT("HeapLock( 0x%lX )\n", (ULONG) hheap );
826
827 EnterCriticalSection(&(pheap->Synchronize));
828 return TRUE;
829 }
830
831 /*********************************************************************
832 * HeapUnlock -- KERNEL32 *
833 *********************************************************************/
834
835 BOOL WINAPI HeapUnlock(HANDLE hheap)
836 {
837 PHEAP pheap=hheap;
838
839 DPRINT("HeapUnlock( 0x%lX )\n", (ULONG) hheap );
840
841 LeaveCriticalSection(&(pheap->Synchronize));
842 return TRUE;
843 }
844
845 /*********************************************************************
846 * HeapCompact -- KERNEL32 *
847 * *
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 *********************************************************************/
851
852 UINT HeapCompact(HANDLE hheap, DWORD flags)
853 {
854 PHEAP pheap=hheap;
855 PHEAP_BLOCK pfree;
856 ULONG freesize;
857 ULONG largestfree;
858
859 if(( flags | pheap->Flags) & HEAP_NO_SERIALIZE )
860 EnterCriticalSection(&(pheap->Synchronize));
861
862 pfree=&(pheap->Start);
863 /* look for the largest free region of memory */
864 largestfree=0;
865 do
866 {
867 freesize=HEAP_SIZE(pfree);
868 if(HEAP_ISFREE(pfree) && freesize>largestfree)
869 largestfree=freesize;
870
871 pfree=HEAP_NEXT(pfree);
872 }
873 while( (LPVOID)pfree < pheap->End );
874
875 if( (flags| pheap->Flags) & HEAP_NO_SERIALIZE )
876 LeaveCriticalSection(&(pheap->Synchronize));
877
878 return largestfree;
879 }
880
881 /*********************************************************************
882 * HeapSize -- KERNEL32 *
883 *********************************************************************/
884 DWORD WINAPI HeapSize(HANDLE hheap, DWORD flags, LPCVOID pmem)
885 {
886 PHEAP pheap=(PHEAP) hheap;
887 PHEAP_BLOCK palloc=((PHEAP_BLOCK)pmem-1);
888 DWORD retval=0;
889
890 DPRINT("HeapSize( 0x%lX, 0x%lX, 0x%lX )\n",
891 (ULONG) hheap, flags, (ULONG) pmem );
892
893 if(pheap->Magic!=MAGIC_HEAP)
894 { SetLastError(ERROR_INVALID_PARAMETER); return 0; }
895
896 if(( flags | pheap->Flags) & HEAP_NO_SERIALIZE )
897 EnterCriticalSection(&(pheap->Synchronize));
898
899 if((pmem> (LPVOID)pheap)&&(pmem < pheap->End))
900 {
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 */
905 else
906 { SetLastError(ERROR_INVALID_PARAMETER); retval = -1; }
907 }
908
909 if( (flags| pheap->Flags) & HEAP_NO_SERIALIZE )
910 LeaveCriticalSection(&(pheap->Synchronize));
911
912 return retval;
913 }
914
915 /*********************************************************************
916 * HeapValidate -- KERNEL32 *
917 * *
918 * NOTE: only implemented in NT *
919 *********************************************************************/
920 BOOL WINAPI HeapValidate(HANDLE hheap, DWORD flags, LPCVOID pmem)
921 {
922 PHEAP pheap=(PHEAP)hheap;
923 PHEAP_BLOCK pcheck;
924 PHEAP_BLOCK pprev;
925 PHEAP_BLOCK pnext;
926 PHEAP_SUBALLOC psub;
927 PHEAP_FRAGMENT pfrag;
928 PHEAP_FRAGMENT pnextfrag;
929 PHEAP_FRAGMENT pprevfrag;
930 PHEAP_BUCKET pbucket;
931 INT i;
932 INT number;
933 INT add;
934
935 if(( flags | pheap->Flags) & HEAP_NO_SERIALIZE )
936 EnterCriticalSection(&(pheap->Synchronize));
937
938 if(pmem==NULL)
939 {
940 pcheck=&(pheap->Start);
941 pprev=NULL;
942 /* verify all blocks */
943 do
944 {
945 pnext=HEAP_NEXT(pcheck);
946 if((pprev)&&(HEAP_PREV(pcheck)!=pprev))
947 {
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));
951 return FALSE;
952 }
953 if(HEAP_ISSUB(pcheck))
954 {
955
956 /* check fragments */
957 psub=(PHEAP_SUBALLOC) ((PHEAP_BLOCK)pcheck+1);
958 pbucket=psub->Bucket;
959 pfrag=(PHEAP_FRAGMENT) ((LPVOID)psub + sizeof(HEAP_SUBALLOC));
960
961 if(psub->NumberFree>pbucket->Number)
962 return FALSE;
963
964 add=pbucket->Size+HEAP_FRAG_ADMIN_SIZE;
965 pprevfrag=NULL;
966 number=0;
967 for(i=0;i<pbucket->Number;i++)
968 {
969 pnextfrag=(PHEAP_FRAGMENT)((LPVOID)pfrag+add);
970 if(pfrag->Magic!=HEAP_FRAG_MAGIC)
971 {
972 dprintf("HeapValidate: fragment %d magic invalid, region 0x%lX,"
973 " previous region 0x%lX\n", i, (ULONG)pcheck, (ULONG)pprev);
974 return FALSE;
975 }
976 if(pfrag->Number!=i)
977 {
978 dprintf("HeapValidate: fragment %d number invalid, region 0x%lX,"
979 " previous region 0x%lX\n", i, (ULONG)pcheck, (ULONG)pprev);
980 return FALSE;
981 }
982 if((psub->Bitmap&(1<<i))==0)
983 number++;
984 if(pfrag->Sub!=psub)
985 {
986 dprintf("HeapValidate: fragment %d suballoc invalid, region 0x%lX,"
987 " previous region 0x%lX\n", i, (ULONG)pcheck, (ULONG)pprev);
988 return FALSE;
989 }
990 pprevfrag=pfrag;
991 pfrag=pnextfrag;
992 }
993 if(number!=psub->NumberFree)
994 {
995 dprintf("HeapValidate: invalid number of free fragments, region 0x%lX,"
996 " previous region 0x%lX\n", (ULONG)pcheck, (ULONG)pprev);
997 return FALSE;
998 }
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);
1002 }
1003 else if(HEAP_ISFREE(pcheck))
1004 {
1005 if(HEAP_RSIZE(pcheck)!=HEAP_SIZE(pcheck))
1006 {
1007 dprintf("HeapValidate: invalid size of free region 0x%lX,"
1008 " previous region 0x%lX\n",
1009 (ULONG) pcheck, (ULONG) pprev);
1010 return FALSE;
1011 }
1012 dprintf("HeapValidate: [0x%08lX-0x%08lX] free\n",
1013 (ULONG) pcheck, (ULONG) pnext );
1014 }
1015 else if(HEAP_ISNORMAL(pcheck))
1016 {
1017 dprintf("HeapValidate: [0x%08lX-0x%08lX] allocated\n",
1018 (ULONG) pcheck, (ULONG) pnext );
1019 }
1020 else
1021 {
1022 dprintf("HeapValidate: invalid tag %x, region 0x%lX,"
1023 " previous region 0x%lX\n", pcheck->Size>>28,
1024 (ULONG)pcheck, (ULONG)pprev);
1025 return FALSE;
1026 }
1027 pprev=pcheck;
1028 pcheck=HEAP_NEXT(pcheck);
1029 }
1030 while( (LPVOID)pcheck < pheap->End );
1031 }
1032
1033 if( (flags| pheap->Flags) & HEAP_NO_SERIALIZE )
1034 LeaveCriticalSection(&(pheap->Synchronize));
1035
1036 return TRUE;
1037 }
1038