GMEM.C
上传用户:bangxh
上传日期:2007-01-31
资源大小:42235k
文件大小:10k
源码类别:

Windows编程

开发平台:

Visual C++

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