2 * Global heap functions
4 * Copyright 1995 Alexandre Julliard
12 #include "selectors.h"
13 #include "stackframe.h"
17 /* Global arena block */
20 DWORD base
; /* Base address */
21 DWORD size
; /* Size in bytes (0 indicates a free block) */
22 HGLOBAL handle
; /* Handle for this block */
23 HGLOBAL hOwner
; /* Owner of this block */
24 BYTE lockCount
; /* Count of GlobalFix() calls */
25 BYTE pageLockCount
; /* Count of GlobalPageLock() calls */
26 BYTE flags
; /* Allocation flags */
27 BYTE selCount
; /* Number of selectors allocated for this block */
30 /* Flags definitions */
31 #define GA_MOVEABLE 0x02 /* same as GMEM_MOVEABLE */
32 #define GA_DGROUP 0x04
33 #define GA_DISCARDABLE 0x08
36 static GLOBALARENA
*pGlobalArena
= NULL
;
37 static int globalArenaSize
= 0;
39 #define GLOBAL_MAX_ALLOC_SIZE 0x00ff0000 /* Largest allocation is 16M - 64K */
41 #define GET_ARENA_PTR(handle) (pGlobalArena + ((handle) >> __AHSHIFT))
43 /***********************************************************************
46 * Return the arena for a given selector, growing the arena array if needed.
48 static GLOBALARENA
*GLOBAL_GetArena( WORD sel
, WORD selcount
)
50 if (((sel
>> __AHSHIFT
) + selcount
) > globalArenaSize
)
52 int newsize
= ((sel
>> __AHSHIFT
) + selcount
+ 0xff) & ~0xff;
53 GLOBALARENA
*pNewArena
= realloc( pGlobalArena
,
54 newsize
* sizeof(GLOBALARENA
) );
55 if (!pNewArena
) return 0;
56 pGlobalArena
= pNewArena
;
57 memset( pGlobalArena
+ globalArenaSize
, 0,
58 (newsize
- globalArenaSize
) * sizeof(GLOBALARENA
) );
59 globalArenaSize
= newsize
;
61 return pGlobalArena
+ (sel
>> __AHSHIFT
);
65 /***********************************************************************
68 * Create a global heap block for a fixed range of linear memory.
70 HGLOBAL
GLOBAL_CreateBlock( WORD flags
, void *ptr
, DWORD size
,
71 HGLOBAL hOwner
, BOOL isCode
,
72 BOOL is32Bit
, BOOL isReadOnly
)
77 /* Allocate the selector(s) */
79 sel
= SELECTOR_AllocBlock( ptr
, size
, isCode
? SEGMENT_CODE
: SEGMENT_DATA
,
80 is32Bit
, isReadOnly
);
82 selcount
= (size
+ 0xffff) / 0x10000;
84 if (!(pArena
= GLOBAL_GetArena( sel
, selcount
)))
90 /* Fill the arena block */
92 pArena
->base
= (DWORD
)ptr
;
93 pArena
->size
= GET_SEL_LIMIT(sel
) + 1;
94 pArena
->handle
= (flags
& GMEM_MOVEABLE
) ? sel
- 1 : sel
;
95 pArena
->hOwner
= hOwner
;
96 pArena
->lockCount
= 0;
97 pArena
->pageLockCount
= 0;
98 pArena
->flags
= flags
& GA_MOVEABLE
;
99 if (flags
& GMEM_DISCARDABLE
) pArena
->flags
|= GA_DISCARDABLE
;
100 if (!isCode
) pArena
->flags
|= GA_DGROUP
;
101 pArena
->selCount
= selcount
;
102 if (selcount
> 1) /* clear the next arena blocks */
103 memset( pArena
+ 1, 0, (selcount
- 1) * sizeof(GLOBALARENA
) );
105 return pArena
->handle
;
109 /***********************************************************************
112 * Free a block allocated by GLOBAL_CreateBlock, without touching
113 * the associated linear memory range.
115 BOOL
GLOBAL_FreeBlock( HGLOBAL handle
)
119 if (!handle
) return TRUE
;
120 sel
= GlobalHandleToSel( handle
);
121 if (FreeSelector( sel
)) return FALSE
; /* failed */
122 memset( GET_ARENA_PTR(handle
), 0, sizeof(GLOBALARENA
) );
127 /***********************************************************************
130 * Implementation of GlobalAlloc()
132 HGLOBAL
GLOBAL_Alloc( WORD flags
, DWORD size
, HGLOBAL hOwner
,
133 BOOL isCode
, BOOL is32Bit
, BOOL isReadOnly
)
138 dprintf_global( stddeb
, "GlobalAlloc: %ld flags=%04x\n", size
, flags
);
142 if (size
>= GLOBAL_MAX_ALLOC_SIZE
- 0x1f) return 0;
143 if (size
== 0) size
= 0x20;
144 else size
= (size
+ 0x1f) & ~0x1f;
146 /* Allocate the linear memory */
148 ptr
= malloc( size
);
151 /* Allocate the selector(s) */
153 handle
= GLOBAL_CreateBlock( flags
, ptr
, size
, hOwner
,
154 isCode
, is32Bit
, isReadOnly
);
161 if (flags
& GMEM_ZEROINIT
) memset( ptr
, 0, size
);
166 /***********************************************************************
167 * GlobalAlloc (KERNEL.15)
169 HGLOBAL
GlobalAlloc( WORD flags
, DWORD size
)
171 HANDLE owner
= GetCurrentPDB();
173 if (flags
& GMEM_DDESHARE
)
174 owner
= GetExePtr(owner
); /* Make it a module handle */
176 return GLOBAL_Alloc( flags
, size
, owner
, FALSE
, FALSE
, FALSE
);
180 /***********************************************************************
181 * GlobalReAlloc (KERNEL.16)
183 HGLOBAL
GlobalReAlloc( HGLOBAL handle
, DWORD size
, WORD flags
)
188 GLOBALARENA
*pArena
, *pNewArena
;
190 dprintf_global( stddeb
, "GlobalReAlloc: %04x %ld flags=%04x\n",
191 handle
, size
, flags
);
192 if (!handle
) return 0;
193 pArena
= GET_ARENA_PTR( handle
);
195 /* Discard the block if requested */
197 if ((size
== 0) && (flags
& GMEM_MOVEABLE
))
199 if (!(pArena
->flags
& GA_MOVEABLE
) ||
200 !(pArena
->flags
& GA_DISCARDABLE
) ||
201 (pArena
->lockCount
> 0) || (pArena
->pageLockCount
> 0)) return 0;
202 free( (void *)pArena
->base
);
208 if (size
> GLOBAL_MAX_ALLOC_SIZE
- 0x20) return 0;
209 if (size
== 0) size
= 0x20;
210 else size
= (size
+ 0x1f) & ~0x1f;
212 /* Change the flags */
214 if (flags
& GMEM_MODIFY
)
216 /* Change the flags, leaving GA_DGROUP alone */
217 pArena
->flags
= (pArena
->flags
& GA_DGROUP
) | (flags
& GA_MOVEABLE
);
218 if (flags
& GMEM_DISCARDABLE
) pArena
->flags
|= GA_DISCARDABLE
;
222 /* Reallocate the linear memory */
224 sel
= GlobalHandleToSel( handle
);
225 ptr
= (void *)pArena
->base
;
226 oldsize
= pArena
->size
;
227 dprintf_global(stddeb
,"oldsize %08lx\n",oldsize
);
228 if (size
== oldsize
) return handle
; /* Nothing to do */
230 ptr
= realloc( ptr
, size
);
234 memset( pArena
, 0, sizeof(GLOBALARENA
) );
238 /* Reallocate the selector(s) */
240 sel
= SELECTOR_ReallocBlock( sel
, ptr
, size
, SEGMENT_DATA
, 0, 0 );
244 memset( pArena
, 0, sizeof(GLOBALARENA
) );
247 selcount
= (size
+ 0xffff) / 0x10000;
249 if (!(pNewArena
= GLOBAL_GetArena( sel
, selcount
)))
256 /* Fill the new arena block */
258 if (pNewArena
!= pArena
) memcpy( pNewArena
, pArena
, sizeof(GLOBALARENA
) );
259 pNewArena
->base
= (DWORD
)ptr
;
260 pNewArena
->size
= GET_SEL_LIMIT(sel
) + 1;
261 pNewArena
->selCount
= selcount
;
262 pNewArena
->handle
= (pNewArena
->flags
& GA_MOVEABLE
) ? sel
- 1 : sel
;
264 if (selcount
> 1) /* clear the next arena blocks */
265 memset( pNewArena
+ 1, 0, (selcount
- 1) * sizeof(GLOBALARENA
) );
267 if ((oldsize
< size
) && (flags
& GMEM_ZEROINIT
))
268 memset( (char *)ptr
+ oldsize
, 0, size
- oldsize
);
269 return pNewArena
->handle
;
273 /***********************************************************************
274 * GlobalFree (KERNEL.17)
276 HGLOBAL
GlobalFree( HGLOBAL handle
)
280 dprintf_global( stddeb
, "GlobalFree: %04x\n", handle
);
281 if (!(ptr
= GlobalLock( handle
))) return handle
; /* failed */
282 if (!GLOBAL_FreeBlock( handle
)) return handle
; /* failed */
288 /***********************************************************************
289 * WIN16_GlobalLock (KERNEL.18)
291 * This is the GlobalLock() function used by 16-bit code.
293 SEGPTR
WIN16_GlobalLock( HGLOBAL handle
)
295 dprintf_global( stddeb
, "WIN16_GlobalLock(%04x) -> %08lx\n",
296 handle
, MAKELONG( 0, GlobalHandleToSel(handle
)) );
297 if (!handle
) return 0;
298 if (!GET_ARENA_PTR(handle
)->base
) return (SEGPTR
)0;
299 return (SEGPTR
)MAKELONG( 0, GlobalHandleToSel(handle
) );
303 /***********************************************************************
304 * GlobalLock (KERNEL.18)
306 * This is the GlobalLock() function used by 32-bit code.
308 LPSTR
GlobalLock( HGLOBAL handle
)
310 dprintf_global( stddeb
, "GlobalLock: %04x\n", handle
);
311 if (!handle
) return 0;
312 return (LPSTR
)GET_ARENA_PTR(handle
)->base
;
316 /***********************************************************************
317 * GlobalUnlock (KERNEL.19)
319 BOOL
GlobalUnlock( HGLOBAL handle
)
321 dprintf_global( stddeb
, "GlobalUnlock: %04x\n", handle
);
326 /***********************************************************************
327 * GlobalSize (KERNEL.20)
329 DWORD
GlobalSize( HGLOBAL handle
)
331 dprintf_global( stddeb
, "GlobalSize: %04x\n", handle
);
332 if (!handle
) return 0;
333 return GET_ARENA_PTR(handle
)->size
;
337 /***********************************************************************
338 * GlobalHandle (KERNEL.21)
340 DWORD
GlobalHandle( WORD sel
)
342 dprintf_global( stddeb
, "GlobalHandle: %04x\n", sel
);
343 return MAKELONG( GET_ARENA_PTR(sel
)->handle
, sel
);
347 /***********************************************************************
348 * GlobalFlags (KERNEL.22)
350 WORD
GlobalFlags( HGLOBAL handle
)
354 dprintf_global( stddeb
, "GlobalFlags: %04x\n", handle
);
355 pArena
= GET_ARENA_PTR(handle
);
356 return pArena
->lockCount
|
357 ((pArena
->flags
& GA_DISCARDABLE
) ? GMEM_DISCARDABLE
: 0) |
358 ((pArena
->base
== 0) ? GMEM_DISCARDED
: 0);
362 /***********************************************************************
363 * LockSegment (KERNEL.23)
365 HGLOBAL
LockSegment( HGLOBAL handle
)
367 dprintf_global( stddeb
, "LockSegment: %04x\n", handle
);
368 if (handle
== (HGLOBAL
)-1) handle
= CURRENT_DS
;
369 GET_ARENA_PTR(handle
)->lockCount
++;
374 /***********************************************************************
375 * UnlockSegment (KERNEL.24)
377 void UnlockSegment( HGLOBAL handle
)
379 dprintf_global( stddeb
, "UnlockSegment: %04x\n", handle
);
380 if (handle
== (HGLOBAL
)-1) handle
= CURRENT_DS
;
381 GET_ARENA_PTR(handle
)->lockCount
--;
382 /* FIXME: this ought to return the lock count in CX (go figure...) */
386 /***********************************************************************
387 * GlobalCompact (KERNEL.25)
389 DWORD
GlobalCompact( DWORD desired
)
391 return GLOBAL_MAX_ALLOC_SIZE
;
395 /***********************************************************************
396 * GlobalFreeAll (KERNEL.26)
398 void GlobalFreeAll( HANDLE owner
)
403 pArena
= pGlobalArena
;
404 for (i
= 0; i
< globalArenaSize
; i
++, pArena
++)
406 if ((pArena
->size
!= 0) && (pArena
->hOwner
== owner
))
407 GlobalFree( pArena
->handle
);
412 /***********************************************************************
413 * GlobalWire (KERNEL.111)
415 SEGPTR
GlobalWire( HGLOBAL handle
)
417 return WIN16_GlobalLock( handle
);
421 /***********************************************************************
422 * GlobalUnWire (KERNEL.112)
424 BOOL
GlobalUnWire( HGLOBAL handle
)
426 return GlobalUnlock( handle
);
430 /***********************************************************************
431 * GlobalDOSAlloc (KERNEL.184)
433 DWORD
GlobalDOSAlloc( DWORD size
)
435 WORD sel
= GlobalAlloc( GMEM_FIXED
, size
);
437 return MAKELONG( sel
, sel
/* this one ought to be a real-mode segment */ );
441 /***********************************************************************
442 * GlobalDOSFree (KERNEL.185)
444 WORD
GlobalDOSFree( WORD sel
)
446 return GlobalFree( GlobalHandle(sel
) ) ? sel
: 0;
450 /***********************************************************************
451 * SetSwapAreaSize (KERNEL.106)
453 LONG
SetSwapAreaSize( WORD size
)
455 dprintf_heap(stdnimp
, "STUB: SetSwapAreaSize(%d)\n", size
);
456 return MAKELONG( size
, 0xffff );
460 /***********************************************************************
461 * GlobalLRUOldest (KERNEL.163)
463 HGLOBAL
GlobalLRUOldest( HGLOBAL handle
)
465 dprintf_global( stddeb
, "GlobalLRUOldest: %04x\n", handle
);
466 if (handle
== (HGLOBAL
)-1) handle
= CURRENT_DS
;
471 /***********************************************************************
472 * GlobalLRUNewest (KERNEL.164)
474 HGLOBAL
GlobalLRUNewest( HGLOBAL handle
)
476 dprintf_global( stddeb
, "GlobalLRUNewest: %04x\n", handle
);
477 if (handle
== (HGLOBAL
)-1) handle
= CURRENT_DS
;
482 /***********************************************************************
483 * GetFreeSpace (KERNEL.169)
485 DWORD
GetFreeSpace( UINT wFlags
)
487 return GLOBAL_MAX_ALLOC_SIZE
;
491 /***********************************************************************
492 * GlobalPageLock (KERNEL.191)
494 WORD
GlobalPageLock( HGLOBAL handle
)
496 dprintf_global( stddeb
, "GlobalPageLock: %04x\n", handle
);
497 return ++(GET_ARENA_PTR(handle
)->pageLockCount
);
501 /***********************************************************************
502 * GlobalPageUnlock (KERNEL.192)
504 WORD
GlobalPageUnlock( HGLOBAL handle
)
506 dprintf_global( stddeb
, "GlobalPageUnlock: %04x\n", handle
);
507 return --(GET_ARENA_PTR(handle
)->pageLockCount
);
511 /***********************************************************************
512 * GlobalFix (KERNEL.197)
514 void GlobalFix( HGLOBAL handle
)
516 dprintf_global( stddeb
, "GlobalFix: %04x\n", handle
);
517 GET_ARENA_PTR(handle
)->lockCount
++;
521 /***********************************************************************
522 * GlobalUnfix (KERNEL.198)
524 void GlobalUnfix( HGLOBAL handle
)
526 dprintf_global( stddeb
, "GlobalUnfix: %04x\n", handle
);
527 GET_ARENA_PTR(handle
)->lockCount
--;
531 /***********************************************************************
532 * FarSetOwner (KERNEL.403)
534 void FarSetOwner( HANDLE handle
, WORD hOwner
)
536 GET_ARENA_PTR(handle
)->hOwner
= hOwner
;
540 /***********************************************************************
541 * FarGetOwner (KERNEL.404)
543 WORD
FarGetOwner( HANDLE handle
)
545 return GET_ARENA_PTR(handle
)->hOwner
;
549 /***********************************************************************
550 * GlobalHandleToSel (TOOLHELP.50)
552 WORD
GlobalHandleToSel( HGLOBAL handle
)
554 dprintf_toolhelp( stddeb
, "GlobalHandleToSel: %04x\n", handle
);
555 if (!handle
) return 0;
558 fprintf( stderr
, "Program attempted invalid selector conversion\n" );
565 /***********************************************************************
566 * GlobalFirst (TOOLHELP.51)
568 BOOL
GlobalFirst( GLOBALENTRY
*pGlobal
, WORD wFlags
)
570 if (wFlags
== GLOBAL_LRU
) return FALSE
;
572 return GlobalNext( pGlobal
, wFlags
);
576 /***********************************************************************
577 * GlobalNext (TOOLHELP.52)
579 BOOL
GlobalNext( GLOBALENTRY
*pGlobal
, WORD wFlags
)
583 if (pGlobal
->dwNext
>= globalArenaSize
) return FALSE
;
584 pArena
= pGlobalArena
+ pGlobal
->dwNext
;
585 if (wFlags
== GLOBAL_FREE
) /* only free blocks */
588 for (i
= pGlobal
->dwNext
; i
< globalArenaSize
; i
++, pArena
++)
589 if (pArena
->size
== 0) break; /* block is free */
590 if (i
>= globalArenaSize
) return FALSE
;
594 pGlobal
->dwAddress
= pArena
->base
;
595 pGlobal
->dwBlockSize
= pArena
->size
;
596 pGlobal
->hBlock
= pArena
->handle
;
597 pGlobal
->wcLock
= pArena
->lockCount
;
598 pGlobal
->wcPageLock
= pArena
->pageLockCount
;
599 pGlobal
->wFlags
= (GetCurrentPDB() == pArena
->hOwner
);
600 pGlobal
->wHeapPresent
= FALSE
;
601 pGlobal
->hOwner
= pArena
->hOwner
;
602 pGlobal
->wType
= GT_UNKNOWN
;
609 /***********************************************************************
610 * GlobalInfo (TOOLHELP.53)
612 BOOL
GlobalInfo( GLOBALINFO
*pInfo
)
617 pInfo
->wcItems
= globalArenaSize
;
618 pInfo
->wcItemsFree
= 0;
619 pInfo
->wcItemsLRU
= 0;
620 for (i
= 0, pArena
= pGlobalArena
; i
< globalArenaSize
; i
++, pArena
++)
621 if (pArena
->size
== 0) pInfo
->wcItemsFree
++;
626 /***********************************************************************
627 * GlobalEntryHandle (TOOLHELP.54)
629 BOOL
GlobalEntryHandle( GLOBALENTRY
*pGlobal
, HGLOBAL hItem
)
635 /***********************************************************************
636 * GlobalEntryModule (TOOLHELP.55)
638 BOOL
GlobalEntryModule( GLOBALENTRY
*pGlobal
, HMODULE hModule
, WORD wSeg
)
644 /***********************************************************************
645 * MemManInfo (TOOLHELP.72)
647 BOOL
MemManInfo( MEMMANINFO
*pInfo
)
652 /***********************************************************************
654 * implements GlobalAlloc (KERNEL32.316)
655 * LocalAlloc (KERNEL32.372)
657 void *GlobalAlloc32(int flags
,int size
)
659 dprintf_global(stddeb
,"GlobalAlloc32(%x,%x)\n",flags
,size
);