|
|
1.1 root 1:
2: /******************************************************************************\
3: * This is a part of the Microsoft Source Code Samples.
4: * Copyright (C) 1993 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:
47: int gmem_panic(void);
48:
49:
50: /* ensure BLKSIZE is multiple of sizeof(DWORD) */
51: #define BLKSIZE 64 /* blk size in bytes */
52: #define ALLOCSIZE 32768
53: #define NBLKS (ALLOCSIZE / BLKSIZE)
54: #define MAPSIZE (NBLKS / 8)
55: #define MAPLONGS (MAPSIZE / sizeof(DWORD))
56: #define TO_BLKS(x) (((x) + BLKSIZE - 1) / BLKSIZE)
57:
58: typedef struct seghdr {
59: HANDLE hseg;
60: CRITICAL_SECTION critsec;
61: struct seghdr FAR * pnext;
62: long nblocks;
63: DWORD segmap[MAPLONGS];
64: } SEGHDR, FAR * SEGHDRP;
65:
66:
67: /* anything above this size, we alloc directly from global heap */
68: #define MAXGALLOC 20000
69:
70:
71: /***************************************************************************
72: * Function: gmem_init
73: *
74: * Purpose:
75: *
76: * init heap - create first segment
77: */
78: HANDLE APIENTRY
79: gmem_init(void)
80: {
81: HANDLE hNew;
82: SEGHDRP hp;
83:
84: /* retry all memory allocations after calling gmem_panic */
85: do {
86: hNew = GlobalAlloc(GHND, ALLOCSIZE);
87: if (hNew == NULL) {
88: if (gmem_panic() == IDIGNORE) {
89: return(NULL);
90: }
91: }
92: } while (hNew == NULL);
93:
94: hp = (SEGHDRP) GlobalLock(hNew);
95: if (hp == NULL) {
96: return(NULL);
97: }
98: hp->hseg = hNew;
99: InitializeCriticalSection(&hp->critsec);
100: hp->pnext = NULL;
101: gbit_init(hp->segmap, NBLKS);
102: gbit_alloc(hp->segmap, 1, TO_BLKS(sizeof(SEGHDR)));
103: hp->nblocks = NBLKS - TO_BLKS(sizeof(SEGHDR));
104:
105: return(hNew);
106: }
107:
108: /***************************************************************************
109: * Function: gmem_get
110: *
111: * Purpose:
112: *
113: * Get memory from heap
114: */
115: LPSTR APIENTRY
116: gmem_get(HANDLE hHeap, int len)
117: {
118: SEGHDRP chainp;
119: HANDLE hNew;
120: SEGHDRP hp;
121: LPSTR chp;
122: long nblks;
123: long start;
124: long nfound;
125:
126:
127: /* the heap is always locked (in gmem_init)- so having got the
128: * pointer, we can always safely unlock it
129: */
130: chainp = (SEGHDRP) GlobalLock(hHeap);
131: GlobalUnlock(hHeap);
132:
133: if (len < 1) {
134: return(NULL);
135: }
136:
137: /*
138: * too big to be worth allocing from heap - get from globalalloc
139: */
140: if (len > MAXGALLOC) {
141: /* retry all memory allocations after calling gmem_panic */
142: do {
143: hNew = GlobalAlloc(GHND, len);
144: if (hNew == NULL) {
145: if (gmem_panic() == IDIGNORE) {
146: return(NULL);
147: }
148: }
149: } while (hNew == NULL);
150:
151: chp = GlobalLock(hNew);
152: if (chp == NULL) {
153: return(NULL);
154: }
155: return(chp);
156: }
157:
158:
159: /*
160: * get critical section during all access to the heap itself
161: */
162: EnterCriticalSection(&chainp->critsec);
163:
164: nblks = TO_BLKS(len + sizeof(HANDLE));
165:
166: for (hp = chainp; hp !=NULL; hp = hp->pnext) {
167: if (hp->nblocks >= nblks) {
168: nfound = gbit_findfree(hp->segmap, nblks,NBLKS, &start);
169: if (nfound >= nblks) {
170: gbit_alloc(hp->segmap, start, nblks);
171: hp->nblocks -= nblks;
172:
173: /* convert blocknr to pointer
174: * store seg handle in block
175: */
176: chp = (LPSTR) hp;
177: chp = &chp[ (start-1) * BLKSIZE];
178: * ( (HANDLE FAR *) chp) = hp->hseg;
179: chp += sizeof(HANDLE);
180:
181: break;
182: }
183: }
184: }
185: if (hp == NULL) {
186: /* retry all memory allocations after calling gmem_panic */
187: do {
188: hNew = GlobalAlloc(GHND, ALLOCSIZE);
189: if (hNew == NULL) {
190: if (gmem_panic() == IDIGNORE) {
191: LeaveCriticalSection(&chainp->critsec);
192: return(NULL);
193: }
194: }
195: } while (hNew == NULL);
196:
197: hp = (SEGHDRP) GlobalLock(hNew);
198: if (hp == NULL) {
199: LeaveCriticalSection(&chainp->critsec);
200: return(NULL);
201: }
202: hp->pnext = chainp->pnext;
203: hp->hseg = hNew;
204: chainp->pnext = hp;
205: gbit_init(hp->segmap, NBLKS);
206: gbit_alloc(hp->segmap, 1, TO_BLKS(sizeof(SEGHDR)));
207: hp->nblocks = NBLKS - TO_BLKS(sizeof(SEGHDR));
208: nfound = gbit_findfree(hp->segmap, nblks, NBLKS, &start);
209: if (nfound >= nblks) {
210: gbit_alloc(hp->segmap, start, nblks);
211: hp->nblocks -= nblks;
212:
213: /* convert block nr to pointer */
214: chp = (LPSTR) hp;
215: chp = &chp[ (start-1) * BLKSIZE];
216: /* add a handle into the block and skip past */
217: * ( (HANDLE FAR *) chp) = hp->hseg;
218: chp += sizeof(HANDLE);
219: }
220: }
221: LeaveCriticalSection(&chainp->critsec);
222: memset(chp, 0, len);
223: return(chp);
224: }
225:
226: /***************************************************************************
227: * Function: gmem_free
228: *
229: * Purpose:
230: *
231: * Free memory alloced
232: */
233: void APIENTRY
234: gmem_free(HANDLE hHeap, LPSTR ptr, int len)
235: {
236: SEGHDRP chainp;
237: SEGHDRP hp;
238: HANDLE hmem;
239: long nblks, blknr;
240: LPSTR chp;
241:
242: if (len < 1) {
243: return;
244: }
245:
246: /*
247: * allocs greater than MAXGALLOC are too big to be worth
248: * allocing from the heap - they will have been allocated
249: * directly from globalalloc
250: */
251: if (len > MAXGALLOC) {
252: hmem = GlobalHandle( (LPSTR) ptr);
253: GlobalUnlock(hmem);
254: GlobalFree(hmem);
255: return;
256: }
257:
258: chainp = (SEGHDRP) GlobalLock(hHeap);
259: EnterCriticalSection(&chainp->critsec);
260:
261:
262: /* just before the ptr we gave the user, is the handle to
263: * the block
264: */
265: chp = (LPSTR) ptr;
266: chp -= sizeof(HANDLE);
267: hmem = * ((HANDLE FAR *) chp);
268: hp = (SEGHDRP) GlobalLock(hmem);
269:
270: nblks = TO_BLKS(len + sizeof(HANDLE));
271:
272: /* convert ptr to block nr */
273: blknr = TO_BLKS( (unsigned) (chp - (LPSTR) hp) ) + 1;
274:
275: gbit_free(hp->segmap, blknr, nblks);
276: hp->nblocks += nblks;
277:
278: GlobalUnlock(hmem);
279:
280: LeaveCriticalSection(&chainp->critsec);
281: GlobalUnlock(hHeap);
282:
283: }
284:
285: /***************************************************************************
286: * Function: gmem_freeall
287: *
288: * Purpose:
289: *
290: * Free heap
291: */
292: void APIENTRY
293: gmem_freeall(HANDLE hHeap)
294: {
295: SEGHDRP chainp;
296: HANDLE hSeg;
297:
298: chainp = (SEGHDRP) GlobalLock(hHeap);
299: /* this segment is always locked - so we need to unlock
300: * it here as well as below
301: */
302: GlobalUnlock(hHeap);
303:
304: /* finished with the critical section -
305: * caller must ensure that at this point there is no
306: * longer any contention
307: */
308: DeleteCriticalSection(&chainp->critsec);
309:
310: while (chainp != NULL) {
311: hSeg = chainp->hseg;
312: chainp = chainp->pnext;
313: GlobalUnlock(hSeg);
314: GlobalFree(hSeg);
315: }
316: }
317:
318: /***************************************************************************
319: * Function: gmem_panic
320: *
321: * Purpose:
322: *
323: * A memory allocation attempt has failed. Return IDIGNORE to ignore the
324: * error and return NULL to the caller, and IDRETRY to retry the allocation
325: * attempt.
326: */
327: int
328: gmem_panic(void)
329: {
330: int code;
331:
332: code = MessageBox(NULL, "Memory allocation failed", "Out Of Memory",
333: MB_ICONSTOP|MB_ABORTRETRYIGNORE);
334: if (code == IDABORT) {
335: /* abort this whole process */
336: ExitProcess(1);
337: } else {
338: return(code);
339: }
340: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.