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