Release 950606
[wine/gsoc_dplay.git] / memory / global.c
blobd7fd15bc68bbe0a1918ed6b64ab40ef2f4d2d3ab
1 /*
2 * Global heap functions
4 * Copyright 1995 Alexandre Julliard
5 */
7 #include <stdlib.h>
8 #include <string.h>
9 #include "windows.h"
10 #include "global.h"
11 #include "toolhelp.h"
12 #include "selectors.h"
13 #include "stackframe.h"
14 #include "stddebug.h"
15 #include "debug.h"
17 /* Global arena block */
18 typedef struct
20 DWORD base; /* Base address */
21 DWORD size; /* Size in bytes (0 indicates a free block) */
22 HGLOBAL handle; /* Handle for this block */
23 HGLOBAL hOwner; /* Owner of this block */
24 BYTE lockCount; /* Count of GlobalFix() calls */
25 BYTE pageLockCount; /* Count of GlobalPageLock() calls */
26 BYTE flags; /* Allocation flags */
27 BYTE selCount; /* Number of selectors allocated for this block */
28 } GLOBALARENA;
30 /* Flags definitions */
31 #define GA_MOVEABLE 0x02 /* same as GMEM_MOVEABLE */
32 #define GA_DGROUP 0x04
33 #define GA_DISCARDABLE 0x08
35 /* Arena array */
36 static GLOBALARENA *pGlobalArena = NULL;
37 static int globalArenaSize = 0;
39 #define GLOBAL_MAX_ALLOC_SIZE 0x00ff0000 /* Largest allocation is 16M - 64K */
41 #define GET_ARENA_PTR(handle) (pGlobalArena + ((handle) >> __AHSHIFT))
43 /***********************************************************************
44 * GLOBAL_GetArena
46 * Return the arena for a given selector, growing the arena array if needed.
48 static GLOBALARENA *GLOBAL_GetArena( WORD sel, WORD selcount )
50 if (((sel >> __AHSHIFT) + selcount) > globalArenaSize)
52 int newsize = ((sel >> __AHSHIFT) + selcount + 0xff) & ~0xff;
53 GLOBALARENA *pNewArena = realloc( pGlobalArena,
54 newsize * sizeof(GLOBALARENA) );
55 if (!pNewArena) return 0;
56 pGlobalArena = pNewArena;
57 memset( pGlobalArena + globalArenaSize, 0,
58 (newsize - globalArenaSize) * sizeof(GLOBALARENA) );
59 globalArenaSize = newsize;
61 return pGlobalArena + (sel >> __AHSHIFT);
65 /***********************************************************************
66 * GLOBAL_CreateBlock
68 * Create a global heap block for a fixed range of linear memory.
70 HGLOBAL GLOBAL_CreateBlock( WORD flags, void *ptr, DWORD size,
71 HGLOBAL hOwner, BOOL isCode,
72 BOOL is32Bit, BOOL isReadOnly )
74 WORD sel, selcount;
75 GLOBALARENA *pArena;
77 /* Allocate the selector(s) */
79 sel = SELECTOR_AllocBlock( ptr, size, isCode ? SEGMENT_CODE : SEGMENT_DATA,
80 is32Bit, isReadOnly );
81 if (!sel) return 0;
82 selcount = (size + 0xffff) / 0x10000;
84 if (!(pArena = GLOBAL_GetArena( sel, selcount )))
86 FreeSelector( sel );
87 return 0;
90 /* Fill the arena block */
92 pArena->base = (DWORD)ptr;
93 pArena->size = GET_SEL_LIMIT(sel) + 1;
94 pArena->handle = (flags & GMEM_MOVEABLE) ? sel - 1 : sel;
95 pArena->hOwner = hOwner;
96 pArena->lockCount = 0;
97 pArena->pageLockCount = 0;
98 pArena->flags = flags & GA_MOVEABLE;
99 if (flags & GMEM_DISCARDABLE) pArena->flags |= GA_DISCARDABLE;
100 if (!isCode) pArena->flags |= GA_DGROUP;
101 pArena->selCount = selcount;
102 if (selcount > 1) /* clear the next arena blocks */
103 memset( pArena + 1, 0, (selcount - 1) * sizeof(GLOBALARENA) );
105 return pArena->handle;
109 /***********************************************************************
110 * GLOBAL_FreeBlock
112 * Free a block allocated by GLOBAL_CreateBlock, without touching
113 * the associated linear memory range.
115 BOOL GLOBAL_FreeBlock( HGLOBAL handle )
117 WORD sel;
119 if (!handle) return TRUE;
120 sel = GlobalHandleToSel( handle );
121 if (FreeSelector( sel )) return FALSE; /* failed */
122 memset( GET_ARENA_PTR(handle), 0, sizeof(GLOBALARENA) );
123 return TRUE;
127 /***********************************************************************
128 * GLOBAL_Alloc
130 * Implementation of GlobalAlloc()
132 HGLOBAL GLOBAL_Alloc( WORD flags, DWORD size, HGLOBAL hOwner,
133 BOOL isCode, BOOL is32Bit, BOOL isReadOnly )
135 void *ptr;
136 HGLOBAL handle;
138 dprintf_global( stddeb, "GlobalAlloc: %ld flags=%04x\n", size, flags );
140 /* Fixup the size */
142 if (size >= GLOBAL_MAX_ALLOC_SIZE - 0x1f) return 0;
143 if (size == 0) size = 0x20;
144 else size = (size + 0x1f) & ~0x1f;
146 /* Allocate the linear memory */
148 ptr = malloc( size );
149 if (!ptr) return 0;
151 /* Allocate the selector(s) */
153 handle = GLOBAL_CreateBlock( flags, ptr, size, hOwner,
154 isCode, is32Bit, isReadOnly);
155 if (!handle)
157 free( ptr );
158 return 0;
161 if (flags & GMEM_ZEROINIT) memset( ptr, 0, size );
162 return handle;
166 /***********************************************************************
167 * GlobalAlloc (KERNEL.15)
169 HGLOBAL GlobalAlloc( WORD flags, DWORD size )
171 HANDLE owner = GetCurrentPDB();
173 if (flags & GMEM_DDESHARE)
174 owner = GetExePtr(owner); /* Make it a module handle */
176 return GLOBAL_Alloc( flags, size, owner, FALSE, FALSE, FALSE );
180 /***********************************************************************
181 * GlobalReAlloc (KERNEL.16)
183 HGLOBAL GlobalReAlloc( HGLOBAL handle, DWORD size, WORD flags )
185 WORD sel, selcount;
186 DWORD oldsize;
187 void *ptr;
188 GLOBALARENA *pArena, *pNewArena;
190 dprintf_global( stddeb, "GlobalReAlloc: %04x %ld flags=%04x\n",
191 handle, size, flags );
192 if (!handle) return 0;
193 pArena = GET_ARENA_PTR( handle );
195 /* Discard the block if requested */
197 if ((size == 0) && (flags & GMEM_MOVEABLE))
199 if (!(pArena->flags & GA_MOVEABLE) ||
200 !(pArena->flags & GA_DISCARDABLE) ||
201 (pArena->lockCount > 0) || (pArena->pageLockCount > 0)) return 0;
202 free( (void *)pArena->base );
203 pArena->base = 0;
206 /* Fixup the size */
208 if (size > GLOBAL_MAX_ALLOC_SIZE - 0x20) return 0;
209 if (size == 0) size = 0x20;
210 else size = (size + 0x1f) & ~0x1f;
212 /* Change the flags */
214 if (flags & GMEM_MODIFY)
216 /* Change the flags, leaving GA_DGROUP alone */
217 pArena->flags = (pArena->flags & GA_DGROUP) | (flags & GA_MOVEABLE);
218 if (flags & GMEM_DISCARDABLE) pArena->flags |= GA_DISCARDABLE;
219 return handle;
222 /* Reallocate the linear memory */
224 sel = GlobalHandleToSel( handle );
225 ptr = (void *)pArena->base;
226 oldsize = pArena->size;
227 dprintf_global(stddeb,"oldsize %08lx\n",oldsize);
228 if (size == oldsize) return handle; /* Nothing to do */
230 ptr = realloc( ptr, size );
231 if (!ptr)
233 FreeSelector( sel );
234 memset( pArena, 0, sizeof(GLOBALARENA) );
235 return 0;
238 /* Reallocate the selector(s) */
240 sel = SELECTOR_ReallocBlock( sel, ptr, size, SEGMENT_DATA, 0, 0 );
241 if (!sel)
243 free( ptr );
244 memset( pArena, 0, sizeof(GLOBALARENA) );
245 return 0;
247 selcount = (size + 0xffff) / 0x10000;
249 if (!(pNewArena = GLOBAL_GetArena( sel, selcount )))
251 free( ptr );
252 FreeSelector( sel );
253 return 0;
256 /* Fill the new arena block */
258 if (pNewArena != pArena) memcpy( pNewArena, pArena, sizeof(GLOBALARENA) );
259 pNewArena->base = (DWORD)ptr;
260 pNewArena->size = GET_SEL_LIMIT(sel) + 1;
261 pNewArena->selCount = selcount;
262 pNewArena->handle = (pNewArena->flags & GA_MOVEABLE) ? sel - 1 : sel;
264 if (selcount > 1) /* clear the next arena blocks */
265 memset( pNewArena + 1, 0, (selcount - 1) * sizeof(GLOBALARENA) );
267 if ((oldsize < size) && (flags & GMEM_ZEROINIT))
268 memset( (char *)ptr + oldsize, 0, size - oldsize );
269 return pNewArena->handle;
273 /***********************************************************************
274 * GlobalFree (KERNEL.17)
276 HGLOBAL GlobalFree( HGLOBAL handle )
278 void *ptr;
280 dprintf_global( stddeb, "GlobalFree: %04x\n", handle );
281 if (!(ptr = GlobalLock( handle ))) return handle; /* failed */
282 if (!GLOBAL_FreeBlock( handle )) return handle; /* failed */
283 free( ptr );
284 return 0;
288 /***********************************************************************
289 * WIN16_GlobalLock (KERNEL.18)
291 * This is the GlobalLock() function used by 16-bit code.
293 SEGPTR WIN16_GlobalLock( HGLOBAL handle )
295 dprintf_global( stddeb, "WIN16_GlobalLock(%04x) -> %08lx\n",
296 handle, MAKELONG( 0, GlobalHandleToSel(handle)) );
297 if (!handle) return 0;
298 if (!GET_ARENA_PTR(handle)->base) return (SEGPTR)0;
299 return (SEGPTR)MAKELONG( 0, GlobalHandleToSel(handle) );
303 /***********************************************************************
304 * GlobalLock (KERNEL.18)
306 * This is the GlobalLock() function used by 32-bit code.
308 LPSTR GlobalLock( HGLOBAL handle )
310 dprintf_global( stddeb, "GlobalLock: %04x\n", handle );
311 if (!handle) return 0;
312 return (LPSTR)GET_ARENA_PTR(handle)->base;
316 /***********************************************************************
317 * GlobalUnlock (KERNEL.19)
319 BOOL GlobalUnlock( HGLOBAL handle )
321 dprintf_global( stddeb, "GlobalUnlock: %04x\n", handle );
322 return 0;
326 /***********************************************************************
327 * GlobalSize (KERNEL.20)
329 DWORD GlobalSize( HGLOBAL handle )
331 dprintf_global( stddeb, "GlobalSize: %04x\n", handle );
332 if (!handle) return 0;
333 return GET_ARENA_PTR(handle)->size;
337 /***********************************************************************
338 * GlobalHandle (KERNEL.21)
340 DWORD GlobalHandle( WORD sel )
342 dprintf_global( stddeb, "GlobalHandle: %04x\n", sel );
343 return MAKELONG( GET_ARENA_PTR(sel)->handle, sel );
347 /***********************************************************************
348 * GlobalFlags (KERNEL.22)
350 WORD GlobalFlags( HGLOBAL handle )
352 GLOBALARENA *pArena;
354 dprintf_global( stddeb, "GlobalFlags: %04x\n", handle );
355 pArena = GET_ARENA_PTR(handle);
356 return pArena->lockCount |
357 ((pArena->flags & GA_DISCARDABLE) ? GMEM_DISCARDABLE : 0) |
358 ((pArena->base == 0) ? GMEM_DISCARDED : 0);
362 /***********************************************************************
363 * LockSegment (KERNEL.23)
365 HGLOBAL LockSegment( HGLOBAL handle )
367 dprintf_global( stddeb, "LockSegment: %04x\n", handle );
368 if (handle == (HGLOBAL)-1) handle = CURRENT_DS;
369 GET_ARENA_PTR(handle)->lockCount++;
370 return handle;
374 /***********************************************************************
375 * UnlockSegment (KERNEL.24)
377 void UnlockSegment( HGLOBAL handle )
379 dprintf_global( stddeb, "UnlockSegment: %04x\n", handle );
380 if (handle == (HGLOBAL)-1) handle = CURRENT_DS;
381 GET_ARENA_PTR(handle)->lockCount--;
382 /* FIXME: this ought to return the lock count in CX (go figure...) */
386 /***********************************************************************
387 * GlobalCompact (KERNEL.25)
389 DWORD GlobalCompact( DWORD desired )
391 return GLOBAL_MAX_ALLOC_SIZE;
395 /***********************************************************************
396 * GlobalFreeAll (KERNEL.26)
398 void GlobalFreeAll( HANDLE owner )
400 DWORD i;
401 GLOBALARENA *pArena;
403 pArena = pGlobalArena;
404 for (i = 0; i < globalArenaSize; i++, pArena++)
406 if ((pArena->size != 0) && (pArena->hOwner == owner))
407 GlobalFree( pArena->handle );
412 /***********************************************************************
413 * GlobalWire (KERNEL.111)
415 SEGPTR GlobalWire( HGLOBAL handle )
417 return WIN16_GlobalLock( handle );
421 /***********************************************************************
422 * GlobalUnWire (KERNEL.112)
424 BOOL GlobalUnWire( HGLOBAL handle )
426 return GlobalUnlock( handle );
430 /***********************************************************************
431 * GlobalDOSAlloc (KERNEL.184)
433 DWORD GlobalDOSAlloc( DWORD size )
435 WORD sel = GlobalAlloc( GMEM_FIXED, size );
436 if (!sel) return 0;
437 return MAKELONG( sel, sel /* this one ought to be a real-mode segment */ );
441 /***********************************************************************
442 * GlobalDOSFree (KERNEL.185)
444 WORD GlobalDOSFree( WORD sel )
446 return GlobalFree( GlobalHandle(sel) ) ? sel : 0;
450 /***********************************************************************
451 * SetSwapAreaSize (KERNEL.106)
453 LONG SetSwapAreaSize( WORD size )
455 dprintf_heap(stdnimp, "STUB: SetSwapAreaSize(%d)\n", size );
456 return MAKELONG( size, 0xffff );
460 /***********************************************************************
461 * GlobalLRUOldest (KERNEL.163)
463 HGLOBAL GlobalLRUOldest( HGLOBAL handle )
465 dprintf_global( stddeb, "GlobalLRUOldest: %04x\n", handle );
466 if (handle == (HGLOBAL)-1) handle = CURRENT_DS;
467 return handle;
471 /***********************************************************************
472 * GlobalLRUNewest (KERNEL.164)
474 HGLOBAL GlobalLRUNewest( HGLOBAL handle )
476 dprintf_global( stddeb, "GlobalLRUNewest: %04x\n", handle );
477 if (handle == (HGLOBAL)-1) handle = CURRENT_DS;
478 return handle;
482 /***********************************************************************
483 * GetFreeSpace (KERNEL.169)
485 DWORD GetFreeSpace( UINT wFlags )
487 return GLOBAL_MAX_ALLOC_SIZE;
491 /***********************************************************************
492 * GlobalPageLock (KERNEL.191)
494 WORD GlobalPageLock( HGLOBAL handle )
496 dprintf_global( stddeb, "GlobalPageLock: %04x\n", handle );
497 return ++(GET_ARENA_PTR(handle)->pageLockCount);
501 /***********************************************************************
502 * GlobalPageUnlock (KERNEL.192)
504 WORD GlobalPageUnlock( HGLOBAL handle )
506 dprintf_global( stddeb, "GlobalPageUnlock: %04x\n", handle );
507 return --(GET_ARENA_PTR(handle)->pageLockCount);
511 /***********************************************************************
512 * GlobalFix (KERNEL.197)
514 void GlobalFix( HGLOBAL handle )
516 dprintf_global( stddeb, "GlobalFix: %04x\n", handle );
517 GET_ARENA_PTR(handle)->lockCount++;
521 /***********************************************************************
522 * GlobalUnfix (KERNEL.198)
524 void GlobalUnfix( HGLOBAL handle )
526 dprintf_global( stddeb, "GlobalUnfix: %04x\n", handle );
527 GET_ARENA_PTR(handle)->lockCount--;
531 /***********************************************************************
532 * FarSetOwner (KERNEL.403)
534 void FarSetOwner( HANDLE handle, WORD hOwner )
536 GET_ARENA_PTR(handle)->hOwner = hOwner;
540 /***********************************************************************
541 * FarGetOwner (KERNEL.404)
543 WORD FarGetOwner( HANDLE handle )
545 return GET_ARENA_PTR(handle)->hOwner;
549 /***********************************************************************
550 * GlobalHandleToSel (TOOLHELP.50)
552 WORD GlobalHandleToSel( HGLOBAL handle )
554 dprintf_toolhelp( stddeb, "GlobalHandleToSel: %04x\n", handle );
555 if (!handle) return 0;
556 if (!(handle & 7))
558 fprintf( stderr, "Program attempted invalid selector conversion\n" );
559 return handle - 1;
561 return handle | 7;
565 /***********************************************************************
566 * GlobalFirst (TOOLHELP.51)
568 BOOL GlobalFirst( GLOBALENTRY *pGlobal, WORD wFlags )
570 if (wFlags == GLOBAL_LRU) return FALSE;
571 pGlobal->dwNext = 0;
572 return GlobalNext( pGlobal, wFlags );
576 /***********************************************************************
577 * GlobalNext (TOOLHELP.52)
579 BOOL GlobalNext( GLOBALENTRY *pGlobal, WORD wFlags)
581 GLOBALARENA *pArena;
583 if (pGlobal->dwNext >= globalArenaSize) return FALSE;
584 pArena = pGlobalArena + pGlobal->dwNext;
585 if (wFlags == GLOBAL_FREE) /* only free blocks */
587 int i;
588 for (i = pGlobal->dwNext; i < globalArenaSize; i++, pArena++)
589 if (pArena->size == 0) break; /* block is free */
590 if (i >= globalArenaSize) return FALSE;
591 pGlobal->dwNext = i;
594 pGlobal->dwAddress = pArena->base;
595 pGlobal->dwBlockSize = pArena->size;
596 pGlobal->hBlock = pArena->handle;
597 pGlobal->wcLock = pArena->lockCount;
598 pGlobal->wcPageLock = pArena->pageLockCount;
599 pGlobal->wFlags = (GetCurrentPDB() == pArena->hOwner);
600 pGlobal->wHeapPresent = FALSE;
601 pGlobal->hOwner = pArena->hOwner;
602 pGlobal->wType = GT_UNKNOWN;
603 pGlobal->wData = 0;
604 pGlobal->dwNext++;
605 return TRUE;
609 /***********************************************************************
610 * GlobalInfo (TOOLHELP.53)
612 BOOL GlobalInfo( GLOBALINFO *pInfo )
614 int i;
615 GLOBALARENA *pArena;
617 pInfo->wcItems = globalArenaSize;
618 pInfo->wcItemsFree = 0;
619 pInfo->wcItemsLRU = 0;
620 for (i = 0, pArena = pGlobalArena; i < globalArenaSize; i++, pArena++)
621 if (pArena->size == 0) pInfo->wcItemsFree++;
622 return TRUE;
626 /***********************************************************************
627 * GlobalEntryHandle (TOOLHELP.54)
629 BOOL GlobalEntryHandle( GLOBALENTRY *pGlobal, HGLOBAL hItem )
631 return FALSE;
635 /***********************************************************************
636 * GlobalEntryModule (TOOLHELP.55)
638 BOOL GlobalEntryModule( GLOBALENTRY *pGlobal, HMODULE hModule, WORD wSeg )
640 return FALSE;
644 /***********************************************************************
645 * MemManInfo (TOOLHELP.72)
647 BOOL MemManInfo( MEMMANINFO *pInfo )
649 return TRUE;
652 /***********************************************************************
653 * GlobalAlloc32
654 * implements GlobalAlloc (KERNEL32.316)
655 * LocalAlloc (KERNEL32.372)
657 void *GlobalAlloc32(int flags,int size)
659 dprintf_global(stddeb,"GlobalAlloc32(%x,%x)\n",flags,size);
660 return malloc(size);