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