Changeset 13 for trunk/src/helpers/memdebug.c
- Timestamp:
- Nov 23, 2000, 7:36:41 PM (25 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/helpers/memdebug.c
r8 r13 1 1 2 2 /* 3 * memdebug.c: 4 * memory debugging helpers. Memory debugging is enabled 5 * if the __XWPMEMDEBUG__ #define is set in setup.h. 3 *@@sourcefile memdebug.c: 4 * memory debugging helpers. 6 5 * 7 6 * Several things are in here which might turn out to … … 12 11 * -- Sophisticated heap debugging functions, which 13 12 * automatically replace malloc() and free() etc. 14 * when XWorkplace is compiled with debug code. 13 * If the __XWPMEMDEBUG__ #define is set before including 14 * memdebug.h, all those standard library calls 15 * are remapped to use the functions in this file 16 * instead. 17 * 18 * At present, malloc(), calloc(), realloc(), strdup() 19 * and free() are supported. 20 * 15 21 * These log every memory allocation made and log 16 22 * much more data compared to the VAC++ memory … … 28 34 * function. 29 35 * 30 * At present, malloc(), calloc(), strdup() and free()31 * are supported. If you invoke free() on a memory block32 * allocated by a function other than the above, you'll33 * get a runtime error.34 *35 36 * These debug functions have been added with V0.9.3 36 37 * and should now be compiler-independent. 37 38 * 38 * -- A PM heap debugging window which shows the statuzs 39 * V0.9.6 added realloc() support and fixed a few bugs. 40 * 41 * -- A PM heap debugging window which shows the status 39 42 * of the heap logging list. See memdCreateMemDebugWindow 40 * for details. 41 * 42 * To enable memory debugging, do the following: 43 * (memdebug_win.c) for details. 44 * 45 * To enable memory debugging, do the following in each (!) 46 * of your code modules: 43 47 * 44 48 * 1) Include at least <stdlib.h> and <string.h>. … … 53 57 * That's all. XWorkplace's setup.h does this automatically 54 58 * if XWorkplace is compiled with debug code. 59 * 60 * A couple of WARNINGS: 61 * 62 * 1) Memory debugging can greatly slow down the system 63 * after a while. When free() is invoked, the memory 64 * that was allocated is freed, but not the memory 65 * log entry (the HEAPITEM) to allow tracing what was 66 * freed. As a result, the linked list of memory items 67 * keeps growing longer, and free() becomes terribly 68 * slow after a while because it must traverse the 69 * entire list for each free() call. Use memdReleaseFreed 70 * from time to time. 71 * 72 * 2) The replacement functions in this file allocate 73 * extra memory for the magic strings. For example, if 74 * you call malloc(100), more than 100 bytes get allocated 75 * to allow for storing the magic strings to detect 76 * memory overwrites. Two magic strings are allocated, 77 * one before the actual buffer, and one behind it. 78 * 79 * As a result, YOU MUST NOT confuse the replacement 80 * memory functions with the original ones. If you 81 * use malloc() in one source file and free() the 82 * buffer in another one where debug memory has not 83 * been enabled, you'll get crashes. 84 * 85 * As a rule of thumb, enable memory debugging for all 86 * your source files or for none. And make sure everything 87 * is recompiled when you change your mind. 55 88 * 56 89 *@@added V0.9.1 (2000-02-12) [umoeller] … … 80 113 #define INCL_DOSERRORS 81 114 82 #define INCL_WINWINDOWMGR83 #define INCL_WINFRAMEMGR84 #define INCL_WINCOUNTRY85 #define INCL_WINSYS86 #define INCL_WINMENUS87 #define INCL_WINSTDCNR88 115 #include <os2.h> 89 116 90 117 #include <stdio.h> 91 118 #include <string.h> 92 // #include <malloc.h>93 119 #include <setjmp.h> 94 120 95 #define DONT_REPLACE_MALLOC // we need the "real" malloc in this file 121 #define DONT_REPLACE_MALLOC // never do debug memory for this 122 #define MEMDEBUG_PRIVATE 96 123 #include "setup.h" 97 124 98 125 #ifdef __XWPMEMDEBUG__ 99 126 100 #include "helpers\cnrh.h"101 127 #include "helpers\except.h" 102 //#include "helpers\memdebug.h" // included by setup.h already128 #include "helpers\memdebug.h" // included by setup.h already 103 129 #include "helpers\stringh.h" 104 #include "helpers\winh.h"105 130 106 131 /* … … 120 145 #define MEMBLOCKMAGIC_TAIL "\250\210&%/dfjsk%#,dlhf\223" 121 146 122 /*123 *@@ HEAPITEM:124 * informational structure created for each125 * malloc() call by memdMalloc. These are stored126 * in a global linked list (G_pHeapItemsRoot).127 *128 * We cannot use the linklist.c functions for129 * managing the linked list because these use130 * malloc in turn, which would lead to infinite131 * loops.132 *133 *@@added V0.9.3 (2000-04-11) [umoeller]134 */135 136 typedef struct _HEAPITEM137 {138 struct _HEAPITEM *pNext; // next item in linked list or NULL if last139 140 void *pAfterMagic; // memory pointer returned by memdMalloc;141 // this points to after the magic string142 unsigned long ulSize; // size of *pData143 144 const char *pcszSourceFile; // as passed to memdMalloc145 unsigned long ulLine; // as passed to memdMalloc146 const char *pcszFunction; // as passed to memdMalloc147 148 DATETIME dtAllocated; // system date/time at time of memdMalloc call149 150 ULONG ulTID; // thread ID that memdMalloc was running on151 152 BOOL fFreed; // TRUE only after item has been freed by memdFree153 } HEAPITEM, *PHEAPITEM;154 155 147 HMTX G_hmtxMallocList = NULLHANDLE; 156 148 157 PHEAPITEM G_pHeapItemsRoot = NULL, 158 G_pHeapItemsLast = NULL; 159 160 PSZ G_pszMemCnrTitle = NULL; 149 extern PHEAPITEM G_pHeapItemsRoot = NULL; 150 PHEAPITEM G_pHeapItemsLast = NULL; 161 151 162 152 PFNCBMEMDLOG G_pMemdLogFunc = NULL; 163 153 164 ULONG G_ulItemsReleased = 0, 165 154 extern ULONG G_ulItemsReleased = 0; 155 extern ULONG G_ulBytesReleased = 0; 166 156 167 157 /* ****************************************************************** … … 189 179 arc = DosCreateMutexSem(NULL, 190 180 &G_hmtxMallocList, 191 0, 192 FALSE);193 194 arc = DosRequestMutexSem(G_hmtxMallocList,195 SEM_INDEFINITE_WAIT);181 0, // unshared 182 TRUE); // request now! 183 else 184 arc = DosRequestMutexSem(G_hmtxMallocList, 185 SEM_INDEFINITE_WAIT); 196 186 197 187 return (arc == NO_ERROR); … … 435 425 pHeapItem->fFreed = TRUE; 436 426 437 /* lstRemoveNode(&G_llHeapItems,438 pNode); */439 427 fFound = TRUE; 440 428 break; 441 } 429 } // if (!pHeapItem->fFreed) 442 430 443 431 pHeapItem = pHeapItem->pNext; … … 452 440 CHAR szMsg[1000]; 453 441 sprintf(szMsg, 454 "free() failed. Calledfrom %s (%s, line %d) for object 0x%lX.",442 "free() called with invalid object from %s (%s, line %d) for object 0x%lX.", 455 443 pcszFunction, 456 444 pcszSourceFile, … … 459 447 G_pMemdLogFunc(szMsg); 460 448 } 449 } 450 451 /* 452 *@@ memdRealloc: 453 * wrapper function for realloc(). See memdMalloc for 454 * details. 455 * 456 *@@added V0.9.6 (2000-11-12) [umoeller] 457 */ 458 459 void* memdRealloc(void *p, 460 size_t stSize, 461 const char *pcszSourceFile, // in: source file name 462 unsigned long ulLine, // in: source line 463 const char *pcszFunction) // in: function name 464 { 465 void *prc = NULL; 466 BOOL fFound = FALSE; 467 468 if (memdLock()) 469 { 470 PHEAPITEM pHeapItem = G_pHeapItemsRoot; 471 472 // search the list with the pointer which was 473 // really returned by the original malloc(), 474 // that is, the byte before the magic string 475 void *pBeforeMagic = ((PBYTE)p) - sizeof(MEMBLOCKMAGIC_HEAD); 476 477 while (pHeapItem) 478 { 479 if (pHeapItem->pAfterMagic == p) 480 // the same address may be allocated and freed 481 // several times, so if this address has been 482 // freed, search on 483 if (!pHeapItem->fFreed) 484 { 485 // found: 486 PVOID pObjNew = 0; 487 ULONG ulError = 0; 488 ULONG cbCopy = 0; 489 PTIB ptib; 490 PPIB ppib; 491 492 // check magic string 493 if (memcmp(pBeforeMagic, 494 MEMBLOCKMAGIC_HEAD, 495 sizeof(MEMBLOCKMAGIC_HEAD)) 496 != 0) 497 ulError = 1; 498 else if (memcmp(((PBYTE)pHeapItem->pAfterMagic) + pHeapItem->ulSize, 499 MEMBLOCKMAGIC_TAIL, 500 sizeof(MEMBLOCKMAGIC_TAIL)) 501 != 0) 502 ulError = 2; 503 504 if (ulError) 505 { 506 // magic block has been overwritten: 507 if (G_pMemdLogFunc) 508 { 509 CHAR szMsg[1000]; 510 sprintf(szMsg, 511 "Magic string %s memory block at 0x%lX has been overwritten.\n" 512 "This was detected by the realloc() call at %s (%s, line %d).\n" 513 "The block was allocated by %s (%s, line %d).", 514 (ulError == 1) ? "before" : "after", 515 p, 516 pcszFunction, 517 pcszSourceFile, 518 ulLine, // free 519 pHeapItem->pcszFunction, 520 pHeapItem->pcszSourceFile, 521 pHeapItem->ulLine); 522 G_pMemdLogFunc(szMsg); 523 } 524 } 525 526 // now reallocate! 527 pObjNew = malloc(stSize // new size 528 + sizeof(MEMBLOCKMAGIC_HEAD) 529 + sizeof(MEMBLOCKMAGIC_TAIL)); 530 531 // store "front" magic string 532 memcpy(pObjNew, 533 MEMBLOCKMAGIC_HEAD, 534 sizeof(MEMBLOCKMAGIC_HEAD)); 535 // return address: first byte after "front" magic string 536 prc = ((PBYTE)pObjNew) + sizeof(MEMBLOCKMAGIC_HEAD); 537 538 // bytes to copy: the smaller of the old and the new size 539 cbCopy = pHeapItem->ulSize; 540 if (stSize < pHeapItem->ulSize) 541 cbCopy = stSize; 542 543 // copy buffer from old memory object 544 memcpy(prc, // after "front" magic 545 pHeapItem->pAfterMagic, 546 cbCopy); 547 548 // store "tail" magic string to block which 549 // will be returned plus the size which was requested 550 memcpy(((PBYTE)prc) + stSize, 551 MEMBLOCKMAGIC_TAIL, 552 sizeof(MEMBLOCKMAGIC_TAIL)); 553 554 // free the old buffer 555 free(pBeforeMagic); 556 557 // update the HEAPITEM 558 pHeapItem->pAfterMagic = prc; // new pointer! 559 pHeapItem->ulSize = stSize; // new size! 560 pHeapItem->pcszSourceFile = pcszSourceFile; 561 pHeapItem->ulLine = ulLine; 562 pHeapItem->pcszFunction = pcszFunction; 563 564 // update date, time, TID 565 DosGetDateTime(&pHeapItem->dtAllocated); 566 pHeapItem->ulTID = 0; 567 if (DosGetInfoBlocks(&ptib, &ppib) == NO_ERROR) 568 if (ptib) 569 if (ptib->tib_ptib2) 570 pHeapItem->ulTID = ptib->tib_ptib2->tib2_ultid; 571 572 fFound = TRUE; 573 break; 574 } // if (!pHeapItem->fFreed) 575 576 pHeapItem = pHeapItem->pNext; 577 } 578 579 memdUnlock(); 580 } 581 582 if (!fFound) 583 if (G_pMemdLogFunc) 584 { 585 CHAR szMsg[1000]; 586 sprintf(szMsg, 587 "realloc() called with invalid object from %s (%s, line %d) for object 0x%lX.", 588 pcszFunction, 589 pcszSourceFile, 590 ulLine, 591 p); 592 G_pMemdLogFunc(szMsg); 593 } 594 595 return (prc); 461 596 } 462 597 … … 485 620 while (pHeapItem) 486 621 { 622 // store next first, because we can change the "next" pointer 487 623 PHEAPITEM pNext = pHeapItem->pNext; // can be NULL 624 488 625 if (pHeapItem->fFreed) 489 626 { 490 // item freed:627 // item was freed: 491 628 if (pPrevious == NULL) 492 629 // head of list: … … 499 636 ulItemsReleased++; 500 637 ulBytesReleased += pHeapItem->ulSize; 638 639 if (pHeapItem == G_pHeapItemsLast) 640 // reset "last item" cache 641 G_pHeapItemsLast = NULL; 501 642 502 643 free(pHeapItem); … … 550 691 #endif 551 692 552 /* ******************************************************************553 * *554 * Heap debugging window *555 * *556 ********************************************************************/557 558 /*559 *@@ MEMRECORD:560 *561 *@@added V0.9.1 (99-12-04) [umoeller]562 */563 564 typedef struct _MEMRECORD565 {566 RECORDCORE recc;567 568 ULONG ulIndex;569 570 CDATE cdateAllocated;571 CTIME ctimeAllocated;572 573 PSZ pszFreed;574 575 ULONG ulTID;576 577 PSZ pszFunction; // points to szFunction578 CHAR szFunction[400];579 580 PSZ pszSource; // points to szSource581 CHAR szSource[CCHMAXPATH];582 583 ULONG ulLine;584 585 PSZ pszAddress; // points to szAddress586 CHAR szAddress[20];587 588 ULONG ulSize;589 590 } MEMRECORD, *PMEMRECORD;591 592 /* ULONG ulHeapItemsCount1,593 ulHeapItemsCount2;594 ULONG ulTotalAllocated,595 ulTotalFreed;596 PMEMRECORD pMemRecordThis = NULL;597 PSZ pszMemCnrTitle = NULL; */598 599 #if 0600 /*601 *@@ fncbMemHeapWalkCount:602 * callback func for _heap_walk function used for603 * fnwpMemDebug.604 *605 *@@added V0.9.1 (99-12-04) [umoeller]606 */607 608 int fncbMemHeapWalkCount(const void *pObject,609 size_t Size,610 int useflag,611 int status,612 const char *filename,613 size_t line)614 {615 // skip all the items which seem to be616 // internal to the runtime617 if ((filename) || (useflag == _FREEENTRY))618 {619 ulHeapItemsCount1++;620 if (useflag == _FREEENTRY)621 ulTotalFreed += Size;622 else623 ulTotalAllocated += Size;624 }625 return (0);626 }627 628 /*629 *@@ fncbMemHeapWalkFill:630 * callback func for _heap_walk function used for631 * fnwpMemDebug.632 *633 *@@added V0.9.1 (99-12-04) [umoeller]634 */635 636 int fncbMemHeapWalkFill(const void *pObject,637 size_t Size,638 int useflag,639 int status,640 const char *filename,641 size_t line)642 {643 // skip all the items which seem to be644 // internal to the runtime645 if ((filename) || (useflag == _FREEENTRY))646 {647 ulHeapItemsCount2++;648 if ((pMemRecordThis) && (ulHeapItemsCount2 < ulHeapItemsCount1))649 {650 pMemRecordThis->ulIndex = ulHeapItemsCount2 - 1;651 652 pMemRecordThis->pObject = pObject;653 pMemRecordThis->useflag = useflag;654 pMemRecordThis->status = status;655 pMemRecordThis->filename = filename;656 657 pMemRecordThis->pszAddress = pMemRecordThis->szAddress;658 659 pMemRecordThis->ulSize = Size;660 661 pMemRecordThis->pszSource = pMemRecordThis->szSource;662 663 pMemRecordThis->ulLine = line;664 665 pMemRecordThis = (PMEMRECORD)pMemRecordThis->recc.preccNextRecord;666 }667 else668 return (1); // stop669 }670 671 return (0);672 }673 674 /*675 *@@ memdCreateRecordsVAC:676 *677 *@@added V0.9.3 (2000-04-10) [umoeller]678 */679 680 VOID memdCreateRecordsVAC(HWND hwndCnr)681 {682 // count heap items683 ulHeapItemsCount1 = 0;684 ulTotalFreed = 0;685 ulTotalAllocated = 0;686 _heap_walk(fncbMemHeapWalkCount);687 688 pMemRecordFirst = (PMEMRECORD)cnrhAllocRecords(hwndCnr,689 sizeof(MEMRECORD),690 ulHeapItemsCount1);691 if (pMemRecordFirst)692 {693 ulHeapItemsCount2 = 0;694 pMemRecordThis = pMemRecordFirst;695 _heap_walk(fncbMemHeapWalkFill);696 697 // the following doesn't work while _heap_walk is running698 pMemRecordThis = pMemRecordFirst;699 while (pMemRecordThis)700 {701 switch (pMemRecordThis->useflag)702 {703 case _USEDENTRY: pMemRecordThis->pszUseFlag = "Used"; break;704 case _FREEENTRY: pMemRecordThis->pszUseFlag = "Freed"; break;705 }706 707 switch (pMemRecordThis->status)708 {709 case _HEAPBADBEGIN: pMemRecordThis->pszStatus = "heap bad begin"; break;710 case _HEAPBADNODE: pMemRecordThis->pszStatus = "heap bad node"; break;711 case _HEAPEMPTY: pMemRecordThis->pszStatus = "heap empty"; break;712 case _HEAPOK: pMemRecordThis->pszStatus = "OK"; break;713 }714 715 sprintf(pMemRecordThis->szAddress, "0x%lX", pMemRecordThis->pObject);716 strcpy(pMemRecordThis->szSource,717 (pMemRecordThis->filename)718 ? pMemRecordThis->filename719 : "?");720 721 pMemRecordThis = (PMEMRECORD)pMemRecordThis->recc.preccNextRecord;722 }723 724 cnrhInsertRecords(hwndCnr,725 NULL, // parent726 (PRECORDCORE)pMemRecordFirst,727 TRUE,728 NULL,729 CRA_RECORDREADONLY,730 ulHeapItemsCount2);731 }732 }733 734 #endif735 736 /*737 *@@ memdCreateRecords:738 *739 *@@added V0.9.3 (2000-04-10) [umoeller]740 */741 742 VOID memdCreateRecords(HWND hwndCnr,743 PULONG pulTotalItems,744 PULONG pulAllocatedItems,745 PULONG pulFreedItems,746 PULONG pulTotalBytes,747 PULONG pulAllocatedBytes,748 PULONG pulFreedBytes)749 {750 // count heap items751 ULONG ulHeapItemsCount1 = 0;752 PMEMRECORD pMemRecordFirst;753 754 if (memdLock())755 {756 // PLISTNODE pNode = lstQueryFirstNode(&G_llHeapItems);757 PHEAPITEM pHeapItem = G_pHeapItemsRoot;758 759 *pulTotalItems = 0;760 *pulAllocatedItems = 0;761 *pulFreedItems = 0;762 763 *pulTotalBytes = 0;764 *pulAllocatedBytes = 0;765 *pulFreedBytes = 0;766 767 while (pHeapItem)768 {769 ulHeapItemsCount1++;770 if (pHeapItem->fFreed)771 {772 (*pulFreedItems)++;773 (*pulFreedBytes) += pHeapItem->ulSize;774 }775 else776 {777 (*pulAllocatedItems)++;778 (*pulAllocatedBytes) += pHeapItem->ulSize;779 }780 781 (*pulTotalBytes) += pHeapItem->ulSize;782 783 pHeapItem = pHeapItem->pNext;784 }785 786 *pulTotalItems = ulHeapItemsCount1;787 788 pMemRecordFirst = (PMEMRECORD)cnrhAllocRecords(hwndCnr,789 sizeof(MEMRECORD),790 ulHeapItemsCount1);791 if (pMemRecordFirst)792 {793 ULONG ulHeapItemsCount2 = 0;794 PMEMRECORD pMemRecordThis = pMemRecordFirst;795 pHeapItem = G_pHeapItemsRoot;796 // PLISTNODE pMemNode = lstQueryFirstNode(&G_llHeapItems);797 798 while ((pMemRecordThis) && (pHeapItem))799 {800 // PHEAPITEM pHeapItem = (PHEAPITEM)pMemNode->pItemData;801 802 pMemRecordThis->ulIndex = ulHeapItemsCount2++;803 804 cnrhDateTimeDos2Win(&pHeapItem->dtAllocated,805 &pMemRecordThis->cdateAllocated,806 &pMemRecordThis->ctimeAllocated);807 808 if (pHeapItem->fFreed)809 pMemRecordThis->pszFreed = "yes";810 811 pMemRecordThis->ulTID = pHeapItem->ulTID;812 813 strcpy(pMemRecordThis->szSource, pHeapItem->pcszSourceFile);814 pMemRecordThis->pszSource = pMemRecordThis->szSource;815 816 pMemRecordThis->ulLine = pHeapItem->ulLine;817 818 strcpy(pMemRecordThis->szFunction, pHeapItem->pcszFunction);819 pMemRecordThis->pszFunction = pMemRecordThis->szFunction;820 821 sprintf(pMemRecordThis->szAddress, "0x%lX", pHeapItem->pAfterMagic);822 pMemRecordThis->pszAddress = pMemRecordThis->szAddress;823 824 pMemRecordThis->ulSize = pHeapItem->ulSize;825 826 827 /* switch (pMemRecordThis->useflag)828 {829 case _USEDENTRY: pMemRecordThis->pszUseFlag = "Used"; break;830 case _FREEENTRY: pMemRecordThis->pszUseFlag = "Freed"; break;831 }832 833 switch (pMemRecordThis->status)834 {835 case _HEAPBADBEGIN: pMemRecordThis->pszStatus = "heap bad begin"; break;836 case _HEAPBADNODE: pMemRecordThis->pszStatus = "heap bad node"; break;837 case _HEAPEMPTY: pMemRecordThis->pszStatus = "heap empty"; break;838 case _HEAPOK: pMemRecordThis->pszStatus = "OK"; break;839 }840 841 sprintf(pMemRecordThis->szAddress, "0x%lX", pMemRecordThis->pObject);842 strcpy(pMemRecordThis->szSource,843 (pMemRecordThis->filename)844 ? pMemRecordThis->filename845 : "?"); */846 847 pMemRecordThis = (PMEMRECORD)pMemRecordThis->recc.preccNextRecord;848 pHeapItem = pHeapItem->pNext;849 }850 851 cnrhInsertRecords(hwndCnr,852 NULL, // parent853 (PRECORDCORE)pMemRecordFirst,854 TRUE,855 NULL,856 CRA_RECORDREADONLY,857 ulHeapItemsCount2);858 }859 860 memdUnlock();861 }862 }863 864 /*865 *@@ mnu_fnCompareIndex:866 *867 *@@added V0.9.1 (99-12-03) [umoeller]868 */869 870 SHORT EXPENTRY mnu_fnCompareIndex(PMEMRECORD pmrc1, PMEMRECORD pmrc2, PVOID pStorage)871 {872 // HAB habDesktop = WinQueryAnchorBlock(HWND_DESKTOP);873 pStorage = pStorage; // to keep the compiler happy874 if ((pmrc1) && (pmrc2))875 if (pmrc1->ulIndex < pmrc2->ulIndex)876 return (-1);877 else if (pmrc1->ulIndex > pmrc2->ulIndex)878 return (1);879 880 return (0);881 }882 883 /*884 *@@ mnu_fnCompareSourceFile:885 *886 *@@added V0.9.1 (99-12-03) [umoeller]887 */888 889 SHORT EXPENTRY mnu_fnCompareSourceFile(PMEMRECORD pmrc1, PMEMRECORD pmrc2, PVOID pStorage)890 {891 HAB habDesktop = WinQueryAnchorBlock(HWND_DESKTOP);892 pStorage = pStorage; // to keep the compiler happy893 if ((pmrc1) && (pmrc2))894 switch (WinCompareStrings(habDesktop, 0, 0,895 pmrc1->szSource,896 pmrc2->szSource,897 0))898 {899 case WCS_LT: return (-1);900 case WCS_GT: return (1);901 default: // equal902 if (pmrc1->ulLine < pmrc2->ulLine)903 return (-1);904 else if (pmrc1->ulLine > pmrc2->ulLine)905 return (1);906 907 }908 909 return (0);910 }911 912 #define ID_MEMCNR 1000913 914 /*915 *@@ memd_fnwpMemDebug:916 * client window proc for the heap debugger window917 * accessible from the Desktop context menu if918 * __XWPMEMDEBUG__ is defined. Otherwise, this is not919 * compiled.920 *921 * Usage: this is a regular PM client window procedure922 * to be used with WinRegisterClass and WinCreateStdWindow.923 * See dtpMenuItemSelected, which uses this.924 *925 * This creates a container with all the memory objects926 * with the size of the client area in turn.927 *928 *@@added V0.9.1 (99-12-04) [umoeller]929 */930 931 932 MRESULT EXPENTRY memd_fnwpMemDebug(HWND hwndClient, ULONG msg, MPARAM mp1, MPARAM mp2)933 {934 MRESULT mrc = 0;935 936 switch (msg)937 {938 case WM_CREATE:939 {940 TRY_LOUD(excpt1, NULL)941 {942 // PCREATESTRUCT pcs = (PCREATESTRUCT)mp2;943 HWND hwndCnr;944 hwndCnr = WinCreateWindow(hwndClient, // parent945 WC_CONTAINER,946 "",947 WS_VISIBLE | CCS_MINIICONS | CCS_READONLY | CCS_SINGLESEL,948 0, 0, 0, 0,949 hwndClient, // owner950 HWND_TOP,951 ID_MEMCNR,952 NULL, NULL);953 if (hwndCnr)954 {955 XFIELDINFO xfi[11];956 PFIELDINFO pfi = NULL;957 PMEMRECORD pMemRecordFirst;958 int i = 0;959 960 ULONG ulTotalItems = 0,961 ulAllocatedItems = 0,962 ulFreedItems = 0;963 ULONG ulTotalBytes = 0,964 ulAllocatedBytes = 0,965 ulFreedBytes = 0;966 967 // set up cnr details view968 xfi[i].ulFieldOffset = FIELDOFFSET(MEMRECORD, ulIndex);969 xfi[i].pszColumnTitle = "No.";970 xfi[i].ulDataType = CFA_ULONG;971 xfi[i++].ulOrientation = CFA_RIGHT;972 973 xfi[i].ulFieldOffset = FIELDOFFSET(MEMRECORD, cdateAllocated);974 xfi[i].pszColumnTitle = "Date";975 xfi[i].ulDataType = CFA_DATE;976 xfi[i++].ulOrientation = CFA_LEFT;977 978 xfi[i].ulFieldOffset = FIELDOFFSET(MEMRECORD, ctimeAllocated);979 xfi[i].pszColumnTitle = "Time";980 xfi[i].ulDataType = CFA_TIME;981 xfi[i++].ulOrientation = CFA_LEFT;982 983 xfi[i].ulFieldOffset = FIELDOFFSET(MEMRECORD, pszFreed);984 xfi[i].pszColumnTitle = "Freed";985 xfi[i].ulDataType = CFA_STRING;986 xfi[i++].ulOrientation = CFA_CENTER;987 988 xfi[i].ulFieldOffset = FIELDOFFSET(MEMRECORD, ulTID);989 xfi[i].pszColumnTitle = "TID";990 xfi[i].ulDataType = CFA_ULONG;991 xfi[i++].ulOrientation = CFA_RIGHT;992 993 xfi[i].ulFieldOffset = FIELDOFFSET(MEMRECORD, pszFunction);994 xfi[i].pszColumnTitle = "Function";995 xfi[i].ulDataType = CFA_STRING;996 xfi[i++].ulOrientation = CFA_LEFT;997 998 xfi[i].ulFieldOffset = FIELDOFFSET(MEMRECORD, pszSource);999 xfi[i].pszColumnTitle = "Source";1000 xfi[i].ulDataType = CFA_STRING;1001 xfi[i++].ulOrientation = CFA_LEFT;1002 1003 xfi[i].ulFieldOffset = FIELDOFFSET(MEMRECORD, ulLine);1004 xfi[i].pszColumnTitle = "Line";1005 xfi[i].ulDataType = CFA_ULONG;1006 xfi[i++].ulOrientation = CFA_RIGHT;1007 1008 xfi[i].ulFieldOffset = FIELDOFFSET(MEMRECORD, ulSize);1009 xfi[i].pszColumnTitle = "Size";1010 xfi[i].ulDataType = CFA_ULONG;1011 xfi[i++].ulOrientation = CFA_RIGHT;1012 1013 xfi[i].ulFieldOffset = FIELDOFFSET(MEMRECORD, pszAddress);1014 xfi[i].pszColumnTitle = "Address";1015 xfi[i].ulDataType = CFA_STRING;1016 xfi[i++].ulOrientation = CFA_LEFT;1017 1018 pfi = cnrhSetFieldInfos(hwndCnr,1019 &xfi[0],1020 i, // array item count1021 TRUE, // no draw lines1022 3); // return column1023 1024 {1025 PSZ pszFont = "9.WarpSans";1026 WinSetPresParam(hwndCnr,1027 PP_FONTNAMESIZE,1028 strlen(pszFont),1029 pszFont);1030 }1031 1032 memdCreateRecords(hwndCnr,1033 &ulTotalItems,1034 &ulAllocatedItems,1035 &ulFreedItems,1036 &ulTotalBytes,1037 &ulAllocatedBytes,1038 &ulFreedBytes);1039 1040 BEGIN_CNRINFO()1041 {1042 CHAR szCnrTitle[1000];1043 CHAR szTotalItems[100],1044 szAllocatedItems[100],1045 szFreedItems[100],1046 szReleasedItems[100];1047 CHAR szTotalBytes[100],1048 szAllocatedBytes[100],1049 szFreedBytes[100],1050 szReleasedBytes[100];1051 sprintf(szCnrTitle,1052 "Total logs in use: %s items = %s bytes\n"1053 " Total in use: %s items = %s bytes\n"1054 " Total freed: %s items = %s bytes\n"1055 "Total logs released: %s items = %s bytes",1056 strhThousandsDouble(szTotalItems,1057 ulTotalItems,1058 '.'),1059 strhThousandsDouble(szTotalBytes,1060 ulTotalBytes,1061 '.'),1062 strhThousandsDouble(szAllocatedItems,1063 ulAllocatedItems,1064 '.'),1065 strhThousandsDouble(szAllocatedBytes,1066 ulAllocatedBytes,1067 '.'),1068 strhThousandsDouble(szFreedItems,1069 ulFreedItems,1070 '.'),1071 strhThousandsDouble(szFreedBytes,1072 ulFreedBytes,1073 '.'),1074 strhThousandsDouble(szReleasedItems,1075 G_ulItemsReleased,1076 '.'),1077 strhThousandsDouble(szReleasedBytes,1078 G_ulBytesReleased,1079 '.'));1080 G_pszMemCnrTitle = strdup(szCnrTitle);1081 cnrhSetTitle(G_pszMemCnrTitle);1082 cnrhSetView(CV_DETAIL | CV_MINI | CA_DETAILSVIEWTITLES1083 | CA_DRAWICON1084 | CA_CONTAINERTITLE | CA_TITLEREADONLY1085 | CA_TITLESEPARATOR | CA_TITLELEFT);1086 cnrhSetSplitBarAfter(pfi);1087 cnrhSetSplitBarPos(250);1088 } END_CNRINFO(hwndCnr);1089 1090 WinSetFocus(HWND_DESKTOP, hwndCnr);1091 }1092 }1093 CATCH(excpt1) {} END_CATCH();1094 1095 mrc = WinDefWindowProc(hwndClient, msg, mp1, mp2);1096 break; }1097 1098 case WM_WINDOWPOSCHANGED:1099 {1100 PSWP pswp = (PSWP)mp1;1101 mrc = WinDefWindowProc(hwndClient, msg, mp1, mp2);1102 if (pswp->fl & SWP_SIZE)1103 {1104 WinSetWindowPos(WinWindowFromID(hwndClient, ID_MEMCNR), // cnr1105 HWND_TOP,1106 0, 0, pswp->cx, pswp->cy,1107 SWP_SIZE | SWP_MOVE | SWP_SHOW);1108 }1109 break; }1110 1111 case WM_CONTROL:1112 {1113 USHORT usItemID = SHORT1FROMMP(mp1),1114 usNotifyCode = SHORT2FROMMP(mp1);1115 if (usItemID == ID_MEMCNR) // cnr1116 {1117 switch (usNotifyCode)1118 {1119 case CN_CONTEXTMENU:1120 {1121 PMEMRECORD precc = (PMEMRECORD)mp2;1122 if (precc == NULL)1123 {1124 // whitespace1125 HWND hwndMenu = WinCreateMenu(HWND_DESKTOP,1126 NULL); // no menu template1127 winhInsertMenuItem(hwndMenu,1128 MIT_END,1129 1001,1130 "Sort by index",1131 MIS_TEXT, 0);1132 winhInsertMenuItem(hwndMenu,1133 MIT_END,1134 1002,1135 "Sort by source file",1136 MIS_TEXT, 0);1137 cnrhShowContextMenu(WinWindowFromID(hwndClient, ID_MEMCNR),1138 NULL, // record1139 hwndMenu,1140 hwndClient);1141 }1142 }1143 }1144 }1145 break; }1146 1147 case WM_COMMAND:1148 switch (SHORT1FROMMP(mp1))1149 {1150 case 1001: // sort by index1151 WinSendMsg(WinWindowFromID(hwndClient, ID_MEMCNR),1152 CM_SORTRECORD,1153 (MPARAM)mnu_fnCompareIndex,1154 0);1155 break;1156 1157 case 1002: // sort by source file1158 WinSendMsg(WinWindowFromID(hwndClient, ID_MEMCNR),1159 CM_SORTRECORD,1160 (MPARAM)mnu_fnCompareSourceFile,1161 0);1162 break;1163 }1164 break;1165 1166 case WM_CLOSE:1167 WinDestroyWindow(WinWindowFromID(hwndClient, ID_MEMCNR));1168 WinDestroyWindow(WinQueryWindow(hwndClient, QW_PARENT));1169 free(G_pszMemCnrTitle);1170 G_pszMemCnrTitle = NULL;1171 break;1172 1173 default:1174 mrc = WinDefWindowProc(hwndClient, msg, mp1, mp2);1175 }1176 1177 return (mrc);1178 }1179 1180 /*1181 *@@ memdCreateMemDebugWindow:1182 * creates a heap debugging window which1183 * is a standard frame with a container,1184 * listing all heap objects ever allocated.1185 *1186 * The client of this standard frame is in1187 * memd_fnwpMemDebug.1188 *1189 * This thing lists all calls to malloc()1190 * which were ever made, including the1191 * source file and source line number which1192 * made the call. Extreeeemely useful for1193 * detecting memory leaks.1194 *1195 * This only works if the memory functions1196 * have been replaced with the debug versions1197 * in this file.1198 */1199 1200 VOID memdCreateMemDebugWindow(VOID)1201 {1202 ULONG flStyle = FCF_TITLEBAR | FCF_SYSMENU | FCF_HIDEMAX1203 | FCF_SIZEBORDER | FCF_SHELLPOSITION1204 | FCF_NOBYTEALIGN | FCF_TASKLIST;1205 if (WinRegisterClass(WinQueryAnchorBlock(HWND_DESKTOP),1206 "XWPMemDebug",1207 memd_fnwpMemDebug, 0L, 0))1208 {1209 HWND hwndClient;1210 HWND hwndMemFrame = WinCreateStdWindow(HWND_DESKTOP,1211 0L,1212 &flStyle,1213 "XWPMemDebug",1214 "Allocated XWorkplace Memory Objects",1215 0L,1216 NULLHANDLE, // resource1217 0,1218 &hwndClient);1219 if (hwndMemFrame)1220 {1221 WinSetWindowPos(hwndMemFrame,1222 HWND_TOP,1223 0, 0, 0, 0,1224 SWP_ZORDER | SWP_SHOW | SWP_ACTIVATE);1225 }1226 }1227 }1228 1229 693 #else 1230 694 void memdDummy(void)
Note:
See TracChangeset
for help on using the changeset viewer.