source: trunk/src/win32k/misc/rmalloc.c@ 10367

Last change on this file since 10367 was 4164, checked in by bird, 25 years ago

Merged in the Grace branch. New Win32k!

File size: 31.5 KB
Line 
1/* $Id: rmalloc.c,v 1.4 2000-09-02 21:08:14 bird Exp $
2 *
3 * Resident Heap.
4 *
5 * Note: This heap does very little checking on input.
6 * Use with care! We're running at Ring-0!
7 *
8 * Copyright (c) 1999-2000 knut st. osmundsen
9 *
10 * Project Odin Software License can be found in LICENSE.TXT
11 *
12 */
13
14#define static
15/******************************************************************************
16* Defined macros and constants
17******************************************************************************/
18#ifdef DEBUG
19 #define DEBUG_ALLOC
20 #undef ALLWAYS_HEAPCHECK
21#endif
22
23#define HEAPANCHOR_SIGNATURE 0xBEEFFEEB
24#define MEMBLOCK_SIGNATURE 0xFEEBBEEF
25
26
27/*#define CB_HDR (sizeof(MEMBLOCK) - 1) /* size of MEMBLOCK header (in bytes) */
28#define CB_HDR ((int)&(((PMEMBLOCK)0)->achUserData[0]))
29#define PNEXT_BLOCK(a) ((PMEMBLOCK)((unsigned)(a) + CB_HDR + (a)->cbSize))
30#define BLOCKSIZE (1024*256) /* 256KB */
31
32
33#define MAX(a, b) (((a) > (b))? (a) : (b))
34#define ALIGN(a, alignment) (((a) + (alignment - 1UL)) & ~(alignment - 1UL))
35 /* aligns something, a, up to nearest alignment boundrary-
36 * Note: Aligment must be a 2**n number. */
37
38
39#define INCL_DOS
40#define INCL_DOSERRORS
41#ifdef RING0
42 #define INCL_NOAPI
43#else
44 #define INCL_DOSMEMMGR
45#endif
46
47
48/******************************************************************************
49* Headerfiles
50******************************************************************************/
51#include <os2.h>
52#include "devSegDf.h" /* Win32k segment definitions. */
53#ifdef RING0
54 #include "dev32hlp.h"
55 #include "asmutils.h"
56#else
57 #include <builtin.h>
58 #define Int3() __interrupt(3)
59#endif
60#include "log.h"
61#include "rmalloc.h"
62#include <memory.h>
63#include "dev32.h"
64#include "macros.h"
65
66
67/******************************************************************************
68* Structs and Typedefs
69******************************************************************************/
70typedef struct _MEMBLOCK /* MB */
71{
72 #ifdef DEBUG_ALLOC
73 unsigned long ulSignature; /* Contains MEMBLOCK_SIGNATURE (0xFEEBBEEF) */
74 #endif
75 unsigned cbSize; /* Size of user space (achBlock)*/
76 struct _MEMBLOCK * pNext; /* Pointer to the next memblock. */
77 unsigned char achUserData[1]; /* User data */
78} MEMBLOCK, *PMEMBLOCK;
79
80
81typedef struct _HeapAnchor /* HA */
82{
83 #ifdef DEBUG_ALLOC
84 unsigned long ulSignature; /* Contains HEAPANCHOR_SIGNATURE */
85 #endif
86 unsigned cbSize; /* Total amount of memory in this block. */
87 struct _HeapAnchor *pNext; /* Pointer to the next anchor block. */
88 struct _HeapAnchor *pPrev; /* Pointer to the previous anchor block. */
89 PMEMBLOCK pmbFree; /* Pointer to the used-memblock chain. */
90 unsigned cbFree; /* Amount of free memory. */
91 PMEMBLOCK pmbUsed; /* Pointer to the used-memblock chain. */
92 unsigned cbUsed; /* Amount of used memory. */
93
94} HEAPANCHOR, *PHEAPANCHOR;
95
96
97
98
99/******************************************************************************
100* Global data
101******************************************************************************/
102static PHEAPANCHOR phaFirst; /* Pointer to the first anchor block.*/
103static PHEAPANCHOR phaLast; /* Pointer to the first anchor block.*/
104static unsigned cbResHeapMax; /* Maximum amount of memory used by the heap. */
105
106#ifndef RING0
107char fResInited; /* init flag */
108#endif
109
110
111/******************************************************************************
112* Internal functions
113******************************************************************************/
114static void resInsertUsed(PHEAPANCHOR pha, PMEMBLOCK pmb);
115static void resInsertFree(PHEAPANCHOR pha, PMEMBLOCK pmb);
116static PMEMBLOCK resGetFreeMemblock(PHEAPANCHOR *ppha, unsigned cbUserSize);
117static PMEMBLOCK resFindUsedBlock(PHEAPANCHOR *ppha, void *pvUser, int fWithin);
118
119
120/**
121 * Inserts a memblock into the used chain.
122 * @param pha Pointer to the heap anchor which the block is to be inserted into.
123 * @param pmb Pointer to memblock to insert into the free list.
124 * @remark Sorts on address.
125 */
126static void resInsertUsed(PHEAPANCHOR pha, PMEMBLOCK pmb)
127{
128 if (pha->pmbUsed == NULL || pha->pmbUsed > pmb)
129 {
130 pmb->pNext = pha->pmbUsed;
131 pha->pmbUsed = pmb;
132 }
133 else
134 {
135 PMEMBLOCK pmbTmp = pha->pmbUsed;
136 while (pmbTmp->pNext != NULL && pmbTmp->pNext < pmb)
137 pmbTmp = pmbTmp->pNext;
138
139 pmb->pNext = pmbTmp->pNext;
140 pmbTmp->pNext= pmb;
141 }
142}
143
144
145/**
146 * Inserts a memblock into the free chain.
147 * Merges blocks adjecent blocks.
148 * @param pha Pointer to the heap anchor which the block is to be inserted into.
149 * @param pmb Pointer to memblock to insert into the free list.
150 * @remark Sorts on address.
151 */
152static void resInsertFree(PHEAPANCHOR pha, PMEMBLOCK pmb)
153{
154 pha->cbFree += pmb->cbSize;
155 if (pmb < pha->pmbFree || pha->pmbFree == NULL)
156 {
157 /* test for merge with first block */
158 if (pha->pmbFree != NULL && PNEXT_BLOCK(pmb) == pha->pmbFree)
159 {
160 pha->cbFree += CB_HDR;
161 pmb->cbSize += CB_HDR + pha->pmbFree->cbSize;
162 pmb->pNext = pha->pmbFree->pNext;
163 #ifdef DEBUG_ALLOC
164 pha->pmbFree->ulSignature = 0xF0EEEE0F;
165 pha->pmbFree->pNext = (void*)~0;
166 #endif
167 }
168 else
169 pmb->pNext = pha->pmbFree;
170 pha->pmbFree = pmb;
171 }
172 else
173 {
174 PMEMBLOCK pmbTmp = pha->pmbFree;
175 while (pmbTmp->pNext != NULL && pmbTmp->pNext < pmb)
176 pmbTmp = pmbTmp->pNext;
177
178 /* test for merge with left block */
179 if (PNEXT_BLOCK(pmbTmp) == pmb)
180 {
181 pmbTmp->cbSize += CB_HDR + pmb->cbSize;
182 pha->cbFree += CB_HDR;
183 #ifdef DEBUG_ALLOC
184 pmb->ulSignature = 0xF0EEEE0F;
185 pmb->pNext = (void*)~0;
186 #endif
187 pmb = pmbTmp;
188 }
189 else
190 {
191 pmb->pNext = pmbTmp->pNext;
192 pmbTmp->pNext = pmb;
193 }
194
195 /* test for merge with right block */
196 if (pmb->pNext != NULL && PNEXT_BLOCK(pmb) == pmb->pNext)
197 {
198 pmb->cbSize += CB_HDR + pmb->pNext->cbSize;
199 pha->cbFree += CB_HDR;
200 #ifdef DEBUG_ALLOC
201 pmb->pNext->ulSignature = 0xF0EEEE0F;
202 #endif
203 pmb->pNext = pmb->pNext->pNext;
204 }
205 }
206}
207
208
209/**
210 * Finds a free block at the requested size.
211 * @returns Pointer to block (not in free list any longer).
212 * @param ppha Upon return the pointer pointed to contains the heap
213 * anchor which the memory block was allocated from.
214 * @param cbUserSize Bytes the user have requested.
215 * @sketch cbUserSize is aligned to nearest 4 bytes.
216 * ...
217 *
218 */
219static PMEMBLOCK resGetFreeMemblock(PHEAPANCHOR *ppha, unsigned cbUserSize)
220{
221 unsigned cbBlockSize;
222 unsigned cbTotalSize = 0;
223
224 cbUserSize = (cbUserSize + 3) & ~3;
225 *ppha = phaFirst;
226 while (*ppha != NULL)
227 {
228 if ((*ppha)->cbFree >= cbUserSize + CB_HDR)
229 {
230 PMEMBLOCK pmbBestFit = NULL;
231 PMEMBLOCK pmbBestFitPrev = NULL;
232 PMEMBLOCK pmbCur = (*ppha)->pmbFree;
233 PMEMBLOCK pmbPrev = NULL;
234
235 /* search for block */
236 while (pmbCur != NULL)
237 {
238 /* check for perfect match first */
239 if (pmbCur->cbSize == cbUserSize)
240 break;
241 /* TODO: The following test may need to be adjusted later. */
242 else if (pmbCur->cbSize >= cbUserSize
243 && (pmbBestFit == NULL || pmbCur->cbSize < pmbBestFit->cbSize)
244 )
245 {
246 pmbBestFit = pmbCur;
247 pmbBestFitPrev = pmbPrev;
248 }
249
250 /* next */
251 pmbPrev = pmbCur;
252 pmbCur = pmbCur->pNext;
253 }
254
255 /* link out block */
256 if (pmbCur != NULL)
257 { /* prefect match */
258 if (pmbPrev != NULL)
259 pmbPrev->pNext = pmbCur->pNext;
260 else
261 (*ppha)->pmbFree = pmbCur->pNext;
262
263 (*ppha)->cbFree -= cbUserSize;
264 (*ppha)->cbUsed += cbUserSize;
265 }
266 else if (pmbBestFit != NULL)
267 { /* best fit */
268 /* two cases 1) split block. 2) block is too small to be splitted. */
269 if (pmbBestFit->cbSize > cbUserSize + CB_HDR)
270 {
271 pmbCur = (PMEMBLOCK)((unsigned)pmbBestFit + pmbBestFit->cbSize - cbUserSize);
272 #ifdef DEBUG_ALLOC
273 pmbCur->ulSignature = MEMBLOCK_SIGNATURE;
274 #endif
275 pmbCur->cbSize = cbUserSize;
276 pmbBestFit->cbSize -= cbUserSize + CB_HDR;
277
278 (*ppha)->cbFree -= cbUserSize + CB_HDR;
279 (*ppha)->cbUsed += cbUserSize;
280 }
281 else
282 {
283 if (pmbBestFitPrev != NULL)
284 pmbBestFitPrev->pNext = pmbBestFit->pNext;
285 else
286 (*ppha)->pmbFree = pmbBestFit->pNext;
287 pmbCur = pmbBestFit;
288
289 (*ppha)->cbFree -= pmbCur->cbSize;
290 (*ppha)->cbUsed += pmbCur->cbSize;
291 }
292 }
293
294 if (pmbCur != NULL)
295 return pmbCur;
296 }
297
298 cbTotalSize += (*ppha)->cbSize;
299
300 /* next heap anchor */
301 *ppha = (*ppha)->pNext;
302 }
303
304 /* add a new heap anchor? */
305 cbBlockSize = ALIGN(cbUserSize + CB_HDR * 2, BLOCKSIZE);
306 if (cbResHeapMax >= cbTotalSize + cbBlockSize)
307 {
308 #ifdef RING0
309 *ppha = D32Hlp_VMAlloc(0UL, cbBlockSize, ~0UL);
310 #else
311 if (DosAllocMem((void*)ppha, cbBlockSize, PAG_COMMIT | PAG_READ | PAG_WRITE) != 0)
312 *ppha = NULL;
313 #endif
314
315 if (*ppha != NULL)
316 {
317 register PHEAPANCHOR pha = *ppha;
318 PMEMBLOCK pmb;
319
320 /* anchor block */
321 #ifdef DEBUG_ALLOC
322 pha->ulSignature = HEAPANCHOR_SIGNATURE;
323 #endif
324 pha->cbSize = cbBlockSize;
325 pha->pmbUsed = NULL;
326 pha->cbUsed = cbUserSize;
327
328 /* free memblock */
329 pha->pmbFree = (PMEMBLOCK)((unsigned)pha + sizeof(*pha));
330 pha->cbFree = cbBlockSize - sizeof(*pha) - CB_HDR * 2 - cbUserSize;
331 #ifdef DEBUG_ALLOC
332 pha->pmbFree->ulSignature = MEMBLOCK_SIGNATURE;
333 #endif
334 pha->pmbFree->cbSize = pha->cbFree;
335 pha->pmbFree->pNext = NULL;
336
337 /* used memblock */
338 pmb = (PMEMBLOCK)((unsigned)pha + cbBlockSize - cbUserSize - CB_HDR);
339 #ifdef DEBUG_ALLOC
340 pmb->ulSignature = MEMBLOCK_SIGNATURE;
341 #endif
342 pmb->cbSize = cbUserSize;
343 pmb->pNext = NULL;
344
345 /* insert into list */
346 pha->pPrev = phaLast;
347 pha->pNext = NULL;
348 if (phaLast == NULL) /* Might never happen but just in case it does. */
349 phaLast = phaFirst = pha;
350 else
351 phaLast->pNext = pha;
352 phaLast = pha;
353
354 return pmb;
355 }
356 else
357 kprintf(("resGetFreeMemblock: Unable to allocate heap memory.\n"));
358 }
359 else
360 {
361 kprintf(("resGetFreeMemblock: Allocation failed, limit reached. \n"
362 " %d(=cbResHeapMax) < %d(=cbTotalSize) + %d(=cbBlockSize)\n",
363 cbResHeapMax, cbTotalSize, cbBlockSize));
364 }
365
366 return NULL;
367}
368
369
370/**
371 * Finds a used memory block.
372 * @returns Pointer to memblock if found.
373 * @param ppha Pointer to pointer to heap anchor block the returned memblock is located in. (output)
374 * @param pvUser User pointer to find the block to.
375 * @param fWithin When this flag is set, the pointer may point anywhere within the block.
376 * When clear, it has to point exactly at the start of the user data area.
377 */
378static PMEMBLOCK resFindUsedBlock(PHEAPANCHOR *ppha, void *pvUser, int fWithin)
379{
380 PMEMBLOCK pmb;
381
382 if (pvUser != NULL && ppha != NULL)
383 {
384 register PHEAPANCHOR pha = phaFirst;
385 while (pha != NULL
386 && !((unsigned)pvUser > (unsigned)pha
387 && (unsigned)pvUser < (unsigned)pha + pha->cbSize))
388 pha = pha->pNext;
389
390 if (pha != NULL)
391 {
392 #ifdef DEBUG_ALLOC
393 if (pha->ulSignature != HEAPANCHOR_SIGNATURE)
394 {
395 kprintf(("resFindUsedBlock: Invalid heapanchor signature.\n"));
396 return NULL;
397 }
398 #endif
399 *ppha = pha;
400 pmb = pha->pmbUsed;
401
402 if (fWithin)
403 {
404 while (pmb != NULL && !(pvUser >= (void*)pmb && pvUser < (void*)PNEXT_BLOCK(pmb)))
405 pmb = pmb->pNext;
406 }
407 else
408 {
409 pvUser = (void*)((unsigned)pvUser - CB_HDR);
410 while (pmb != NULL && pvUser != (void*)pmb)
411 pmb = pmb->pNext;
412 }
413 #ifdef DEBUG_ALLOC
414 if (pmb != NULL && pmb->ulSignature != MEMBLOCK_SIGNATURE)
415 {
416 kprintf(("resFindUsedBlock: Invalid memoryblock signature.\n"));
417 pmb = NULL;
418 }
419 #endif
420 }
421 else
422 pmb = NULL;
423 }
424 else
425 pmb = NULL;
426
427 return pmb;
428}
429
430
431/**
432 * Initiate the heap "subsystem".
433 * @returns 0 on success, not 0 on error.
434 * @param cbSizeInit The initial size of the heap in bytes.
435 * @param cbSizeMax Maximum heapsize in bytes.
436 */
437int resHeapInit(unsigned cbSizeInit, unsigned cbSizeMax)
438{
439 unsigned cbSize = MAX(BLOCKSIZE, cbSizeInit);
440
441 cbResHeapMax = cbSizeMax;
442
443 #ifdef RING0
444 phaFirst = D32Hlp_VMAlloc(0UL, cbSize, ~0UL);
445 #else
446 if (DosAllocMem((void*)&phaFirst, cbSize, PAG_COMMIT | PAG_READ | PAG_WRITE) != 0)
447 phaFirst = NULL;
448 #endif
449 if (phaFirst == NULL)
450 {
451 kprintf(("unable to allocate heap memory.\n"));
452 Int3();
453 return -1;
454 }
455
456 #ifdef DEBUG_ALLOC
457 phaFirst->ulSignature = HEAPANCHOR_SIGNATURE;
458 #endif
459 phaFirst->cbSize = cbSize;
460 phaFirst->pNext = NULL;
461 phaFirst->pPrev = NULL;
462 phaFirst->pmbUsed = NULL;
463 phaFirst->cbUsed = 0UL;
464 phaFirst->pmbFree = (PMEMBLOCK)((unsigned)phaFirst+sizeof(*phaFirst));
465 phaFirst->cbFree = cbSize - sizeof(*phaFirst) - CB_HDR;
466
467 #ifdef DEBUG_ALLOC
468 phaFirst->pmbFree->ulSignature = MEMBLOCK_SIGNATURE;
469 #endif
470 phaFirst->pmbFree->cbSize = phaFirst->cbFree;
471 phaFirst->pmbFree->pNext = NULL;
472 phaLast = phaFirst;
473
474 #ifdef ALLWAYS_HEAPCHECK
475 if (!_res_heap_check())
476 {
477 /* error! */
478 kprintf(("%s: _res_heap_check failed!\n", "heapInit"));
479 Int3();
480 return -2;
481 }
482 #endif
483 #ifdef RING3
484 fInited = TRUE;
485 #endif
486 return 0;
487}
488
489
490/**
491 * malloc - allocates a given amount of memory.
492 * @returns Pointer to allocated memory.
493 * NULL if out of memory. (Or memory to fragmented.)
494 * @param cbSize Bytes user requests us to allocate. This is aligned
495 * to four bytes.
496 */
497void * rmalloc(unsigned cbSize)
498{
499 void *pvRet = NULL;
500
501 #ifdef ALLWAYS_HEAPCHECK
502 if (!_res_heap_check())
503 {
504 kprintf(("rmalloc: _res_heap_check failed!\n"));
505 return NULL;
506 }
507 #endif
508
509 if (cbSize != 0)
510 {
511 PHEAPANCHOR pha;
512 PMEMBLOCK pmb = resGetFreeMemblock(SSToDS(&pha), cbSize);
513 if (pmb != NULL)
514 {
515 resInsertUsed(pha, pmb);
516 pvRet = &pmb->achUserData[0];
517 }
518 }
519 else
520 { /* error! */
521 kprintf(("rmalloc: error cbSize = 0\n"));
522 }
523
524 return pvRet;
525}
526
527
528/**
529 * Reallocate a heapblock.
530 * @returns Pointer to new heapblock.
531 * @param pv Pointer to the block to realloc.
532 * @param cbNew The new block size.
533 */
534void *rrealloc(void *pv, unsigned cbNew)
535{
536 PMEMBLOCK pmb;
537 PHEAPANCHOR pha;
538
539 pmb = resFindUsedBlock(SSToDS(&pha), pv, FALSE);
540 if (pmb != NULL)
541 {
542 void *pvRet;
543
544 cbNew = ALIGN(cbNew, 4);
545 if (cbNew <= pmb->cbSize)
546 { /* shrink block */
547 pvRet = pv;
548 if (cbNew + CB_HDR < pmb->cbSize)
549 { /* split block */
550 PMEMBLOCK pmbNew = (PMEMBLOCK)((unsigned)pmb + CB_HDR + cbNew);
551 #ifdef DEBUG_ALLOC
552 pmbNew->ulSignature = MEMBLOCK_SIGNATURE;
553 #endif
554 pmbNew->cbSize = pmb->cbSize - cbNew - CB_HDR;
555 pmbNew->pNext = NULL;
556 pha->cbUsed -= pmb->cbSize - cbNew;
557 pmb->cbSize = cbNew;
558 resInsertFree(pha, pmbNew);
559 }
560 }
561 else
562 { /* expand block - this code may be more optimized... */
563 pvRet = rmalloc(cbNew);
564 if (pvRet != NULL)
565 {
566 memcpy(pvRet, pv, pmb->cbSize);
567 rfree(pv);
568 }
569 }
570 return pvRet;
571 }
572 return NULL;
573}
574
575
576/**
577 * Frees a block.
578 * @param pv User pointer.
579 */
580void rfree(void *pv)
581{
582 #ifdef ALLWAYS_HEAPCHECK
583 if (!_res_heap_check())
584 {
585 kprintf(("rfree: _res_heap_check failed!\n"));
586 return;
587 }
588 #endif
589
590 if (pv != NULL)
591 {
592 PHEAPANCHOR pha = phaFirst;
593
594 while (pha != NULL
595 && !((unsigned)pv > (unsigned)pha
596 && (unsigned)pv < (unsigned)pha + pha->cbSize))
597 pha = pha->pNext;
598
599 if (pha != NULL)
600 {
601 PMEMBLOCK pmbCur = pha->pmbUsed;
602 PMEMBLOCK pmbPrev = NULL;
603 pv = (void*)((unsigned)pv - CB_HDR);
604
605 while (pmbCur != NULL &&
606 #ifdef DEBUG_ALLOC /* pointer within block */
607 !(pv >= (void*)pmbCur && (void*)((unsigned)pv + CB_HDR) < (void*)PNEXT_BLOCK(pmbCur))
608 #else
609 pv != (void*)pmbCur
610 #endif
611 )
612 {
613 pmbPrev = pmbCur;
614 pmbCur = pmbCur->pNext;
615 }
616
617 if (pmbCur != NULL)
618 {
619 #ifdef DEBUG_ALLOC
620 if (pmbCur->ulSignature != MEMBLOCK_SIGNATURE)
621 {
622 kprintf(("rfree: Invalid memoryblock signature - pmbCur\n"));
623 return;
624 }
625 if (pmbPrev != NULL && pmbPrev->ulSignature != MEMBLOCK_SIGNATURE)
626 {
627 kprintf(("rfree: Invalid memoryblock signature - pmbPrev\n"));
628 return;
629 }
630 #endif
631 if (pv == pmbCur)
632 {
633 if (pmbPrev != NULL)
634 pmbPrev->pNext = pmbCur->pNext;
635 else
636 pha->pmbUsed = pmbCur->pNext;
637 pha->cbUsed -= pmbCur->cbSize;
638
639 resInsertFree(pha, pmbCur);
640
641 #ifdef ALLWAYS_HEAPCHECK
642 if (!_res_heap_check())
643 kprintf(("rfree: _res_heap_check failed 3!\n"));
644 #endif
645 }
646 else
647 kprintf(("rfree: pv is not pointing to start of block.\n"));
648 }
649 else
650 kprintf(("rfree: heap block not found!\n"));
651 }
652 else
653 kprintf(("rfree: heap block not within the large blocks!\n"));
654 }
655 else
656 kprintf(("rfree: Free received a NULL pointer!\n"));
657}
658
659
660/**
661 * Gets the size of a block.
662 * @returns Bytes in a block.
663 */
664unsigned _res_msize(void *pv)
665{
666 PHEAPANCHOR pha;
667 PMEMBLOCK pmb;
668
669 #ifdef ALLWAYS_HEAPCHECK
670 if (!_res_heap_check())
671 kprintf(("_msize: _res_heap_check failed!\n"));
672 #endif
673
674 pmb = resFindUsedBlock(SSToDS(&pha), pv, FALSE);
675 return pmb != NULL ? pmb->cbSize : 0;
676}
677
678
679/**
680 * Checks if pv is a valid heappointer.
681 * @returns 1 if valid. 0 if invalid.
682 * @param pv User data pointer.
683 */
684int _res_validptr(void *pv)
685{
686 PHEAPANCHOR pha;
687 PMEMBLOCK pmb;
688
689 #ifdef ALLWAYS_HEAPCHECK
690 if (!_res_heap_check())
691 kprintf(("_validptr: _res_heap_check failed!\n"));
692 #endif
693
694 pmb = resFindUsedBlock(SSToDS(&pha), pv, TRUE);
695 return pmb != NULL;
696}
697
698
699/**
700 * Checks that the dataaera made up by pv and cbSize valid with in the heap.
701 * @returns 1 if valid. 0 if invalid.
702 * @param pv User data pointer.
703 * @param cbSize Size of data which has to be valid.
704 */
705int _res_validptr2(void *pv, unsigned cbSize)
706{
707 PHEAPANCHOR pha;
708 PMEMBLOCK pmb;
709
710 #ifdef ALLWAYS_HEAPCHECK
711 if (!_res_heap_check())
712 kprintf(("_validptr: _res_heap_check failed!\n"));
713 #endif
714
715 pmb = resFindUsedBlock(SSToDS(&pha), pv, TRUE);
716 return pmb != NULL ? (pmb->cbSize - ((unsigned)pv - (unsigned)pmb - CB_HDR)) >= cbSize : FALSE;
717}
718
719
720/**
721 * Get amount of free memory (in bytes)
722 * @returns Amount of free memory (in bytes).
723 * @remark Note that this amount is of all free memory blocks and
724 * that these blocks are fragmented.
725 * You'll probably not be able to allocate a single block
726 * of the returned size.
727 */
728unsigned _res_memfree(void)
729{
730 PHEAPANCHOR pha = phaFirst;
731 unsigned cb;
732
733 #ifdef ALLWAYS_HEAPCHECK
734 if (!_res_heap_check())
735 kprintf(("res_memfree: _res_heap_check failed!\n"));
736 #endif
737
738 for (cb = 0; pha != NULL; pha = pha->pNext)
739 cb += pha->cbFree;
740
741 return cb;
742}
743
744
745/**
746 * Checks heap integrety.
747 * @returns TRUE when ok.
748 * FALSE on error.
749 * NULL if out of memory. (Or memory to fragmented.)
750 */
751int _res_heap_check(void)
752{
753#ifdef DEBUG_ALLOC
754 PHEAPANCHOR pha = phaFirst;
755 PHEAPANCHOR phaPrev = NULL;
756
757
758 while (pha != NULL)
759 {
760 PMEMBLOCK pmbFree = pha->pmbFree;
761 PMEMBLOCK pmbUsed = pha->pmbUsed;
762 PMEMBLOCK pmbLast = NULL;
763 unsigned cbFree = 0;
764 unsigned cbUsed = 0;
765 unsigned cbSize = sizeof(*pha);
766
767 /*
768 * Check the heap anchor.
769 */
770 if (pha->ulSignature != HEAPANCHOR_SIGNATURE)
771 {
772 kprintf(("_res_heap_check: invalid signature for pha=0x%08x\n", pha));
773 return FALSE;
774 }
775
776 if (pha->cbFree + pha->cbUsed >= pha->cbSize || pha->cbSize == 0)
777 {
778 kprintf(("_res_heap_check: cbFree + cbUsed >= cbSize for pha=0x%08x\n", pha));
779 return FALSE;
780 }
781
782 if (pha->pPrev != phaPrev)
783 {
784 kprintf(("_res_heap_check: internal error - error in heap anchor chain.\n"));
785 return FALSE;
786 }
787
788 if ((unsigned)MINNOTNULL(pmbFree, pmbUsed) != (unsigned)(pha+1))
789 {
790 kprintf(("_res_heap_check: The first free/used block don't start at start of memory\n"
791 " block. pmbFree=0x%08x, pmbUsed=0x%08x, pha+1=0x%08x\n",
792 pmbFree, pmbUsed, pha+1));
793 return FALSE;
794 }
795
796
797 /*
798 * Check the lists
799 */
800 while (pmbFree != NULL || pmbUsed != NULL)
801 {
802 /** @sketch:
803 * Check signatures and for lost memory.
804 *
805 * three cases:
806 * 1) pmbUsed adjecent to pmbUsed->pNext
807 * 2) pmbUsed adjecent to pmbFree
808 * 3) pmbFree adjecent to pmbFree->pNext
809 * 4) pmbFree adjecent to pmbUsed
810 * 5) pmbUsed is the last block
811 * 6) pmbFree is the last block
812 */
813 if (!( (pmbUsed != NULL && PNEXT_BLOCK(pmbUsed) == pmbUsed->pNext) /* 1.*/
814 || (pmbUsed != NULL && PNEXT_BLOCK(pmbUsed) == pmbFree) /* 2.*/
815 || (pmbFree != NULL && PNEXT_BLOCK(pmbFree) == pmbFree->pNext) /* 3.*/
816 || (pmbFree != NULL && PNEXT_BLOCK(pmbFree) == pmbUsed) /* 4.*/
817 || (pmbUsed != NULL && pmbFree == NULL && pmbUsed->pNext == NULL) /* 5.*/
818 || (pmbFree != NULL && pmbUsed == NULL && pmbFree->pNext == NULL) /* 6.*/
819 )
820 )
821 {
822 /* error hole */
823 kprintf(("_res_heap_check: internal error - memory hole!\n"));
824 return FALSE;
825 }
826
827 /* check signature and advance to the next block */
828 if (pmbUsed != NULL && (pmbFree == NULL || pmbUsed < pmbFree))
829 {
830 cbSize += CB_HDR + pmbUsed->cbSize;
831 cbUsed += pmbUsed->cbSize;
832 if (pmbUsed->ulSignature != MEMBLOCK_SIGNATURE)
833 return FALSE;
834 pmbLast = pmbUsed;
835 pmbUsed = pmbUsed->pNext;
836 }
837 else
838 {
839 cbSize += CB_HDR + pmbFree->cbSize;
840 cbFree += pmbFree->cbSize;
841 if (pmbFree->ulSignature != MEMBLOCK_SIGNATURE)
842 return FALSE;
843 pmbLast = pmbFree;
844 pmbFree = pmbFree->pNext;
845 }
846 }
847
848
849 /*
850 * Check the cbFree and cbUsed.
851 */
852 if (cbFree != pha->cbFree)
853 {
854 kprintf(("_res_heap_check: cbFree(%d) != pha->cbFree(%d)\n", cbFree, pha->cbFree));
855 return FALSE;
856 }
857
858 if (cbUsed != pha->cbUsed)
859 {
860 kprintf(("_res_heap_check: cbUsed(%d) != pha->cbUsed(%d)\n", cbUsed, pha->cbUsed));
861 return FALSE;
862 }
863
864 if (cbSize != pha->cbSize)
865 {
866 kprintf(("_res_heap_check: cbTotal(%d) != pha->cbSize(%d)\n", cbSize, pha->cbSize));
867 return FALSE;
868 }
869 /*
870 * Check right most node.
871 */
872 if (pmbLast == NULL || (unsigned)pha + pha->cbSize != (unsigned)PNEXT_BLOCK(pmbLast))
873 {
874 kprintf(("_res_heap_check: The last free/used block dont end at the end of memory block.\n"
875 " pmbLast(end)=0x%08x, pha+pha->cbSize=0x%08x\n",
876 pmbLast != NULL ? PNEXT_BLOCK(pmbLast) : NULL, (unsigned)pha + pha->cbSize));
877 return FALSE;
878 }
879
880
881 /*
882 * Next heap anchor
883 */
884 phaPrev = pha;
885 pha = pha->pNext;
886 }
887
888 /* check that end of chain is phaLast */
889 if (phaPrev != phaLast)
890 {
891 kprintf(("_res_heap_check: internal error - heap anchor chain didn't end on phaLast\n"));
892 return FALSE;
893 }
894
895#endif
896
897 return TRUE;
898}
899
900
901
902/**
903 * Frees unused heapanchors.
904 */
905void _res_heapmin(void)
906{
907 PHEAPANCHOR pha = phaLast;
908
909 while (pha != NULL && pha != phaFirst)
910 {
911 if (pha->cbUsed == 0)
912 {
913 APIRET rc;
914 PHEAPANCHOR phaToBeFreed = pha;
915 if (pha->pPrev != NULL)
916 pha->pPrev->pNext = pha->pNext;
917 else
918 phaFirst = pha->pPrev->pNext;
919 if (pha->pNext != NULL)
920 pha->pNext->pPrev = pha->pPrev;
921 else
922 phaLast = pha->pPrev;
923 pha = pha->pPrev;
924
925 /* free heap */
926 #ifdef RING0
927 rc = D32Hlp_VMFree(phaToBeFreed);
928 #else
929 rc = DosFreeMem(phaToBeFreed);
930 #endif
931 if (rc != NO_ERROR)
932 kprintf(("_res_heapmin: DosFreeMem failed for pha=0x%08x, rc = %d\n",
933 pha, rc));
934 }
935 else
936 pha = pha->pPrev;
937 }
938}
939
940
941/**
942 * Dumps a summary of the subheaps (heapanchor chain).
943 */
944void _res_dump_subheaps(void)
945{
946 PHEAPANCHOR pha;
947 int i;
948 unsigned cbTotalFree;
949 unsigned cTotalFree;
950 unsigned cbTotalUsed;
951 unsigned cTotalUsed;
952
953 kprintf(("------------------------------------\n"
954 "- Dumping subheap blocks (summary) -\n"
955 "------------------------------------\n"
956 ));
957
958 i = 0;
959 cTotalFree = 0;
960 cTotalUsed = 0;
961 cbTotalFree = 0;
962 cbTotalUsed = 0;
963 pha = phaFirst;
964 while (pha != NULL)
965 {
966 PMEMBLOCK pmb;
967 unsigned cbFree = 0;
968 unsigned cFree = 0;
969 unsigned cbUsed = 0;
970 unsigned cUsed = 0;
971
972
973 pmb = pha->pmbUsed;
974 while (pmb != NULL)
975 {
976 cUsed++;
977 cbUsed += pmb->cbSize;
978 pmb = pmb->pNext;
979 }
980
981 pmb = pha->pmbFree;
982 while (pmb != NULL)
983 {
984 cFree++;
985 cbFree += pmb->cbSize;
986 pmb = pmb->pNext;
987 }
988
989 kprintf(("HeapAnchor %2d addr=0x%08x cbSize=%6d cbFree=%6d cbUsed=%6d cUsed=%4d cFree=%d\n",
990 i, pha, pha->cbSize, pha->cbFree, pha->cbUsed, cUsed, cFree));
991
992 cTotalFree += cFree;
993 cbTotalFree += cbFree;
994 cTotalUsed += cUsed;
995 cbTotalUsed += cbUsed;
996
997 /* next */
998 pha = pha->pNext;
999 i++;
1000 }
1001
1002 kprintf(("-----------------------------------------------------------------------------\n"
1003 " Free=%d #Free=%d AverageFree=%d Used=%d #Used=%d AverageUsed=%d\n"
1004 "-----------------------------------------------------------------------------\n",
1005 cbTotalFree, cTotalFree, cTotalFree > 0 ? cbTotalFree / cTotalFree : 0,
1006 cbTotalUsed, cTotalUsed, cTotalUsed > 0 ? cbTotalUsed / cTotalUsed : 0
1007 ));
1008}
1009
1010
1011/**
1012 * Dumps all allocated memory.
1013 */
1014void _res_dump_allocated(unsigned cb)
1015{
1016 PHEAPANCHOR pha;
1017 unsigned cBlocks;
1018 unsigned cbAllocated;
1019
1020 kprintf(("----------------------------\n"
1021 "- Dumping allocated blocks -\n"
1022 "----------------------------\n"));
1023
1024 cBlocks = 0;
1025 cbAllocated = 0;
1026 pha = phaFirst;
1027 while (pha != NULL)
1028 {
1029 PMEMBLOCK pmb = pha->pmbUsed;
1030 while (pmb != NULL)
1031 {
1032 int i;
1033 cBlocks++;
1034 cbAllocated += pmb->cbSize;
1035
1036 kprintf(("pvUserData=0x%08x cbSize=%6d\n",
1037 &pmb->achUserData[0], pmb->cbSize
1038 ));
1039 /* dump cb of the block */
1040 i = 0;
1041 while (i < cb)
1042 {
1043 int j;
1044
1045 /* hex */
1046 j = 0;
1047 while (j < 16)
1048 {
1049 if (j+i < cb && j+i < pmb->cbSize)
1050 kprintf((" %02x", pmb->achUserData[j+i]));
1051 else
1052 kprintf((" "));
1053 if (j == 7)
1054 kprintf((" -"));
1055 j++;
1056 }
1057
1058 /* ascii */
1059 j = 0;
1060 kprintf((" "));
1061 while (j < 16 && j+i < pmb->cbSize && j+i < cb)
1062 {
1063 kprintf(("%c", pmb->achUserData[j+i] < 0x20 ? '.' : pmb->achUserData[j+i]));
1064 j++;
1065 }
1066 kprintf(("\n"));
1067 i += j;
1068 }
1069
1070 /* next */
1071 pmb = pmb->pNext;
1072 }
1073
1074 /* next */
1075 pha = pha->pNext;
1076 }
1077
1078 kprintf((
1079 "---------------------------------------------\n"
1080 " #Blocks=%6d Allocated=%9d (bytes)\n"
1081 "---------------------------------------------\n",
1082 cBlocks, cbAllocated
1083 ));
1084
1085}
Note: See TracBrowser for help on using the repository browser.