2 * Global heap functions
4 * Copyright 1995 Alexandre Julliard
16 #include "selectors.h"
18 #include "stackframe.h"
23 /* Global arena block */
26 DWORD base; /* Base address (0 if discarded) */
27 DWORD size; /* Size in bytes (0 indicates a free block) */
28 HGLOBAL16 handle; /* Handle for this block */
29 HGLOBAL16 hOwner; /* Owner of this block */
30 BYTE lockCount; /* Count of GlobalFix() calls */
31 BYTE pageLockCount; /* Count of GlobalPageLock() calls */
32 BYTE flags; /* Allocation flags */
33 BYTE selCount; /* Number of selectors allocated for this block */
39 /* Flags definitions */
40 #define GA_MOVEABLE 0x02 /* same as GMEM_MOVEABLE */
41 #define GA_DGROUP 0x04
42 #define GA_DISCARDABLE 0x08
43 #define GA_IPCSHARE 0x10 /* same as GMEM_DDESHARE */
46 static GLOBALARENA *pGlobalArena = NULL;
47 static int globalArenaSize = 0;
49 #define GLOBAL_MAX_ALLOC_SIZE 0x00ff0000 /* Largest allocation is 16M - 64K */
51 #define GET_ARENA_PTR(handle) (pGlobalArena + ((handle) >> __AHSHIFT))
53 /***********************************************************************
56 * Return the arena for a given selector, growing the arena array if needed.
58 static GLOBALARENA *GLOBAL_GetArena( WORD sel, WORD selcount )
60 if (((sel >> __AHSHIFT) + selcount) > globalArenaSize)
62 int newsize = ((sel >> __AHSHIFT) + selcount + 0xff) & ~0xff;
63 GLOBALARENA *pNewArena = realloc( pGlobalArena,
64 newsize * sizeof(GLOBALARENA) );
65 if (!pNewArena) return 0;
66 pGlobalArena = pNewArena;
67 memset( pGlobalArena + globalArenaSize, 0,
68 (newsize - globalArenaSize) * sizeof(GLOBALARENA) );
69 globalArenaSize = newsize;
71 return pGlobalArena + (sel >> __AHSHIFT);
79 for (i = globalArenaSize-1 ; i>=0 ; i--) {
80 if (pGlobalArena[i].size!=0 && (pGlobalArena[i].handle & 0x8000)){
82 printf("0x%08x, ",pGlobalArena[i].handle);
90 /***********************************************************************
93 * Create a global heap block for a fixed range of linear memory.
95 HGLOBAL16 GLOBAL_CreateBlock( WORD flags, const void *ptr, DWORD size,
96 HGLOBAL16 hOwner, BOOL16 isCode,
97 BOOL16 is32Bit, BOOL16 isReadOnly,
103 /* Allocate the selector(s) */
105 sel = SELECTOR_AllocBlock( ptr, size,
106 isCode ? SEGMENT_CODE : SEGMENT_DATA,
107 is32Bit, isReadOnly );
110 selcount = (size + 0xffff) / 0x10000;
112 if (!(pArena = GLOBAL_GetArena( sel, selcount )))
114 SELECTOR_FreeBlock( sel, selcount );
118 /* Fill the arena block */
120 pArena->base = (DWORD)ptr;
121 pArena->size = GET_SEL_LIMIT(sel) + 1;
124 if ((flags & GMEM_DDESHARE) && Options.ipc)
126 pArena->handle = shmdata->handle;
127 pArena->shmid = shmdata->shmid;
132 pArena->handle = (flags & GMEM_MOVEABLE) ? sel - 1 : sel;
136 pArena->handle = (flags & GMEM_MOVEABLE) ? sel - 1 : sel;
138 pArena->hOwner = hOwner;
139 pArena->lockCount = 0;
140 pArena->pageLockCount = 0;
141 pArena->flags = flags & GA_MOVEABLE;
142 if (flags & GMEM_DISCARDABLE) pArena->flags |= GA_DISCARDABLE;
143 if (flags & GMEM_DDESHARE) pArena->flags |= GA_IPCSHARE;
144 if (!isCode) pArena->flags |= GA_DGROUP;
145 pArena->selCount = selcount;
146 if (selcount > 1) /* clear the next arena blocks */
147 memset( pArena + 1, 0, (selcount - 1) * sizeof(GLOBALARENA) );
149 return pArena->handle;
153 /***********************************************************************
156 * Free a block allocated by GLOBAL_CreateBlock, without touching
157 * the associated linear memory range.
159 BOOL16 GLOBAL_FreeBlock( HGLOBAL16 handle )
164 if (!handle) return TRUE;
165 sel = GlobalHandleToSel( handle );
166 pArena = GET_ARENA_PTR(sel);
167 SELECTOR_FreeBlock( sel, (pArena->size + 0xffff) / 0x10000 );
168 memset( pArena, 0, sizeof(GLOBALARENA) );
173 /***********************************************************************
176 * Implementation of GlobalAlloc16()
178 HGLOBAL16 GLOBAL_Alloc( UINT16 flags, DWORD size, HGLOBAL16 hOwner,
179 BOOL16 isCode, BOOL16 is32Bit, BOOL16 isReadOnly )
185 dprintf_global( stddeb, "GlobalAlloc: %ld flags=%04x\n", size, flags );
187 /* If size is 0, create a discarded block */
189 if (size == 0) return GLOBAL_CreateBlock( flags, NULL, 1, hOwner, isCode,
190 is32Bit, isReadOnly, NULL );
194 if (size >= GLOBAL_MAX_ALLOC_SIZE - 0x1f) return 0;
195 size = (size + 0x1f) & ~0x1f;
197 /* Allocate the linear memory */
200 if ((flags & GMEM_DDESHARE) && Options.ipc)
201 ptr = DDE_malloc(flags, size, &shmdata);
203 #endif /* CONFIG_IPC */
205 ptr = HeapAlloc( SystemHeap, 0, size );
209 /* Allocate the selector(s) */
211 handle = GLOBAL_CreateBlock( flags, ptr, size, hOwner,
212 isCode, is32Bit, isReadOnly, &shmdata);
215 HeapFree( SystemHeap, 0, ptr );
219 if (flags & GMEM_ZEROINIT) memset( ptr, 0, size );
225 /***********************************************************************
228 * Find the arena for a given handle
229 * (when handle is not serial - e.g. DDE)
231 static GLOBALARENA *GLOBAL_FindArena( HGLOBAL16 handle)
234 for (i = globalArenaSize-1 ; i>=0 ; i--) {
235 if (pGlobalArena[i].size!=0 && pGlobalArena[i].handle == handle)
236 return ( &pGlobalArena[i] );
242 /***********************************************************************
243 * DDE_GlobalHandleToSel
246 WORD DDE_GlobalHandleToSel( HGLOBAL16 handle )
251 pArena= GLOBAL_FindArena(handle);
253 int ArenaIdx = pArena - pGlobalArena;
255 /* See if synchronized to the shared memory */
256 return DDE_SyncHandle(handle, ( ArenaIdx << __AHSHIFT) | 7);
259 /* attach the block */
260 DDE_AttachHandle(handle, &segptr);
262 return SELECTOROF( segptr );
264 #endif /* CONFIG_IPC */
267 /***********************************************************************
268 * GlobalAlloc16 (KERNEL.15)
270 HGLOBAL16 GlobalAlloc16( UINT16 flags, DWORD size )
272 HANDLE16 owner = GetCurrentPDB();
274 if (flags & GMEM_DDESHARE)
275 owner = GetExePtr(owner); /* Make it a module handle */
276 return GLOBAL_Alloc( flags, size, owner, FALSE, FALSE, FALSE );
280 /***********************************************************************
281 * GlobalReAlloc16 (KERNEL.16)
283 HGLOBAL16 GlobalReAlloc16( HGLOBAL16 handle, DWORD size, UINT16 flags )
288 GLOBALARENA *pArena, *pNewArena;
289 WORD sel = GlobalHandleToSel( handle );
291 dprintf_global( stddeb, "GlobalReAlloc16: %04x %ld flags=%04x\n",
292 handle, size, flags );
293 if (!handle) return 0;
296 if (Options.ipc && (flags & GMEM_DDESHARE || is_dde_handle(handle))) {
298 "GlobalReAlloc16: shared memory reallocating unimplemented\n");
301 #endif /* CONFIG_IPC */
303 pArena = GET_ARENA_PTR( handle );
305 /* Discard the block if requested */
307 if ((size == 0) && (flags & GMEM_MOVEABLE) && !(flags & GMEM_MODIFY))
309 if (!(pArena->flags & GA_MOVEABLE) ||
310 !(pArena->flags & GA_DISCARDABLE) ||
311 (pArena->lockCount > 0) || (pArena->pageLockCount > 0)) return 0;
312 HeapFree( SystemHeap, 0, (void *)pArena->base );
314 /* Note: we rely on the fact that SELECTOR_ReallocBlock won't */
315 /* change the selector if we are shrinking the block */
316 SELECTOR_ReallocBlock( sel, 0, 1, SEGMENT_DATA, 0, 0 );
322 if (size > GLOBAL_MAX_ALLOC_SIZE - 0x20) return 0;
323 if (size == 0) size = 0x20;
324 else size = (size + 0x1f) & ~0x1f;
326 /* Change the flags */
328 if (flags & GMEM_MODIFY)
330 /* Change the flags, leaving GA_DGROUP alone */
331 pArena->flags = (pArena->flags & GA_DGROUP) | (flags & GA_MOVEABLE);
332 if (flags & GMEM_DISCARDABLE) pArena->flags |= GA_DISCARDABLE;
336 /* Reallocate the linear memory */
338 ptr = (void *)pArena->base;
339 oldsize = pArena->size;
340 dprintf_global(stddeb,"oldsize %08lx\n",oldsize);
341 if (ptr && (size == oldsize)) return handle; /* Nothing to do */
343 ptr = HeapReAlloc( SystemHeap, 0, ptr, size );
346 SELECTOR_FreeBlock( sel, (oldsize + 0xffff) / 0x10000 );
347 memset( pArena, 0, sizeof(GLOBALARENA) );
351 /* Reallocate the selector(s) */
353 sel = SELECTOR_ReallocBlock( sel, ptr, size, SEGMENT_DATA, 0, 0 );
356 HeapFree( SystemHeap, 0, ptr );
357 memset( pArena, 0, sizeof(GLOBALARENA) );
360 selcount = (size + 0xffff) / 0x10000;
362 if (!(pNewArena = GLOBAL_GetArena( sel, selcount )))
364 HeapFree( SystemHeap, 0, ptr );
365 SELECTOR_FreeBlock( sel, selcount );
369 /* Fill the new arena block */
371 if (pNewArena != pArena) memcpy( pNewArena, pArena, sizeof(GLOBALARENA) );
372 pNewArena->base = (DWORD)ptr;
373 pNewArena->size = GET_SEL_LIMIT(sel) + 1;
374 pNewArena->selCount = selcount;
375 pNewArena->handle = (pNewArena->flags & GA_MOVEABLE) ? sel - 1 : sel;
377 if (selcount > 1) /* clear the next arena blocks */
378 memset( pNewArena + 1, 0, (selcount - 1) * sizeof(GLOBALARENA) );
380 if ((oldsize < size) && (flags & GMEM_ZEROINIT))
381 memset( (char *)ptr + oldsize, 0, size - oldsize );
382 return pNewArena->handle;
386 /***********************************************************************
387 * GlobalFree16 (KERNEL.17)
389 HGLOBAL16 GlobalFree16( HGLOBAL16 handle )
391 void *ptr = GlobalLock16( handle );
393 dprintf_global( stddeb, "GlobalFree16: %04x\n", handle );
394 if (!GLOBAL_FreeBlock( handle )) return handle; /* failed */
396 if (is_dde_handle(handle)) return DDE_GlobalFree(handle);
397 #endif /* CONFIG_IPC */
398 if (ptr) HeapFree( SystemHeap, 0, ptr );
403 /***********************************************************************
404 * WIN16_GlobalLock16 (KERNEL.18)
406 * This is the GlobalLock16() function used by 16-bit code.
408 SEGPTR WIN16_GlobalLock16( HGLOBAL16 handle )
410 dprintf_global( stddeb, "WIN16_GlobalLock16(%04x) -> %08lx\n",
411 handle, MAKELONG( 0, GlobalHandleToSel(handle)) );
412 if (!handle) return 0;
415 if (is_dde_handle(handle))
416 return PTR_SEG_OFF_TO_SEGPTR( DDE_GlobalHandleToSel(handle), 0 );
417 #endif /* CONFIG_IPC */
419 if (!GET_ARENA_PTR(handle)->base) return (SEGPTR)0;
420 return PTR_SEG_OFF_TO_SEGPTR( GlobalHandleToSel(handle), 0 );
424 /***********************************************************************
425 * GlobalLock16 (KERNEL.18)
427 * This is the GlobalLock16() function used by 32-bit code.
429 LPVOID GlobalLock16( HGLOBAL16 handle )
431 if (!handle) return 0;
433 if (is_dde_handle(handle)) return DDE_AttachHandle(handle, NULL);
435 return (LPVOID)GET_ARENA_PTR(handle)->base;
439 /***********************************************************************
440 * GlobalUnlock16 (KERNEL.19)
442 BOOL16 GlobalUnlock16( HGLOBAL16 handle )
444 dprintf_global( stddeb, "GlobalUnlock16: %04x\n", handle );
449 /***********************************************************************
450 * GlobalSize16 (KERNEL.20)
452 DWORD GlobalSize16( HGLOBAL16 handle )
454 dprintf_global( stddeb, "GlobalSize16: %04x\n", handle );
455 if (!handle) return 0;
456 return GET_ARENA_PTR(handle)->size;
460 /***********************************************************************
461 * GlobalHandle16 (KERNEL.21)
463 DWORD GlobalHandle16( WORD sel )
465 dprintf_global( stddeb, "GlobalHandle16: %04x\n", sel );
466 return MAKELONG( GET_ARENA_PTR(sel)->handle, GlobalHandleToSel(sel) );
470 /***********************************************************************
471 * GlobalFlags16 (KERNEL.22)
473 UINT16 GlobalFlags16( HGLOBAL16 handle )
477 dprintf_global( stddeb, "GlobalFlags16: %04x\n", handle );
478 pArena = GET_ARENA_PTR(handle);
479 return pArena->lockCount |
480 ((pArena->flags & GA_DISCARDABLE) ? GMEM_DISCARDABLE : 0) |
481 ((pArena->base == 0) ? GMEM_DISCARDED : 0);
485 /***********************************************************************
486 * LockSegment16 (KERNEL.23)
488 HGLOBAL16 LockSegment16( HGLOBAL16 handle )
490 dprintf_global( stddeb, "LockSegment: %04x\n", handle );
491 if (handle == (HGLOBAL16)-1) handle = CURRENT_DS;
492 GET_ARENA_PTR(handle)->lockCount++;
497 /***********************************************************************
498 * UnlockSegment16 (KERNEL.24)
500 void UnlockSegment16( HGLOBAL16 handle )
502 dprintf_global( stddeb, "UnlockSegment: %04x\n", handle );
503 if (handle == (HGLOBAL16)-1) handle = CURRENT_DS;
504 GET_ARENA_PTR(handle)->lockCount--;
505 /* FIXME: this ought to return the lock count in CX (go figure...) */
509 /***********************************************************************
510 * GlobalCompact16 (KERNEL.25)
512 DWORD GlobalCompact16( DWORD desired )
514 return GLOBAL_MAX_ALLOC_SIZE;
518 /***********************************************************************
519 * GlobalFreeAll (KERNEL.26)
521 void GlobalFreeAll( HGLOBAL16 owner )
526 pArena = pGlobalArena;
527 for (i = 0; i < globalArenaSize; i++, pArena++)
529 if ((pArena->size != 0) && (pArena->hOwner == owner))
530 GlobalFree16( pArena->handle );
535 /***********************************************************************
536 * GlobalWire (KERNEL.111)
538 SEGPTR GlobalWire( HGLOBAL16 handle )
540 return WIN16_GlobalLock16( handle );
544 /***********************************************************************
545 * GlobalUnWire (KERNEL.112)
547 BOOL16 GlobalUnWire( HGLOBAL16 handle )
549 return GlobalUnlock16( handle );
553 /***********************************************************************
554 * SetSwapAreaSize (KERNEL.106)
556 LONG SetSwapAreaSize( WORD size )
558 dprintf_global(stdnimp, "STUB: SetSwapAreaSize(%d)\n", size );
559 return MAKELONG( size, 0xffff );
563 /***********************************************************************
564 * GlobalLRUOldest (KERNEL.163)
566 HGLOBAL16 GlobalLRUOldest( HGLOBAL16 handle )
568 dprintf_global( stddeb, "GlobalLRUOldest: %04x\n", handle );
569 if (handle == (HGLOBAL16)-1) handle = CURRENT_DS;
574 /***********************************************************************
575 * GlobalLRUNewest (KERNEL.164)
577 HGLOBAL16 GlobalLRUNewest( HGLOBAL16 handle )
579 dprintf_global( stddeb, "GlobalLRUNewest: %04x\n", handle );
580 if (handle == (HGLOBAL16)-1) handle = CURRENT_DS;
585 /***********************************************************************
586 * GetFreeSpace (KERNEL.169)
588 DWORD GetFreeSpace( UINT16 wFlags )
592 GlobalMemoryStatus( &ms );
593 return ms.dwAvailVirtual;
597 /***********************************************************************
598 * GlobalPageLock (KERNEL.191)
600 WORD GlobalPageLock( HGLOBAL16 handle )
602 dprintf_global( stddeb, "GlobalPageLock: %04x\n", handle );
603 return ++(GET_ARENA_PTR(handle)->pageLockCount);
607 /***********************************************************************
608 * GlobalPageUnlock (KERNEL.192)
610 WORD GlobalPageUnlock( HGLOBAL16 handle )
612 dprintf_global( stddeb, "GlobalPageUnlock: %04x\n", handle );
613 return --(GET_ARENA_PTR(handle)->pageLockCount);
617 /***********************************************************************
618 * GlobalFix (KERNEL.197)
620 void GlobalFix( HGLOBAL16 handle )
622 dprintf_global( stddeb, "GlobalFix: %04x\n", handle );
623 GET_ARENA_PTR(handle)->lockCount++;
627 /***********************************************************************
628 * GlobalUnfix (KERNEL.198)
630 void GlobalUnfix( HGLOBAL16 handle )
632 dprintf_global( stddeb, "GlobalUnfix: %04x\n", handle );
633 GET_ARENA_PTR(handle)->lockCount--;
637 /***********************************************************************
638 * FarSetOwner (KERNEL.403)
640 void FarSetOwner( HGLOBAL16 handle, HANDLE16 hOwner )
642 GET_ARENA_PTR(handle)->hOwner = hOwner;
646 /***********************************************************************
647 * FarGetOwner (KERNEL.404)
649 HANDLE16 FarGetOwner( HGLOBAL16 handle )
651 return GET_ARENA_PTR(handle)->hOwner;
655 /***********************************************************************
656 * GlobalHandleToSel (TOOLHELP.50)
658 WORD GlobalHandleToSel( HGLOBAL16 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 BOOL16 GlobalFirst( GLOBALENTRY *pGlobal, WORD wFlags )
679 if (wFlags == GLOBAL_LRU) return FALSE;
681 return GlobalNext( pGlobal, wFlags );
685 /***********************************************************************
686 * GlobalNext (TOOLHELP.52)
688 BOOL16 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 BOOL16 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 BOOL16 GlobalEntryHandle( GLOBALENTRY *pGlobal, HGLOBAL16 hItem )
744 /***********************************************************************
745 * GlobalEntryModule (TOOLHELP.55)
747 BOOL16 GlobalEntryModule( GLOBALENTRY *pGlobal, HMODULE16 hModule, WORD wSeg )
753 /***********************************************************************
754 * MemManInfo (TOOLHELP.72)
756 BOOL16 MemManInfo( MEMMANINFO *info )
760 if (info->dwSize < sizeof(MEMMANINFO)) return FALSE;
761 GlobalMemoryStatus( &status );
762 info->wPageSize = getpagesize();
763 info->dwLargestFreeBlock = status.dwAvailVirtual;
764 info->dwMaxPagesAvailable = info->dwLargestFreeBlock / info->wPageSize;
765 info->dwMaxPagesLockable = info->dwMaxPagesAvailable;
766 info->dwTotalLinearSpace = status.dwTotalVirtual / info->wPageSize;
767 info->dwTotalUnlockedPages = info->dwTotalLinearSpace;
768 info->dwFreePages = info->dwMaxPagesAvailable;
769 info->dwTotalPages = info->dwTotalLinearSpace;
770 info->dwFreeLinearSpace = info->dwMaxPagesAvailable;
771 info->dwSwapFilePages = status.dwTotalPageFile / info->wPageSize;
776 /***********************************************************************
777 * GlobalAlloc32 (KERNEL32.315)
779 HGLOBAL32 GlobalAlloc32( UINT32 flags, DWORD size )
783 if (flags & GMEM_MOVEABLE)
784 fprintf( stderr, "GlobalAlloc32: unimplemented flag GMEM_MOVEABLE\n" );
786 if (flags & GMEM_ZEROINIT) heapFlags |= HEAP_ZERO_MEMORY;
787 return (HGLOBAL32)HeapAlloc( GetProcessHeap(), heapFlags, size );
791 /***********************************************************************
792 * GlobalCompact32 (KERNEL32.316)
794 DWORD GlobalCompact32( DWORD minfree )
796 return 0; /* GlobalCompact does nothing in Win32 */
800 /***********************************************************************
801 * GlobalFlags32 (KERNEL32.321)
803 UINT32 GlobalFlags32( HGLOBAL32 handle )
809 /***********************************************************************
810 * GlobalFree32 (KERNEL32.322)
812 HGLOBAL32 GlobalFree32( HGLOBAL32 handle )
814 return HeapFree( GetProcessHeap(), 0, (LPVOID)handle ) ? 0 : handle;
818 /***********************************************************************
819 * GlobalHandle32 (KERNEL32.325)
821 HGLOBAL32 GlobalHandle32( LPCVOID ptr )
823 return (HGLOBAL32)ptr;
827 /***********************************************************************
828 * GlobalLock32 (KERNEL32.326)
830 LPVOID GlobalLock32( HGLOBAL32 handle )
832 return (LPVOID)handle;
836 /***********************************************************************
837 * GlobalReAlloc32 (KERNEL32.328)
839 HGLOBAL32 GlobalReAlloc32( HGLOBAL32 handle, DWORD size, UINT32 flags )
841 if (flags & GMEM_MODIFY)
843 fprintf( stderr, "GlobalReAlloc32: GMEM_MODIFY not supported\n" );
847 return (HGLOBAL32)HeapReAlloc( GetProcessHeap(), 0, (LPVOID)handle, size );
851 /***********************************************************************
852 * GlobalSize32 (KERNEL32.329)
854 DWORD GlobalSize32( HGLOBAL32 handle )
856 return HeapSize( GetProcessHeap(), 0, (LPVOID)handle );
860 /***********************************************************************
861 * GlobalUnlock32 (KERNEL32.332)
863 BOOL32 GlobalUnlock32( HGLOBAL32 handle )
869 /***********************************************************************
870 * GlobalMemoryStatus (KERNEL32.327)
872 VOID GlobalMemoryStatus( LPMEMORYSTATUS lpmem )
875 FILE *f = fopen( "/proc/meminfo", "r" );
879 int total, used, free;
881 lpmem->dwTotalPhys = lpmem->dwAvailPhys = 0;
882 lpmem->dwTotalPageFile = lpmem->dwAvailPageFile = 0;
883 while (fgets( buffer, sizeof(buffer), f ))
885 if (sscanf( buffer, "Mem: %d %d %d", &total, &used, &free ))
887 lpmem->dwTotalPhys += total;
888 lpmem->dwAvailPhys += free;
890 else if (sscanf( buffer, "Swap: %d %d %d", &total, &used, &free ))
892 lpmem->dwTotalPageFile += total;
893 lpmem->dwAvailPageFile += free;
898 if (lpmem->dwTotalPhys)
900 lpmem->dwTotalVirtual = lpmem->dwTotalPhys+lpmem->dwTotalPageFile;
901 lpmem->dwAvailVirtual = lpmem->dwAvailPhys+lpmem->dwAvailPageFile;
902 lpmem->dwMemoryLoad = (lpmem->dwTotalVirtual-lpmem->dwAvailVirtual)
903 * 100 / lpmem->dwTotalVirtual;
908 /* FIXME: should do something for other systems */
909 lpmem->dwMemoryLoad = 0;
910 lpmem->dwTotalPhys = 16*1024*1024;
911 lpmem->dwAvailPhys = 16*1024*1024;
912 lpmem->dwTotalPageFile = 16*1024*1024;
913 lpmem->dwAvailPageFile = 16*1024*1024;
914 lpmem->dwTotalVirtual = 32*1024*1024;
915 lpmem->dwAvailVirtual = 32*1024*1024;