2 * Global heap functions
4 * Copyright 1995 Alexandre Julliard
16 #include "selectors.h"
19 #include "stackframe.h"
24 /* Global arena block */
27 DWORD base; /* Base address (0 if discarded) */
28 DWORD size; /* Size in bytes (0 indicates a free block) */
29 HGLOBAL16 handle; /* Handle for this block */
30 HGLOBAL16 hOwner; /* Owner of this block */
31 BYTE lockCount; /* Count of GlobalFix() calls */
32 BYTE pageLockCount; /* Count of GlobalPageLock() calls */
33 BYTE flags; /* Allocation flags */
34 BYTE selCount; /* Number of selectors allocated for this block */
40 /* Flags definitions */
41 #define GA_MOVEABLE 0x02 /* same as GMEM_MOVEABLE */
42 #define GA_DGROUP 0x04
43 #define GA_DISCARDABLE 0x08
44 #define GA_IPCSHARE 0x10 /* same as GMEM_DDESHARE */
47 static GLOBALARENA *pGlobalArena = NULL;
48 static int globalArenaSize = 0;
50 #define GLOBAL_MAX_ALLOC_SIZE 0x00ff0000 /* Largest allocation is 16M - 64K */
52 #define VALID_HANDLE(handle) (((handle)>>__AHSHIFT)<globalArenaSize)
53 #define GET_ARENA_PTR(handle) (pGlobalArena + ((handle) >> __AHSHIFT))
55 /***********************************************************************
58 * Return the arena for a given selector, growing the arena array if needed.
60 static GLOBALARENA *GLOBAL_GetArena( WORD sel, WORD selcount )
62 if (((sel >> __AHSHIFT) + selcount) > globalArenaSize)
64 int newsize = ((sel >> __AHSHIFT) + selcount + 0xff) & ~0xff;
65 GLOBALARENA *pNewArena = realloc( pGlobalArena,
66 newsize * sizeof(GLOBALARENA) );
67 if (!pNewArena) return 0;
68 pGlobalArena = pNewArena;
69 memset( pGlobalArena + globalArenaSize, 0,
70 (newsize - globalArenaSize) * sizeof(GLOBALARENA) );
71 globalArenaSize = newsize;
73 return pGlobalArena + (sel >> __AHSHIFT);
81 for (i = globalArenaSize-1 ; i>=0 ; i--) {
82 if (pGlobalArena[i].size!=0 && (pGlobalArena[i].handle & 0x8000)){
84 DUMP("0x%08x, ",pGlobalArena[i].handle);
92 /***********************************************************************
95 * Create a global heap block for a fixed range of linear memory.
97 HGLOBAL16 GLOBAL_CreateBlock( WORD flags, const void *ptr, DWORD size,
98 HGLOBAL16 hOwner, BOOL16 isCode,
99 BOOL16 is32Bit, BOOL16 isReadOnly,
105 /* Allocate the selector(s) */
107 sel = SELECTOR_AllocBlock( ptr, size,
108 isCode ? SEGMENT_CODE : SEGMENT_DATA,
109 is32Bit, isReadOnly );
112 selcount = (size + 0xffff) / 0x10000;
114 if (!(pArena = GLOBAL_GetArena( sel, selcount )))
116 SELECTOR_FreeBlock( sel, selcount );
120 /* Fill the arena block */
122 pArena->base = (DWORD)ptr;
123 pArena->size = GET_SEL_LIMIT(sel) + 1;
126 if (flags & GMEM_DDESHARE)
128 pArena->handle = shmdata->handle;
129 pArena->shmid = shmdata->shmid;
134 pArena->handle = (flags & GMEM_MOVEABLE) ? sel - 1 : sel;
138 pArena->handle = (flags & GMEM_MOVEABLE) ? sel - 1 : sel;
140 pArena->hOwner = hOwner;
141 pArena->lockCount = 0;
142 pArena->pageLockCount = 0;
143 pArena->flags = flags & GA_MOVEABLE;
144 if (flags & GMEM_DISCARDABLE) pArena->flags |= GA_DISCARDABLE;
145 if (flags & GMEM_DDESHARE) pArena->flags |= GA_IPCSHARE;
146 if (!isCode) pArena->flags |= GA_DGROUP;
147 pArena->selCount = selcount;
148 if (selcount > 1) /* clear the next arena blocks */
149 memset( pArena + 1, 0, (selcount - 1) * sizeof(GLOBALARENA) );
151 return pArena->handle;
155 /***********************************************************************
158 * Free a block allocated by GLOBAL_CreateBlock, without touching
159 * the associated linear memory range.
161 BOOL16 GLOBAL_FreeBlock( HGLOBAL16 handle )
166 if (!handle) return TRUE;
167 sel = GlobalHandleToSel( handle );
168 if (!VALID_HANDLE(sel))
170 pArena = GET_ARENA_PTR(sel);
171 SELECTOR_FreeBlock( sel, (pArena->size + 0xffff) / 0x10000 );
172 memset( pArena, 0, sizeof(GLOBALARENA) );
177 /***********************************************************************
180 * Implementation of GlobalAlloc16()
182 HGLOBAL16 GLOBAL_Alloc( UINT16 flags, DWORD size, HGLOBAL16 hOwner,
183 BOOL16 isCode, BOOL16 is32Bit, BOOL16 isReadOnly )
189 TRACE(global, "%ld flags=%04x\n", size, flags );
191 /* If size is 0, create a discarded block */
193 if (size == 0) return GLOBAL_CreateBlock( flags, NULL, 1, hOwner, isCode,
194 is32Bit, isReadOnly, NULL );
198 if (size >= GLOBAL_MAX_ALLOC_SIZE - 0x1f) return 0;
199 size = (size + 0x1f) & ~0x1f;
201 /* Allocate the linear memory */
204 if (flags & GMEM_DDESHARE)
205 ptr = DDE_malloc(flags, size, &shmdata);
207 #endif /* CONFIG_IPC */
209 ptr = HeapAlloc( SystemHeap, 0, size );
211 /* FIXME: free discardable blocks and try again? */
214 /* Allocate the selector(s) */
216 handle = GLOBAL_CreateBlock( flags, ptr, size, hOwner,
217 isCode, is32Bit, isReadOnly, &shmdata);
220 HeapFree( SystemHeap, 0, ptr );
224 if (flags & GMEM_ZEROINIT) memset( ptr, 0, size );
230 /***********************************************************************
233 * Find the arena for a given handle
234 * (when handle is not serial - e.g. DDE)
236 static GLOBALARENA *GLOBAL_FindArena( HGLOBAL16 handle)
239 for (i = globalArenaSize-1 ; i>=0 ; i--) {
240 if (pGlobalArena[i].size!=0 && pGlobalArena[i].handle == handle)
241 return ( &pGlobalArena[i] );
247 /***********************************************************************
248 * DDE_GlobalHandleToSel
251 WORD DDE_GlobalHandleToSel( HGLOBAL16 handle )
256 pArena= GLOBAL_FindArena(handle);
258 int ArenaIdx = pArena - pGlobalArena;
260 /* See if synchronized to the shared memory */
261 return DDE_SyncHandle(handle, ( ArenaIdx << __AHSHIFT) | 7);
264 /* attach the block */
265 DDE_AttachHandle(handle, &segptr);
267 return SELECTOROF( segptr );
269 #endif /* CONFIG_IPC */
272 /***********************************************************************
273 * GlobalAlloc16 (KERNEL.15)
278 HGLOBAL16 WINAPI GlobalAlloc16(
279 UINT16 flags, /* [in] Object allocation attributes */
280 DWORD size /* [in] Number of bytes to allocate */
282 HANDLE16 owner = GetCurrentPDB();
284 if (flags & GMEM_DDESHARE)
285 owner = GetExePtr(owner); /* Make it a module handle */
286 return GLOBAL_Alloc( flags, size, owner, FALSE, FALSE, FALSE );
290 /***********************************************************************
291 * GlobalReAlloc16 (KERNEL.16)
296 HGLOBAL16 WINAPI GlobalReAlloc16(
297 HGLOBAL16 handle, /* [in] Handle of global memory object */
298 DWORD size, /* [in] New size of block */
299 UINT16 flags /* [in] How to reallocate object */
304 GLOBALARENA *pArena, *pNewArena;
305 WORD sel = GlobalHandleToSel( handle );
307 TRACE(global, "%04x %ld flags=%04x\n",
308 handle, size, flags );
309 if (!handle) return 0;
312 if (flags & GMEM_DDESHARE || is_dde_handle(handle))
314 FIXME(global, "shared memory reallocating unimplemented\n");
317 #endif /* CONFIG_IPC */
319 if (!VALID_HANDLE(handle)) {
320 WARN(global, "Invalid handle 0x%04x!\n", handle);
323 pArena = GET_ARENA_PTR( handle );
325 /* Discard the block if requested */
327 if ((size == 0) && (flags & GMEM_MOVEABLE) && !(flags & GMEM_MODIFY))
329 if (!(pArena->flags & GA_MOVEABLE) ||
330 !(pArena->flags & GA_DISCARDABLE) ||
331 (pArena->lockCount > 0) || (pArena->pageLockCount > 0)) return 0;
332 HeapFree( SystemHeap, 0, (void *)pArena->base );
335 /* Note: we rely on the fact that SELECTOR_ReallocBlock won't
336 * change the selector if we are shrinking the block.
337 * FIXME: shouldn't we keep selectors until the block is deleted?
339 SELECTOR_ReallocBlock( sel, 0, 1, SEGMENT_DATA, 0, 0 );
345 if (size > GLOBAL_MAX_ALLOC_SIZE - 0x20) return 0;
346 if (size == 0) size = 0x20;
347 else size = (size + 0x1f) & ~0x1f;
349 /* Change the flags */
351 if (flags & GMEM_MODIFY)
353 /* Change the flags, leaving GA_DGROUP alone */
354 pArena->flags = (pArena->flags & GA_DGROUP) | (flags & GA_MOVEABLE);
355 if (flags & GMEM_DISCARDABLE) pArena->flags |= GA_DISCARDABLE;
359 /* Reallocate the linear memory */
361 ptr = (void *)pArena->base;
362 oldsize = pArena->size;
363 TRACE(global,"oldsize %08lx\n",oldsize);
364 if (ptr && (size == oldsize)) return handle; /* Nothing to do */
366 ptr = HeapReAlloc( SystemHeap, 0, ptr, size );
369 SELECTOR_FreeBlock( sel, (oldsize + 0xffff) / 0x10000 );
370 memset( pArena, 0, sizeof(GLOBALARENA) );
374 /* Reallocate the selector(s) */
376 sel = SELECTOR_ReallocBlock( sel, ptr, size, SEGMENT_DATA, 0, 0 );
379 HeapFree( SystemHeap, 0, ptr );
380 memset( pArena, 0, sizeof(GLOBALARENA) );
383 selcount = (size + 0xffff) / 0x10000;
385 if (!(pNewArena = GLOBAL_GetArena( sel, selcount )))
387 HeapFree( SystemHeap, 0, ptr );
388 SELECTOR_FreeBlock( sel, selcount );
392 /* Fill the new arena block */
394 if (pNewArena != pArena) memcpy( pNewArena, pArena, sizeof(GLOBALARENA) );
395 pNewArena->base = (DWORD)ptr;
396 pNewArena->size = GET_SEL_LIMIT(sel) + 1;
397 pNewArena->selCount = selcount;
398 pNewArena->handle = (pNewArena->flags & GA_MOVEABLE) ? sel - 1 : sel;
400 if (selcount > 1) /* clear the next arena blocks */
401 memset( pNewArena + 1, 0, (selcount - 1) * sizeof(GLOBALARENA) );
403 if ((oldsize < size) && (flags & GMEM_ZEROINIT))
404 memset( (char *)ptr + oldsize, 0, size - oldsize );
405 return pNewArena->handle;
409 /***********************************************************************
410 * GlobalFree16 (KERNEL.17)
415 HGLOBAL16 WINAPI GlobalFree16(
416 HGLOBAL16 handle /* [in] Handle of global memory object */
420 if (!VALID_HANDLE(handle)) {
421 WARN(global,"Invalid handle 0x%04x passed to GlobalFree16!\n",handle);
424 ptr = (void *)GET_ARENA_PTR(handle)->base;
426 TRACE(global, "%04x\n", handle );
427 if (!GLOBAL_FreeBlock( handle )) return handle; /* failed */
429 if (is_dde_handle(handle)) return DDE_GlobalFree(handle);
430 #endif /* CONFIG_IPC */
431 if (ptr) HeapFree( SystemHeap, 0, ptr );
436 /***********************************************************************
437 * WIN16_GlobalLock16 (KERNEL.18)
439 * This is the GlobalLock16() function used by 16-bit code.
441 SEGPTR WINAPI WIN16_GlobalLock16( HGLOBAL16 handle )
443 TRACE(global, "(%04x) -> %08lx\n",
444 handle, MAKELONG( 0, GlobalHandleToSel(handle)) );
447 if (handle == (HGLOBAL16)-1) handle = CURRENT_DS;
450 if (is_dde_handle(handle))
451 return PTR_SEG_OFF_TO_SEGPTR( DDE_GlobalHandleToSel(handle), 0 );
452 #endif /* CONFIG_IPC */
454 if (!VALID_HANDLE(handle)) {
455 WARN(global,"Invalid handle 0x%04x passed to WIN16_GlobalLock16!\n",handle);
458 if (!GET_ARENA_PTR(handle)->base) return (SEGPTR)0;
459 GET_ARENA_PTR(handle)->lockCount++;
460 return PTR_SEG_OFF_TO_SEGPTR( GlobalHandleToSel(handle), 0 );
461 /* FIXME: put segment value in CX as well */
467 /***********************************************************************
468 * GlobalLock16 (KERNEL.18)
470 * This is the GlobalLock16() function used by 32-bit code.
473 * Pointer to first byte of memory block
476 LPVOID WINAPI GlobalLock16(
477 HGLOBAL16 handle /* [in] Handle of global memory object */
479 if (!handle) return 0;
480 if (!VALID_HANDLE(handle))
482 GET_ARENA_PTR(handle)->lockCount++;
484 if (is_dde_handle(handle)) return DDE_AttachHandle(handle, NULL);
486 return (LPVOID)GET_ARENA_PTR(handle)->base;
490 /***********************************************************************
491 * GlobalUnlock16 (KERNEL.19)
493 * Should the return values be cast to booleans?
496 * TRUE: Object is still locked
497 * FALSE: Object is unlocked
499 BOOL16 WINAPI GlobalUnlock16(
500 HGLOBAL16 handle /* [in] Handle of global memory object */
502 GLOBALARENA *pArena = GET_ARENA_PTR(handle);
503 if (!VALID_HANDLE(handle)) {
504 WARN(global,"Invalid handle 0x%04x passed to GlobalUnlock16!\n",handle);
507 TRACE(global, "%04x\n", handle );
508 if (pArena->lockCount) pArena->lockCount--;
509 return pArena->lockCount;
513 /***********************************************************************
514 * GlobalSize16 (KERNEL.20)
516 * Size in bytes of object
519 DWORD WINAPI GlobalSize16(
520 HGLOBAL16 handle /* [in] Handle of global memory object */
522 TRACE(global, "%04x\n", handle );
523 if (!handle) return 0;
524 if (!VALID_HANDLE(handle))
526 return GET_ARENA_PTR(handle)->size;
530 /***********************************************************************
531 * GlobalHandle16 (KERNEL.21)
533 * Why is GlobalHandleToSel used here with the sel as input?
539 DWORD WINAPI GlobalHandle16(
540 WORD sel /* [in] Address of global memory block */
542 TRACE(global, "%04x\n", sel );
543 if (!VALID_HANDLE(sel)) {
544 WARN(global,"Invalid handle 0x%04x passed to GlobalHandle16!\n",sel);
547 return MAKELONG( GET_ARENA_PTR(sel)->handle, GlobalHandleToSel(sel) );
550 /***********************************************************************
551 * GlobalHandleNoRIP (KERNEL.159)
553 DWORD WINAPI GlobalHandleNoRIP( WORD sel )
556 for (i = globalArenaSize-1 ; i>=0 ; i--) {
557 if (pGlobalArena[i].size!=0 && pGlobalArena[i].handle == sel)
558 return MAKELONG( GET_ARENA_PTR(sel)->handle, GlobalHandleToSel(sel) );
564 /***********************************************************************
565 * GlobalFlags16 (KERNEL.22)
567 * Should this return GMEM_INVALID_HANDLE instead of 0 on invalid
571 * Value specifying flags and lock count
572 * GMEM_INVALID_HANDLE: Invalid handle
574 UINT16 WINAPI GlobalFlags16(
575 HGLOBAL16 handle /* [in] Handle of global memory object */
579 TRACE(global, "%04x\n", handle );
580 if (!VALID_HANDLE(handle)) {
581 WARN(global,"Invalid handle 0x%04x passed to GlobalFlags16!\n",handle);
584 pArena = GET_ARENA_PTR(handle);
585 return pArena->lockCount |
586 ((pArena->flags & GA_DISCARDABLE) ? GMEM_DISCARDABLE : 0) |
587 ((pArena->base == 0) ? GMEM_DISCARDED : 0);
591 /***********************************************************************
592 * LockSegment16 (KERNEL.23)
594 HGLOBAL16 WINAPI LockSegment16( HGLOBAL16 handle )
596 TRACE(global, "%04x\n", handle );
597 if (handle == (HGLOBAL16)-1) handle = CURRENT_DS;
598 if (!VALID_HANDLE(handle)) {
599 WARN(global,"Invalid handle 0x%04x passed to LockSegment16!\n",handle);
602 GET_ARENA_PTR(handle)->lockCount++;
607 /***********************************************************************
608 * UnlockSegment16 (KERNEL.24)
610 void WINAPI UnlockSegment16( HGLOBAL16 handle )
612 TRACE(global, "%04x\n", handle );
613 if (handle == (HGLOBAL16)-1) handle = CURRENT_DS;
614 if (!VALID_HANDLE(handle)) {
615 WARN(global,"Invalid handle 0x%04x passed to UnlockSegment16!\n",handle);
618 GET_ARENA_PTR(handle)->lockCount--;
619 /* FIXME: this ought to return the lock count in CX (go figure...) */
623 /***********************************************************************
624 * GlobalCompact16 (KERNEL.25)
626 DWORD WINAPI GlobalCompact16( DWORD desired )
628 return GLOBAL_MAX_ALLOC_SIZE;
632 /***********************************************************************
633 * GlobalFreeAll (KERNEL.26)
635 void WINAPI GlobalFreeAll( HGLOBAL16 owner )
640 pArena = pGlobalArena;
641 for (i = 0; i < globalArenaSize; i++, pArena++)
643 if ((pArena->size != 0) && (pArena->hOwner == owner))
644 GlobalFree16( pArena->handle );
649 /***********************************************************************
650 * GlobalWire16 (KERNEL.111)
652 SEGPTR WINAPI GlobalWire16( HGLOBAL16 handle )
654 return WIN16_GlobalLock16( handle );
658 /***********************************************************************
659 * GlobalUnWire16 (KERNEL.112)
661 BOOL16 WINAPI GlobalUnWire16( HGLOBAL16 handle )
663 return !GlobalUnlock16( handle );
667 /***********************************************************************
668 * SetSwapAreaSize16 (KERNEL.106)
670 LONG WINAPI SetSwapAreaSize16( WORD size )
672 FIXME(global, "(%d) - stub!\n", size );
673 return MAKELONG( size, 0xffff );
677 /***********************************************************************
678 * GlobalLRUOldest (KERNEL.163)
680 HGLOBAL16 WINAPI GlobalLRUOldest( HGLOBAL16 handle )
682 TRACE(global, "%04x\n", handle );
683 if (handle == (HGLOBAL16)-1) handle = CURRENT_DS;
688 /***********************************************************************
689 * GlobalLRUNewest (KERNEL.164)
691 HGLOBAL16 WINAPI GlobalLRUNewest( HGLOBAL16 handle )
693 TRACE(global, "%04x\n", handle );
694 if (handle == (HGLOBAL16)-1) handle = CURRENT_DS;
699 /***********************************************************************
700 * GetFreeSpace16 (KERNEL.169)
702 DWORD WINAPI GetFreeSpace16( UINT16 wFlags )
705 GlobalMemoryStatus( &ms );
706 return ms.dwAvailVirtual;
709 /***********************************************************************
710 * GlobalDOSAlloc (KERNEL.184)
712 * Address (HW=Paragraph segment; LW=Selector)
714 DWORD WINAPI GlobalDOSAlloc(
715 DWORD size /* [in] Number of bytes to be allocated */
718 LPVOID lpBlock = DOSMEM_GetBlock( size, &uParagraph );
722 HMODULE16 hModule = GetModuleHandle16("KERNEL");
725 wSelector = GLOBAL_CreateBlock(GMEM_FIXED, lpBlock, size,
726 hModule, 0, 0, 0, NULL );
727 return MAKELONG(wSelector,uParagraph);
733 /***********************************************************************
734 * GlobalDOSFree (KERNEL.185)
739 WORD WINAPI GlobalDOSFree(
740 WORD sel /* [in] Selector */
742 DWORD block = GetSelectorBase(sel);
744 if( block && block < 0x100000 )
746 LPVOID lpBlock = DOSMEM_MapDosToLinear( block );
747 if( DOSMEM_FreeBlock( lpBlock ) )
748 GLOBAL_FreeBlock( sel );
755 /***********************************************************************
756 * GlobalPageLock (KERNEL.191)
758 WORD WINAPI GlobalPageLock( HGLOBAL16 handle )
760 TRACE(global, "%04x\n", handle );
761 if (!VALID_HANDLE(handle)) {
762 WARN(global,"Invalid handle 0x%04x passed to GlobalPageLock!\n",handle);
765 return ++(GET_ARENA_PTR(handle)->pageLockCount);
769 /***********************************************************************
770 * GlobalPageUnlock (KERNEL.192)
772 WORD WINAPI GlobalPageUnlock( HGLOBAL16 handle )
774 TRACE(global, "%04x\n", handle );
775 if (!VALID_HANDLE(handle)) {
776 WARN(global,"Invalid handle 0x%04x passed to GlobalPageUnlock!\n",handle);
779 return --(GET_ARENA_PTR(handle)->pageLockCount);
783 /***********************************************************************
784 * GlobalFix16 (KERNEL.197)
786 void WINAPI GlobalFix16( HGLOBAL16 handle )
788 TRACE(global, "%04x\n", handle );
789 if (!VALID_HANDLE(handle)) {
790 WARN(global,"Invalid handle 0x%04x passed to GlobalFix16!\n",handle);
793 GET_ARENA_PTR(handle)->lockCount++;
797 /***********************************************************************
798 * GlobalUnfix16 (KERNEL.198)
800 void WINAPI GlobalUnfix16( HGLOBAL16 handle )
802 TRACE(global, "%04x\n", handle );
803 if (!VALID_HANDLE(handle)) {
804 WARN(global,"Invalid handle 0x%04x passed to GlobalUnfix16!\n",handle);
807 GET_ARENA_PTR(handle)->lockCount--;
811 /***********************************************************************
812 * FarSetOwner (KERNEL.403)
814 void WINAPI FarSetOwner( HGLOBAL16 handle, HANDLE16 hOwner )
816 if (!VALID_HANDLE(handle)) {
817 WARN(global,"Invalid handle 0x%04x passed to FarSetOwner!\n",handle);
820 GET_ARENA_PTR(handle)->hOwner = hOwner;
824 /***********************************************************************
825 * FarGetOwner (KERNEL.404)
827 HANDLE16 WINAPI FarGetOwner( HGLOBAL16 handle )
829 if (!VALID_HANDLE(handle)) {
830 WARN(global,"Invalid handle 0x%04x passed to FarGetOwner!\n",handle);
833 return GET_ARENA_PTR(handle)->hOwner;
837 /***********************************************************************
838 * GlobalHandleToSel (TOOLHELP.50)
840 WORD WINAPI GlobalHandleToSel( HGLOBAL16 handle )
842 TRACE(toolhelp, "%04x\n", handle );
843 if (!handle) return 0;
845 if (is_dde_handle(handle)) return DDE_GlobalHandleToSel(handle);
847 if (!VALID_HANDLE(handle)) {
848 WARN(global,"Invalid handle 0x%04x passed to GlobalHandleToSel!\n",handle);
853 WARN(global, "Program attempted invalid selector conversion\n" );
860 /***********************************************************************
861 * GlobalFirst (TOOLHELP.51)
863 BOOL16 WINAPI GlobalFirst( GLOBALENTRY *pGlobal, WORD wFlags )
865 if (wFlags == GLOBAL_LRU) return FALSE;
867 return GlobalNext( pGlobal, wFlags );
871 /***********************************************************************
872 * GlobalNext (TOOLHELP.52)
874 BOOL16 WINAPI GlobalNext( GLOBALENTRY *pGlobal, WORD wFlags)
878 if (pGlobal->dwNext >= globalArenaSize) return FALSE;
879 pArena = pGlobalArena + pGlobal->dwNext;
880 if (wFlags == GLOBAL_FREE) /* only free blocks */
883 for (i = pGlobal->dwNext; i < globalArenaSize; i++, pArena++)
884 if (pArena->size == 0) break; /* block is free */
885 if (i >= globalArenaSize) return FALSE;
889 pGlobal->dwAddress = pArena->base;
890 pGlobal->dwBlockSize = pArena->size;
891 pGlobal->hBlock = pArena->handle;
892 pGlobal->wcLock = pArena->lockCount;
893 pGlobal->wcPageLock = pArena->pageLockCount;
894 pGlobal->wFlags = (GetCurrentPDB() == pArena->hOwner);
895 pGlobal->wHeapPresent = FALSE;
896 pGlobal->hOwner = pArena->hOwner;
897 pGlobal->wType = GT_UNKNOWN;
904 /***********************************************************************
905 * GlobalInfo (TOOLHELP.53)
907 BOOL16 WINAPI GlobalInfo( GLOBALINFO *pInfo )
912 pInfo->wcItems = globalArenaSize;
913 pInfo->wcItemsFree = 0;
914 pInfo->wcItemsLRU = 0;
915 for (i = 0, pArena = pGlobalArena; i < globalArenaSize; i++, pArena++)
916 if (pArena->size == 0) pInfo->wcItemsFree++;
921 /***********************************************************************
922 * GlobalEntryHandle (TOOLHELP.54)
924 BOOL16 WINAPI GlobalEntryHandle( GLOBALENTRY *pGlobal, HGLOBAL16 hItem )
926 GLOBALARENA *pArena = GET_ARENA_PTR(hItem);
928 pGlobal->dwAddress = pArena->base;
929 pGlobal->dwBlockSize = pArena->size;
930 pGlobal->hBlock = pArena->handle;
931 pGlobal->wcLock = pArena->lockCount;
932 pGlobal->wcPageLock = pArena->pageLockCount;
933 pGlobal->wFlags = (GetCurrentPDB() == pArena->hOwner);
934 pGlobal->wHeapPresent = FALSE;
935 pGlobal->hOwner = pArena->hOwner;
936 pGlobal->wType = GT_UNKNOWN;
943 /***********************************************************************
944 * GlobalEntryModule (TOOLHELP.55)
946 BOOL16 WINAPI GlobalEntryModule( GLOBALENTRY *pGlobal, HMODULE16 hModule,
953 /***********************************************************************
954 * MemManInfo (TOOLHELP.72)
956 BOOL16 WINAPI MemManInfo( MEMMANINFO *info )
961 * Not unsurprisingly although the documention says you
962 * _must_ provide the size in the dwSize field, this function
963 * (under Windows) always fills the structure and returns true.
965 GlobalMemoryStatus( &status );
966 info->wPageSize = VIRTUAL_GetPageSize();
967 info->dwLargestFreeBlock = status.dwAvailVirtual;
968 info->dwMaxPagesAvailable = info->dwLargestFreeBlock / info->wPageSize;
969 info->dwMaxPagesLockable = info->dwMaxPagesAvailable;
970 info->dwTotalLinearSpace = status.dwTotalVirtual / info->wPageSize;
971 info->dwTotalUnlockedPages = info->dwTotalLinearSpace;
972 info->dwFreePages = info->dwMaxPagesAvailable;
973 info->dwTotalPages = info->dwTotalLinearSpace;
974 info->dwFreeLinearSpace = info->dwMaxPagesAvailable;
975 info->dwSwapFilePages = status.dwTotalPageFile / info->wPageSize;
979 /***********************************************************************
980 * GetFreeMemInfo (KERNEL.316)
982 DWORD WINAPI GetFreeMemInfo(void)
986 return MAKELONG( info.dwTotalLinearSpace, info.dwMaxPagesAvailable );
990 * Win32 Global heap functions (GlobalXXX).
991 * These functions included in Win32 for compatibility with 16 bit Windows
992 * Especially the moveable blocks and handles are oldish.
993 * But the ability to directly allocate memory with GPTR and LPTR is widely
996 * The handle stuff looks horrible, but it's implemented almost like Win95
1001 #define MAGIC_GLOBAL_USED 0x5342
1002 #define GLOBAL_LOCK_MAX 0xFF
1003 #define HANDLE_TO_INTERN(h) ((PGLOBAL32_INTERN)(((char *)(h))-2))
1004 #define INTERN_TO_HANDLE(i) ((HGLOBAL32) &((i)->Pointer))
1005 #define POINTER_TO_HANDLE(p) (*(((HGLOBAL32 *)(p))-1))
1006 #define ISHANDLE(h) (((DWORD)(h)&2)!=0)
1007 #define ISPOINTER(h) (((DWORD)(h)&2)==0)
1009 typedef struct __GLOBAL32_INTERN
1012 LPVOID Pointer WINE_PACKED;
1015 } GLOBAL32_INTERN, *PGLOBAL32_INTERN;
1018 /***********************************************************************
1019 * GlobalAlloc32 (KERNEL32.315)
1024 HGLOBAL32 WINAPI GlobalAlloc32(
1025 UINT32 flags, /* [in] Object allocation attributes */
1026 DWORD size /* [in] Number of bytes to allocate */
1028 PGLOBAL32_INTERN pintern;
1032 if(flags&GMEM_ZEROINIT)
1033 hpflags=HEAP_ZERO_MEMORY;
1037 if((flags & GMEM_MOVEABLE)==0) /* POINTER */
1039 palloc=HeapAlloc(GetProcessHeap(), hpflags, size);
1040 return (HGLOBAL32) palloc;
1044 /* HeapLock(GetProcessHeap()); */
1046 pintern=HeapAlloc(GetProcessHeap(), 0, sizeof(GLOBAL32_INTERN));
1049 palloc=HeapAlloc(GetProcessHeap(), hpflags, size+sizeof(HGLOBAL32));
1050 *(HGLOBAL32 *)palloc=INTERN_TO_HANDLE(pintern);
1051 pintern->Pointer=palloc+sizeof(HGLOBAL32);
1054 pintern->Pointer=NULL;
1055 pintern->Magic=MAGIC_GLOBAL_USED;
1056 pintern->Flags=flags>>8;
1057 pintern->LockCount=0;
1059 /* HeapUnlock(GetProcessHeap()); */
1061 return INTERN_TO_HANDLE(pintern);
1066 /***********************************************************************
1067 * GlobalLock32 (KERNEL32.326)
1069 * Pointer to first byte of block
1072 LPVOID WINAPI GlobalLock32(
1073 HGLOBAL32 hmem /* [in] Handle of global memory object */
1075 PGLOBAL32_INTERN pintern;
1079 return (LPVOID) hmem;
1081 /* HeapLock(GetProcessHeap()); */
1083 pintern=HANDLE_TO_INTERN(hmem);
1084 if(pintern->Magic==MAGIC_GLOBAL_USED)
1086 if(pintern->LockCount<GLOBAL_LOCK_MAX)
1087 pintern->LockCount++;
1088 palloc=pintern->Pointer;
1092 WARN(global, "invalid handle\n");
1093 palloc=(LPVOID) NULL;
1095 /* HeapUnlock(GetProcessHeap()); */;
1100 /***********************************************************************
1101 * GlobalUnlock32 (KERNEL32.332)
1103 * TRUE: Object is still locked
1104 * FALSE: Object is unlocked
1106 BOOL32 WINAPI GlobalUnlock32(
1107 HGLOBAL32 hmem /* [in] Handle of global memory object */
1109 PGLOBAL32_INTERN pintern;
1115 /* HeapLock(GetProcessHeap()); */
1116 pintern=HANDLE_TO_INTERN(hmem);
1118 if(pintern->Magic==MAGIC_GLOBAL_USED)
1120 if((pintern->LockCount<GLOBAL_LOCK_MAX)&&(pintern->LockCount>0))
1121 pintern->LockCount--;
1123 locked=(pintern->LockCount==0) ? FALSE : TRUE;
1127 WARN(global, "invalid handle\n");
1130 /* HeapUnlock(GetProcessHeap()); */
1135 /***********************************************************************
1136 * GlobalHandle32 (KERNEL32.325)
1137 * Returns the handle associated with the specified pointer.
1140 * Since there in only one goto, can it be removed and the return
1147 HGLOBAL32 WINAPI GlobalHandle32(
1148 LPCVOID pmem /* [in] Pointer to global memory block */
1152 if (!HEAP_IsInsideHeap( GetProcessHeap(), 0, pmem )) goto error;
1153 handle = POINTER_TO_HANDLE(pmem);
1154 if (HEAP_IsInsideHeap( GetProcessHeap(), 0, (LPCVOID)handle ))
1156 if (HANDLE_TO_INTERN(handle)->Magic == MAGIC_GLOBAL_USED)
1157 return handle; /* valid moveable block */
1159 /* maybe FIXED block */
1160 if (HeapValidate( GetProcessHeap(), 0, pmem ))
1161 return (HGLOBAL32)pmem; /* valid fixed block */
1164 SetLastError( ERROR_INVALID_HANDLE );
1169 /***********************************************************************
1170 * GlobalReAlloc32 (KERNEL32.328)
1175 HGLOBAL32 WINAPI GlobalReAlloc32(
1176 HGLOBAL32 hmem, /* [in] Handle of global memory object */
1177 DWORD size, /* [in] New size of block */
1178 UINT32 flags /* [in] How to reallocate object */
1182 PGLOBAL32_INTERN pintern;
1185 /* HeapLock(GetProcessHeap()); */
1186 if(flags & GMEM_MODIFY) /* modify flags */
1188 if( ISPOINTER(hmem) && (flags & GMEM_MOVEABLE))
1190 /* make a fixed block moveable
1191 * actually only NT is able to do this. But it's soo simple
1193 size=HeapSize(GetProcessHeap(), 0, (LPVOID) hmem);
1194 hnew=GlobalAlloc32( flags, size);
1195 palloc=GlobalLock32(hnew);
1196 memcpy(palloc, (LPVOID) hmem, size);
1197 GlobalUnlock32(hnew);
1200 else if( ISPOINTER(hmem) &&(flags & GMEM_DISCARDABLE))
1202 /* change the flags to make our block "discardable" */
1203 pintern=HANDLE_TO_INTERN(hmem);
1204 pintern->Flags = pintern->Flags | (GMEM_DISCARDABLE >> 8);
1209 SetLastError(ERROR_INVALID_PARAMETER);
1217 /* reallocate fixed memory */
1218 hnew=(HGLOBAL32)HeapReAlloc(GetProcessHeap(), 0, (LPVOID) hmem, size);
1222 /* reallocate a moveable block */
1223 pintern=HANDLE_TO_INTERN(hmem);
1224 if(pintern->LockCount>1) {
1225 ERR(global,"handle 0x%08lx is still locked, cannot realloc!\n",(DWORD)hmem);
1226 SetLastError(ERROR_INVALID_HANDLE);
1230 if(pintern->Pointer)
1232 palloc=HeapReAlloc(GetProcessHeap(), 0,
1233 pintern->Pointer-sizeof(HGLOBAL32),
1234 size+sizeof(HGLOBAL32) );
1235 pintern->Pointer=palloc+sizeof(HGLOBAL32);
1239 palloc=HeapAlloc(GetProcessHeap(), 0, size+sizeof(HGLOBAL32));
1240 *(HGLOBAL32 *)palloc=hmem;
1241 pintern->Pointer=palloc+sizeof(HGLOBAL32);
1246 if(pintern->Pointer)
1248 HeapFree(GetProcessHeap(), 0, pintern->Pointer-sizeof(HGLOBAL32));
1249 pintern->Pointer=NULL;
1254 /* HeapUnlock(GetProcessHeap()); */
1259 /***********************************************************************
1260 * GlobalFree32 (KERNEL32.322)
1265 HGLOBAL32 WINAPI GlobalFree32(
1266 HGLOBAL32 hmem /* [in] Handle of global memory object */
1268 PGLOBAL32_INTERN pintern;
1269 HGLOBAL32 hreturned = 0;
1271 if(ISPOINTER(hmem)) /* POINTER */
1273 if(!HeapFree(GetProcessHeap(), 0, (LPVOID) hmem)) hmem = 0;
1277 /* HeapLock(GetProcessHeap()); */
1278 pintern=HANDLE_TO_INTERN(hmem);
1280 if(pintern->Magic==MAGIC_GLOBAL_USED)
1282 if(pintern->LockCount!=0)
1283 SetLastError(ERROR_INVALID_HANDLE);
1284 if(pintern->Pointer)
1285 if(!HeapFree(GetProcessHeap(), 0,
1286 (char *)(pintern->Pointer)-sizeof(HGLOBAL32)))
1288 if(!HeapFree(GetProcessHeap(), 0, pintern))
1291 /* HeapUnlock(GetProcessHeap()); */
1297 /***********************************************************************
1298 * GlobalSize32 (KERNEL32.329)
1300 * Size in bytes of the global memory object
1303 DWORD WINAPI GlobalSize32(
1304 HGLOBAL32 hmem /* [in] Handle of global memory object */
1307 PGLOBAL32_INTERN pintern;
1311 retval=HeapSize(GetProcessHeap(), 0, (LPVOID) hmem);
1315 /* HeapLock(GetProcessHeap()); */
1316 pintern=HANDLE_TO_INTERN(hmem);
1318 if(pintern->Magic==MAGIC_GLOBAL_USED)
1320 retval=HeapSize(GetProcessHeap(), 0,
1321 (char *)(pintern->Pointer)-sizeof(HGLOBAL32))-4;
1325 WARN(global, "invalid handle\n");
1328 /* HeapUnlock(GetProcessHeap()); */
1334 /***********************************************************************
1335 * GlobalWire32 (KERNEL32.333)
1337 LPVOID WINAPI GlobalWire32(HGLOBAL32 hmem)
1339 return GlobalLock32( hmem );
1343 /***********************************************************************
1344 * GlobalUnWire32 (KERNEL32.330)
1346 BOOL32 WINAPI GlobalUnWire32(HGLOBAL32 hmem)
1348 return GlobalUnlock32( hmem);
1352 /***********************************************************************
1353 * GlobalFix32 (KERNEL32.320)
1355 VOID WINAPI GlobalFix32(HGLOBAL32 hmem)
1357 GlobalLock32( hmem );
1361 /***********************************************************************
1362 * GlobalUnfix32 (KERNEL32.331)
1364 VOID WINAPI GlobalUnfix32(HGLOBAL32 hmem)
1366 GlobalUnlock32( hmem);
1370 /***********************************************************************
1371 * GlobalFlags32 (KERNEL32.321)
1372 * Returns information about the specified global memory object
1375 * Should this return GMEM_INVALID_HANDLE on invalid handle?
1378 * Value specifying allocation flags and lock count
1379 * GMEM_INVALID_HANDLE: Failure
1381 UINT32 WINAPI GlobalFlags32(
1382 HGLOBAL32 hmem /* [in] Handle to global memory object */
1385 PGLOBAL32_INTERN pintern;
1393 /* HeapLock(GetProcessHeap()); */
1394 pintern=HANDLE_TO_INTERN(hmem);
1395 if(pintern->Magic==MAGIC_GLOBAL_USED)
1397 retval=pintern->LockCount + (pintern->Flags<<8);
1398 if(pintern->Pointer==0)
1399 retval|= GMEM_DISCARDED;
1403 WARN(global,"Invalid handle: %04x", hmem);
1406 /* HeapUnlock(GetProcessHeap()); */
1412 /***********************************************************************
1413 * GlobalCompact32 (KERNEL32.316)
1415 DWORD WINAPI GlobalCompact32( DWORD minfree )
1417 return 0; /* GlobalCompact does nothing in Win32 */
1421 /***********************************************************************
1422 * GlobalMemoryStatus (KERNEL32.327)
1426 VOID WINAPI GlobalMemoryStatus(
1427 LPMEMORYSTATUS lpmem
1430 FILE *f = fopen( "/proc/meminfo", "r" );
1434 int total, used, free;
1436 lpmem->dwTotalPhys = lpmem->dwAvailPhys = 0;
1437 lpmem->dwTotalPageFile = lpmem->dwAvailPageFile = 0;
1438 while (fgets( buffer, sizeof(buffer), f ))
1440 /* old style /proc/meminfo ... */
1441 if (sscanf( buffer, "Mem: %d %d %d", &total, &used, &free ))
1443 lpmem->dwTotalPhys += total;
1444 lpmem->dwAvailPhys += free;
1446 if (sscanf( buffer, "Swap: %d %d %d", &total, &used, &free ))
1448 lpmem->dwTotalPageFile += total;
1449 lpmem->dwAvailPageFile += free;
1452 /* new style /proc/meminfo ... */
1453 if (sscanf(buffer, "MemTotal: %d", &total))
1454 lpmem->dwTotalPhys = total*1024;
1455 if (sscanf(buffer, "MemFree: %d", &free))
1456 lpmem->dwAvailPhys = free*1024;
1457 if (sscanf(buffer, "SwapTotal: %d", &total))
1458 lpmem->dwTotalPageFile = total*1024;
1459 if (sscanf(buffer, "SwapFree: %d", &free))
1460 lpmem->dwAvailPageFile = free*1024;
1464 if (lpmem->dwTotalPhys)
1466 lpmem->dwTotalVirtual = lpmem->dwTotalPhys+lpmem->dwTotalPageFile;
1467 lpmem->dwAvailVirtual = lpmem->dwAvailPhys+lpmem->dwAvailPageFile;
1468 lpmem->dwMemoryLoad = (lpmem->dwTotalVirtual-lpmem->dwAvailVirtual)
1469 / (lpmem->dwTotalVirtual / 100);
1474 /* FIXME: should do something for other systems */
1475 lpmem->dwMemoryLoad = 0;
1476 lpmem->dwTotalPhys = 16*1024*1024;
1477 lpmem->dwAvailPhys = 16*1024*1024;
1478 lpmem->dwTotalPageFile = 16*1024*1024;
1479 lpmem->dwAvailPageFile = 16*1024*1024;
1480 lpmem->dwTotalVirtual = 32*1024*1024;
1481 lpmem->dwAvailVirtual = 32*1024*1024;
1485 /**********************************************************************
1486 * WOWGlobalAllocLock (KERNEL32.62)
1488 * Combined GlobalAlloc and GlobalLock.
1490 SEGPTR WINAPI WOWGlobalAllocLock16(DWORD flags,DWORD cb,HGLOBAL16 *hmem)
1493 xhmem = GlobalAlloc16(flags,cb);
1494 if (hmem) *hmem = xhmem;
1495 return WIN16_GlobalLock16(xhmem);
1499 /**********************************************************************
1500 * WOWGlobalUnlockFree (KERNEL32.64)
1502 * Combined GlobalUnlock and GlobalFree.
1504 WORD WOWGlobalUnlockFree16(DWORD vpmem) {
1505 if (!GlobalUnlock16(HIWORD(vpmem)))
1507 return GlobalFree16(HIWORD(vpmem));