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

Last change on this file since 2501 was 2501, checked in by bird, 26 years ago

Temporary backup checkin.

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