source: trunk/src/kernel32/os2heap.cpp

Last change on this file was 21932, checked in by dmik, 14 years ago

kernel32: More logging.

File size: 12.7 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#include <_ras.h>
44
45#ifdef RAS
46RAS_TRACK_HANDLE rthHeap = 0;
47#endif
48
49#ifndef HEAP_NO_SERIALIZE
50 #define HEAP_NO_SERIALIZE 1
51#endif
52
53#ifndef HEAP_ZERO_MEMORY
54 #define HEAP_ZERO_MEMORY 8
55#endif
56
57void * _LNK_CONV getmoreHeapMem(Heap_t pHeap, size_t *size, int *clean);
58void _LNK_CONV releaseHeapMem(Heap_t pHeap, void *block, size_t size);
59
60VMutex heaplistmutex; //protects linked lists of heaps
61
62
63//******************************************************************************
64// Fast Heap Handle Management
65//******************************************************************************
66
67HANDLE fhhm_lastHandle = 0;
68OS2Heap* fhhm_lastHeap = NULL;
69
70
71//******************************************************************************
72//******************************************************************************
73OS2Heap::OS2Heap(DWORD flOptions, DWORD dwInitialSize, DWORD dwMaximumSize)
74{
75 OS2Heap *curheap = OS2Heap::heap;
76
77#ifdef DEBUG
78 totalAlloc = 0;
79#endif
80 fInitialized = 0;
81 nrHeaps = 0;
82 heapelem = NULL;
83
84 /* round the size up to a multiple of 64K */
85 //NOTE: MUST use 64kb here or else we are at risk of running out of virtual
86 // memory space. (when allocating 4kb we actually get 4kb + 60k uncommited)
87 dwInitialSize = ( (dwInitialSize / 65536) + 1) * 65536;
88
89 this->dwMaximumSize = dwMaximumSize;
90 this->dwInitialSize = dwInitialSize;
91 this->flOptions = flOptions;
92
93 heaplistmutex.enter();
94 if(curheap != NULL) {
95 while(curheap->next != NULL) {
96 curheap = curheap->next;
97 }
98 curheap->next = this;
99 }
100 else heap = this;
101 next = NULL;
102
103#ifdef RAS
104 if (!rthHeap)
105 {
106 RasRegisterObjectTracking (&rthHeap, "Heap*, Global* and Local* memory",
107 0, RAS_TRACK_FLAG_MEMORY | RAS_TRACK_FLAG_LOG_AT_EXIT,
108 NULL, NULL);
109 }
110#endif
111
112 heaplistmutex.leave();
113
114 APIRET rc;
115
116 rc = DosAllocMem((PPVOID)&pInitialHeapMem, dwInitialSize, PAG_READ|PAG_WRITE|PAG_COMMIT);
117 if(rc != 0) {
118 dprintf(("OS2Heap::OS2Heap: DosAllocSharedMem failed with %d", rc));
119 DebugInt3();
120 }
121 uheap = _ucreate(pInitialHeapMem, dwInitialSize, _BLOCK_CLEAN,
122 _HEAP_REGULAR, getmoreHeapMem, releaseHeapMem);
123 if(uheap == NULL) {
124 DosFreeMem(pInitialHeapMem);
125 pInitialHeapMem = NULL;
126 dprintf(("OS2Heap::OS2Heap: _ucreate failed!"));
127 DebugInt3();
128 }
129 hPrimaryHeap = (HANDLE)uheap;
130 dprintf(("KERNEL32: HeapCreate: initial size %d, max size %d (flags %X) returned %X\n", dwInitialSize, dwMaximumSize, flOptions, hPrimaryHeap));
131}
132//******************************************************************************
133//******************************************************************************
134OS2Heap::~OS2Heap()
135{
136 OS2Heap *curheap = OS2Heap::heap;
137 int i;
138
139 // invalidate handle cache
140 fhhm_lastHandle = 0;
141 fhhm_lastHeap = NULL;
142
143 dprintf(("dtr OS2Heap, hPrimaryHeap = %X\n", hPrimaryHeap));
144
145 heaplistmutex.enter();
146 if(heap == this) {
147 heap = next;
148 }
149 else {
150 while(curheap->next != NULL) {
151 if(curheap->next == this) {
152 curheap->next = next;
153 break;
154 }
155 curheap = curheap->next;
156 }
157 }
158 heaplistmutex.leave();
159
160 if(uheap) {
161 _uclose(uheap);
162 _udestroy(uheap, _FORCE);
163 uheap = NULL;
164 }
165 if(pInitialHeapMem) {
166 DosFreeMem(pInitialHeapMem);
167 pInitialHeapMem = NULL;
168 }
169
170 dprintf(("dtr OS2Heap, hPrimaryHeap = %X done\n", hPrimaryHeap));
171}
172//******************************************************************************
173//******************************************************************************
174LPVOID OS2Heap::Alloc(DWORD dwFlags, DWORD dwBytes)
175{
176 HEAPELEM *lpHeapObj;
177 LPVOID lpMem;
178 DWORD dwAllocBytes;
179
180#if 0
181 extern HANDLE Heap_ProcessHeap;
182 dprintf(("OS2Heap::Alloc(%x:%x:%x) %x %d\n",
183 this, getHeapHandle(), Heap_ProcessHeap, dwFlags, dwBytes));
184#endif
185
186 //size must be multiple of 8 bytes
187 dwAllocBytes = HEAP_ALIGN(dwBytes);
188
189 lpMem = _umalloc(uheap, dwAllocBytes + HEAP_OVERHEAD);
190 if(lpMem == NULL) {
191 dprintf(("OS2Heap::Alloc, lpMem == NULL"));
192 return(NULL);
193 }
194
195 RasTrackMemAlloc (rthHeap, dwAllocBytes);
196
197 if(dwFlags & HEAP_ZERO_MEMORY) {
198 memset(lpMem, 0, dwAllocBytes+HEAP_OVERHEAD);
199 }
200
201#ifdef DEBUG
202 totalAlloc += dwAllocBytes;
203#endif
204
205 //align at 8 byte boundary
206 lpHeapObj = (HEAPELEM *)HEAP_ALIGN(lpMem);
207 lpHeapObj->lpMem = lpMem;
208 lpHeapObj->magic = MAGIC_NR_HEAP;
209 lpHeapObj->orgsize = dwBytes; //original size
210 lpHeapObj->cursize = dwBytes; //original size
211
212 return(LPVOID)(lpHeapObj+1);
213}
214//******************************************************************************
215//******************************************************************************
216DWORD OS2Heap::Size(DWORD dwFlags, PVOID lpMem)
217{
218 HEAPELEM *helem = GET_HEAPOBJ(lpMem);
219
220 if(lpMem == NULL) {
221 dprintf(("OS2Heap::Size lpMem == NULL\n"));
222 return -1;
223 }
224 /* verify lpMem address */
225 if (lpMem >= (LPVOID)ulMaxAddr || lpMem < (LPVOID)0x10000)
226 {
227 dprintf(("OS2Heap::Size ERROR BAD HEAP POINTER:%X\n", lpMem));
228 return -1;
229 }
230
231 if(helem->magic != MAGIC_NR_HEAP)
232 {
233 dprintf(("OS2Heap::Size ERROR BAD HEAP POINTER:%X\n", lpMem));
234 return -1;
235 }
236 return helem->cursize; //return current size of memory block
237}
238//******************************************************************************
239//******************************************************************************
240LPVOID OS2Heap::ReAlloc(DWORD dwFlags, LPVOID lpMem, DWORD dwBytes)
241{
242 HEAPELEM *helem = GET_HEAPOBJ(lpMem);
243 LPVOID lpNewMem;
244 int i, maxSize;
245
246 if (dwBytes == 0) return NULL; // intercept stupid parameters
247
248 //NOTE: Allocate memory using Alloc -> WINE controls depend on this, even
249 // though it apparently doesn't work in Windows.
250 if (lpMem == 0) return Alloc(dwFlags, dwBytes);
251// if (lpMem == 0) return NULL;
252
253 if (helem->magic != MAGIC_NR_HEAP)
254 {
255 dprintf(("OS2Heap::ReAlloc ERROR BAD HEAP POINTER:%X\n", lpMem));
256 return lpMem;
257 }
258
259 maxSize = HEAP_ALIGN(helem->orgsize);
260 if (dwBytes <= maxSize) {
261 dprintf(("ReAlloc with smaller size than original (%d); return old pointer", maxSize));
262
263 RasTrackMemRealloc (rthHeap, helem->cursize, dwBytes);
264
265 //update current size so HeapSize will return the right value
266 helem->cursize = dwBytes;
267 return lpMem; // if reallocation with same size don't do anything
268 }
269 lpNewMem = Alloc(dwFlags, dwBytes);
270 memcpy(lpNewMem, lpMem, dwBytes < maxSize ? dwBytes : maxSize);
271 Free(0, lpMem);
272
273 if(lpNewMem == NULL)
274 {
275 dprintf(("OS2Heap::ReAlloc, no more memory left\n"));
276 }
277
278 return(lpNewMem);
279}
280//******************************************************************************
281//******************************************************************************
282BOOL OS2Heap::Free(DWORD dwFlags, LPVOID lpMem)
283{
284 HEAPELEM *helem = GET_HEAPOBJ(lpMem);
285
286 /* verify lpMem address */
287 if (lpMem >= (LPVOID)ulMaxAddr || lpMem < (LPVOID)0x10000)
288 {
289 dprintf(("OS2Heap::Free ERROR BAD HEAP POINTER:%X\n", lpMem));
290 return FALSE;
291 }
292
293 if(helem->magic != MAGIC_NR_HEAP)
294 {
295 dprintf(("OS2Heap::Free ERROR BAD HEAP POINTER:%X\n", lpMem));
296 return FALSE;
297 }
298
299#ifdef DEBUG1
300 int size = Size(0, lpMem);
301 dprintf(("OS2Heap::Free lpMem = %X, size %d\n", lpMem, size));
302#ifdef DEBUG
303 totalAlloc -= size;
304#endif
305#endif
306
307 RasTrackMemFree (rthHeap, helem->cursize);
308
309 free(helem->lpMem);
310
311 return(TRUE);
312}
313//******************************************************************************
314//******************************************************************************
315DWORD OS2Heap::Compact(DWORD dwFlags)
316{
317 dprintf(("OS2Heap::Compact, %X- stub\n", dwFlags));
318 return(0);
319}
320//******************************************************************************
321//******************************************************************************
322BOOL OS2Heap::Validate(DWORD dwFlags, LPCVOID lpMem)
323{
324 HEAPELEM *helem = GET_HEAPOBJ(lpMem);
325
326 dprintf(("OS2Heap::Validate, %X %X", dwFlags, lpMem));
327
328 /* verify lpMem address */
329 if (lpMem >= (LPVOID)ulMaxAddr || lpMem < (LPVOID)0x10000)
330 {
331 dprintf(("OS2Heap::Validate BAD HEAP POINTER:%X\n", lpMem));
332 return FALSE;
333 }
334
335 if(helem->magic != MAGIC_NR_HEAP)
336 {
337 dprintf(("OS2Heap::Validate BAD HEAP POINTER:%X\n", lpMem));
338 return FALSE;
339 }
340 return(TRUE);
341}
342//******************************************************************************
343//******************************************************************************
344BOOL OS2Heap::Walk(void *lpEntry)
345{
346 dprintf(("OS2Heap::Walk, %X - stub? (TRUE)\n", lpEntry));
347 return(TRUE);
348}
349//******************************************************************************
350//******************************************************************************
351OS2Heap *OS2Heap::find(HANDLE hHeap)
352{
353/* PH moved to inlineable macro ...
354 * // check against cache first
355 * if (fhhm_lastHeap)
356 * if (hHeap == fhhm_lastHandle)
357 * {
358 * return fhhm_lastHeap;
359 * }
360 *
361 */
362
363 OS2Heap *curheap = OS2Heap::heap;
364
365 //@@@PH NT programs seem to assume heap 0 is always valid?!
366 if (hHeap == 0)
367 if (curheap != NULL)
368 {
369 fhhm_lastHandle = hHeap;
370 fhhm_lastHeap = curheap;
371 return curheap;
372 }
373
374 while(curheap != NULL)
375 {
376 if(curheap->hPrimaryHeap == hHeap)
377 {
378 fhhm_lastHandle = hHeap;
379 fhhm_lastHeap = curheap;
380 return(curheap);
381 }
382 curheap = curheap->next;
383 }
384 dprintf(("Heap %X not found!\n", hHeap));
385 fhhm_lastHandle = hHeap;
386 fhhm_lastHeap = NULL;
387 return(NULL);
388}
389//******************************************************************************
390//******************************************************************************
391OS2Heap *OS2Heap::heap = NULL;
392
393
394//******************************************************************************
395//******************************************************************************
396void * _LNK_CONV getmoreHeapMem(Heap_t pHeap, size_t *size, int *clean)
397{
398 APIRET rc;
399 PVOID newblock;
400
401 dprintf(("KERNEL32: getmoreHeapMem(%08xh, %08xh, %08xh)", pHeap, *size, *clean));
402
403 /* round the size up to a multiple of 64K */
404 //NOTE: MUST use 64kb here or else we are at risk of running out of virtual
405 // memory space. (when allocating 4kb we actually get 4kb + 60k uncommited)
406 *size = ( (*size / 65536) + 1) * 65536;
407
408 rc = DosAllocMem(&newblock, *size, PAG_READ|PAG_WRITE|PAG_COMMIT|PAG_EXECUTE);
409 if(rc != 0) {
410 dprintf(("getmoreHeapMem: DosAllocMem failed with %d", rc));
411 return FALSE;
412 }
413 *clean = _BLOCK_CLEAN;
414 dprintf(("KERNEL32: getmoreHeapMem %x %d", newblock, *size));
415 return newblock;
416}
417//******************************************************************************
418//******************************************************************************
419void _LNK_CONV releaseHeapMem(Heap_t pHeap, void *block, size_t size)
420{
421 dprintf(("KERNEL32: releaseHeapMem %x %x %d", pHeap, block, size));
422 DosFreeMem(block);
423}
424//******************************************************************************
425//******************************************************************************
Note: See TracBrowser for help on using the repository browser.