source: trunk/src/kernel32/os2heap.cpp@ 8877

Last change on this file since 8877 was 8877, checked in by sandervl, 23 years ago

Rewrote algorithm for 64kb alignment in VirtualAlloc'ed memory; allocation changes for heap (in 64kb chunks) & PE image (align at 64kb)

File size: 12.1 KB
Line 
1/* $Id: os2heap.cpp,v 1.33 2002-07-15 14:28:51 sandervl Exp $ */
2
3/*
4 * Heap class for OS/2
5 *
6 * Copyright 1998-2002 Sander van Leeuwen <sandervl@xs4all.nl>
7 *
8 *
9 * NOTE: Do NOT use high memory here. Risky with 16 bits tcpip stack
10 * If this is ever changed, then you must use VirtualAlloc!
11 *
12 * NOTE: ReAlloc allocates memory using Alloc if memory pointer == NULL
13 * WINE controls depend on this, even though it apparently
14 * doesn't work like this in Windows.
15 * NOTE: Round up size to next 8 bytes boundary
16 * When reallocating memory block, don't use different
17 * memory block unless new size is larger than old size
18 * (rounded up to next 8 bytes boundary)
19 * (Verified this behaviour in NT4 (Global/Heap(Re)Alloc);
20 * fixes crashes in Opera 5.12 which relies on this 'feature')
21 *
22 * Project Odin Software License can be found in LICENSE.TXT
23 *
24 */
25#define INCL_DOSMEMMGR
26#define INCL_DOSSEMAPHORES
27#define INCL_DOSERRORS
28#include <os2wrap.h> //Odin32 OS/2 api wrappers
29#include <stdlib.h>
30#include <string.h>
31#include <umalloc.h>
32
33#include "win32type.h"
34#include "os2heap.h"
35#include "misc.h"
36#include "vmutex.h"
37#include "initterm.h"
38#include <odin32validate.h>
39
40#define DBG_LOCALLOG DBG_os2heap
41#include "dbglocal.h"
42
43#ifndef HEAP_NO_SERIALIZE
44 #define HEAP_NO_SERIALIZE 1
45#endif
46
47#ifndef HEAP_ZERO_MEMORY
48 #define HEAP_ZERO_MEMORY 8
49#endif
50
51void * _LNK_CONV getmoreHeapMem(Heap_t pHeap, size_t *size, int *clean);
52void _LNK_CONV releaseHeapMem(Heap_t pHeap, void *block, size_t size);
53
54VMutex heaplistmutex; //protects linked lists of heaps
55
56
57//******************************************************************************
58// Fast Heap Handle Management
59//******************************************************************************
60
61HANDLE fhhm_lastHandle = 0;
62OS2Heap* fhhm_lastHeap = NULL;
63
64
65//******************************************************************************
66//******************************************************************************
67OS2Heap::OS2Heap(DWORD flOptions, DWORD dwInitialSize, DWORD dwMaximumSize)
68{
69 OS2Heap *curheap = OS2Heap::heap;
70
71#ifdef DEBUG
72 totalAlloc = 0;
73#endif
74 fInitialized = 0;
75 nrHeaps = 0;
76 heapelem = NULL;
77
78 /* round the size up to a multiple of 64K */
79 //NOTE: MUST use 64kb here or else we are at risk of running out of virtual
80 // memory space. (when allocating 4kb we actually get 4kb + 60k uncommited)
81 dwInitialSize = ( (dwInitialSize / 65536) + 1) * 65536;
82
83 this->dwMaximumSize = dwMaximumSize;
84 this->dwInitialSize = dwInitialSize;
85 this->flOptions = flOptions;
86
87 heaplistmutex.enter();
88 if(curheap != NULL) {
89 while(curheap->next != NULL) {
90 curheap = curheap->next;
91 }
92 curheap->next = this;
93 }
94 else heap = this;
95 next = NULL;
96
97 heaplistmutex.leave();
98
99 APIRET rc;
100
101 rc = DosAllocMem((PPVOID)&pInitialHeapMem, dwInitialSize, PAG_READ|PAG_WRITE|PAG_COMMIT);
102 if(rc != 0) {
103 dprintf(("OS2Heap::OS2Heap: DosAllocSharedMem failed with %d", rc));
104 DebugInt3();
105 }
106 uheap = _ucreate(pInitialHeapMem, dwInitialSize, _BLOCK_CLEAN,
107 _HEAP_REGULAR, getmoreHeapMem, releaseHeapMem);
108 if(uheap == NULL) {
109 DosFreeMem(pInitialHeapMem);
110 pInitialHeapMem = NULL;
111 dprintf(("OS2Heap::OS2Heap: _ucreate failed!"));
112 DebugInt3();
113 }
114 hPrimaryHeap = (HANDLE)uheap;
115 dprintf(("KERNEL32: HeapCreate: initial size %d, max size %d (flags %X) returned %X\n", dwInitialSize, dwMaximumSize, flOptions, hPrimaryHeap));
116}
117//******************************************************************************
118//******************************************************************************
119OS2Heap::~OS2Heap()
120{
121 OS2Heap *curheap = OS2Heap::heap;
122 int i;
123
124 // invalidate handle cache
125 fhhm_lastHandle = 0;
126 fhhm_lastHeap = NULL;
127
128 dprintf(("dtr OS2Heap, hPrimaryHeap = %X\n", hPrimaryHeap));
129
130 heaplistmutex.enter();
131 if(heap == this) {
132 heap = next;
133 }
134 else {
135 while(curheap->next != NULL) {
136 if(curheap->next == this) {
137 curheap->next = next;
138 break;
139 }
140 curheap = curheap->next;
141 }
142 }
143 heaplistmutex.leave();
144
145 if(uheap) {
146 _uclose(uheap);
147 _udestroy(uheap, _FORCE);
148 uheap = NULL;
149 }
150 if(pInitialHeapMem) {
151 DosFreeMem(pInitialHeapMem);
152 pInitialHeapMem = NULL;
153 }
154
155 dprintf(("dtr OS2Heap, hPrimaryHeap = %X done\n", hPrimaryHeap));
156}
157//******************************************************************************
158//******************************************************************************
159LPVOID OS2Heap::Alloc(DWORD dwFlags, DWORD dwBytes)
160{
161 HEAPELEM *lpHeapObj;
162 LPVOID lpMem;
163 DWORD dwAllocBytes;
164
165// dprintf(("OS2Heap::Alloc\n"));
166
167 //size must be multiple of 8 bytes
168 dwAllocBytes = HEAP_ALIGN(dwBytes);
169
170 lpMem = _umalloc(uheap, dwAllocBytes + HEAP_OVERHEAD);
171 if(lpMem == NULL) {
172 dprintf(("OS2Heap::Alloc, lpMem == NULL"));
173 return(NULL);
174 }
175 if(dwFlags & HEAP_ZERO_MEMORY) {
176 memset(lpMem, 0, dwAllocBytes+HEAP_OVERHEAD);
177 }
178
179#ifdef DEBUG
180 totalAlloc += dwAllocBytes;
181#endif
182
183 //align at 8 byte boundary
184 lpHeapObj = (HEAPELEM *)HEAP_ALIGN(lpMem);
185 lpHeapObj->lpMem = lpMem;
186 lpHeapObj->magic = MAGIC_NR_HEAP;
187 lpHeapObj->orgsize = dwBytes; //original size
188 lpHeapObj->cursize = dwBytes; //original size
189
190 return(LPVOID)(lpHeapObj+1);
191}
192//******************************************************************************
193//******************************************************************************
194DWORD OS2Heap::Size(DWORD dwFlags, PVOID lpMem)
195{
196 HEAPELEM *helem = GET_HEAPOBJ(lpMem);
197
198 if(lpMem == NULL) {
199 dprintf(("OS2Heap::Size lpMem == NULL\n"));
200 return -1;
201 }
202 /* verify lpMem address */
203 if (lpMem >= (LPVOID)ulMaxAddr || lpMem < (LPVOID)0x10000)
204 {
205 dprintf(("OS2Heap::Size ERROR BAD HEAP POINTER:%X\n", lpMem));
206 return -1;
207 }
208
209 if(helem->magic != MAGIC_NR_HEAP)
210 {
211 dprintf(("OS2Heap::Size ERROR BAD HEAP POINTER:%X\n", lpMem));
212 return -1;
213 }
214 return helem->cursize; //return current size of memory block
215}
216//******************************************************************************
217//******************************************************************************
218LPVOID OS2Heap::ReAlloc(DWORD dwFlags, LPVOID lpMem, DWORD dwBytes)
219{
220 HEAPELEM *helem = GET_HEAPOBJ(lpMem);
221 LPVOID lpNewMem;
222 int i, maxSize;
223
224 if (dwBytes == 0) return NULL; // intercept stupid parameters
225
226 //NOTE: Allocate memory using Alloc -> WINE controls depend on this, even
227 // though it apparently doesn't work in Windows.
228 if (lpMem == 0) return Alloc(dwFlags, dwBytes);
229// if (lpMem == 0) return NULL;
230
231 if (helem->magic != MAGIC_NR_HEAP)
232 {
233 dprintf(("OS2Heap::ReAlloc ERROR BAD HEAP POINTER:%X\n", lpMem));
234 return lpMem;
235 }
236
237 maxSize = HEAP_ALIGN(helem->orgsize);
238 if (dwBytes <= maxSize) {
239 dprintf(("ReAlloc with smaller size than original (%d); return old pointer", maxSize));
240 //update current size so HeapSize will return the right value
241 helem->cursize = dwBytes;
242 return lpMem; // if reallocation with same size don't do anything
243 }
244 lpNewMem = Alloc(dwFlags, dwBytes);
245 memcpy(lpNewMem, lpMem, dwBytes < maxSize ? dwBytes : maxSize);
246 Free(0, lpMem);
247
248 if(lpNewMem == NULL)
249 {
250 dprintf(("OS2Heap::ReAlloc, no more memory left\n"));
251 }
252
253 return(lpNewMem);
254}
255//******************************************************************************
256//******************************************************************************
257BOOL OS2Heap::Free(DWORD dwFlags, LPVOID lpMem)
258{
259 HEAPELEM *helem = GET_HEAPOBJ(lpMem);
260
261 /* verify lpMem address */
262 if (lpMem >= (LPVOID)ulMaxAddr || lpMem < (LPVOID)0x10000)
263 {
264 dprintf(("OS2Heap::Free ERROR BAD HEAP POINTER:%X\n", lpMem));
265 return FALSE;
266 }
267
268 if(helem->magic != MAGIC_NR_HEAP)
269 {
270 dprintf(("OS2Heap::Free ERROR BAD HEAP POINTER:%X\n", lpMem));
271 return FALSE;
272 }
273
274#ifdef DEBUG1
275 int size = Size(0, lpMem);
276 dprintf(("OS2Heap::Free lpMem = %X, size %d\n", lpMem, size));
277#ifdef DEBUG
278 totalAlloc -= size;
279#endif
280#endif
281
282 free(helem->lpMem);
283 return(TRUE);
284}
285//******************************************************************************
286//******************************************************************************
287DWORD OS2Heap::Compact(DWORD dwFlags)
288{
289 dprintf(("OS2Heap::Compact, %X- stub\n", dwFlags));
290 return(0);
291}
292//******************************************************************************
293//******************************************************************************
294BOOL OS2Heap::Validate(DWORD dwFlags, LPCVOID lpMem)
295{
296 HEAPELEM *helem = GET_HEAPOBJ(lpMem);
297
298 dprintf(("OS2Heap::Validate, %X %X", dwFlags, lpMem));
299
300 /* verify lpMem address */
301 if (lpMem >= (LPVOID)ulMaxAddr || lpMem < (LPVOID)0x10000)
302 {
303 dprintf(("OS2Heap::Validate BAD HEAP POINTER:%X\n", lpMem));
304 return FALSE;
305 }
306
307 if(helem->magic != MAGIC_NR_HEAP)
308 {
309 dprintf(("OS2Heap::Validate BAD HEAP POINTER:%X\n", lpMem));
310 return FALSE;
311 }
312 return(TRUE);
313}
314//******************************************************************************
315//******************************************************************************
316BOOL OS2Heap::Walk(void *lpEntry)
317{
318 dprintf(("OS2Heap::Walk, %X - stub? (TRUE)\n", lpEntry));
319 return(TRUE);
320}
321//******************************************************************************
322//******************************************************************************
323OS2Heap *OS2Heap::find(HANDLE hHeap)
324{
325/* PH moved to inlineable macro ...
326 * // check against cache first
327 * if (fhhm_lastHeap)
328 * if (hHeap == fhhm_lastHandle)
329 * {
330 * return fhhm_lastHeap;
331 * }
332 *
333 */
334
335 OS2Heap *curheap = OS2Heap::heap;
336
337 //@@@PH NT programs seem to assume heap 0 is always valid?!
338 if (hHeap == 0)
339 if (curheap != NULL)
340 {
341 fhhm_lastHandle = hHeap;
342 fhhm_lastHeap = curheap;
343 return curheap;
344 }
345
346 while(curheap != NULL)
347 {
348 if(curheap->hPrimaryHeap == hHeap)
349 {
350 fhhm_lastHandle = hHeap;
351 fhhm_lastHeap = curheap;
352 return(curheap);
353 }
354 curheap = curheap->next;
355 }
356 dprintf(("Heap %X not found!\n", hHeap));
357 fhhm_lastHandle = hHeap;
358 fhhm_lastHeap = NULL;
359 return(NULL);
360}
361//******************************************************************************
362//******************************************************************************
363OS2Heap *OS2Heap::heap = NULL;
364
365
366//******************************************************************************
367//******************************************************************************
368void * _LNK_CONV getmoreHeapMem(Heap_t pHeap, size_t *size, int *clean)
369{
370 APIRET rc;
371 PVOID newblock;
372
373 dprintf(("KERNEL32: getmoreHeapMem(%08xh, %08xh, %08xh)", pHeap, *size, *clean));
374
375 /* round the size up to a multiple of 64K */
376 //NOTE: MUST use 64kb here or else we are at risk of running out of virtual
377 // memory space. (when allocating 4kb we actually get 4kb + 60k uncommited)
378 *size = ( (*size / 65536) + 1) * 65536;
379
380 rc = DosAllocMem(&newblock, *size, PAG_READ|PAG_WRITE|PAG_COMMIT|PAG_EXECUTE);
381 if(rc != 0) {
382 dprintf(("getmoreHeapMem: DosAllocMem failed with %d", rc));
383 return FALSE;
384 }
385 *clean = _BLOCK_CLEAN;
386 dprintf(("KERNEL32: getmoreHeapMem %x %d", newblock, *size));
387 return newblock;
388}
389//******************************************************************************
390//******************************************************************************
391void _LNK_CONV releaseHeapMem(Heap_t pHeap, void *block, size_t size)
392{
393 dprintf(("KERNEL32: releaseHeapMem %x %x %d", pHeap, block, size));
394 DosFreeMem(block);
395}
396//******************************************************************************
397//******************************************************************************
Note: See TracBrowser for help on using the repository browser.