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

Last change on this file since 21302 was 21302, checked in by ydario, 16 years ago

Kernel32 updates.

File size: 12.6 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// dprintf(("OS2Heap::Alloc\n"));
181
182 //size must be multiple of 8 bytes
183 dwAllocBytes = HEAP_ALIGN(dwBytes);
184
185 lpMem = _umalloc(uheap, dwAllocBytes + HEAP_OVERHEAD);
186 if(lpMem == NULL) {
187 dprintf(("OS2Heap::Alloc, lpMem == NULL"));
188 return(NULL);
189 }
190
191 RasTrackMemAlloc (rthHeap, dwAllocBytes);
192
193 if(dwFlags & HEAP_ZERO_MEMORY) {
194 memset(lpMem, 0, dwAllocBytes+HEAP_OVERHEAD);
195 }
196
197#ifdef DEBUG
198 totalAlloc += dwAllocBytes;
199#endif
200
201 //align at 8 byte boundary
202 lpHeapObj = (HEAPELEM *)HEAP_ALIGN(lpMem);
203 lpHeapObj->lpMem = lpMem;
204 lpHeapObj->magic = MAGIC_NR_HEAP;
205 lpHeapObj->orgsize = dwBytes; //original size
206 lpHeapObj->cursize = dwBytes; //original size
207
208 return(LPVOID)(lpHeapObj+1);
209}
210//******************************************************************************
211//******************************************************************************
212DWORD OS2Heap::Size(DWORD dwFlags, PVOID lpMem)
213{
214 HEAPELEM *helem = GET_HEAPOBJ(lpMem);
215
216 if(lpMem == NULL) {
217 dprintf(("OS2Heap::Size lpMem == NULL\n"));
218 return -1;
219 }
220 /* verify lpMem address */
221 if (lpMem >= (LPVOID)ulMaxAddr || lpMem < (LPVOID)0x10000)
222 {
223 dprintf(("OS2Heap::Size ERROR BAD HEAP POINTER:%X\n", lpMem));
224 return -1;
225 }
226
227 if(helem->magic != MAGIC_NR_HEAP)
228 {
229 dprintf(("OS2Heap::Size ERROR BAD HEAP POINTER:%X\n", lpMem));
230 return -1;
231 }
232 return helem->cursize; //return current size of memory block
233}
234//******************************************************************************
235//******************************************************************************
236LPVOID OS2Heap::ReAlloc(DWORD dwFlags, LPVOID lpMem, DWORD dwBytes)
237{
238 HEAPELEM *helem = GET_HEAPOBJ(lpMem);
239 LPVOID lpNewMem;
240 int i, maxSize;
241
242 if (dwBytes == 0) return NULL; // intercept stupid parameters
243
244 //NOTE: Allocate memory using Alloc -> WINE controls depend on this, even
245 // though it apparently doesn't work in Windows.
246 if (lpMem == 0) return Alloc(dwFlags, dwBytes);
247// if (lpMem == 0) return NULL;
248
249 if (helem->magic != MAGIC_NR_HEAP)
250 {
251 dprintf(("OS2Heap::ReAlloc ERROR BAD HEAP POINTER:%X\n", lpMem));
252 return lpMem;
253 }
254
255 maxSize = HEAP_ALIGN(helem->orgsize);
256 if (dwBytes <= maxSize) {
257 dprintf(("ReAlloc with smaller size than original (%d); return old pointer", maxSize));
258
259 RasTrackMemRealloc (rthHeap, helem->cursize, dwBytes);
260
261 //update current size so HeapSize will return the right value
262 helem->cursize = dwBytes;
263 return lpMem; // if reallocation with same size don't do anything
264 }
265 lpNewMem = Alloc(dwFlags, dwBytes);
266 memcpy(lpNewMem, lpMem, dwBytes < maxSize ? dwBytes : maxSize);
267 Free(0, lpMem);
268
269 if(lpNewMem == NULL)
270 {
271 dprintf(("OS2Heap::ReAlloc, no more memory left\n"));
272 }
273
274 return(lpNewMem);
275}
276//******************************************************************************
277//******************************************************************************
278BOOL OS2Heap::Free(DWORD dwFlags, LPVOID lpMem)
279{
280 HEAPELEM *helem = GET_HEAPOBJ(lpMem);
281
282 /* verify lpMem address */
283 if (lpMem >= (LPVOID)ulMaxAddr || lpMem < (LPVOID)0x10000)
284 {
285 dprintf(("OS2Heap::Free ERROR BAD HEAP POINTER:%X\n", lpMem));
286 return FALSE;
287 }
288
289 if(helem->magic != MAGIC_NR_HEAP)
290 {
291 dprintf(("OS2Heap::Free ERROR BAD HEAP POINTER:%X\n", lpMem));
292 return FALSE;
293 }
294
295#ifdef DEBUG1
296 int size = Size(0, lpMem);
297 dprintf(("OS2Heap::Free lpMem = %X, size %d\n", lpMem, size));
298#ifdef DEBUG
299 totalAlloc -= size;
300#endif
301#endif
302
303 RasTrackMemFree (rthHeap, helem->cursize);
304
305 free(helem->lpMem);
306
307 return(TRUE);
308}
309//******************************************************************************
310//******************************************************************************
311DWORD OS2Heap::Compact(DWORD dwFlags)
312{
313 dprintf(("OS2Heap::Compact, %X- stub\n", dwFlags));
314 return(0);
315}
316//******************************************************************************
317//******************************************************************************
318BOOL OS2Heap::Validate(DWORD dwFlags, LPCVOID lpMem)
319{
320 HEAPELEM *helem = GET_HEAPOBJ(lpMem);
321
322 dprintf(("OS2Heap::Validate, %X %X", dwFlags, lpMem));
323
324 /* verify lpMem address */
325 if (lpMem >= (LPVOID)ulMaxAddr || lpMem < (LPVOID)0x10000)
326 {
327 dprintf(("OS2Heap::Validate BAD HEAP POINTER:%X\n", lpMem));
328 return FALSE;
329 }
330
331 if(helem->magic != MAGIC_NR_HEAP)
332 {
333 dprintf(("OS2Heap::Validate BAD HEAP POINTER:%X\n", lpMem));
334 return FALSE;
335 }
336 return(TRUE);
337}
338//******************************************************************************
339//******************************************************************************
340BOOL OS2Heap::Walk(void *lpEntry)
341{
342 dprintf(("OS2Heap::Walk, %X - stub? (TRUE)\n", lpEntry));
343 return(TRUE);
344}
345//******************************************************************************
346//******************************************************************************
347OS2Heap *OS2Heap::find(HANDLE hHeap)
348{
349/* PH moved to inlineable macro ...
350 * // check against cache first
351 * if (fhhm_lastHeap)
352 * if (hHeap == fhhm_lastHandle)
353 * {
354 * return fhhm_lastHeap;
355 * }
356 *
357 */
358
359 OS2Heap *curheap = OS2Heap::heap;
360
361 //@@@PH NT programs seem to assume heap 0 is always valid?!
362 if (hHeap == 0)
363 if (curheap != NULL)
364 {
365 fhhm_lastHandle = hHeap;
366 fhhm_lastHeap = curheap;
367 return curheap;
368 }
369
370 while(curheap != NULL)
371 {
372 if(curheap->hPrimaryHeap == hHeap)
373 {
374 fhhm_lastHandle = hHeap;
375 fhhm_lastHeap = curheap;
376 return(curheap);
377 }
378 curheap = curheap->next;
379 }
380 dprintf(("Heap %X not found!\n", hHeap));
381 fhhm_lastHandle = hHeap;
382 fhhm_lastHeap = NULL;
383 return(NULL);
384}
385//******************************************************************************
386//******************************************************************************
387OS2Heap *OS2Heap::heap = NULL;
388
389
390//******************************************************************************
391//******************************************************************************
392void * _LNK_CONV getmoreHeapMem(Heap_t pHeap, size_t *size, int *clean)
393{
394 APIRET rc;
395 PVOID newblock;
396
397 dprintf(("KERNEL32: getmoreHeapMem(%08xh, %08xh, %08xh)", pHeap, *size, *clean));
398
399 /* round the size up to a multiple of 64K */
400 //NOTE: MUST use 64kb here or else we are at risk of running out of virtual
401 // memory space. (when allocating 4kb we actually get 4kb + 60k uncommited)
402 *size = ( (*size / 65536) + 1) * 65536;
403
404 rc = DosAllocMem(&newblock, *size, PAG_READ|PAG_WRITE|PAG_COMMIT|PAG_EXECUTE);
405 if(rc != 0) {
406 dprintf(("getmoreHeapMem: DosAllocMem failed with %d", rc));
407 return FALSE;
408 }
409 *clean = _BLOCK_CLEAN;
410 dprintf(("KERNEL32: getmoreHeapMem %x %d", newblock, *size));
411 return newblock;
412}
413//******************************************************************************
414//******************************************************************************
415void _LNK_CONV releaseHeapMem(Heap_t pHeap, void *block, size_t size)
416{
417 dprintf(("KERNEL32: releaseHeapMem %x %x %d", pHeap, block, size));
418 DosFreeMem(block);
419}
420//******************************************************************************
421//******************************************************************************
Note: See TracBrowser for help on using the repository browser.