Release 970329
[wine/multimedia.git] / memory / global.c
blobf5d7d186228e1e135de334b48c4986f554036ba3
1 /*
2 * Global heap functions
4 * Copyright 1995 Alexandre Julliard
5 */
7 #include <sys/types.h>
8 #include <stdlib.h>
9 #include <unistd.h>
10 #include <string.h>
12 #include "windows.h"
13 #include "global.h"
14 #include "heap.h"
15 #include "toolhelp.h"
16 #include "selectors.h"
17 #include "miscemu.h"
18 #include "dde_mem.h"
19 #include "stackframe.h"
20 #include "options.h"
21 #include "stddebug.h"
22 #include "debug.h"
23 #include "winerror.h"
25 /* Global arena block */
26 typedef struct
28 DWORD base; /* Base address (0 if discarded) */
29 DWORD size; /* Size in bytes (0 indicates a free block) */
30 HGLOBAL16 handle; /* Handle for this block */
31 HGLOBAL16 hOwner; /* Owner of this block */
32 BYTE lockCount; /* Count of GlobalFix() calls */
33 BYTE pageLockCount; /* Count of GlobalPageLock() calls */
34 BYTE flags; /* Allocation flags */
35 BYTE selCount; /* Number of selectors allocated for this block */
36 #ifdef CONFIG_IPC
37 int shmid;
38 #endif
39 } GLOBALARENA;
41 /* Flags definitions */
42 #define GA_MOVEABLE 0x02 /* same as GMEM_MOVEABLE */
43 #define GA_DGROUP 0x04
44 #define GA_DISCARDABLE 0x08
45 #define GA_IPCSHARE 0x10 /* same as GMEM_DDESHARE */
47 /* Arena array */
48 static GLOBALARENA *pGlobalArena = NULL;
49 static int globalArenaSize = 0;
51 #define GLOBAL_MAX_ALLOC_SIZE 0x00ff0000 /* Largest allocation is 16M - 64K */
53 #define GET_ARENA_PTR(handle) (pGlobalArena + ((handle) >> __AHSHIFT))
55 /***********************************************************************
56 * GLOBAL_GetArena
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);
77 void debug_handles()
79 int printed=0;
80 int i;
81 for (i = globalArenaSize-1 ; i>=0 ; i--) {
82 if (pGlobalArena[i].size!=0 && (pGlobalArena[i].handle & 0x8000)){
83 printed=1;
84 printf("0x%08x, ",pGlobalArena[i].handle);
87 if (printed)
88 printf("\n");
92 /***********************************************************************
93 * GLOBAL_CreateBlock
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,
100 SHMDATA *shmdata )
102 WORD sel, selcount;
103 GLOBALARENA *pArena;
105 /* Allocate the selector(s) */
107 sel = SELECTOR_AllocBlock( ptr, size,
108 isCode ? SEGMENT_CODE : SEGMENT_DATA,
109 is32Bit, isReadOnly );
111 if (!sel) return 0;
112 selcount = (size + 0xffff) / 0x10000;
114 if (!(pArena = GLOBAL_GetArena( sel, selcount )))
116 SELECTOR_FreeBlock( sel, selcount );
117 return 0;
120 /* Fill the arena block */
122 pArena->base = (DWORD)ptr;
123 pArena->size = GET_SEL_LIMIT(sel) + 1;
125 #ifdef CONFIG_IPC
126 if ((flags & GMEM_DDESHARE) && Options.ipc)
128 pArena->handle = shmdata->handle;
129 pArena->shmid = shmdata->shmid;
130 shmdata->sel = sel;
132 else
134 pArena->handle = (flags & GMEM_MOVEABLE) ? sel - 1 : sel;
135 pArena->shmid = 0;
137 #else
138 pArena->handle = (flags & GMEM_MOVEABLE) ? sel - 1 : sel;
139 #endif
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 /***********************************************************************
156 * GLOBAL_FreeBlock
158 * Free a block allocated by GLOBAL_CreateBlock, without touching
159 * the associated linear memory range.
161 BOOL16 GLOBAL_FreeBlock( HGLOBAL16 handle )
163 WORD sel;
164 GLOBALARENA *pArena;
166 if (!handle) return TRUE;
167 sel = GlobalHandleToSel( handle );
168 pArena = GET_ARENA_PTR(sel);
169 SELECTOR_FreeBlock( sel, (pArena->size + 0xffff) / 0x10000 );
170 memset( pArena, 0, sizeof(GLOBALARENA) );
171 return TRUE;
175 /***********************************************************************
176 * GLOBAL_Alloc
178 * Implementation of GlobalAlloc16()
180 HGLOBAL16 GLOBAL_Alloc( UINT16 flags, DWORD size, HGLOBAL16 hOwner,
181 BOOL16 isCode, BOOL16 is32Bit, BOOL16 isReadOnly )
183 void *ptr;
184 HGLOBAL16 handle;
185 SHMDATA shmdata;
187 dprintf_global( stddeb, "GlobalAlloc: %ld flags=%04x\n", size, flags );
189 /* If size is 0, create a discarded block */
191 if (size == 0) return GLOBAL_CreateBlock( flags, NULL, 1, hOwner, isCode,
192 is32Bit, isReadOnly, NULL );
194 /* Fixup the size */
196 if (size >= GLOBAL_MAX_ALLOC_SIZE - 0x1f) return 0;
197 size = (size + 0x1f) & ~0x1f;
199 /* Allocate the linear memory */
201 #ifdef CONFIG_IPC
202 if ((flags & GMEM_DDESHARE) && Options.ipc)
203 ptr = DDE_malloc(flags, size, &shmdata);
204 else
205 #endif /* CONFIG_IPC */
207 ptr = HeapAlloc( SystemHeap, 0, size );
209 if (!ptr) return 0;
211 /* Allocate the selector(s) */
213 handle = GLOBAL_CreateBlock( flags, ptr, size, hOwner,
214 isCode, is32Bit, isReadOnly, &shmdata);
215 if (!handle)
217 HeapFree( SystemHeap, 0, ptr );
218 return 0;
221 if (flags & GMEM_ZEROINIT) memset( ptr, 0, size );
222 return handle;
226 #ifdef CONFIG_IPC
227 /***********************************************************************
228 * GLOBAL_FindArena
230 * Find the arena for a given handle
231 * (when handle is not serial - e.g. DDE)
233 static GLOBALARENA *GLOBAL_FindArena( HGLOBAL16 handle)
235 int i;
236 for (i = globalArenaSize-1 ; i>=0 ; i--) {
237 if (pGlobalArena[i].size!=0 && pGlobalArena[i].handle == handle)
238 return ( &pGlobalArena[i] );
240 return NULL;
244 /***********************************************************************
245 * DDE_GlobalHandleToSel
248 WORD DDE_GlobalHandleToSel( HGLOBAL16 handle )
250 GLOBALARENA *pArena;
251 SEGPTR segptr;
253 pArena= GLOBAL_FindArena(handle);
254 if (pArena) {
255 int ArenaIdx = pArena - pGlobalArena;
257 /* See if synchronized to the shared memory */
258 return DDE_SyncHandle(handle, ( ArenaIdx << __AHSHIFT) | 7);
261 /* attach the block */
262 DDE_AttachHandle(handle, &segptr);
264 return SELECTOROF( segptr );
266 #endif /* CONFIG_IPC */
269 /***********************************************************************
270 * GlobalAlloc16 (KERNEL.15)
272 HGLOBAL16 GlobalAlloc16( UINT16 flags, DWORD size )
274 HANDLE16 owner = GetCurrentPDB();
276 if (flags & GMEM_DDESHARE)
277 owner = GetExePtr(owner); /* Make it a module handle */
278 return GLOBAL_Alloc( flags, size, owner, FALSE, FALSE, FALSE );
282 /***********************************************************************
283 * GlobalReAlloc16 (KERNEL.16)
285 HGLOBAL16 GlobalReAlloc16( HGLOBAL16 handle, DWORD size, UINT16 flags )
287 WORD selcount;
288 DWORD oldsize;
289 void *ptr;
290 GLOBALARENA *pArena, *pNewArena;
291 WORD sel = GlobalHandleToSel( handle );
293 dprintf_global( stddeb, "GlobalReAlloc16: %04x %ld flags=%04x\n",
294 handle, size, flags );
295 if (!handle) return 0;
297 #ifdef CONFIG_IPC
298 if (Options.ipc && (flags & GMEM_DDESHARE || is_dde_handle(handle))) {
299 fprintf(stdnimp,
300 "GlobalReAlloc16: shared memory reallocating unimplemented\n");
301 return 0;
303 #endif /* CONFIG_IPC */
305 pArena = GET_ARENA_PTR( handle );
307 /* Discard the block if requested */
309 if ((size == 0) && (flags & GMEM_MOVEABLE) && !(flags & GMEM_MODIFY))
311 if (!(pArena->flags & GA_MOVEABLE) ||
312 !(pArena->flags & GA_DISCARDABLE) ||
313 (pArena->lockCount > 0) || (pArena->pageLockCount > 0)) return 0;
314 HeapFree( SystemHeap, 0, (void *)pArena->base );
315 pArena->base = 0;
316 /* Note: we rely on the fact that SELECTOR_ReallocBlock won't */
317 /* change the selector if we are shrinking the block */
318 SELECTOR_ReallocBlock( sel, 0, 1, SEGMENT_DATA, 0, 0 );
319 return handle;
322 /* Fixup the size */
324 if (size > GLOBAL_MAX_ALLOC_SIZE - 0x20) return 0;
325 if (size == 0) size = 0x20;
326 else size = (size + 0x1f) & ~0x1f;
328 /* Change the flags */
330 if (flags & GMEM_MODIFY)
332 /* Change the flags, leaving GA_DGROUP alone */
333 pArena->flags = (pArena->flags & GA_DGROUP) | (flags & GA_MOVEABLE);
334 if (flags & GMEM_DISCARDABLE) pArena->flags |= GA_DISCARDABLE;
335 return handle;
338 /* Reallocate the linear memory */
340 ptr = (void *)pArena->base;
341 oldsize = pArena->size;
342 dprintf_global(stddeb,"oldsize %08lx\n",oldsize);
343 if (ptr && (size == oldsize)) return handle; /* Nothing to do */
345 ptr = HeapReAlloc( SystemHeap, 0, ptr, size );
346 if (!ptr)
348 SELECTOR_FreeBlock( sel, (oldsize + 0xffff) / 0x10000 );
349 memset( pArena, 0, sizeof(GLOBALARENA) );
350 return 0;
353 /* Reallocate the selector(s) */
355 sel = SELECTOR_ReallocBlock( sel, ptr, size, SEGMENT_DATA, 0, 0 );
356 if (!sel)
358 HeapFree( SystemHeap, 0, ptr );
359 memset( pArena, 0, sizeof(GLOBALARENA) );
360 return 0;
362 selcount = (size + 0xffff) / 0x10000;
364 if (!(pNewArena = GLOBAL_GetArena( sel, selcount )))
366 HeapFree( SystemHeap, 0, ptr );
367 SELECTOR_FreeBlock( sel, selcount );
368 return 0;
371 /* Fill the new arena block */
373 if (pNewArena != pArena) memcpy( pNewArena, pArena, sizeof(GLOBALARENA) );
374 pNewArena->base = (DWORD)ptr;
375 pNewArena->size = GET_SEL_LIMIT(sel) + 1;
376 pNewArena->selCount = selcount;
377 pNewArena->handle = (pNewArena->flags & GA_MOVEABLE) ? sel - 1 : sel;
379 if (selcount > 1) /* clear the next arena blocks */
380 memset( pNewArena + 1, 0, (selcount - 1) * sizeof(GLOBALARENA) );
382 if ((oldsize < size) && (flags & GMEM_ZEROINIT))
383 memset( (char *)ptr + oldsize, 0, size - oldsize );
384 return pNewArena->handle;
388 /***********************************************************************
389 * GlobalFree16 (KERNEL.17)
391 HGLOBAL16 GlobalFree16( HGLOBAL16 handle )
393 void *ptr = GlobalLock16( handle );
395 dprintf_global( stddeb, "GlobalFree16: %04x\n", handle );
396 if (!GLOBAL_FreeBlock( handle )) return handle; /* failed */
397 #ifdef CONFIG_IPC
398 if (is_dde_handle(handle)) return DDE_GlobalFree(handle);
399 #endif /* CONFIG_IPC */
400 if (ptr) HeapFree( SystemHeap, 0, ptr );
401 return 0;
405 /***********************************************************************
406 * WIN16_GlobalLock16 (KERNEL.18)
408 * This is the GlobalLock16() function used by 16-bit code.
410 SEGPTR WIN16_GlobalLock16( HGLOBAL16 handle )
412 dprintf_global( stddeb, "WIN16_GlobalLock16(%04x) -> %08lx\n",
413 handle, MAKELONG( 0, GlobalHandleToSel(handle)) );
414 if (!handle) return 0;
416 #ifdef CONFIG_IPC
417 if (is_dde_handle(handle))
418 return PTR_SEG_OFF_TO_SEGPTR( DDE_GlobalHandleToSel(handle), 0 );
419 #endif /* CONFIG_IPC */
421 if (!GET_ARENA_PTR(handle)->base) return (SEGPTR)0;
422 return PTR_SEG_OFF_TO_SEGPTR( GlobalHandleToSel(handle), 0 );
426 /***********************************************************************
427 * GlobalLock16 (KERNEL.18)
429 * This is the GlobalLock16() function used by 32-bit code.
431 LPVOID GlobalLock16( HGLOBAL16 handle )
433 if (!handle) return 0;
434 #ifdef CONFIG_IPC
435 if (is_dde_handle(handle)) return DDE_AttachHandle(handle, NULL);
436 #endif
437 return (LPVOID)GET_ARENA_PTR(handle)->base;
441 /***********************************************************************
442 * GlobalUnlock16 (KERNEL.19)
444 BOOL16 GlobalUnlock16( HGLOBAL16 handle )
446 dprintf_global( stddeb, "GlobalUnlock16: %04x\n", handle );
447 return 0;
451 /***********************************************************************
452 * GlobalSize16 (KERNEL.20)
454 DWORD GlobalSize16( HGLOBAL16 handle )
456 dprintf_global( stddeb, "GlobalSize16: %04x\n", handle );
457 if (!handle) return 0;
458 return GET_ARENA_PTR(handle)->size;
462 /***********************************************************************
463 * GlobalHandle16 (KERNEL.21)
465 DWORD GlobalHandle16( WORD sel )
467 dprintf_global( stddeb, "GlobalHandle16: %04x\n", sel );
468 return MAKELONG( GET_ARENA_PTR(sel)->handle, GlobalHandleToSel(sel) );
472 /***********************************************************************
473 * GlobalFlags16 (KERNEL.22)
475 UINT16 GlobalFlags16( HGLOBAL16 handle )
477 GLOBALARENA *pArena;
479 dprintf_global( stddeb, "GlobalFlags16: %04x\n", handle );
480 pArena = GET_ARENA_PTR(handle);
481 return pArena->lockCount |
482 ((pArena->flags & GA_DISCARDABLE) ? GMEM_DISCARDABLE : 0) |
483 ((pArena->base == 0) ? GMEM_DISCARDED : 0);
487 /***********************************************************************
488 * LockSegment16 (KERNEL.23)
490 HGLOBAL16 LockSegment16( HGLOBAL16 handle )
492 dprintf_global( stddeb, "LockSegment: %04x\n", handle );
493 if (handle == (HGLOBAL16)-1) handle = CURRENT_DS;
494 GET_ARENA_PTR(handle)->lockCount++;
495 return handle;
499 /***********************************************************************
500 * UnlockSegment16 (KERNEL.24)
502 void UnlockSegment16( HGLOBAL16 handle )
504 dprintf_global( stddeb, "UnlockSegment: %04x\n", handle );
505 if (handle == (HGLOBAL16)-1) handle = CURRENT_DS;
506 GET_ARENA_PTR(handle)->lockCount--;
507 /* FIXME: this ought to return the lock count in CX (go figure...) */
511 /***********************************************************************
512 * GlobalCompact16 (KERNEL.25)
514 DWORD GlobalCompact16( DWORD desired )
516 return GLOBAL_MAX_ALLOC_SIZE;
520 /***********************************************************************
521 * GlobalFreeAll (KERNEL.26)
523 void GlobalFreeAll( HGLOBAL16 owner )
525 DWORD i;
526 GLOBALARENA *pArena;
528 pArena = pGlobalArena;
529 for (i = 0; i < globalArenaSize; i++, pArena++)
531 if ((pArena->size != 0) && (pArena->hOwner == owner))
532 GlobalFree16( pArena->handle );
537 /***********************************************************************
538 * GlobalWire16 (KERNEL.111)
540 SEGPTR GlobalWire16( HGLOBAL16 handle )
542 return WIN16_GlobalLock16( handle );
546 /***********************************************************************
547 * GlobalUnWire16 (KERNEL.112)
549 BOOL16 GlobalUnWire16( HGLOBAL16 handle )
551 return GlobalUnlock16( handle );
555 /***********************************************************************
556 * SetSwapAreaSize (KERNEL.106)
558 LONG SetSwapAreaSize( WORD size )
560 dprintf_global(stdnimp, "STUB: SetSwapAreaSize(%d)\n", size );
561 return MAKELONG( size, 0xffff );
565 /***********************************************************************
566 * GlobalLRUOldest (KERNEL.163)
568 HGLOBAL16 GlobalLRUOldest( HGLOBAL16 handle )
570 dprintf_global( stddeb, "GlobalLRUOldest: %04x\n", handle );
571 if (handle == (HGLOBAL16)-1) handle = CURRENT_DS;
572 return handle;
576 /***********************************************************************
577 * GlobalLRUNewest (KERNEL.164)
579 HGLOBAL16 GlobalLRUNewest( HGLOBAL16 handle )
581 dprintf_global( stddeb, "GlobalLRUNewest: %04x\n", handle );
582 if (handle == (HGLOBAL16)-1) handle = CURRENT_DS;
583 return handle;
587 /***********************************************************************
588 * GetFreeSpace16 (KERNEL.169)
590 DWORD GetFreeSpace16( UINT16 wFlags )
592 MEMORYSTATUS ms;
593 GlobalMemoryStatus( &ms );
594 return ms.dwAvailVirtual;
597 /***********************************************************************
598 * GlobalDOSAlloc (KERNEL.184)
600 DWORD GlobalDOSAlloc(DWORD size)
602 UINT16 uParagraph;
603 LPVOID lpBlock = DOSMEM_GetBlock( size, &uParagraph );
605 if( lpBlock )
607 HMODULE16 hModule = GetModuleHandle16("KERNEL");
608 WORD wSelector;
610 wSelector = GLOBAL_CreateBlock(GMEM_FIXED, lpBlock, size,
611 hModule, 0, 0, 0, NULL );
612 return MAKELONG(wSelector,uParagraph);
614 return 0;
617 /***********************************************************************
618 * GlobalDOSFree (KERNEL.185)
620 WORD GlobalDOSFree(WORD sel)
622 DWORD block = GetSelectorBase(sel);
624 if( block && block < 0x100000 )
626 LPVOID lpBlock = DOSMEM_MapDosToLinear( block );
627 if( DOSMEM_FreeBlock( lpBlock ) )
628 GLOBAL_FreeBlock( sel );
629 sel = 0;
631 return sel;
634 /***********************************************************************
635 * GlobalPageLock (KERNEL.191)
637 WORD GlobalPageLock( HGLOBAL16 handle )
639 dprintf_global( stddeb, "GlobalPageLock: %04x\n", handle );
640 return ++(GET_ARENA_PTR(handle)->pageLockCount);
644 /***********************************************************************
645 * GlobalPageUnlock (KERNEL.192)
647 WORD GlobalPageUnlock( HGLOBAL16 handle )
649 dprintf_global( stddeb, "GlobalPageUnlock: %04x\n", handle );
650 return --(GET_ARENA_PTR(handle)->pageLockCount);
654 /***********************************************************************
655 * GlobalFix16 (KERNEL.197)
657 void GlobalFix16( HGLOBAL16 handle )
659 dprintf_global( stddeb, "GlobalFix16: %04x\n", handle );
660 GET_ARENA_PTR(handle)->lockCount++;
664 /***********************************************************************
665 * GlobalUnfix16 (KERNEL.198)
667 void GlobalUnfix16( HGLOBAL16 handle )
669 dprintf_global( stddeb, "GlobalUnfix16: %04x\n", handle );
670 GET_ARENA_PTR(handle)->lockCount--;
674 /***********************************************************************
675 * FarSetOwner (KERNEL.403)
677 void FarSetOwner( HGLOBAL16 handle, HANDLE16 hOwner )
679 GET_ARENA_PTR(handle)->hOwner = hOwner;
683 /***********************************************************************
684 * FarGetOwner (KERNEL.404)
686 HANDLE16 FarGetOwner( HGLOBAL16 handle )
688 return GET_ARENA_PTR(handle)->hOwner;
692 /***********************************************************************
693 * GlobalHandleToSel (TOOLHELP.50)
695 WORD GlobalHandleToSel( HGLOBAL16 handle )
697 dprintf_toolhelp( stddeb, "GlobalHandleToSel: %04x\n", handle );
698 if (!handle) return 0;
699 #ifdef CONFIG_IPC
700 if (is_dde_handle(handle)) return DDE_GlobalHandleToSel(handle);
701 #endif
702 if (!(handle & 7))
704 fprintf( stderr, "Program attempted invalid selector conversion\n" );
705 return handle - 1;
707 return handle | 7;
711 /***********************************************************************
712 * GlobalFirst (TOOLHELP.51)
714 BOOL16 GlobalFirst( GLOBALENTRY *pGlobal, WORD wFlags )
716 if (wFlags == GLOBAL_LRU) return FALSE;
717 pGlobal->dwNext = 0;
718 return GlobalNext( pGlobal, wFlags );
722 /***********************************************************************
723 * GlobalNext (TOOLHELP.52)
725 BOOL16 GlobalNext( GLOBALENTRY *pGlobal, WORD wFlags)
727 GLOBALARENA *pArena;
729 if (pGlobal->dwNext >= globalArenaSize) return FALSE;
730 pArena = pGlobalArena + pGlobal->dwNext;
731 if (wFlags == GLOBAL_FREE) /* only free blocks */
733 int i;
734 for (i = pGlobal->dwNext; i < globalArenaSize; i++, pArena++)
735 if (pArena->size == 0) break; /* block is free */
736 if (i >= globalArenaSize) return FALSE;
737 pGlobal->dwNext = i;
740 pGlobal->dwAddress = pArena->base;
741 pGlobal->dwBlockSize = pArena->size;
742 pGlobal->hBlock = pArena->handle;
743 pGlobal->wcLock = pArena->lockCount;
744 pGlobal->wcPageLock = pArena->pageLockCount;
745 pGlobal->wFlags = (GetCurrentPDB() == pArena->hOwner);
746 pGlobal->wHeapPresent = FALSE;
747 pGlobal->hOwner = pArena->hOwner;
748 pGlobal->wType = GT_UNKNOWN;
749 pGlobal->wData = 0;
750 pGlobal->dwNext++;
751 return TRUE;
755 /***********************************************************************
756 * GlobalInfo (TOOLHELP.53)
758 BOOL16 GlobalInfo( GLOBALINFO *pInfo )
760 int i;
761 GLOBALARENA *pArena;
763 pInfo->wcItems = globalArenaSize;
764 pInfo->wcItemsFree = 0;
765 pInfo->wcItemsLRU = 0;
766 for (i = 0, pArena = pGlobalArena; i < globalArenaSize; i++, pArena++)
767 if (pArena->size == 0) pInfo->wcItemsFree++;
768 return TRUE;
772 /***********************************************************************
773 * GlobalEntryHandle (TOOLHELP.54)
775 BOOL16 GlobalEntryHandle( GLOBALENTRY *pGlobal, HGLOBAL16 hItem )
777 return FALSE;
781 /***********************************************************************
782 * GlobalEntryModule (TOOLHELP.55)
784 BOOL16 GlobalEntryModule( GLOBALENTRY *pGlobal, HMODULE16 hModule, WORD wSeg )
786 return FALSE;
790 /***********************************************************************
791 * MemManInfo (TOOLHELP.72)
793 BOOL16 MemManInfo( MEMMANINFO *info )
795 MEMORYSTATUS status;
798 * Not unsurprisingly although the documention says you
799 * _must_ provide the size in the dwSize field, this function
800 * (under Windows) always fills the structure and returns true.
802 GlobalMemoryStatus( &status );
803 #ifdef __svr4__
804 info->wPageSize = sysconf(_SC_PAGESIZE);
805 #else
806 info->wPageSize = getpagesize();
807 #endif
808 info->dwLargestFreeBlock = status.dwAvailVirtual;
809 info->dwMaxPagesAvailable = info->dwLargestFreeBlock / info->wPageSize;
810 info->dwMaxPagesLockable = info->dwMaxPagesAvailable;
811 info->dwTotalLinearSpace = status.dwTotalVirtual / info->wPageSize;
812 info->dwTotalUnlockedPages = info->dwTotalLinearSpace;
813 info->dwFreePages = info->dwMaxPagesAvailable;
814 info->dwTotalPages = info->dwTotalLinearSpace;
815 info->dwFreeLinearSpace = info->dwMaxPagesAvailable;
816 info->dwSwapFilePages = status.dwTotalPageFile / info->wPageSize;
817 return TRUE;
821 * Win32 Global heap functions (GlobalXXX).
822 * These functions included in Win32 for compatibility with 16 bit Windows
823 * Especially the moveable blocks and handles are oldish.
824 * But the ability to directly allocate memory with GPTR and LPTR is widely
825 * used.
827 * The handle stuff looks horrible, but it's implemented almost like Win95
828 * does it.
832 #define MAGIC_GLOBAL_USED 0x5342
833 #define GLOBAL_LOCK_MAX 0xFF
834 #define HANDLE_TO_INTERN(h) (PGLOBAL32_INTERN)(((char *)(h))-2)
835 #define INTERN_TO_HANDLE(i) ((HGLOBAL32) &((i)->Pointer))
836 #define POINTER_TO_HANDLE(p) (*(((HGLOBAL32 *)(p))-1))
837 #define ISHANDLE(h) (((DWORD)(h)&2)!=0)
838 #define ISPOINTER(h) (((DWORD)(h)&2)==0)
840 typedef struct __GLOBAL32_INTERN
842 WORD Magic;
843 LPVOID Pointer WINE_PACKED;
844 BYTE Flags;
845 BYTE LockCount;
846 } GLOBAL32_INTERN, *PGLOBAL32_INTERN;
849 /***********************************************************************
850 * GlobalAlloc32 (KERNEL32.315)
852 HGLOBAL32 GlobalAlloc32(UINT32 flags, DWORD size)
854 PGLOBAL32_INTERN pintern;
855 DWORD hpflags;
856 LPVOID palloc;
858 if(flags&GMEM_ZEROINIT)
859 hpflags=HEAP_ZERO_MEMORY;
860 else
861 hpflags=0;
863 if((flags & GMEM_MOVEABLE)==0) /* POINTER */
865 palloc=HeapAlloc(GetProcessHeap(), hpflags, size);
866 return (HGLOBAL32) palloc;
868 else /* HANDLE */
870 /* HeapLock(GetProcessHeap()); */
872 pintern=HeapAlloc(GetProcessHeap(), 0, sizeof(GLOBAL32_INTERN));
873 if(size)
875 palloc=HeapAlloc(GetProcessHeap(), 0, size+sizeof(HGLOBAL32));
876 *(HGLOBAL32 *)palloc=INTERN_TO_HANDLE(pintern);
877 pintern->Pointer=palloc+sizeof(HGLOBAL32);
879 else
880 pintern->Pointer=NULL;
881 pintern->Magic=MAGIC_GLOBAL_USED;
882 pintern->Flags=flags>>8;
883 pintern->LockCount=0;
885 /* HeapUnlock(GetProcessHeap()); */
887 return INTERN_TO_HANDLE(pintern);
892 /***********************************************************************
893 * GlobalLock32 (KERNEL32.326)
895 LPVOID GlobalLock32(HGLOBAL32 hmem)
897 PGLOBAL32_INTERN pintern;
898 LPVOID palloc;
900 if(ISPOINTER(hmem))
901 return (LPVOID) hmem;
903 /* HeapLock(GetProcessHeap()); */
905 pintern=HANDLE_TO_INTERN(hmem);
906 if(pintern->Magic==MAGIC_GLOBAL_USED)
908 if(pintern->LockCount<GLOBAL_LOCK_MAX)
909 pintern->LockCount++;
910 palloc=pintern->Pointer;
912 else
914 dprintf_global(stddeb, "GlobalLock32: invalid handle\n");
915 palloc=(LPVOID) NULL;
917 /* HeapUnlock(GetProcessHeap()); */;
918 return palloc;
922 /***********************************************************************
923 * GlobalUnlock32 (KERNEL32.332)
925 BOOL32 GlobalUnlock32(HGLOBAL32 hmem)
927 PGLOBAL32_INTERN pintern;
928 BOOL32 locked;
930 if(ISPOINTER(hmem))
931 return FALSE;
933 /* HeapLock(GetProcessHeap()); */
934 pintern=HANDLE_TO_INTERN(hmem);
936 if(pintern->Magic==MAGIC_GLOBAL_USED)
938 if((pintern->LockCount<GLOBAL_LOCK_MAX)&&(pintern->LockCount>0))
939 pintern->LockCount--;
941 locked=(pintern->LockCount==0) ? FALSE : TRUE;
943 else
945 dprintf_global(stddeb, "GlobalUnlock32: invalid handle\n");
946 locked=FALSE;
948 /* HeapUnlock(GetProcessHeap()); */
949 return locked;
953 /***********************************************************************
954 * GlobalHandle32 (KERNEL32.325)
956 HGLOBAL32 GlobalHandle32(LPCVOID pmem)
958 return (HGLOBAL32) POINTER_TO_HANDLE(pmem);
962 /***********************************************************************
963 * GlobalReAlloc32 (KERNEL32.328)
965 HGLOBAL32 GlobalReAlloc32(HGLOBAL32 hmem, DWORD size, UINT32 flags)
967 LPVOID palloc;
968 HGLOBAL32 hnew;
969 PGLOBAL32_INTERN pintern;
971 hnew=NULL;
972 /* HeapLock(GetProcessHeap()); */
973 if(flags & GMEM_MODIFY) /* modify flags */
975 if( ISPOINTER(hmem) && (flags & GMEM_MOVEABLE))
977 /* make a fixed block moveable
978 * actually only NT is able to do this. But it's soo simple
980 size=HeapSize(GetProcessHeap(), 0, (LPVOID) hmem);
981 hnew=GlobalAlloc32( flags, size);
982 palloc=GlobalLock32(hnew);
983 memcpy(palloc, (LPVOID) hmem, size);
984 GlobalUnlock32(hnew);
985 GlobalFree32(hmem);
987 else if( ISPOINTER(hmem) &&(flags & GMEM_DISCARDABLE))
989 /* change the flags to make our block "discardable" */
990 pintern=HANDLE_TO_INTERN(hmem);
991 pintern->Flags = pintern->Flags | (GMEM_DISCARDABLE >> 8);
992 hnew=hmem;
994 else
996 SetLastError(ERROR_INVALID_PARAMETER);
997 hnew=NULL;
1000 else
1002 if(ISPOINTER(hmem))
1004 /* reallocate fixed memory */
1005 hnew=(HGLOBAL32)HeapReAlloc(GetProcessHeap(), 0, (LPVOID) hmem, size);
1007 else
1009 /* reallocate a moveable block */
1010 pintern=HANDLE_TO_INTERN(hmem);
1011 if(pintern->LockCount!=0)
1012 SetLastError(ERROR_INVALID_HANDLE);
1013 else if(size!=0)
1015 hnew=hmem;
1016 if(pintern->Pointer)
1018 palloc=HeapReAlloc(GetProcessHeap(), 0,
1019 pintern->Pointer-sizeof(HGLOBAL32),
1020 size+sizeof(HGLOBAL32) );
1021 pintern->Pointer=palloc+sizeof(HGLOBAL32);
1023 else
1025 palloc=HeapAlloc(GetProcessHeap(), 0, size+sizeof(HGLOBAL32));
1026 *(HGLOBAL32 *)palloc=hmem;
1027 pintern->Pointer=palloc+sizeof(HGLOBAL32);
1030 else
1032 if(pintern->Pointer)
1034 HeapFree(GetProcessHeap(), 0, pintern->Pointer-sizeof(HGLOBAL32));
1035 pintern->Pointer=NULL;
1040 /* HeapUnlock(GetProcessHeap()); */
1041 return hnew;
1045 /***********************************************************************
1046 * GlobalFree32 (KERNEL32.322)
1048 HGLOBAL32 GlobalFree32(HGLOBAL32 hmem)
1050 PGLOBAL32_INTERN pintern;
1051 HGLOBAL32 hreturned=NULL;
1053 if(ISPOINTER(hmem)) /* POINTER */
1055 if(!HeapFree(GetProcessHeap(), 0, (LPVOID) hmem))
1056 hmem=NULL;
1058 else /* HANDLE */
1060 /* HeapLock(GetProcessHeap()); */
1061 pintern=HANDLE_TO_INTERN(hmem);
1063 if(pintern->Magic==MAGIC_GLOBAL_USED)
1065 if(pintern->LockCount!=0)
1066 SetLastError(ERROR_INVALID_HANDLE);
1067 if(pintern->Pointer)
1068 if(!HeapFree(GetProcessHeap(), 0,
1069 (char *)(pintern->Pointer)-sizeof(HGLOBAL32)))
1070 hreturned=hmem;
1071 if(!HeapFree(GetProcessHeap(), 0, pintern))
1072 hreturned=hmem;
1074 /* HeapUnlock(GetProcessHeap()); */
1076 return hreturned;
1080 /***********************************************************************
1081 * GlobalSize32 (KERNEL32.329)
1083 DWORD GlobalSize32(HGLOBAL32 hmem)
1085 DWORD retval;
1086 PGLOBAL32_INTERN pintern;
1088 if(ISPOINTER(hmem))
1090 retval=HeapSize(GetProcessHeap(), 0, (LPVOID) hmem);
1092 else
1094 /* HeapLock(GetProcessHeap()); */
1095 pintern=HANDLE_TO_INTERN(hmem);
1097 if(pintern->Magic==MAGIC_GLOBAL_USED)
1099 retval=HeapSize(GetProcessHeap(), 0,
1100 (char *)(pintern->Pointer)-sizeof(HGLOBAL32))-4;
1102 else
1104 dprintf_global(stddeb, "GlobalSize32: invalid handle\n");
1105 retval=0;
1107 /* HeapUnlock(GetProcessHeap()); */
1109 return retval;
1113 /***********************************************************************
1114 * GlobalWire32 (KERNEL32.333)
1116 LPVOID GlobalWire32(HGLOBAL32 hmem)
1118 return GlobalLock32( hmem );
1122 /***********************************************************************
1123 * GlobalUnWire32 (KERNEL32.330)
1125 BOOL32 GlobalUnWire32(HGLOBAL32 hmem)
1127 return GlobalUnlock32( hmem);
1131 /***********************************************************************
1132 * GlobalFix32 (KERNEL32.320)
1134 VOID GlobalFix32(HGLOBAL32 hmem)
1136 GlobalLock32( hmem );
1140 /***********************************************************************
1141 * GlobalUnfix32 (KERNEL32.331)
1143 VOID GlobalUnfix32(HGLOBAL32 hmem)
1145 GlobalUnlock32( hmem);
1149 /***********************************************************************
1150 * GlobalFlags32 (KERNEL32.321)
1152 UINT32 GlobalFlags32(HGLOBAL32 hmem)
1154 DWORD retval;
1155 PGLOBAL32_INTERN pintern;
1157 if(ISPOINTER(hmem))
1159 retval=0;
1161 else
1163 /* HeapLock(GetProcessHeap()); */
1164 pintern=HANDLE_TO_INTERN(hmem);
1165 if(pintern->Magic==MAGIC_GLOBAL_USED)
1167 retval=pintern->LockCount + (pintern->Flags<<8);
1168 if(pintern->Pointer==0)
1169 retval|= GMEM_DISCARDED;
1171 else
1173 dprintf_global(stddeb,"GlobalFlags32: invalid handle\n");
1174 retval=0;
1176 /* HeapUnlock(GetProcessHeap()); */
1178 return retval;
1182 /***********************************************************************
1183 * GlobalCompact32 (KERNEL32.316)
1185 DWORD GlobalCompact32( DWORD minfree )
1187 return 0; /* GlobalCompact does nothing in Win32 */
1191 /***********************************************************************
1192 * GlobalMemoryStatus (KERNEL32.327)
1194 VOID GlobalMemoryStatus( LPMEMORYSTATUS lpmem )
1196 #ifdef linux
1197 FILE *f = fopen( "/proc/meminfo", "r" );
1198 if (f)
1200 char buffer[256];
1201 int total, used, free;
1203 lpmem->dwTotalPhys = lpmem->dwAvailPhys = 0;
1204 lpmem->dwTotalPageFile = lpmem->dwAvailPageFile = 0;
1205 while (fgets( buffer, sizeof(buffer), f ))
1207 if (sscanf( buffer, "Mem: %d %d %d", &total, &used, &free ))
1209 lpmem->dwTotalPhys += total;
1210 lpmem->dwAvailPhys += free;
1212 else if (sscanf( buffer, "Swap: %d %d %d", &total, &used, &free ))
1214 lpmem->dwTotalPageFile += total;
1215 lpmem->dwAvailPageFile += free;
1218 fclose( f );
1220 if (lpmem->dwTotalPhys)
1222 lpmem->dwTotalVirtual = lpmem->dwTotalPhys+lpmem->dwTotalPageFile;
1223 lpmem->dwAvailVirtual = lpmem->dwAvailPhys+lpmem->dwAvailPageFile;
1224 lpmem->dwMemoryLoad = (lpmem->dwTotalVirtual-lpmem->dwAvailVirtual)
1225 * 100 / lpmem->dwTotalVirtual;
1226 return;
1229 #endif
1230 /* FIXME: should do something for other systems */
1231 lpmem->dwMemoryLoad = 0;
1232 lpmem->dwTotalPhys = 16*1024*1024;
1233 lpmem->dwAvailPhys = 16*1024*1024;
1234 lpmem->dwTotalPageFile = 16*1024*1024;
1235 lpmem->dwAvailPageFile = 16*1024*1024;
1236 lpmem->dwTotalVirtual = 32*1024*1024;
1237 lpmem->dwAvailVirtual = 32*1024*1024;