2 * Global heap functions
4 * Copyright 1995 Alexandre Julliard
14 #include "selectors.h"
16 #include "stackframe.h"
21 /* Global arena block */
24 DWORD base
; /* Base address */
25 DWORD size
; /* Size in bytes (0 indicates a free block) */
26 HGLOBAL handle
; /* Handle for this block */
27 HGLOBAL hOwner
; /* Owner of this block */
28 BYTE lockCount
; /* Count of GlobalFix() calls */
29 BYTE pageLockCount
; /* Count of GlobalPageLock() calls */
30 BYTE flags
; /* Allocation flags */
31 BYTE selCount
; /* Number of selectors allocated for this block */
35 /* Flags definitions */
36 #define GA_MOVEABLE 0x02 /* same as GMEM_MOVEABLE */
37 #define GA_DGROUP 0x04
38 #define GA_DISCARDABLE 0x08
39 #define GA_IPCSHARE 0x10 /* same as GMEM_DDESHARE */
42 static GLOBALARENA
*pGlobalArena
= NULL
;
43 static int globalArenaSize
= 0;
45 #define GLOBAL_MAX_ALLOC_SIZE 0x00ff0000 /* Largest allocation is 16M - 64K */
47 #define GET_ARENA_PTR(handle) (pGlobalArena + ((handle) >> __AHSHIFT))
49 /***********************************************************************
52 * Return the arena for a given selector, growing the arena array if needed.
54 static GLOBALARENA
*GLOBAL_GetArena( WORD sel
, WORD selcount
)
56 if (((sel
>> __AHSHIFT
) + selcount
) > globalArenaSize
)
58 int newsize
= ((sel
>> __AHSHIFT
) + selcount
+ 0xff) & ~0xff;
59 GLOBALARENA
*pNewArena
= realloc( pGlobalArena
,
60 newsize
* sizeof(GLOBALARENA
) );
61 if (!pNewArena
) return 0;
62 pGlobalArena
= pNewArena
;
63 memset( pGlobalArena
+ globalArenaSize
, 0,
64 (newsize
- globalArenaSize
) * sizeof(GLOBALARENA
) );
65 globalArenaSize
= newsize
;
67 return pGlobalArena
+ (sel
>> __AHSHIFT
);
75 for (i
= globalArenaSize
-1 ; i
>=0 ; i
--) {
76 if (pGlobalArena
[i
].size
!=0 && (pGlobalArena
[i
].handle
& 0x8000)){
78 printf("0x%08x, ",pGlobalArena
[i
].handle
);
86 /***********************************************************************
89 * Create a global heap block for a fixed range of linear memory.
91 HGLOBAL
GLOBAL_CreateBlock( WORD flags
, const void *ptr
, DWORD size
,
92 HGLOBAL hOwner
, BOOL isCode
,
93 BOOL is32Bit
, BOOL isReadOnly
,
99 /* Allocate the selector(s) */
101 sel
= SELECTOR_AllocBlock( ptr
, size
,
102 isCode
? SEGMENT_CODE
: SEGMENT_DATA
,
103 is32Bit
, isReadOnly
);
106 selcount
= (size
+ 0xffff) / 0x10000;
108 if (!(pArena
= GLOBAL_GetArena( sel
, selcount
)))
114 /* Fill the arena block */
116 pArena
->base
= (DWORD
)ptr
;
117 pArena
->size
= GET_SEL_LIMIT(sel
) + 1;
118 if ((flags
& GMEM_DDESHARE
) && Options
.ipc
)
120 pArena
->handle
= shmdata
->handle
;
121 pArena
->shmid
= shmdata
->shmid
;
126 pArena
->handle
= (flags
& GMEM_MOVEABLE
) ? sel
- 1 : sel
;
129 pArena
->hOwner
= hOwner
;
130 pArena
->lockCount
= 0;
131 pArena
->pageLockCount
= 0;
132 pArena
->flags
= flags
& GA_MOVEABLE
;
133 if (flags
& GMEM_DISCARDABLE
) pArena
->flags
|= GA_DISCARDABLE
;
134 if (flags
& GMEM_DDESHARE
) pArena
->flags
|= GA_IPCSHARE
;
135 if (!isCode
) pArena
->flags
|= GA_DGROUP
;
136 pArena
->selCount
= selcount
;
137 if (selcount
> 1) /* clear the next arena blocks */
138 memset( pArena
+ 1, 0, (selcount
- 1) * sizeof(GLOBALARENA
) );
140 return pArena
->handle
;
144 /***********************************************************************
147 * Free a block allocated by GLOBAL_CreateBlock, without touching
148 * the associated linear memory range.
150 BOOL
GLOBAL_FreeBlock( HGLOBAL handle
)
154 if (!handle
) return TRUE
;
155 sel
= GlobalHandleToSel( handle
);
156 if (FreeSelector( sel
)) return FALSE
; /* failed */
157 memset( GET_ARENA_PTR(sel
), 0, sizeof(GLOBALARENA
) );
162 /***********************************************************************
165 * Implementation of GlobalAlloc()
167 HGLOBAL
GLOBAL_Alloc( WORD flags
, DWORD size
, HGLOBAL hOwner
,
168 BOOL isCode
, BOOL is32Bit
, BOOL isReadOnly
)
174 dprintf_global( stddeb
, "GlobalAlloc: %ld flags=%04x\n", size
, flags
);
178 if (size
>= GLOBAL_MAX_ALLOC_SIZE
- 0x1f) return 0;
179 if (size
== 0) size
= 0x20;
180 else size
= (size
+ 0x1f) & ~0x1f;
182 /* Allocate the linear memory */
185 if ((flags
& GMEM_DDESHARE
) && Options
.ipc
)
186 ptr
= DDE_malloc(flags
, size
, &shmdata
);
188 #endif /* CONFIG_IPC */
189 ptr
= malloc( size
);
192 /* Allocate the selector(s) */
194 handle
= GLOBAL_CreateBlock( flags
, ptr
, size
, hOwner
,
195 isCode
, is32Bit
, isReadOnly
, &shmdata
);
202 if (flags
& GMEM_ZEROINIT
) memset( ptr
, 0, size
);
208 /***********************************************************************
211 * Find the arena for a given handle
212 * (when handle is not serial - e.g. DDE)
214 static GLOBALARENA
*GLOBAL_FindArena( HGLOBAL handle
)
217 for (i
= globalArenaSize
-1 ; i
>=0 ; i
--) {
218 if (pGlobalArena
[i
].size
!=0 && pGlobalArena
[i
].handle
== handle
)
219 return ( &pGlobalArena
[i
] );
225 /***********************************************************************
226 * DDE_GlobalHandleToSel
229 WORD
DDE_GlobalHandleToSel( HGLOBAL handle
)
234 pArena
= GLOBAL_FindArena(handle
);
236 int ArenaIdx
= pArena
- pGlobalArena
;
238 /* See if synchronized to the shared memory */
239 return DDE_SyncHandle(handle
, ( ArenaIdx
<< __AHSHIFT
) | 7);
242 /* attach the block */
243 DDE_AttachHandle(handle
, &segptr
);
245 return SELECTOROF( segptr
);
247 #endif /* CONFIG_IPC */
250 /***********************************************************************
251 * GlobalAlloc (KERNEL.15)
253 HGLOBAL
GlobalAlloc( WORD flags
, DWORD size
)
255 HANDLE owner
= GetCurrentPDB();
257 if (flags
& GMEM_DDESHARE
)
258 owner
= GetExePtr(owner
); /* Make it a module handle */
259 return GLOBAL_Alloc( flags
, size
, owner
, FALSE
, FALSE
, FALSE
);
263 /***********************************************************************
264 * GlobalReAlloc (KERNEL.16)
266 HGLOBAL
GlobalReAlloc( HGLOBAL handle
, DWORD size
, WORD flags
)
271 GLOBALARENA
*pArena
, *pNewArena
;
272 WORD sel
= GlobalHandleToSel( handle
);
274 dprintf_global( stddeb
, "GlobalReAlloc: %04x %ld flags=%04x\n",
275 handle
, size
, flags
);
276 if (!handle
) return 0;
279 if (Options
.ipc
&& (flags
& GMEM_DDESHARE
|| is_dde_handle(handle
))) {
281 "GlobalReAlloc: shared memory reallocating unimplemented\n");
284 #endif /* CONFIG_IPC */
286 pArena
= GET_ARENA_PTR( handle
);
288 /* Discard the block if requested */
290 if ((size
== 0) && (flags
& GMEM_MOVEABLE
) && !(flags
& GMEM_MODIFY
))
292 if (!(pArena
->flags
& GA_MOVEABLE
) ||
293 !(pArena
->flags
& GA_DISCARDABLE
) ||
294 (pArena
->lockCount
> 0) || (pArena
->pageLockCount
> 0)) return 0;
295 free( (void *)pArena
->base
);
297 /* Note: we rely on the fact that SELECTOR_ReallocBlock won't */
298 /* change the selector if we are shrinking the block */
299 SELECTOR_ReallocBlock( sel
, 0, 1, SEGMENT_DATA
, 0, 0 );
305 if (size
> GLOBAL_MAX_ALLOC_SIZE
- 0x20) return 0;
306 if (size
== 0) size
= 0x20;
307 else size
= (size
+ 0x1f) & ~0x1f;
309 /* Change the flags */
311 if (flags
& GMEM_MODIFY
)
313 /* Change the flags, leaving GA_DGROUP alone */
314 pArena
->flags
= (pArena
->flags
& GA_DGROUP
) | (flags
& GA_MOVEABLE
);
315 if (flags
& GMEM_DISCARDABLE
) pArena
->flags
|= GA_DISCARDABLE
;
319 /* Reallocate the linear memory */
321 ptr
= (void *)pArena
->base
;
322 oldsize
= pArena
->size
;
323 dprintf_global(stddeb
,"oldsize %08lx\n",oldsize
);
324 if (size
== oldsize
) return handle
; /* Nothing to do */
326 ptr
= realloc( ptr
, size
);
330 memset( pArena
, 0, sizeof(GLOBALARENA
) );
334 /* Reallocate the selector(s) */
336 sel
= SELECTOR_ReallocBlock( sel
, ptr
, size
, SEGMENT_DATA
, 0, 0 );
340 memset( pArena
, 0, sizeof(GLOBALARENA
) );
343 selcount
= (size
+ 0xffff) / 0x10000;
345 if (!(pNewArena
= GLOBAL_GetArena( sel
, selcount
)))
352 /* Fill the new arena block */
354 if (pNewArena
!= pArena
) memcpy( pNewArena
, pArena
, sizeof(GLOBALARENA
) );
355 pNewArena
->base
= (DWORD
)ptr
;
356 pNewArena
->size
= GET_SEL_LIMIT(sel
) + 1;
357 pNewArena
->selCount
= selcount
;
358 pNewArena
->handle
= (pNewArena
->flags
& GA_MOVEABLE
) ? sel
- 1 : sel
;
360 if (selcount
> 1) /* clear the next arena blocks */
361 memset( pNewArena
+ 1, 0, (selcount
- 1) * sizeof(GLOBALARENA
) );
363 if ((oldsize
< size
) && (flags
& GMEM_ZEROINIT
))
364 memset( (char *)ptr
+ oldsize
, 0, size
- oldsize
);
365 return pNewArena
->handle
;
369 /***********************************************************************
370 * GlobalFree (KERNEL.17)
372 HGLOBAL
GlobalFree( HGLOBAL handle
)
374 void *ptr
= GlobalLock( handle
);
376 dprintf_global( stddeb
, "GlobalFree: %04x\n", handle
);
377 if (!GLOBAL_FreeBlock( handle
)) return handle
; /* failed */
379 if (is_dde_handle(handle
)) return DDE_GlobalFree(handle
);
380 #endif /* CONFIG_IPC */
381 if (ptr
) free( ptr
);
386 /***********************************************************************
387 * WIN16_GlobalLock (KERNEL.18)
389 * This is the GlobalLock() function used by 16-bit code.
391 SEGPTR
WIN16_GlobalLock( HGLOBAL handle
)
393 dprintf_global( stddeb
, "WIN16_GlobalLock(%04x) -> %08lx\n",
394 handle
, MAKELONG( 0, GlobalHandleToSel(handle
)) );
395 if (!handle
) return 0;
398 if (is_dde_handle(handle
))
399 return (SEGPTR
)MAKELONG( 0, DDE_GlobalHandleToSel(handle
) );
400 #endif /* CONFIG_IPC */
402 if (!GET_ARENA_PTR(handle
)->base
) return (SEGPTR
)0;
403 return (SEGPTR
)MAKELONG( 0, GlobalHandleToSel(handle
) );
407 /***********************************************************************
408 * GlobalLock (KERNEL.18)
410 * This is the GlobalLock() function used by 32-bit code.
412 LPVOID
GlobalLock( HGLOBAL handle
)
414 if (!handle
) return 0;
416 if (is_dde_handle(handle
)) return DDE_AttachHandle(handle
, NULL
);
418 return (LPSTR
)GET_ARENA_PTR(handle
)->base
;
422 /***********************************************************************
423 * GlobalUnlock (KERNEL.19)
425 BOOL
GlobalUnlock( HGLOBAL handle
)
427 dprintf_global( stddeb
, "GlobalUnlock: %04x\n", handle
);
432 /***********************************************************************
433 * GlobalSize (KERNEL.20)
435 DWORD
GlobalSize( HGLOBAL handle
)
437 dprintf_global( stddeb
, "GlobalSize: %04x\n", handle
);
438 if (!handle
) return 0;
439 return GET_ARENA_PTR(handle
)->size
;
443 /***********************************************************************
444 * GlobalHandle (KERNEL.21)
446 DWORD
GlobalHandle( WORD sel
)
448 dprintf_global( stddeb
, "GlobalHandle: %04x\n", sel
);
449 return MAKELONG( GET_ARENA_PTR(sel
)->handle
, GlobalHandleToSel(sel
) );
453 /***********************************************************************
454 * GlobalFlags (KERNEL.22)
456 WORD
GlobalFlags( HGLOBAL handle
)
460 dprintf_global( stddeb
, "GlobalFlags: %04x\n", handle
);
461 pArena
= GET_ARENA_PTR(handle
);
462 return pArena
->lockCount
|
463 ((pArena
->flags
& GA_DISCARDABLE
) ? GMEM_DISCARDABLE
: 0) |
464 ((pArena
->base
== 0) ? GMEM_DISCARDED
: 0);
468 /***********************************************************************
469 * LockSegment (KERNEL.23)
471 HGLOBAL
LockSegment( HGLOBAL handle
)
473 dprintf_global( stddeb
, "LockSegment: %04x\n", handle
);
474 if (handle
== (HGLOBAL
)-1) handle
= CURRENT_DS
;
475 GET_ARENA_PTR(handle
)->lockCount
++;
480 /***********************************************************************
481 * UnlockSegment (KERNEL.24)
483 void UnlockSegment( HGLOBAL handle
)
485 dprintf_global( stddeb
, "UnlockSegment: %04x\n", handle
);
486 if (handle
== (HGLOBAL
)-1) handle
= CURRENT_DS
;
487 GET_ARENA_PTR(handle
)->lockCount
--;
488 /* FIXME: this ought to return the lock count in CX (go figure...) */
492 /***********************************************************************
493 * GlobalCompact (KERNEL.25)
495 DWORD
GlobalCompact( DWORD desired
)
497 return GLOBAL_MAX_ALLOC_SIZE
;
501 /***********************************************************************
502 * GlobalFreeAll (KERNEL.26)
504 void GlobalFreeAll( HANDLE owner
)
509 pArena
= pGlobalArena
;
510 for (i
= 0; i
< globalArenaSize
; i
++, pArena
++)
512 if ((pArena
->size
!= 0) && (pArena
->hOwner
== owner
))
513 GlobalFree( pArena
->handle
);
518 /***********************************************************************
519 * GlobalWire (KERNEL.111)
521 SEGPTR
GlobalWire( HGLOBAL handle
)
523 return WIN16_GlobalLock( handle
);
527 /***********************************************************************
528 * GlobalUnWire (KERNEL.112)
530 BOOL
GlobalUnWire( HGLOBAL handle
)
532 return GlobalUnlock( handle
);
536 /***********************************************************************
537 * GlobalDOSAlloc (KERNEL.184)
539 DWORD
GlobalDOSAlloc( DWORD size
)
541 WORD sel
= GlobalAlloc( GMEM_FIXED
, size
);
543 return MAKELONG( sel
, sel
/* this one ought to be a real-mode segment */ );
547 /***********************************************************************
548 * GlobalDOSFree (KERNEL.185)
550 WORD
GlobalDOSFree( WORD sel
)
552 return GlobalFree( GlobalHandle(sel
) ) ? sel
: 0;
556 /***********************************************************************
557 * SetSwapAreaSize (KERNEL.106)
559 LONG
SetSwapAreaSize( WORD size
)
561 dprintf_global(stdnimp
, "STUB: SetSwapAreaSize(%d)\n", size
);
562 return MAKELONG( size
, 0xffff );
566 /***********************************************************************
567 * GlobalLRUOldest (KERNEL.163)
569 HGLOBAL
GlobalLRUOldest( HGLOBAL handle
)
571 dprintf_global( stddeb
, "GlobalLRUOldest: %04x\n", handle
);
572 if (handle
== (HGLOBAL
)-1) handle
= CURRENT_DS
;
577 /***********************************************************************
578 * GlobalLRUNewest (KERNEL.164)
580 HGLOBAL
GlobalLRUNewest( HGLOBAL handle
)
582 dprintf_global( stddeb
, "GlobalLRUNewest: %04x\n", handle
);
583 if (handle
== (HGLOBAL
)-1) handle
= CURRENT_DS
;
588 /***********************************************************************
589 * GetFreeSpace (KERNEL.169)
591 DWORD
GetFreeSpace( UINT wFlags
)
593 return GLOBAL_MAX_ALLOC_SIZE
;
597 /***********************************************************************
598 * GlobalPageLock (KERNEL.191)
600 WORD
GlobalPageLock( HGLOBAL handle
)
602 dprintf_global( stddeb
, "GlobalPageLock: %04x\n", handle
);
603 return ++(GET_ARENA_PTR(handle
)->pageLockCount
);
607 /***********************************************************************
608 * GlobalPageUnlock (KERNEL.192)
610 WORD
GlobalPageUnlock( HGLOBAL handle
)
612 dprintf_global( stddeb
, "GlobalPageUnlock: %04x\n", handle
);
613 return --(GET_ARENA_PTR(handle
)->pageLockCount
);
617 /***********************************************************************
618 * GlobalFix (KERNEL.197)
620 void GlobalFix( HGLOBAL handle
)
622 dprintf_global( stddeb
, "GlobalFix: %04x\n", handle
);
623 GET_ARENA_PTR(handle
)->lockCount
++;
627 /***********************************************************************
628 * GlobalUnfix (KERNEL.198)
630 void GlobalUnfix( HGLOBAL handle
)
632 dprintf_global( stddeb
, "GlobalUnfix: %04x\n", handle
);
633 GET_ARENA_PTR(handle
)->lockCount
--;
637 /***********************************************************************
638 * FarSetOwner (KERNEL.403)
640 void FarSetOwner( HANDLE handle
, WORD hOwner
)
642 GET_ARENA_PTR(handle
)->hOwner
= hOwner
;
646 /***********************************************************************
647 * FarGetOwner (KERNEL.404)
649 WORD
FarGetOwner( HANDLE handle
)
651 return GET_ARENA_PTR(handle
)->hOwner
;
655 /***********************************************************************
656 * GlobalHandleToSel (TOOLHELP.50)
658 WORD
GlobalHandleToSel( HGLOBAL handle
)
660 dprintf_toolhelp( stddeb
, "GlobalHandleToSel: %04x\n", handle
);
661 if (!handle
) return 0;
663 if (is_dde_handle(handle
)) return DDE_GlobalHandleToSel(handle
);
667 fprintf( stderr
, "Program attempted invalid selector conversion\n" );
674 /***********************************************************************
675 * GlobalFirst (TOOLHELP.51)
677 BOOL
GlobalFirst( GLOBALENTRY
*pGlobal
, WORD wFlags
)
679 if (wFlags
== GLOBAL_LRU
) return FALSE
;
681 return GlobalNext( pGlobal
, wFlags
);
685 /***********************************************************************
686 * GlobalNext (TOOLHELP.52)
688 BOOL
GlobalNext( GLOBALENTRY
*pGlobal
, WORD wFlags
)
692 if (pGlobal
->dwNext
>= globalArenaSize
) return FALSE
;
693 pArena
= pGlobalArena
+ pGlobal
->dwNext
;
694 if (wFlags
== GLOBAL_FREE
) /* only free blocks */
697 for (i
= pGlobal
->dwNext
; i
< globalArenaSize
; i
++, pArena
++)
698 if (pArena
->size
== 0) break; /* block is free */
699 if (i
>= globalArenaSize
) return FALSE
;
703 pGlobal
->dwAddress
= pArena
->base
;
704 pGlobal
->dwBlockSize
= pArena
->size
;
705 pGlobal
->hBlock
= pArena
->handle
;
706 pGlobal
->wcLock
= pArena
->lockCount
;
707 pGlobal
->wcPageLock
= pArena
->pageLockCount
;
708 pGlobal
->wFlags
= (GetCurrentPDB() == pArena
->hOwner
);
709 pGlobal
->wHeapPresent
= FALSE
;
710 pGlobal
->hOwner
= pArena
->hOwner
;
711 pGlobal
->wType
= GT_UNKNOWN
;
718 /***********************************************************************
719 * GlobalInfo (TOOLHELP.53)
721 BOOL
GlobalInfo( GLOBALINFO
*pInfo
)
726 pInfo
->wcItems
= globalArenaSize
;
727 pInfo
->wcItemsFree
= 0;
728 pInfo
->wcItemsLRU
= 0;
729 for (i
= 0, pArena
= pGlobalArena
; i
< globalArenaSize
; i
++, pArena
++)
730 if (pArena
->size
== 0) pInfo
->wcItemsFree
++;
735 /***********************************************************************
736 * GlobalEntryHandle (TOOLHELP.54)
738 BOOL
GlobalEntryHandle( GLOBALENTRY
*pGlobal
, HGLOBAL hItem
)
744 /***********************************************************************
745 * GlobalEntryModule (TOOLHELP.55)
747 BOOL
GlobalEntryModule( GLOBALENTRY
*pGlobal
, HMODULE hModule
, WORD wSeg
)
753 /***********************************************************************
754 * MemManInfo (TOOLHELP.72)
756 BOOL
MemManInfo( MEMMANINFO
*pInfo
)
761 /***********************************************************************
763 * implements GlobalAlloc (KERNEL32.316)
764 * LocalAlloc (KERNEL32.372)
766 void *GlobalAlloc32(int flags
,int size
)
768 dprintf_global(stddeb
,"GlobalAlloc32(%x,%x)\n",flags
,size
);