2 * Global heap functions
4 * Copyright 1995 Alexandre Julliard
13 #include "selectors.h"
15 #include "stackframe.h"
19 /* Global arena block */
22 DWORD base
; /* Base address */
23 DWORD size
; /* Size in bytes (0 indicates a free block) */
24 HGLOBAL handle
; /* Handle for this block */
25 HGLOBAL hOwner
; /* Owner of this block */
26 BYTE lockCount
; /* Count of GlobalFix() calls */
27 BYTE pageLockCount
; /* Count of GlobalPageLock() calls */
28 BYTE flags
; /* Allocation flags */
29 BYTE selCount
; /* Number of selectors allocated for this block */
33 /* Flags definitions */
34 #define GA_MOVEABLE 0x02 /* same as GMEM_MOVEABLE */
35 #define GA_DGROUP 0x04
36 #define GA_DISCARDABLE 0x08
37 #define GA_IPCSHARE 0x10 /* same as GMEM_DDESHARE */
40 static GLOBALARENA
*pGlobalArena
= NULL
;
41 static int globalArenaSize
= 0;
43 #define GLOBAL_MAX_ALLOC_SIZE 0x00ff0000 /* Largest allocation is 16M - 64K */
45 #define GET_ARENA_PTR(handle) (pGlobalArena + ((handle) >> __AHSHIFT))
47 /***********************************************************************
50 * Return the arena for a given selector, growing the arena array if needed.
52 static GLOBALARENA
*GLOBAL_GetArena( WORD sel
, WORD selcount
)
54 if (((sel
>> __AHSHIFT
) + selcount
) > globalArenaSize
)
56 int newsize
= ((sel
>> __AHSHIFT
) + selcount
+ 0xff) & ~0xff;
57 GLOBALARENA
*pNewArena
= realloc( pGlobalArena
,
58 newsize
* sizeof(GLOBALARENA
) );
59 if (!pNewArena
) return 0;
60 pGlobalArena
= pNewArena
;
61 memset( pGlobalArena
+ globalArenaSize
, 0,
62 (newsize
- globalArenaSize
) * sizeof(GLOBALARENA
) );
63 globalArenaSize
= newsize
;
65 return pGlobalArena
+ (sel
>> __AHSHIFT
);
73 for (i
= globalArenaSize
-1 ; i
>=0 ; i
--) {
74 if (pGlobalArena
[i
].size
!=0 && (pGlobalArena
[i
].handle
& 0x8000)){
76 printf("0x%08x, ",pGlobalArena
[i
].handle
);
82 /***********************************************************************
85 * Find the arena for a given handle
86 * (when handle is not serial - e.g. DDE)
88 static GLOBALARENA
*GLOBAL_FindArena( HGLOBAL handle
)
91 for (i
= globalArenaSize
-1 ; i
>=0 ; i
--) {
92 if (pGlobalArena
[i
].size
!=0 && pGlobalArena
[i
].handle
== handle
)
93 return ( &pGlobalArena
[i
] );
99 /***********************************************************************
102 * Create a global heap block for a fixed range of linear memory.
104 HGLOBAL
GLOBAL_CreateBlock( WORD flags
, void *ptr
, DWORD size
,
105 HGLOBAL hOwner
, BOOL isCode
,
106 BOOL is32Bit
, BOOL isReadOnly
,
112 /* Allocate the selector(s) */
114 sel
= SELECTOR_AllocBlock( ptr
, size
,
115 isCode
? SEGMENT_CODE
: SEGMENT_DATA
,
116 is32Bit
, isReadOnly
);
119 selcount
= (size
+ 0xffff) / 0x10000;
121 if (!(pArena
= GLOBAL_GetArena( sel
, selcount
)))
127 /* Fill the arena block */
129 pArena
->base
= (DWORD
)ptr
;
130 pArena
->size
= GET_SEL_LIMIT(sel
) + 1;
131 if (flags
& GMEM_DDESHARE
)
133 pArena
->handle
= shmdata
->handle
;
134 pArena
->shmid
= shmdata
->shmid
;
139 pArena
->handle
= (flags
& GMEM_MOVEABLE
) ? sel
- 1 : sel
;
142 pArena
->hOwner
= hOwner
;
143 pArena
->lockCount
= 0;
144 pArena
->pageLockCount
= 0;
145 pArena
->flags
= flags
& GA_MOVEABLE
;
146 if (flags
& GMEM_DISCARDABLE
) pArena
->flags
|= GA_DISCARDABLE
;
147 if (flags
& GMEM_DDESHARE
) pArena
->flags
|= GA_IPCSHARE
;
148 if (!isCode
) pArena
->flags
|= GA_DGROUP
;
149 pArena
->selCount
= selcount
;
150 if (selcount
> 1) /* clear the next arena blocks */
151 memset( pArena
+ 1, 0, (selcount
- 1) * sizeof(GLOBALARENA
) );
153 return pArena
->handle
;
157 /***********************************************************************
160 * Free a block allocated by GLOBAL_CreateBlock, without touching
161 * the associated linear memory range.
163 BOOL
GLOBAL_FreeBlock( HGLOBAL handle
)
167 if (!handle
) return TRUE
;
168 sel
= GlobalHandleToSel( handle
);
169 if (FreeSelector( sel
)) return FALSE
; /* failed */
170 memset( GET_ARENA_PTR(sel
), 0, sizeof(GLOBALARENA
) );
175 /***********************************************************************
178 * Implementation of GlobalAlloc()
180 HGLOBAL
GLOBAL_Alloc( WORD flags
, DWORD size
, HGLOBAL hOwner
,
181 BOOL isCode
, BOOL is32Bit
, BOOL isReadOnly
)
187 dprintf_global( stddeb
, "GlobalAlloc: %ld flags=%04x\n", size
, flags
);
191 if (size
>= GLOBAL_MAX_ALLOC_SIZE
- 0x1f) return 0;
192 if (size
== 0) size
= 0x20;
193 else size
= (size
+ 0x1f) & ~0x1f;
195 /* Allocate the linear memory */
197 if (flags
& GMEM_DDESHARE
)
198 ptr
= DDE_malloc(flags
, size
, &shmdata
);
200 ptr
= malloc( size
);
203 /* Allocate the selector(s) */
205 handle
= GLOBAL_CreateBlock( flags
, ptr
, size
, hOwner
,
206 isCode
, is32Bit
, isReadOnly
, &shmdata
);
213 if (flags
& GMEM_ZEROINIT
) memset( ptr
, 0, size
);
217 /***********************************************************************
218 * DDE_GlobalHandleToSel
221 WORD
DDE_GlobalHandleToSel( HGLOBAL handle
)
226 pArena
= GLOBAL_FindArena(handle
);
228 int ArenaIdx
= pArena
- pGlobalArena
;
230 /* See if synchronized to the shared memory */
231 return DDE_SyncHandle(handle
, ( ArenaIdx
<< __AHSHIFT
) | 7);
234 /* attach the block */
235 DDE_AttachHandle(handle
, &segptr
);
237 return SELECTOROF( segptr
);
241 /***********************************************************************
242 * GlobalAlloc (KERNEL.15)
244 HGLOBAL
GlobalAlloc( WORD flags
, DWORD size
)
246 HANDLE owner
= GetCurrentPDB();
248 if (flags
& GMEM_DDESHARE
)
249 owner
= GetExePtr(owner
); /* Make it a module handle */
250 return GLOBAL_Alloc( flags
, size
, owner
, FALSE
, FALSE
, FALSE
);
254 /***********************************************************************
255 * GlobalReAlloc (KERNEL.16)
257 HGLOBAL
GlobalReAlloc( HGLOBAL handle
, DWORD size
, WORD flags
)
262 GLOBALARENA
*pArena
, *pNewArena
;
263 WORD sel
= GlobalHandleToSel( handle
);
265 dprintf_global( stddeb
, "GlobalReAlloc: %04x %ld flags=%04x\n",
266 handle
, size
, flags
);
267 if (!handle
) return 0;
269 if (flags
& GMEM_DDESHARE
|| is_dde_handle(handle
)) {
271 "GlobalReAlloc: shared memory reallocating unimplemented\n");
275 pArena
= GET_ARENA_PTR( handle
);
277 /* Discard the block if requested */
279 if ((size
== 0) && (flags
& GMEM_MOVEABLE
) && !(flags
& GMEM_MODIFY
))
281 if (!(pArena
->flags
& GA_MOVEABLE
) ||
282 !(pArena
->flags
& GA_DISCARDABLE
) ||
283 (pArena
->lockCount
> 0) || (pArena
->pageLockCount
> 0)) return 0;
284 free( (void *)pArena
->base
);
286 /* Note: we rely on the fact that SELECTOR_ReallocBlock won't */
287 /* change the selector if we are shrinking the block */
288 SELECTOR_ReallocBlock( sel
, 0, 1, SEGMENT_DATA
, 0, 0 );
294 if (size
> GLOBAL_MAX_ALLOC_SIZE
- 0x20) return 0;
295 if (size
== 0) size
= 0x20;
296 else size
= (size
+ 0x1f) & ~0x1f;
298 /* Change the flags */
300 if (flags
& GMEM_MODIFY
)
302 /* Change the flags, leaving GA_DGROUP alone */
303 pArena
->flags
= (pArena
->flags
& GA_DGROUP
) | (flags
& GA_MOVEABLE
);
304 if (flags
& GMEM_DISCARDABLE
) pArena
->flags
|= GA_DISCARDABLE
;
308 /* Reallocate the linear memory */
310 ptr
= (void *)pArena
->base
;
311 oldsize
= pArena
->size
;
312 dprintf_global(stddeb
,"oldsize %08lx\n",oldsize
);
313 if (size
== oldsize
) return handle
; /* Nothing to do */
315 ptr
= realloc( ptr
, size
);
319 memset( pArena
, 0, sizeof(GLOBALARENA
) );
323 /* Reallocate the selector(s) */
325 sel
= SELECTOR_ReallocBlock( sel
, ptr
, size
, SEGMENT_DATA
, 0, 0 );
329 memset( pArena
, 0, sizeof(GLOBALARENA
) );
332 selcount
= (size
+ 0xffff) / 0x10000;
334 if (!(pNewArena
= GLOBAL_GetArena( sel
, selcount
)))
341 /* Fill the new arena block */
343 if (pNewArena
!= pArena
) memcpy( pNewArena
, pArena
, sizeof(GLOBALARENA
) );
344 pNewArena
->base
= (DWORD
)ptr
;
345 pNewArena
->size
= GET_SEL_LIMIT(sel
) + 1;
346 pNewArena
->selCount
= selcount
;
347 pNewArena
->handle
= (pNewArena
->flags
& GA_MOVEABLE
) ? sel
- 1 : sel
;
349 if (selcount
> 1) /* clear the next arena blocks */
350 memset( pNewArena
+ 1, 0, (selcount
- 1) * sizeof(GLOBALARENA
) );
352 if ((oldsize
< size
) && (flags
& GMEM_ZEROINIT
))
353 memset( (char *)ptr
+ oldsize
, 0, size
- oldsize
);
354 return pNewArena
->handle
;
358 /***********************************************************************
359 * GlobalFree (KERNEL.17)
361 HGLOBAL
GlobalFree( HGLOBAL handle
)
363 void *ptr
= GlobalLock( handle
);
365 dprintf_global( stddeb
, "GlobalFree: %04x\n", handle
);
366 if (!GLOBAL_FreeBlock( handle
)) return handle
; /* failed */
367 if (is_dde_handle(handle
)) return DDE_GlobalFree(handle
);
368 if (ptr
) free( ptr
);
373 /***********************************************************************
374 * WIN16_GlobalLock (KERNEL.18)
376 * This is the GlobalLock() function used by 16-bit code.
378 SEGPTR
WIN16_GlobalLock( HGLOBAL handle
)
380 dprintf_global( stddeb
, "WIN16_GlobalLock(%04x) -> %08lx\n",
381 handle
, MAKELONG( 0, GlobalHandleToSel(handle
)) );
382 if (!handle
) return 0;
383 if ( !is_dde_handle(handle
) && !GET_ARENA_PTR(handle
)->base
)
386 return (SEGPTR
)MAKELONG( 0, GlobalHandleToSel(handle
) );
390 /***********************************************************************
391 * GlobalLock (KERNEL.18)
393 * This is the GlobalLock() function used by 32-bit code.
395 LPSTR
GlobalLock( HGLOBAL handle
)
397 if (!handle
) return 0;
398 if (is_dde_handle(handle
)) {
399 return DDE_AttachHandle(handle
, NULL
);
401 return (LPSTR
)GET_ARENA_PTR(handle
)->base
;
405 /***********************************************************************
406 * GlobalUnlock (KERNEL.19)
408 BOOL
GlobalUnlock( HGLOBAL handle
)
410 dprintf_global( stddeb
, "GlobalUnlock: %04x\n", handle
);
415 /***********************************************************************
416 * GlobalSize (KERNEL.20)
418 DWORD
GlobalSize( HGLOBAL handle
)
420 dprintf_global( stddeb
, "GlobalSize: %04x\n", handle
);
421 if (!handle
) return 0;
422 return GET_ARENA_PTR(handle
)->size
;
426 /***********************************************************************
427 * GlobalHandle (KERNEL.21)
429 DWORD
GlobalHandle( WORD sel
)
431 dprintf_global( stddeb
, "GlobalHandle: %04x\n", sel
);
432 return MAKELONG( GET_ARENA_PTR(sel
)->handle
, sel
);
436 /***********************************************************************
437 * GlobalFlags (KERNEL.22)
439 WORD
GlobalFlags( HGLOBAL handle
)
443 dprintf_global( stddeb
, "GlobalFlags: %04x\n", handle
);
444 pArena
= GET_ARENA_PTR(handle
);
445 return pArena
->lockCount
|
446 ((pArena
->flags
& GA_DISCARDABLE
) ? GMEM_DISCARDABLE
: 0) |
447 ((pArena
->base
== 0) ? GMEM_DISCARDED
: 0);
451 /***********************************************************************
452 * LockSegment (KERNEL.23)
454 HGLOBAL
LockSegment( HGLOBAL handle
)
456 dprintf_global( stddeb
, "LockSegment: %04x\n", handle
);
457 if (handle
== (HGLOBAL
)-1) handle
= CURRENT_DS
;
458 GET_ARENA_PTR(handle
)->lockCount
++;
463 /***********************************************************************
464 * UnlockSegment (KERNEL.24)
466 void UnlockSegment( HGLOBAL handle
)
468 dprintf_global( stddeb
, "UnlockSegment: %04x\n", handle
);
469 if (handle
== (HGLOBAL
)-1) handle
= CURRENT_DS
;
470 GET_ARENA_PTR(handle
)->lockCount
--;
471 /* FIXME: this ought to return the lock count in CX (go figure...) */
475 /***********************************************************************
476 * GlobalCompact (KERNEL.25)
478 DWORD
GlobalCompact( DWORD desired
)
480 return GLOBAL_MAX_ALLOC_SIZE
;
484 /***********************************************************************
485 * GlobalFreeAll (KERNEL.26)
487 void GlobalFreeAll( HANDLE owner
)
492 pArena
= pGlobalArena
;
493 for (i
= 0; i
< globalArenaSize
; i
++, pArena
++)
495 if ((pArena
->size
!= 0) && (pArena
->hOwner
== owner
))
496 GlobalFree( pArena
->handle
);
501 /***********************************************************************
502 * GlobalWire (KERNEL.111)
504 SEGPTR
GlobalWire( HGLOBAL handle
)
506 return WIN16_GlobalLock( handle
);
510 /***********************************************************************
511 * GlobalUnWire (KERNEL.112)
513 BOOL
GlobalUnWire( HGLOBAL handle
)
515 return GlobalUnlock( handle
);
519 /***********************************************************************
520 * GlobalDOSAlloc (KERNEL.184)
522 DWORD
GlobalDOSAlloc( DWORD size
)
524 WORD sel
= GlobalAlloc( GMEM_FIXED
, size
);
526 return MAKELONG( sel
, sel
/* this one ought to be a real-mode segment */ );
530 /***********************************************************************
531 * GlobalDOSFree (KERNEL.185)
533 WORD
GlobalDOSFree( WORD sel
)
535 return GlobalFree( GlobalHandle(sel
) ) ? sel
: 0;
539 /***********************************************************************
540 * SetSwapAreaSize (KERNEL.106)
542 LONG
SetSwapAreaSize( WORD size
)
544 dprintf_global(stdnimp
, "STUB: SetSwapAreaSize(%d)\n", size
);
545 return MAKELONG( size
, 0xffff );
549 /***********************************************************************
550 * GlobalLRUOldest (KERNEL.163)
552 HGLOBAL
GlobalLRUOldest( HGLOBAL handle
)
554 dprintf_global( stddeb
, "GlobalLRUOldest: %04x\n", handle
);
555 if (handle
== (HGLOBAL
)-1) handle
= CURRENT_DS
;
560 /***********************************************************************
561 * GlobalLRUNewest (KERNEL.164)
563 HGLOBAL
GlobalLRUNewest( HGLOBAL handle
)
565 dprintf_global( stddeb
, "GlobalLRUNewest: %04x\n", handle
);
566 if (handle
== (HGLOBAL
)-1) handle
= CURRENT_DS
;
571 /***********************************************************************
572 * GetFreeSpace (KERNEL.169)
574 DWORD
GetFreeSpace( UINT wFlags
)
576 return GLOBAL_MAX_ALLOC_SIZE
;
580 /***********************************************************************
581 * GlobalPageLock (KERNEL.191)
583 WORD
GlobalPageLock( HGLOBAL handle
)
585 dprintf_global( stddeb
, "GlobalPageLock: %04x\n", handle
);
586 return ++(GET_ARENA_PTR(handle
)->pageLockCount
);
590 /***********************************************************************
591 * GlobalPageUnlock (KERNEL.192)
593 WORD
GlobalPageUnlock( HGLOBAL handle
)
595 dprintf_global( stddeb
, "GlobalPageUnlock: %04x\n", handle
);
596 return --(GET_ARENA_PTR(handle
)->pageLockCount
);
600 /***********************************************************************
601 * GlobalFix (KERNEL.197)
603 void GlobalFix( HGLOBAL handle
)
605 dprintf_global( stddeb
, "GlobalFix: %04x\n", handle
);
606 GET_ARENA_PTR(handle
)->lockCount
++;
610 /***********************************************************************
611 * GlobalUnfix (KERNEL.198)
613 void GlobalUnfix( HGLOBAL handle
)
615 dprintf_global( stddeb
, "GlobalUnfix: %04x\n", handle
);
616 GET_ARENA_PTR(handle
)->lockCount
--;
620 /***********************************************************************
621 * FarSetOwner (KERNEL.403)
623 void FarSetOwner( HANDLE handle
, WORD hOwner
)
625 GET_ARENA_PTR(handle
)->hOwner
= hOwner
;
629 /***********************************************************************
630 * FarGetOwner (KERNEL.404)
632 WORD
FarGetOwner( HANDLE handle
)
634 return GET_ARENA_PTR(handle
)->hOwner
;
638 /***********************************************************************
639 * GlobalHandleToSel (TOOLHELP.50)
641 WORD
GlobalHandleToSel( HGLOBAL handle
)
643 dprintf_toolhelp( stddeb
, "GlobalHandleToSel: %04x\n", handle
);
644 if (!handle
) return 0;
645 if (is_dde_handle(handle
))
646 return DDE_GlobalHandleToSel(handle
);
650 fprintf( stderr
, "Program attempted invalid selector conversion\n" );
657 /***********************************************************************
658 * GlobalFirst (TOOLHELP.51)
660 BOOL
GlobalFirst( GLOBALENTRY
*pGlobal
, WORD wFlags
)
662 if (wFlags
== GLOBAL_LRU
) return FALSE
;
664 return GlobalNext( pGlobal
, wFlags
);
668 /***********************************************************************
669 * GlobalNext (TOOLHELP.52)
671 BOOL
GlobalNext( GLOBALENTRY
*pGlobal
, WORD wFlags
)
675 if (pGlobal
->dwNext
>= globalArenaSize
) return FALSE
;
676 pArena
= pGlobalArena
+ pGlobal
->dwNext
;
677 if (wFlags
== GLOBAL_FREE
) /* only free blocks */
680 for (i
= pGlobal
->dwNext
; i
< globalArenaSize
; i
++, pArena
++)
681 if (pArena
->size
== 0) break; /* block is free */
682 if (i
>= globalArenaSize
) return FALSE
;
686 pGlobal
->dwAddress
= pArena
->base
;
687 pGlobal
->dwBlockSize
= pArena
->size
;
688 pGlobal
->hBlock
= pArena
->handle
;
689 pGlobal
->wcLock
= pArena
->lockCount
;
690 pGlobal
->wcPageLock
= pArena
->pageLockCount
;
691 pGlobal
->wFlags
= (GetCurrentPDB() == pArena
->hOwner
);
692 pGlobal
->wHeapPresent
= FALSE
;
693 pGlobal
->hOwner
= pArena
->hOwner
;
694 pGlobal
->wType
= GT_UNKNOWN
;
701 /***********************************************************************
702 * GlobalInfo (TOOLHELP.53)
704 BOOL
GlobalInfo( GLOBALINFO
*pInfo
)
709 pInfo
->wcItems
= globalArenaSize
;
710 pInfo
->wcItemsFree
= 0;
711 pInfo
->wcItemsLRU
= 0;
712 for (i
= 0, pArena
= pGlobalArena
; i
< globalArenaSize
; i
++, pArena
++)
713 if (pArena
->size
== 0) pInfo
->wcItemsFree
++;
718 /***********************************************************************
719 * GlobalEntryHandle (TOOLHELP.54)
721 BOOL
GlobalEntryHandle( GLOBALENTRY
*pGlobal
, HGLOBAL hItem
)
727 /***********************************************************************
728 * GlobalEntryModule (TOOLHELP.55)
730 BOOL
GlobalEntryModule( GLOBALENTRY
*pGlobal
, HMODULE hModule
, WORD wSeg
)
736 /***********************************************************************
737 * MemManInfo (TOOLHELP.72)
739 BOOL
MemManInfo( MEMMANINFO
*pInfo
)
744 /***********************************************************************
746 * implements GlobalAlloc (KERNEL32.316)
747 * LocalAlloc (KERNEL32.372)
749 void *GlobalAlloc32(int flags
,int size
)
751 dprintf_global(stddeb
,"GlobalAlloc32(%x,%x)\n",flags
,size
);