home *** CD-ROM | disk | FTP | other *** search
/ Tricks of the Windows Gam…ming Gurus (2nd Edition) / Disc2.iso / msdn_vcb / samples / vc98 / sdk / sdktools / windiff / gmem.c < prev    next >
C/C++ Source or Header  |  1997-10-05  |  11KB  |  349 lines

  1.  
  2. /******************************************************************************\
  3. *       This is a part of the Microsoft Source Code Samples. 
  4. *       Copyright (C) 1993-1997 Microsoft Corporation.
  5. *       All rights reserved. 
  6. *       This source code is only intended as a supplement to 
  7. *       Microsoft Development Tools and/or WinHelp documentation.
  8. *       See these sources for detailed information regarding the 
  9. *       Microsoft samples programs.
  10. \******************************************************************************/
  11.  
  12. /****************************** Module Header *******************************
  13. * Module Name: GMEM.C
  14. *
  15. * Memory utility functions.
  16. *
  17. * Functions:
  18. *
  19. * gmem_panic()
  20. * gmem_init()
  21. * gmem_get()
  22. * gmem_free()
  23. * gmem_freeall()
  24. *
  25. * Comments:
  26. *
  27. * Global heap functions - allocate and free many small
  28. * pieces of memory by calling global alloc for large pieces
  29. * and breaking them up. A heap contains a critical section, so
  30. * multiple simultaneous calls to gmem_get and gmem_free will be
  31. * protected.
  32. *
  33. * gmem_freeall should not be called until all other users have finished
  34. * with the heap.
  35. *
  36. * Out-of-memory is not something we regard as normal.
  37. * If we cannot allocate memory - we put up an abort-retry-ignore
  38. * error, and only return from the function if the user selects ignore.
  39. *
  40. ****************************************************************************/
  41.  
  42. #include <windows.h>
  43. #include <memory.h>
  44.  
  45. #include "gutils.h"
  46. #include "gutilsrc.h"
  47.  
  48. int gmem_panic(void);
  49.  
  50.  
  51. /* ensure BLKSIZE is multiple of sizeof(DWORD) */
  52. #define BLKSIZE         64               /* blk size in bytes */
  53. #define ALLOCSIZE       32768
  54. #define NBLKS           (ALLOCSIZE / BLKSIZE)
  55. #define MAPSIZE         (NBLKS / 8)
  56. #define MAPLONGS        (MAPSIZE / sizeof(DWORD))
  57. #define TO_BLKS(x)      (((x) + BLKSIZE - 1) / BLKSIZE)
  58.  
  59. typedef struct seghdr {
  60.         HANDLE hseg;
  61.         CRITICAL_SECTION critsec;
  62.         struct seghdr FAR * pnext;
  63.         long nblocks;
  64.         DWORD segmap[MAPLONGS];
  65. } SEGHDR, FAR * SEGHDRP;
  66.  
  67.  
  68. /* anything above this size, we alloc directly from global heap */
  69. #define MAXGALLOC       20000
  70.  
  71.  
  72. /***************************************************************************
  73.  * Function: gmem_init
  74.  *
  75.  * Purpose:
  76.  *
  77.  * init heap - create first segment
  78.  */
  79. HANDLE APIENTRY
  80. gmem_init(void)
  81. {
  82.         HANDLE hNew;
  83.         SEGHDRP hp;
  84.  
  85.         /* retry all memory allocations after calling gmem_panic */
  86.         do {
  87.                 hNew = GlobalAlloc(GHND, ALLOCSIZE);
  88.                 if (hNew == NULL) {
  89.                         if (gmem_panic() == IDIGNORE) {
  90.                                 return(NULL);
  91.                         }
  92.                 }
  93.         } while  (hNew == NULL);
  94.  
  95.         hp = (SEGHDRP) GlobalLock(hNew);
  96.         if (hp == NULL) {
  97.                 return(NULL);
  98.         }
  99.         hp->hseg = hNew;
  100.         InitializeCriticalSection(&hp->critsec);
  101.         hp->pnext = NULL;
  102.         gbit_init(hp->segmap, NBLKS);
  103.         gbit_alloc(hp->segmap, 1, TO_BLKS(sizeof(SEGHDR)));
  104.         hp->nblocks = NBLKS - TO_BLKS(sizeof(SEGHDR));
  105.  
  106.         return(hNew);
  107. }
  108.  
  109. /***************************************************************************
  110.  * Function: gmem_get
  111.  *
  112.  * Purpose:
  113.  *
  114.  * Get memory from heap
  115.  */
  116. LPSTR APIENTRY
  117. gmem_get(HANDLE hHeap, int len)
  118. {
  119.         SEGHDRP chainp;
  120.         HANDLE hNew;
  121.         SEGHDRP hp;
  122.         LPSTR chp;
  123.         long nblks;
  124.         long start;
  125.         long nfound;
  126.  
  127.  
  128.         /* the heap is always locked (in gmem_init)- so having got the
  129.          * pointer, we can always safely unlock it
  130.          */
  131.         chainp = (SEGHDRP) GlobalLock(hHeap);
  132.         GlobalUnlock(hHeap);
  133.  
  134.         if (len < 1) {
  135.                 return(NULL);
  136.         }
  137.  
  138.         /*
  139.          * too big to be worth allocing from heap - get from globalalloc
  140.          */
  141.         if (len > MAXGALLOC) {
  142.                 /* retry all memory allocations after calling gmem_panic */
  143.                 do {
  144.                         hNew = GlobalAlloc(GHND, len);
  145.                         if (hNew == NULL) {
  146.                                 if (gmem_panic() == IDIGNORE) {
  147.                                         return(NULL);
  148.                                 }
  149.                         }
  150.                 } while  (hNew == NULL);
  151.  
  152.                 chp = GlobalLock(hNew);
  153.                 if (chp == NULL) {
  154.                         return(NULL);
  155.                 }
  156.                 return(chp);
  157.         }
  158.  
  159.  
  160.         /*
  161.          * get critical section during all access to the heap itself
  162.          */
  163.         EnterCriticalSection(&chainp->critsec);
  164.  
  165.         nblks = TO_BLKS(len + sizeof(HANDLE));
  166.  
  167.         for (hp = chainp; hp !=NULL; hp = hp->pnext) {
  168.                 if (hp->nblocks >= nblks) {
  169.                         nfound = gbit_findfree(hp->segmap, nblks,NBLKS, &start);
  170.                         if (nfound >= nblks) {
  171.                                 gbit_alloc(hp->segmap, start, nblks);
  172.                                 hp->nblocks -= nblks;
  173.  
  174.                                 /* convert blocknr to pointer
  175.                                  * store seg handle in block
  176.                                  */
  177.                                 chp = (LPSTR) hp;
  178.                                 chp = &chp[ (start-1) * BLKSIZE];
  179.                                 * ( (HANDLE FAR *) chp) = hp->hseg;
  180.                                 chp += sizeof(HANDLE);
  181.  
  182.                                 break;
  183.                         }
  184.                 }
  185.         }
  186.         if (hp == NULL) {
  187.                 /* retry all memory allocations after calling gmem_panic */
  188.                 do {
  189.                         hNew = GlobalAlloc(GHND, ALLOCSIZE);
  190.                         if (hNew == NULL) {
  191.                                 if (gmem_panic() == IDIGNORE) {
  192.                                         LeaveCriticalSection(&chainp->critsec);
  193.                                         return(NULL);
  194.                                 }
  195.                         }
  196.                 } while  (hNew == NULL);
  197.  
  198.                 hp = (SEGHDRP) GlobalLock(hNew);
  199.                 if (hp == NULL) {
  200.                         LeaveCriticalSection(&chainp->critsec);
  201.                         return(NULL);
  202.                 }
  203.                 hp->pnext = chainp->pnext;
  204.                 hp->hseg = hNew;
  205.                 chainp->pnext = hp;
  206.                 gbit_init(hp->segmap, NBLKS);
  207.                 gbit_alloc(hp->segmap, 1, TO_BLKS(sizeof(SEGHDR)));
  208.                 hp->nblocks = NBLKS - TO_BLKS(sizeof(SEGHDR));
  209.                 nfound = gbit_findfree(hp->segmap, nblks, NBLKS, &start);
  210.                 if (nfound >= nblks) {
  211.                         gbit_alloc(hp->segmap, start, nblks);
  212.                         hp->nblocks -= nblks;
  213.  
  214.                         /* convert block nr to pointer */
  215.                         chp = (LPSTR) hp;
  216.                         chp = &chp[ (start-1) * BLKSIZE];
  217.                         /* add a handle into the block and skip past */
  218.                         * ( (HANDLE FAR *) chp) = hp->hseg;
  219.                         chp += sizeof(HANDLE);
  220.                 }
  221.         }
  222.         LeaveCriticalSection(&chainp->critsec);
  223.         memset(chp, 0, len);
  224.         return(chp);
  225. }
  226.  
  227. /***************************************************************************
  228.  * Function: gmem_free
  229.  *
  230.  * Purpose:
  231.  *
  232.  * Free memory alloced
  233.  */
  234. void APIENTRY
  235. gmem_free(HANDLE hHeap, LPSTR ptr, int len)
  236. {
  237.         SEGHDRP chainp;
  238.         SEGHDRP hp;
  239.         HANDLE hmem;
  240.         long nblks, blknr;
  241.         LPSTR chp;
  242.  
  243.         if (len < 1) {
  244.                 return;
  245.         }
  246.  
  247.         /*
  248.          * allocs greater than MAXGALLOC are too big to be worth
  249.          * allocing from the heap - they will have been allocated
  250.          * directly from globalalloc
  251.          */
  252.         if (len > MAXGALLOC) {
  253.                 hmem = GlobalHandle( (LPSTR) ptr);
  254.                 GlobalUnlock(hmem);
  255.                 GlobalFree(hmem);
  256.                 return;
  257.         }
  258.  
  259.         chainp = (SEGHDRP) GlobalLock(hHeap);
  260.         EnterCriticalSection(&chainp->critsec);
  261.  
  262.  
  263.         /* just before the ptr we gave the user, is the handle to
  264.          * the block
  265.          */
  266.         chp = (LPSTR) ptr;
  267.         chp -= sizeof(HANDLE);
  268.         hmem = * ((HANDLE FAR *) chp);
  269.         hp = (SEGHDRP) GlobalLock(hmem);
  270.  
  271.         nblks = TO_BLKS(len + sizeof(HANDLE));
  272.  
  273.         /* convert ptr to block nr */
  274.         blknr = TO_BLKS( (unsigned) (chp - (LPSTR) hp) ) + 1;
  275.  
  276.         gbit_free(hp->segmap, blknr, nblks);
  277.         hp->nblocks += nblks;
  278.  
  279.         GlobalUnlock(hmem);
  280.  
  281.    LeaveCriticalSection(&chainp->critsec);
  282.         GlobalUnlock(hHeap);
  283.  
  284. }
  285.  
  286. /***************************************************************************
  287.  * Function: gmem_freeall
  288.  *
  289.  * Purpose:
  290.  *
  291.  * Free heap
  292.  */
  293. void APIENTRY
  294. gmem_freeall(HANDLE hHeap)
  295. {
  296.         SEGHDRP chainp;
  297.         HANDLE hSeg;
  298.  
  299.         chainp = (SEGHDRP) GlobalLock(hHeap);
  300.         /* this segment is always locked - so we need to unlock
  301.          * it here as well as below
  302.          */
  303.         GlobalUnlock(hHeap);
  304.  
  305.         /* finished with the critical section  -
  306.          * caller must ensure that at this point there is no
  307.          * longer any contention
  308.          */
  309.         DeleteCriticalSection(&chainp->critsec);
  310.  
  311.         while (chainp != NULL) {
  312.                 hSeg = chainp->hseg;
  313.                 chainp = chainp->pnext;
  314.                 GlobalUnlock(hSeg);
  315.                 GlobalFree(hSeg);
  316.         }
  317. }
  318.  
  319. /***************************************************************************
  320.  * Function: gmem_panic
  321.  *
  322.  * Purpose:
  323.  *
  324.  * A memory allocation attempt has failed. Return IDIGNORE to ignore the
  325.  * error and return NULL to the caller, and IDRETRY to retry the allocation
  326.  * attempt.
  327.  */
  328. int
  329. gmem_panic(void)
  330. {
  331.         int code;
  332.         extern HANDLE hLibInst;
  333.     TCHAR szBuf1[512];
  334.         TCHAR szBuf2[512];
  335.  
  336.         LoadString(hLibInst, IDS_MEMORY_ALLOC_FAIL, szBuf1, sizeof(szBuf1));
  337.         LoadString(hLibInst, IDS_OUT_OF_MEMORY, szBuf2, sizeof(szBuf2));
  338.  
  339.         code = MessageBox(NULL, szBuf1, szBuf2,
  340.                         MB_ICONSTOP|MB_ABORTRETRYIGNORE);
  341.         if (code == IDABORT) {
  342.                 /* abort this whole process */
  343.                 ExitProcess(1);
  344.         } else {
  345.                 return(code);
  346.         }
  347. }
  348.  
  349.