Release 951226
[wine.git] / memory / global.c
blob6d540a374626a8196bb3a70d8d067f2f428d0978
1 /*
2 * Global heap functions
4 * Copyright 1995 Alexandre Julliard
5 */
7 #include <sys/types.h>
8 #include <stdlib.h>
9 #include <string.h>
11 #include "windows.h"
12 #include "global.h"
13 #include "toolhelp.h"
14 #include "selectors.h"
15 #include "dde_mem.h"
16 #include "stackframe.h"
17 #include "options.h"
18 #include "stddebug.h"
19 #include "debug.h"
21 /* Global arena block */
22 typedef struct
24 DWORD base; /* Base address */
25 DWORD size; /* Size in bytes (0 indicates a free block) */
26 HGLOBAL handle; /* Handle for this block */
27 HGLOBAL hOwner; /* Owner of this block */
28 BYTE lockCount; /* Count of GlobalFix() calls */
29 BYTE pageLockCount; /* Count of GlobalPageLock() calls */
30 BYTE flags; /* Allocation flags */
31 BYTE selCount; /* Number of selectors allocated for this block */
32 int shmid;
33 } GLOBALARENA;
35 /* Flags definitions */
36 #define GA_MOVEABLE 0x02 /* same as GMEM_MOVEABLE */
37 #define GA_DGROUP 0x04
38 #define GA_DISCARDABLE 0x08
39 #define GA_IPCSHARE 0x10 /* same as GMEM_DDESHARE */
41 /* Arena array */
42 static GLOBALARENA *pGlobalArena = NULL;
43 static int globalArenaSize = 0;
45 #define GLOBAL_MAX_ALLOC_SIZE 0x00ff0000 /* Largest allocation is 16M - 64K */
47 #define GET_ARENA_PTR(handle) (pGlobalArena + ((handle) >> __AHSHIFT))
49 /***********************************************************************
50 * GLOBAL_GetArena
52 * Return the arena for a given selector, growing the arena array if needed.
54 static GLOBALARENA *GLOBAL_GetArena( WORD sel, WORD selcount )
56 if (((sel >> __AHSHIFT) + selcount) > globalArenaSize)
58 int newsize = ((sel >> __AHSHIFT) + selcount + 0xff) & ~0xff;
59 GLOBALARENA *pNewArena = realloc( pGlobalArena,
60 newsize * sizeof(GLOBALARENA) );
61 if (!pNewArena) return 0;
62 pGlobalArena = pNewArena;
63 memset( pGlobalArena + globalArenaSize, 0,
64 (newsize - globalArenaSize) * sizeof(GLOBALARENA) );
65 globalArenaSize = newsize;
67 return pGlobalArena + (sel >> __AHSHIFT);
71 void debug_handles()
73 int printed=0;
74 int i;
75 for (i = globalArenaSize-1 ; i>=0 ; i--) {
76 if (pGlobalArena[i].size!=0 && (pGlobalArena[i].handle & 0x8000)){
77 printed=1;
78 printf("0x%08x, ",pGlobalArena[i].handle);
81 if (printed)
82 printf("\n");
86 /***********************************************************************
87 * GLOBAL_CreateBlock
89 * Create a global heap block for a fixed range of linear memory.
91 HGLOBAL GLOBAL_CreateBlock( WORD flags, const void *ptr, DWORD size,
92 HGLOBAL hOwner, BOOL isCode,
93 BOOL is32Bit, BOOL isReadOnly,
94 SHMDATA *shmdata )
96 WORD sel, selcount;
97 GLOBALARENA *pArena;
99 /* Allocate the selector(s) */
101 sel = SELECTOR_AllocBlock( ptr, size,
102 isCode ? SEGMENT_CODE : SEGMENT_DATA,
103 is32Bit, isReadOnly );
105 if (!sel) return 0;
106 selcount = (size + 0xffff) / 0x10000;
108 if (!(pArena = GLOBAL_GetArena( sel, selcount )))
110 FreeSelector( sel );
111 return 0;
114 /* Fill the arena block */
116 pArena->base = (DWORD)ptr;
117 pArena->size = GET_SEL_LIMIT(sel) + 1;
118 if ((flags & GMEM_DDESHARE) && Options.ipc)
120 pArena->handle = shmdata->handle;
121 pArena->shmid = shmdata->shmid;
122 shmdata->sel = sel;
124 else
126 pArena->handle = (flags & GMEM_MOVEABLE) ? sel - 1 : sel;
127 pArena->shmid = 0;
129 pArena->hOwner = hOwner;
130 pArena->lockCount = 0;
131 pArena->pageLockCount = 0;
132 pArena->flags = flags & GA_MOVEABLE;
133 if (flags & GMEM_DISCARDABLE) pArena->flags |= GA_DISCARDABLE;
134 if (flags & GMEM_DDESHARE) pArena->flags |= GA_IPCSHARE;
135 if (!isCode) pArena->flags |= GA_DGROUP;
136 pArena->selCount = selcount;
137 if (selcount > 1) /* clear the next arena blocks */
138 memset( pArena + 1, 0, (selcount - 1) * sizeof(GLOBALARENA) );
140 return pArena->handle;
144 /***********************************************************************
145 * GLOBAL_FreeBlock
147 * Free a block allocated by GLOBAL_CreateBlock, without touching
148 * the associated linear memory range.
150 BOOL GLOBAL_FreeBlock( HGLOBAL handle )
152 WORD sel;
154 if (!handle) return TRUE;
155 sel = GlobalHandleToSel( handle );
156 if (FreeSelector( sel )) return FALSE; /* failed */
157 memset( GET_ARENA_PTR(sel), 0, sizeof(GLOBALARENA) );
158 return TRUE;
162 /***********************************************************************
163 * GLOBAL_Alloc
165 * Implementation of GlobalAlloc()
167 HGLOBAL GLOBAL_Alloc( WORD flags, DWORD size, HGLOBAL hOwner,
168 BOOL isCode, BOOL is32Bit, BOOL isReadOnly )
170 void *ptr;
171 HGLOBAL handle;
172 SHMDATA shmdata;
174 dprintf_global( stddeb, "GlobalAlloc: %ld flags=%04x\n", size, flags );
176 /* Fixup the size */
178 if (size >= GLOBAL_MAX_ALLOC_SIZE - 0x1f) return 0;
179 if (size == 0) size = 0x20;
180 else size = (size + 0x1f) & ~0x1f;
182 /* Allocate the linear memory */
184 #ifdef CONFIG_IPC
185 if ((flags & GMEM_DDESHARE) && Options.ipc)
186 ptr = DDE_malloc(flags, size, &shmdata);
187 else
188 #endif /* CONFIG_IPC */
189 ptr = malloc( size );
190 if (!ptr) return 0;
192 /* Allocate the selector(s) */
194 handle = GLOBAL_CreateBlock( flags, ptr, size, hOwner,
195 isCode, is32Bit, isReadOnly, &shmdata);
196 if (!handle)
198 free( ptr );
199 return 0;
202 if (flags & GMEM_ZEROINIT) memset( ptr, 0, size );
203 return handle;
207 #ifdef CONFIG_IPC
208 /***********************************************************************
209 * GLOBAL_FindArena
211 * Find the arena for a given handle
212 * (when handle is not serial - e.g. DDE)
214 static GLOBALARENA *GLOBAL_FindArena( HGLOBAL handle)
216 int i;
217 for (i = globalArenaSize-1 ; i>=0 ; i--) {
218 if (pGlobalArena[i].size!=0 && pGlobalArena[i].handle == handle)
219 return ( &pGlobalArena[i] );
221 return NULL;
225 /***********************************************************************
226 * DDE_GlobalHandleToSel
229 WORD DDE_GlobalHandleToSel( HGLOBAL handle )
231 GLOBALARENA *pArena;
232 SEGPTR segptr;
234 pArena= GLOBAL_FindArena(handle);
235 if (pArena) {
236 int ArenaIdx = pArena - pGlobalArena;
238 /* See if synchronized to the shared memory */
239 return DDE_SyncHandle(handle, ( ArenaIdx << __AHSHIFT) | 7);
242 /* attach the block */
243 DDE_AttachHandle(handle, &segptr);
245 return SELECTOROF( segptr );
247 #endif /* CONFIG_IPC */
250 /***********************************************************************
251 * GlobalAlloc (KERNEL.15)
253 HGLOBAL GlobalAlloc( WORD flags, DWORD size )
255 HANDLE owner = GetCurrentPDB();
257 if (flags & GMEM_DDESHARE)
258 owner = GetExePtr(owner); /* Make it a module handle */
259 return GLOBAL_Alloc( flags, size, owner, FALSE, FALSE, FALSE );
263 /***********************************************************************
264 * GlobalReAlloc (KERNEL.16)
266 HGLOBAL GlobalReAlloc( HGLOBAL handle, DWORD size, WORD flags )
268 WORD selcount;
269 DWORD oldsize;
270 void *ptr;
271 GLOBALARENA *pArena, *pNewArena;
272 WORD sel = GlobalHandleToSel( handle );
274 dprintf_global( stddeb, "GlobalReAlloc: %04x %ld flags=%04x\n",
275 handle, size, flags );
276 if (!handle) return 0;
278 #ifdef CONFIG_IPC
279 if (Options.ipc && (flags & GMEM_DDESHARE || is_dde_handle(handle))) {
280 fprintf(stdnimp,
281 "GlobalReAlloc: shared memory reallocating unimplemented\n");
282 return 0;
284 #endif /* CONFIG_IPC */
286 pArena = GET_ARENA_PTR( handle );
288 /* Discard the block if requested */
290 if ((size == 0) && (flags & GMEM_MOVEABLE) && !(flags & GMEM_MODIFY))
292 if (!(pArena->flags & GA_MOVEABLE) ||
293 !(pArena->flags & GA_DISCARDABLE) ||
294 (pArena->lockCount > 0) || (pArena->pageLockCount > 0)) return 0;
295 free( (void *)pArena->base );
296 pArena->base = 0;
297 /* Note: we rely on the fact that SELECTOR_ReallocBlock won't */
298 /* change the selector if we are shrinking the block */
299 SELECTOR_ReallocBlock( sel, 0, 1, SEGMENT_DATA, 0, 0 );
300 return handle;
303 /* Fixup the size */
305 if (size > GLOBAL_MAX_ALLOC_SIZE - 0x20) return 0;
306 if (size == 0) size = 0x20;
307 else size = (size + 0x1f) & ~0x1f;
309 /* Change the flags */
311 if (flags & GMEM_MODIFY)
313 /* Change the flags, leaving GA_DGROUP alone */
314 pArena->flags = (pArena->flags & GA_DGROUP) | (flags & GA_MOVEABLE);
315 if (flags & GMEM_DISCARDABLE) pArena->flags |= GA_DISCARDABLE;
316 return handle;
319 /* Reallocate the linear memory */
321 ptr = (void *)pArena->base;
322 oldsize = pArena->size;
323 dprintf_global(stddeb,"oldsize %08lx\n",oldsize);
324 if (size == oldsize) return handle; /* Nothing to do */
326 ptr = realloc( ptr, size );
327 if (!ptr)
329 FreeSelector( sel );
330 memset( pArena, 0, sizeof(GLOBALARENA) );
331 return 0;
334 /* Reallocate the selector(s) */
336 sel = SELECTOR_ReallocBlock( sel, ptr, size, SEGMENT_DATA, 0, 0 );
337 if (!sel)
339 free( ptr );
340 memset( pArena, 0, sizeof(GLOBALARENA) );
341 return 0;
343 selcount = (size + 0xffff) / 0x10000;
345 if (!(pNewArena = GLOBAL_GetArena( sel, selcount )))
347 free( ptr );
348 FreeSelector( sel );
349 return 0;
352 /* Fill the new arena block */
354 if (pNewArena != pArena) memcpy( pNewArena, pArena, sizeof(GLOBALARENA) );
355 pNewArena->base = (DWORD)ptr;
356 pNewArena->size = GET_SEL_LIMIT(sel) + 1;
357 pNewArena->selCount = selcount;
358 pNewArena->handle = (pNewArena->flags & GA_MOVEABLE) ? sel - 1 : sel;
360 if (selcount > 1) /* clear the next arena blocks */
361 memset( pNewArena + 1, 0, (selcount - 1) * sizeof(GLOBALARENA) );
363 if ((oldsize < size) && (flags & GMEM_ZEROINIT))
364 memset( (char *)ptr + oldsize, 0, size - oldsize );
365 return pNewArena->handle;
369 /***********************************************************************
370 * GlobalFree (KERNEL.17)
372 HGLOBAL GlobalFree( HGLOBAL handle )
374 void *ptr = GlobalLock( handle );
376 dprintf_global( stddeb, "GlobalFree: %04x\n", handle );
377 if (!GLOBAL_FreeBlock( handle )) return handle; /* failed */
378 #ifdef CONFIG_IPC
379 if (is_dde_handle(handle)) return DDE_GlobalFree(handle);
380 #endif /* CONFIG_IPC */
381 if (ptr) free( ptr );
382 return 0;
386 /***********************************************************************
387 * WIN16_GlobalLock (KERNEL.18)
389 * This is the GlobalLock() function used by 16-bit code.
391 SEGPTR WIN16_GlobalLock( HGLOBAL handle )
393 dprintf_global( stddeb, "WIN16_GlobalLock(%04x) -> %08lx\n",
394 handle, MAKELONG( 0, GlobalHandleToSel(handle)) );
395 if (!handle) return 0;
397 #ifdef CONFIG_IPC
398 if (is_dde_handle(handle))
399 return (SEGPTR)MAKELONG( 0, DDE_GlobalHandleToSel(handle) );
400 #endif /* CONFIG_IPC */
402 if (!GET_ARENA_PTR(handle)->base) return (SEGPTR)0;
403 return (SEGPTR)MAKELONG( 0, GlobalHandleToSel(handle) );
407 /***********************************************************************
408 * GlobalLock (KERNEL.18)
410 * This is the GlobalLock() function used by 32-bit code.
412 LPVOID GlobalLock( HGLOBAL handle )
414 if (!handle) return 0;
415 #ifdef CONFIG_IPC
416 if (is_dde_handle(handle)) return DDE_AttachHandle(handle, NULL);
417 #endif
418 return (LPSTR)GET_ARENA_PTR(handle)->base;
422 /***********************************************************************
423 * GlobalUnlock (KERNEL.19)
425 BOOL GlobalUnlock( HGLOBAL handle )
427 dprintf_global( stddeb, "GlobalUnlock: %04x\n", handle );
428 return 0;
432 /***********************************************************************
433 * GlobalSize (KERNEL.20)
435 DWORD GlobalSize( HGLOBAL handle )
437 dprintf_global( stddeb, "GlobalSize: %04x\n", handle );
438 if (!handle) return 0;
439 return GET_ARENA_PTR(handle)->size;
443 /***********************************************************************
444 * GlobalHandle (KERNEL.21)
446 DWORD GlobalHandle( WORD sel )
448 dprintf_global( stddeb, "GlobalHandle: %04x\n", sel );
449 return MAKELONG( GET_ARENA_PTR(sel)->handle, GlobalHandleToSel(sel) );
453 /***********************************************************************
454 * GlobalFlags (KERNEL.22)
456 WORD GlobalFlags( HGLOBAL handle )
458 GLOBALARENA *pArena;
460 dprintf_global( stddeb, "GlobalFlags: %04x\n", handle );
461 pArena = GET_ARENA_PTR(handle);
462 return pArena->lockCount |
463 ((pArena->flags & GA_DISCARDABLE) ? GMEM_DISCARDABLE : 0) |
464 ((pArena->base == 0) ? GMEM_DISCARDED : 0);
468 /***********************************************************************
469 * LockSegment (KERNEL.23)
471 HGLOBAL LockSegment( HGLOBAL handle )
473 dprintf_global( stddeb, "LockSegment: %04x\n", handle );
474 if (handle == (HGLOBAL)-1) handle = CURRENT_DS;
475 GET_ARENA_PTR(handle)->lockCount++;
476 return handle;
480 /***********************************************************************
481 * UnlockSegment (KERNEL.24)
483 void UnlockSegment( HGLOBAL handle )
485 dprintf_global( stddeb, "UnlockSegment: %04x\n", handle );
486 if (handle == (HGLOBAL)-1) handle = CURRENT_DS;
487 GET_ARENA_PTR(handle)->lockCount--;
488 /* FIXME: this ought to return the lock count in CX (go figure...) */
492 /***********************************************************************
493 * GlobalCompact (KERNEL.25)
495 DWORD GlobalCompact( DWORD desired )
497 return GLOBAL_MAX_ALLOC_SIZE;
501 /***********************************************************************
502 * GlobalFreeAll (KERNEL.26)
504 void GlobalFreeAll( HANDLE owner )
506 DWORD i;
507 GLOBALARENA *pArena;
509 pArena = pGlobalArena;
510 for (i = 0; i < globalArenaSize; i++, pArena++)
512 if ((pArena->size != 0) && (pArena->hOwner == owner))
513 GlobalFree( pArena->handle );
518 /***********************************************************************
519 * GlobalWire (KERNEL.111)
521 SEGPTR GlobalWire( HGLOBAL handle )
523 return WIN16_GlobalLock( handle );
527 /***********************************************************************
528 * GlobalUnWire (KERNEL.112)
530 BOOL GlobalUnWire( HGLOBAL handle )
532 return GlobalUnlock( handle );
536 /***********************************************************************
537 * GlobalDOSAlloc (KERNEL.184)
539 DWORD GlobalDOSAlloc( DWORD size )
541 WORD sel = GlobalAlloc( GMEM_FIXED, size );
542 if (!sel) return 0;
543 return MAKELONG( sel, sel /* this one ought to be a real-mode segment */ );
547 /***********************************************************************
548 * GlobalDOSFree (KERNEL.185)
550 WORD GlobalDOSFree( WORD sel )
552 return GlobalFree( GlobalHandle(sel) ) ? sel : 0;
556 /***********************************************************************
557 * SetSwapAreaSize (KERNEL.106)
559 LONG SetSwapAreaSize( WORD size )
561 dprintf_global(stdnimp, "STUB: SetSwapAreaSize(%d)\n", size );
562 return MAKELONG( size, 0xffff );
566 /***********************************************************************
567 * GlobalLRUOldest (KERNEL.163)
569 HGLOBAL GlobalLRUOldest( HGLOBAL handle )
571 dprintf_global( stddeb, "GlobalLRUOldest: %04x\n", handle );
572 if (handle == (HGLOBAL)-1) handle = CURRENT_DS;
573 return handle;
577 /***********************************************************************
578 * GlobalLRUNewest (KERNEL.164)
580 HGLOBAL GlobalLRUNewest( HGLOBAL handle )
582 dprintf_global( stddeb, "GlobalLRUNewest: %04x\n", handle );
583 if (handle == (HGLOBAL)-1) handle = CURRENT_DS;
584 return handle;
588 /***********************************************************************
589 * GetFreeSpace (KERNEL.169)
591 DWORD GetFreeSpace( UINT wFlags )
593 return GLOBAL_MAX_ALLOC_SIZE;
597 /***********************************************************************
598 * GlobalPageLock (KERNEL.191)
600 WORD GlobalPageLock( HGLOBAL handle )
602 dprintf_global( stddeb, "GlobalPageLock: %04x\n", handle );
603 return ++(GET_ARENA_PTR(handle)->pageLockCount);
607 /***********************************************************************
608 * GlobalPageUnlock (KERNEL.192)
610 WORD GlobalPageUnlock( HGLOBAL handle )
612 dprintf_global( stddeb, "GlobalPageUnlock: %04x\n", handle );
613 return --(GET_ARENA_PTR(handle)->pageLockCount);
617 /***********************************************************************
618 * GlobalFix (KERNEL.197)
620 void GlobalFix( HGLOBAL handle )
622 dprintf_global( stddeb, "GlobalFix: %04x\n", handle );
623 GET_ARENA_PTR(handle)->lockCount++;
627 /***********************************************************************
628 * GlobalUnfix (KERNEL.198)
630 void GlobalUnfix( HGLOBAL handle )
632 dprintf_global( stddeb, "GlobalUnfix: %04x\n", handle );
633 GET_ARENA_PTR(handle)->lockCount--;
637 /***********************************************************************
638 * FarSetOwner (KERNEL.403)
640 void FarSetOwner( HANDLE handle, WORD hOwner )
642 GET_ARENA_PTR(handle)->hOwner = hOwner;
646 /***********************************************************************
647 * FarGetOwner (KERNEL.404)
649 WORD FarGetOwner( HANDLE handle )
651 return GET_ARENA_PTR(handle)->hOwner;
655 /***********************************************************************
656 * GlobalHandleToSel (TOOLHELP.50)
658 WORD GlobalHandleToSel( HGLOBAL handle )
660 dprintf_toolhelp( stddeb, "GlobalHandleToSel: %04x\n", handle );
661 if (!handle) return 0;
662 #ifdef CONFIG_IPC
663 if (is_dde_handle(handle)) return DDE_GlobalHandleToSel(handle);
664 #endif
665 if (!(handle & 7))
667 fprintf( stderr, "Program attempted invalid selector conversion\n" );
668 return handle - 1;
670 return handle | 7;
674 /***********************************************************************
675 * GlobalFirst (TOOLHELP.51)
677 BOOL GlobalFirst( GLOBALENTRY *pGlobal, WORD wFlags )
679 if (wFlags == GLOBAL_LRU) return FALSE;
680 pGlobal->dwNext = 0;
681 return GlobalNext( pGlobal, wFlags );
685 /***********************************************************************
686 * GlobalNext (TOOLHELP.52)
688 BOOL GlobalNext( GLOBALENTRY *pGlobal, WORD wFlags)
690 GLOBALARENA *pArena;
692 if (pGlobal->dwNext >= globalArenaSize) return FALSE;
693 pArena = pGlobalArena + pGlobal->dwNext;
694 if (wFlags == GLOBAL_FREE) /* only free blocks */
696 int i;
697 for (i = pGlobal->dwNext; i < globalArenaSize; i++, pArena++)
698 if (pArena->size == 0) break; /* block is free */
699 if (i >= globalArenaSize) return FALSE;
700 pGlobal->dwNext = i;
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;
712 pGlobal->wData = 0;
713 pGlobal->dwNext++;
714 return TRUE;
718 /***********************************************************************
719 * GlobalInfo (TOOLHELP.53)
721 BOOL GlobalInfo( GLOBALINFO *pInfo )
723 int i;
724 GLOBALARENA *pArena;
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++;
731 return TRUE;
735 /***********************************************************************
736 * GlobalEntryHandle (TOOLHELP.54)
738 BOOL GlobalEntryHandle( GLOBALENTRY *pGlobal, HGLOBAL hItem )
740 return FALSE;
744 /***********************************************************************
745 * GlobalEntryModule (TOOLHELP.55)
747 BOOL GlobalEntryModule( GLOBALENTRY *pGlobal, HMODULE hModule, WORD wSeg )
749 return FALSE;
753 /***********************************************************************
754 * MemManInfo (TOOLHELP.72)
756 BOOL MemManInfo( MEMMANINFO *pInfo )
758 return TRUE;
761 /***********************************************************************
762 * GlobalAlloc32
763 * implements GlobalAlloc (KERNEL32.316)
764 * LocalAlloc (KERNEL32.372)
766 void *GlobalAlloc32(int flags,int size)
768 dprintf_global(stddeb,"GlobalAlloc32(%x,%x)\n",flags,size);
769 return malloc(size);