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

Last change on this file since 7728 was 7728, checked in by sandervl, 24 years ago

Heap(Re)Alloc changes: allocate in multiples of 8 bytes and allow the memory block to grow to this boundary with HeapReAlloc before returning a new pointer

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