Release 970329
[wine] / memory / global.c
1 /*
2  * Global heap functions
3  *
4  * Copyright 1995 Alexandre Julliard
5  */
6
7 #include <sys/types.h>
8 #include <stdlib.h>
9 #include <unistd.h>
10 #include <string.h>
11
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"
24
25   /* Global arena block */
26 typedef struct
27 {
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;
40
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 */
46
47   /* Arena array */
48 static GLOBALARENA *pGlobalArena = NULL;
49 static int globalArenaSize = 0;
50
51 #define GLOBAL_MAX_ALLOC_SIZE 0x00ff0000  /* Largest allocation is 16M - 64K */
52
53 #define GET_ARENA_PTR(handle)  (pGlobalArena + ((handle) >> __AHSHIFT))
54
55 /***********************************************************************
56  *           GLOBAL_GetArena
57  *
58  * Return the arena for a given selector, growing the arena array if needed.
59  */
60 static GLOBALARENA *GLOBAL_GetArena( WORD sel, WORD selcount )
61 {
62     if (((sel >> __AHSHIFT) + selcount) > globalArenaSize)
63     {
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;
72     }
73     return pGlobalArena + (sel >> __AHSHIFT);
74 }
75
76
77 void debug_handles()
78 {
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);
85         }
86     }
87     if (printed)
88         printf("\n");
89 }
90
91
92 /***********************************************************************
93  *           GLOBAL_CreateBlock
94  *
95  * Create a global heap block for a fixed range of linear memory.
96  */
97 HGLOBAL16 GLOBAL_CreateBlock( WORD flags, const void *ptr, DWORD size,
98                               HGLOBAL16 hOwner, BOOL16 isCode,
99                               BOOL16 is32Bit, BOOL16 isReadOnly,
100                               SHMDATA *shmdata  )
101 {
102     WORD sel, selcount;
103     GLOBALARENA *pArena;
104
105       /* Allocate the selector(s) */
106
107     sel = SELECTOR_AllocBlock( ptr, size,
108                               isCode ? SEGMENT_CODE : SEGMENT_DATA,
109                               is32Bit, isReadOnly );
110     
111     if (!sel) return 0;
112     selcount = (size + 0xffff) / 0x10000;
113
114     if (!(pArena = GLOBAL_GetArena( sel, selcount )))
115     {
116         SELECTOR_FreeBlock( sel, selcount );
117         return 0;
118     }
119
120       /* Fill the arena block */
121
122     pArena->base = (DWORD)ptr;
123     pArena->size = GET_SEL_LIMIT(sel) + 1;
124
125 #ifdef CONFIG_IPC
126     if ((flags & GMEM_DDESHARE) && Options.ipc)
127     {
128         pArena->handle = shmdata->handle;
129         pArena->shmid  = shmdata->shmid;
130         shmdata->sel   = sel;
131     }
132     else
133     {
134         pArena->handle = (flags & GMEM_MOVEABLE) ? sel - 1 : sel;
135         pArena->shmid  = 0;
136     }
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) );
150
151     return pArena->handle;
152 }
153
154
155 /***********************************************************************
156  *           GLOBAL_FreeBlock
157  *
158  * Free a block allocated by GLOBAL_CreateBlock, without touching
159  * the associated linear memory range.
160  */
161 BOOL16 GLOBAL_FreeBlock( HGLOBAL16 handle )
162 {
163     WORD sel;
164     GLOBALARENA *pArena;
165
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;
172 }
173
174
175 /***********************************************************************
176  *           GLOBAL_Alloc
177  *
178  * Implementation of GlobalAlloc16()
179  */
180 HGLOBAL16 GLOBAL_Alloc( UINT16 flags, DWORD size, HGLOBAL16 hOwner,
181                         BOOL16 isCode, BOOL16 is32Bit, BOOL16 isReadOnly )
182 {
183     void *ptr;
184     HGLOBAL16 handle;
185     SHMDATA shmdata;
186
187     dprintf_global( stddeb, "GlobalAlloc: %ld flags=%04x\n", size, flags );
188
189     /* If size is 0, create a discarded block */
190
191     if (size == 0) return GLOBAL_CreateBlock( flags, NULL, 1, hOwner, isCode,
192                                               is32Bit, isReadOnly, NULL );
193
194     /* Fixup the size */
195
196     if (size >= GLOBAL_MAX_ALLOC_SIZE - 0x1f) return 0;
197     size = (size + 0x1f) & ~0x1f;
198
199       /* Allocate the linear memory */
200
201 #ifdef CONFIG_IPC
202     if ((flags & GMEM_DDESHARE) && Options.ipc)
203         ptr = DDE_malloc(flags, size, &shmdata);
204     else 
205 #endif  /* CONFIG_IPC */
206     {
207         ptr = HeapAlloc( SystemHeap, 0, size );
208     }
209     if (!ptr) return 0;
210
211       /* Allocate the selector(s) */
212
213     handle = GLOBAL_CreateBlock( flags, ptr, size, hOwner,
214                                 isCode, is32Bit, isReadOnly, &shmdata);
215     if (!handle)
216     {
217         HeapFree( SystemHeap, 0, ptr );
218         return 0;
219     }
220
221     if (flags & GMEM_ZEROINIT) memset( ptr, 0, size );
222     return handle;
223 }
224
225
226 #ifdef CONFIG_IPC
227 /***********************************************************************
228  *           GLOBAL_FindArena
229  *
230  * Find the arena  for a given handle
231  * (when handle is not serial - e.g. DDE)
232  */
233 static GLOBALARENA *GLOBAL_FindArena( HGLOBAL16 handle)
234 {
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] );
239     }
240     return NULL;
241 }
242
243
244 /***********************************************************************
245  *           DDE_GlobalHandleToSel
246  */
247
248 WORD DDE_GlobalHandleToSel( HGLOBAL16 handle )
249 {
250     GLOBALARENA *pArena;
251     SEGPTR segptr;
252     
253     pArena= GLOBAL_FindArena(handle);
254     if (pArena) {
255         int ArenaIdx = pArena - pGlobalArena;
256
257         /* See if synchronized to the shared memory  */
258         return DDE_SyncHandle(handle, ( ArenaIdx << __AHSHIFT) | 7);
259     }
260
261     /* attach the block */
262     DDE_AttachHandle(handle, &segptr);
263
264     return SELECTOROF( segptr );
265 }
266 #endif  /* CONFIG_IPC */
267
268
269 /***********************************************************************
270  *           GlobalAlloc16   (KERNEL.15)
271  */
272 HGLOBAL16 GlobalAlloc16( UINT16 flags, DWORD size )
273 {
274     HANDLE16 owner = GetCurrentPDB();
275
276     if (flags & GMEM_DDESHARE)
277         owner = GetExePtr(owner);  /* Make it a module handle */
278     return GLOBAL_Alloc( flags, size, owner, FALSE, FALSE, FALSE );
279 }
280
281
282 /***********************************************************************
283  *           GlobalReAlloc16   (KERNEL.16)
284  */
285 HGLOBAL16 GlobalReAlloc16( HGLOBAL16 handle, DWORD size, UINT16 flags )
286 {
287     WORD selcount;
288     DWORD oldsize;
289     void *ptr;
290     GLOBALARENA *pArena, *pNewArena;
291     WORD sel = GlobalHandleToSel( handle );
292
293     dprintf_global( stddeb, "GlobalReAlloc16: %04x %ld flags=%04x\n",
294                     handle, size, flags );
295     if (!handle) return 0;
296     
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;
302     }
303 #endif  /* CONFIG_IPC */
304
305     pArena = GET_ARENA_PTR( handle );
306
307       /* Discard the block if requested */
308
309     if ((size == 0) && (flags & GMEM_MOVEABLE) && !(flags & GMEM_MODIFY))
310     {
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;
320     }
321
322       /* Fixup the size */
323
324     if (size > GLOBAL_MAX_ALLOC_SIZE - 0x20) return 0;
325     if (size == 0) size = 0x20;
326     else size = (size + 0x1f) & ~0x1f;
327
328       /* Change the flags */
329
330     if (flags & GMEM_MODIFY)
331     {
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;
336     }
337
338       /* Reallocate the linear memory */
339
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 */
344
345     ptr = HeapReAlloc( SystemHeap, 0, ptr, size );
346     if (!ptr)
347     {
348         SELECTOR_FreeBlock( sel, (oldsize + 0xffff) / 0x10000 );
349         memset( pArena, 0, sizeof(GLOBALARENA) );
350         return 0;
351     }
352
353       /* Reallocate the selector(s) */
354
355     sel = SELECTOR_ReallocBlock( sel, ptr, size, SEGMENT_DATA, 0, 0 );
356     if (!sel)
357     {
358         HeapFree( SystemHeap, 0, ptr );
359         memset( pArena, 0, sizeof(GLOBALARENA) );
360         return 0;
361     }
362     selcount = (size + 0xffff) / 0x10000;
363
364     if (!(pNewArena = GLOBAL_GetArena( sel, selcount )))
365     {
366         HeapFree( SystemHeap, 0, ptr );
367         SELECTOR_FreeBlock( sel, selcount );
368         return 0;
369     }
370
371       /* Fill the new arena block */
372
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;
378
379     if (selcount > 1)  /* clear the next arena blocks */
380         memset( pNewArena + 1, 0, (selcount - 1) * sizeof(GLOBALARENA) );
381
382     if ((oldsize < size) && (flags & GMEM_ZEROINIT))
383         memset( (char *)ptr + oldsize, 0, size - oldsize );
384     return pNewArena->handle;
385 }
386
387
388 /***********************************************************************
389  *           GlobalFree16   (KERNEL.17)
390  */
391 HGLOBAL16 GlobalFree16( HGLOBAL16 handle )
392 {
393     void *ptr = GlobalLock16( handle );
394
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;
402 }
403
404
405 /***********************************************************************
406  *           WIN16_GlobalLock16   (KERNEL.18)
407  *
408  * This is the GlobalLock16() function used by 16-bit code.
409  */
410 SEGPTR WIN16_GlobalLock16( HGLOBAL16 handle )
411 {
412     dprintf_global( stddeb, "WIN16_GlobalLock16(%04x) -> %08lx\n",
413                     handle, MAKELONG( 0, GlobalHandleToSel(handle)) );
414     if (!handle) return 0;
415
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 */
420
421     if (!GET_ARENA_PTR(handle)->base) return (SEGPTR)0;
422     return PTR_SEG_OFF_TO_SEGPTR( GlobalHandleToSel(handle), 0 );
423 }
424
425
426 /***********************************************************************
427  *           GlobalLock16   (KERNEL.18)
428  *
429  * This is the GlobalLock16() function used by 32-bit code.
430  */
431 LPVOID GlobalLock16( HGLOBAL16 handle )
432 {
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;
438 }
439
440
441 /***********************************************************************
442  *           GlobalUnlock16   (KERNEL.19)
443  */
444 BOOL16 GlobalUnlock16( HGLOBAL16 handle )
445 {
446     dprintf_global( stddeb, "GlobalUnlock16: %04x\n", handle );
447     return 0;
448 }
449
450
451 /***********************************************************************
452  *           GlobalSize16   (KERNEL.20)
453  */
454 DWORD GlobalSize16( HGLOBAL16 handle )
455 {
456     dprintf_global( stddeb, "GlobalSize16: %04x\n", handle );
457     if (!handle) return 0;
458     return GET_ARENA_PTR(handle)->size;
459 }
460
461
462 /***********************************************************************
463  *           GlobalHandle16   (KERNEL.21)
464  */
465 DWORD GlobalHandle16( WORD sel )
466 {
467     dprintf_global( stddeb, "GlobalHandle16: %04x\n", sel );
468     return MAKELONG( GET_ARENA_PTR(sel)->handle, GlobalHandleToSel(sel) );
469 }
470
471
472 /***********************************************************************
473  *           GlobalFlags16   (KERNEL.22)
474  */
475 UINT16 GlobalFlags16( HGLOBAL16 handle )
476 {
477     GLOBALARENA *pArena;
478
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);
484 }
485
486
487 /***********************************************************************
488  *           LockSegment16   (KERNEL.23)
489  */
490 HGLOBAL16 LockSegment16( HGLOBAL16 handle )
491 {
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;
496 }
497
498
499 /***********************************************************************
500  *           UnlockSegment16   (KERNEL.24)
501  */
502 void UnlockSegment16( HGLOBAL16 handle )
503 {
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...) */
508 }
509
510
511 /***********************************************************************
512  *           GlobalCompact16   (KERNEL.25)
513  */
514 DWORD GlobalCompact16( DWORD desired )
515 {
516     return GLOBAL_MAX_ALLOC_SIZE;
517 }
518
519
520 /***********************************************************************
521  *           GlobalFreeAll   (KERNEL.26)
522  */
523 void GlobalFreeAll( HGLOBAL16 owner )
524 {
525     DWORD i;
526     GLOBALARENA *pArena;
527
528     pArena = pGlobalArena;
529     for (i = 0; i < globalArenaSize; i++, pArena++)
530     {
531         if ((pArena->size != 0) && (pArena->hOwner == owner))
532             GlobalFree16( pArena->handle );
533     }
534 }
535
536
537 /***********************************************************************
538  *           GlobalWire16   (KERNEL.111)
539  */
540 SEGPTR GlobalWire16( HGLOBAL16 handle )
541 {
542     return WIN16_GlobalLock16( handle );
543 }
544
545
546 /***********************************************************************
547  *           GlobalUnWire16   (KERNEL.112)
548  */
549 BOOL16 GlobalUnWire16( HGLOBAL16 handle )
550 {
551     return GlobalUnlock16( handle );
552 }
553
554
555 /***********************************************************************
556  *           SetSwapAreaSize   (KERNEL.106)
557  */
558 LONG SetSwapAreaSize( WORD size )
559 {
560     dprintf_global(stdnimp, "STUB: SetSwapAreaSize(%d)\n", size );
561     return MAKELONG( size, 0xffff );
562 }
563
564
565 /***********************************************************************
566  *           GlobalLRUOldest   (KERNEL.163)
567  */
568 HGLOBAL16 GlobalLRUOldest( HGLOBAL16 handle )
569 {
570     dprintf_global( stddeb, "GlobalLRUOldest: %04x\n", handle );
571     if (handle == (HGLOBAL16)-1) handle = CURRENT_DS;
572     return handle;
573 }
574
575
576 /***********************************************************************
577  *           GlobalLRUNewest   (KERNEL.164)
578  */
579 HGLOBAL16 GlobalLRUNewest( HGLOBAL16 handle )
580 {
581     dprintf_global( stddeb, "GlobalLRUNewest: %04x\n", handle );
582     if (handle == (HGLOBAL16)-1) handle = CURRENT_DS;
583     return handle;
584 }
585
586
587 /***********************************************************************
588  *           GetFreeSpace16   (KERNEL.169)
589  */
590 DWORD GetFreeSpace16( UINT16 wFlags )
591 {
592     MEMORYSTATUS ms;
593     GlobalMemoryStatus( &ms );
594     return ms.dwAvailVirtual;
595 }
596
597 /***********************************************************************
598  *           GlobalDOSAlloc   (KERNEL.184)
599  */
600 DWORD GlobalDOSAlloc(DWORD size)
601 {
602    UINT16    uParagraph;
603    LPVOID    lpBlock = DOSMEM_GetBlock( size, &uParagraph );
604    
605    if( lpBlock )
606    {
607        HMODULE16 hModule = GetModuleHandle16("KERNEL");
608        WORD      wSelector;
609    
610        wSelector = GLOBAL_CreateBlock(GMEM_FIXED, lpBlock, size, 
611                                       hModule, 0, 0, 0, NULL );
612        return MAKELONG(wSelector,uParagraph);
613    }
614    return 0;
615 }
616
617 /***********************************************************************
618  *           GlobalDOSFree      (KERNEL.185)
619  */
620 WORD GlobalDOSFree(WORD sel)
621 {
622    DWORD   block = GetSelectorBase(sel);
623
624    if( block && block < 0x100000 ) 
625    {
626        LPVOID lpBlock = DOSMEM_MapDosToLinear( block );
627        if( DOSMEM_FreeBlock( lpBlock ) )
628            GLOBAL_FreeBlock( sel );
629        sel = 0;
630    }
631    return sel;
632 }
633
634 /***********************************************************************
635  *           GlobalPageLock   (KERNEL.191)
636  */
637 WORD GlobalPageLock( HGLOBAL16 handle )
638 {
639     dprintf_global( stddeb, "GlobalPageLock: %04x\n", handle );
640     return ++(GET_ARENA_PTR(handle)->pageLockCount);
641 }
642
643
644 /***********************************************************************
645  *           GlobalPageUnlock   (KERNEL.192)
646  */
647 WORD GlobalPageUnlock( HGLOBAL16 handle )
648 {
649     dprintf_global( stddeb, "GlobalPageUnlock: %04x\n", handle );
650     return --(GET_ARENA_PTR(handle)->pageLockCount);
651 }
652
653
654 /***********************************************************************
655  *           GlobalFix16   (KERNEL.197)
656  */
657 void GlobalFix16( HGLOBAL16 handle )
658 {
659     dprintf_global( stddeb, "GlobalFix16: %04x\n", handle );
660     GET_ARENA_PTR(handle)->lockCount++;
661 }
662
663
664 /***********************************************************************
665  *           GlobalUnfix16   (KERNEL.198)
666  */
667 void GlobalUnfix16( HGLOBAL16 handle )
668 {
669     dprintf_global( stddeb, "GlobalUnfix16: %04x\n", handle );
670     GET_ARENA_PTR(handle)->lockCount--;
671 }
672
673
674 /***********************************************************************
675  *           FarSetOwner   (KERNEL.403)
676  */
677 void FarSetOwner( HGLOBAL16 handle, HANDLE16 hOwner )
678 {
679     GET_ARENA_PTR(handle)->hOwner = hOwner;
680 }
681
682
683 /***********************************************************************
684  *           FarGetOwner   (KERNEL.404)
685  */
686 HANDLE16 FarGetOwner( HGLOBAL16 handle )
687 {
688     return GET_ARENA_PTR(handle)->hOwner;
689 }
690
691
692 /***********************************************************************
693  *           GlobalHandleToSel   (TOOLHELP.50)
694  */
695 WORD GlobalHandleToSel( HGLOBAL16 handle )
696 {
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))
703     {
704         fprintf( stderr, "Program attempted invalid selector conversion\n" );
705         return handle - 1;
706     }
707     return handle | 7;
708 }
709
710
711 /***********************************************************************
712  *           GlobalFirst   (TOOLHELP.51)
713  */
714 BOOL16 GlobalFirst( GLOBALENTRY *pGlobal, WORD wFlags )
715 {
716     if (wFlags == GLOBAL_LRU) return FALSE;
717     pGlobal->dwNext = 0;
718     return GlobalNext( pGlobal, wFlags );
719 }
720
721
722 /***********************************************************************
723  *           GlobalNext   (TOOLHELP.52)
724  */
725 BOOL16 GlobalNext( GLOBALENTRY *pGlobal, WORD wFlags)
726 {
727     GLOBALARENA *pArena;
728
729     if (pGlobal->dwNext >= globalArenaSize) return FALSE;
730     pArena = pGlobalArena + pGlobal->dwNext;
731     if (wFlags == GLOBAL_FREE)  /* only free blocks */
732     {
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;
738     }
739
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;
752 }
753
754
755 /***********************************************************************
756  *           GlobalInfo   (TOOLHELP.53)
757  */
758 BOOL16 GlobalInfo( GLOBALINFO *pInfo )
759 {
760     int i;
761     GLOBALARENA *pArena;
762
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;
769 }
770
771
772 /***********************************************************************
773  *           GlobalEntryHandle   (TOOLHELP.54)
774  */
775 BOOL16 GlobalEntryHandle( GLOBALENTRY *pGlobal, HGLOBAL16 hItem )
776 {
777     return FALSE;
778 }
779
780
781 /***********************************************************************
782  *           GlobalEntryModule   (TOOLHELP.55)
783  */
784 BOOL16 GlobalEntryModule( GLOBALENTRY *pGlobal, HMODULE16 hModule, WORD wSeg )
785 {
786     return FALSE;
787 }
788
789
790 /***********************************************************************
791  *           MemManInfo   (TOOLHELP.72)
792  */
793 BOOL16 MemManInfo( MEMMANINFO *info )
794 {
795     MEMORYSTATUS status;
796
797     /*
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.
801      */
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;
818 }
819
820 /*
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.
826  *
827  * The handle stuff looks horrible, but it's implemented almost like Win95
828  * does it. 
829  *
830  */
831
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)
839
840 typedef struct __GLOBAL32_INTERN
841 {
842    WORD         Magic;
843    LPVOID       Pointer WINE_PACKED;
844    BYTE         Flags;
845    BYTE         LockCount;
846 } GLOBAL32_INTERN, *PGLOBAL32_INTERN;
847
848
849 /***********************************************************************
850  *           GlobalAlloc32   (KERNEL32.315)
851  */
852 HGLOBAL32 GlobalAlloc32(UINT32 flags, DWORD size)
853 {
854    PGLOBAL32_INTERN     pintern;
855    DWORD                hpflags;
856    LPVOID               palloc;
857
858    if(flags&GMEM_ZEROINIT)
859       hpflags=HEAP_ZERO_MEMORY;
860    else
861       hpflags=0;
862    
863    if((flags & GMEM_MOVEABLE)==0) /* POINTER */
864    {
865       palloc=HeapAlloc(GetProcessHeap(), hpflags, size);
866       return (HGLOBAL32) palloc;
867    }
868    else  /* HANDLE */
869    {
870       /* HeapLock(GetProcessHeap()); */
871
872       pintern=HeapAlloc(GetProcessHeap(), 0,  sizeof(GLOBAL32_INTERN));
873       if(size)
874       {
875          palloc=HeapAlloc(GetProcessHeap(), 0, size+sizeof(HGLOBAL32));
876          *(HGLOBAL32 *)palloc=INTERN_TO_HANDLE(pintern);
877          pintern->Pointer=palloc+sizeof(HGLOBAL32);
878       }
879       else
880          pintern->Pointer=NULL;
881       pintern->Magic=MAGIC_GLOBAL_USED;
882       pintern->Flags=flags>>8;
883       pintern->LockCount=0;
884       
885       /* HeapUnlock(GetProcessHeap()); */
886        
887       return INTERN_TO_HANDLE(pintern);
888    }
889 }
890
891
892 /***********************************************************************
893  *           GlobalLock32   (KERNEL32.326)
894  */
895 LPVOID  GlobalLock32(HGLOBAL32 hmem)
896 {
897    PGLOBAL32_INTERN pintern;
898    LPVOID           palloc;
899
900    if(ISPOINTER(hmem))
901       return (LPVOID) hmem;
902
903    /* HeapLock(GetProcessHeap()); */
904    
905    pintern=HANDLE_TO_INTERN(hmem);
906    if(pintern->Magic==MAGIC_GLOBAL_USED)
907    {
908       if(pintern->LockCount<GLOBAL_LOCK_MAX)
909          pintern->LockCount++;
910       palloc=pintern->Pointer;
911    }
912    else
913    {
914       dprintf_global(stddeb, "GlobalLock32: invalid handle\n");
915       palloc=(LPVOID) NULL;
916    }
917    /* HeapUnlock(GetProcessHeap()); */;
918    return palloc;
919 }
920
921
922 /***********************************************************************
923  *           GlobalUnlock32   (KERNEL32.332)
924  */
925 BOOL32 GlobalUnlock32(HGLOBAL32 hmem)
926 {
927    PGLOBAL32_INTERN       pintern;
928    BOOL32                 locked;
929
930    if(ISPOINTER(hmem))
931       return FALSE;
932
933    /* HeapLock(GetProcessHeap()); */
934    pintern=HANDLE_TO_INTERN(hmem);
935    
936    if(pintern->Magic==MAGIC_GLOBAL_USED)
937    {
938       if((pintern->LockCount<GLOBAL_LOCK_MAX)&&(pintern->LockCount>0))
939          pintern->LockCount--;
940
941       locked=(pintern->LockCount==0) ? FALSE : TRUE;
942    }
943    else
944    {
945       dprintf_global(stddeb, "GlobalUnlock32: invalid handle\n");
946       locked=FALSE;
947    }
948    /* HeapUnlock(GetProcessHeap()); */
949    return locked;
950 }
951
952
953 /***********************************************************************
954  *           GlobalHandle32   (KERNEL32.325)
955  */
956 HGLOBAL32 GlobalHandle32(LPCVOID pmem)
957 {
958    return (HGLOBAL32) POINTER_TO_HANDLE(pmem);
959 }
960
961
962 /***********************************************************************
963  *           GlobalReAlloc32   (KERNEL32.328)
964  */
965 HGLOBAL32 GlobalReAlloc32(HGLOBAL32 hmem, DWORD size, UINT32 flags)
966 {
967    LPVOID               palloc;
968    HGLOBAL32            hnew;
969    PGLOBAL32_INTERN     pintern;
970
971    hnew=NULL;
972    /* HeapLock(GetProcessHeap()); */
973    if(flags & GMEM_MODIFY) /* modify flags */
974    {
975       if( ISPOINTER(hmem) && (flags & GMEM_MOVEABLE))
976       {
977          /* make a fixed block moveable
978           * actually only NT is able to do this. But it's soo simple
979           */
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);
986       }
987       else if( ISPOINTER(hmem) &&(flags & GMEM_DISCARDABLE))
988       {
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;
993       }
994       else
995       {
996          SetLastError(ERROR_INVALID_PARAMETER);
997          hnew=NULL;
998       }
999    }
1000    else
1001    {
1002       if(ISPOINTER(hmem))
1003       {
1004          /* reallocate fixed memory */
1005          hnew=(HGLOBAL32)HeapReAlloc(GetProcessHeap(), 0, (LPVOID) hmem, size);
1006       }
1007       else
1008       {
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)
1014          {
1015             hnew=hmem;
1016             if(pintern->Pointer)
1017             {
1018                palloc=HeapReAlloc(GetProcessHeap(), 0,
1019                                   pintern->Pointer-sizeof(HGLOBAL32),
1020                                   size+sizeof(HGLOBAL32) );
1021                pintern->Pointer=palloc+sizeof(HGLOBAL32);
1022             }
1023             else
1024             {
1025                palloc=HeapAlloc(GetProcessHeap(), 0, size+sizeof(HGLOBAL32));
1026                *(HGLOBAL32 *)palloc=hmem;
1027                pintern->Pointer=palloc+sizeof(HGLOBAL32);
1028             }
1029          }
1030          else
1031          {
1032             if(pintern->Pointer)
1033             {
1034                HeapFree(GetProcessHeap(), 0, pintern->Pointer-sizeof(HGLOBAL32));
1035                pintern->Pointer=NULL;
1036             }
1037          }
1038       }
1039    }
1040    /* HeapUnlock(GetProcessHeap()); */
1041    return hnew;
1042 }
1043
1044
1045 /***********************************************************************
1046  *           GlobalFree32   (KERNEL32.322)
1047  */
1048 HGLOBAL32 GlobalFree32(HGLOBAL32 hmem)
1049 {
1050    PGLOBAL32_INTERN pintern;
1051    HGLOBAL32        hreturned=NULL;
1052    
1053    if(ISPOINTER(hmem)) /* POINTER */
1054    {
1055       if(!HeapFree(GetProcessHeap(), 0, (LPVOID) hmem))
1056          hmem=NULL;
1057    }
1058    else  /* HANDLE */
1059    {
1060       /* HeapLock(GetProcessHeap()); */      
1061       pintern=HANDLE_TO_INTERN(hmem);
1062       
1063       if(pintern->Magic==MAGIC_GLOBAL_USED)
1064       {  
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;
1073       }      
1074       /* HeapUnlock(GetProcessHeap()); */
1075    }
1076    return hreturned;
1077 }
1078
1079
1080 /***********************************************************************
1081  *           GlobalSize32   (KERNEL32.329)
1082  */
1083 DWORD  GlobalSize32(HGLOBAL32 hmem)
1084 {
1085    DWORD                retval;
1086    PGLOBAL32_INTERN     pintern;
1087
1088    if(ISPOINTER(hmem)) 
1089    {
1090       retval=HeapSize(GetProcessHeap(), 0,  (LPVOID) hmem);
1091    }
1092    else
1093    {
1094       /* HeapLock(GetProcessHeap()); */
1095       pintern=HANDLE_TO_INTERN(hmem);
1096       
1097       if(pintern->Magic==MAGIC_GLOBAL_USED)
1098       {
1099          retval=HeapSize(GetProcessHeap(), 0, 
1100                          (char *)(pintern->Pointer)-sizeof(HGLOBAL32))-4;
1101       }
1102       else
1103       {
1104          dprintf_global(stddeb, "GlobalSize32: invalid handle\n");
1105          retval=0;
1106       }
1107       /* HeapUnlock(GetProcessHeap()); */
1108    }
1109    return retval;
1110 }
1111
1112
1113 /***********************************************************************
1114  *           GlobalWire32   (KERNEL32.333)
1115  */
1116 LPVOID  GlobalWire32(HGLOBAL32 hmem)
1117 {
1118    return GlobalLock32( hmem );
1119 }
1120
1121
1122 /***********************************************************************
1123  *           GlobalUnWire32   (KERNEL32.330)
1124  */
1125 BOOL32  GlobalUnWire32(HGLOBAL32 hmem)
1126 {
1127    return GlobalUnlock32( hmem);
1128 }
1129
1130
1131 /***********************************************************************
1132  *           GlobalFix32   (KERNEL32.320)
1133  */
1134 VOID  GlobalFix32(HGLOBAL32 hmem)
1135 {
1136     GlobalLock32( hmem );
1137 }
1138
1139
1140 /***********************************************************************
1141  *           GlobalUnfix32   (KERNEL32.331)
1142  */
1143 VOID  GlobalUnfix32(HGLOBAL32 hmem)
1144 {
1145    GlobalUnlock32( hmem);
1146 }
1147
1148
1149 /***********************************************************************
1150  *           GlobalFlags32   (KERNEL32.321)
1151  */
1152 UINT32  GlobalFlags32(HGLOBAL32 hmem)
1153 {
1154    DWORD                retval;
1155    PGLOBAL32_INTERN     pintern;
1156    
1157    if(ISPOINTER(hmem))
1158    {
1159       retval=0;
1160    }
1161    else
1162    {
1163       /* HeapLock(GetProcessHeap()); */
1164       pintern=HANDLE_TO_INTERN(hmem);
1165       if(pintern->Magic==MAGIC_GLOBAL_USED)
1166       {               
1167          retval=pintern->LockCount + (pintern->Flags<<8);
1168          if(pintern->Pointer==0)
1169             retval|= GMEM_DISCARDED;
1170       }
1171       else
1172       {
1173          dprintf_global(stddeb,"GlobalFlags32: invalid handle\n");
1174          retval=0;
1175       }
1176       /* HeapUnlock(GetProcessHeap()); */
1177    }
1178    return retval;
1179 }
1180
1181
1182 /***********************************************************************
1183  *           GlobalCompact32   (KERNEL32.316)
1184  */
1185 DWORD GlobalCompact32( DWORD minfree )
1186 {
1187     return 0;  /* GlobalCompact does nothing in Win32 */
1188 }
1189
1190
1191 /***********************************************************************
1192  *           GlobalMemoryStatus   (KERNEL32.327)
1193  */
1194 VOID GlobalMemoryStatus( LPMEMORYSTATUS lpmem )
1195 {
1196 #ifdef linux
1197     FILE *f = fopen( "/proc/meminfo", "r" );
1198     if (f)
1199     {
1200         char buffer[256];
1201         int total, used, free;
1202
1203         lpmem->dwTotalPhys = lpmem->dwAvailPhys = 0;
1204         lpmem->dwTotalPageFile = lpmem->dwAvailPageFile = 0;
1205         while (fgets( buffer, sizeof(buffer), f ))
1206         {
1207             if (sscanf( buffer, "Mem: %d %d %d", &total, &used, &free ))
1208             {
1209                 lpmem->dwTotalPhys += total;
1210                 lpmem->dwAvailPhys += free;
1211             }
1212             else if (sscanf( buffer, "Swap: %d %d %d", &total, &used, &free ))
1213             {
1214                 lpmem->dwTotalPageFile += total;
1215                 lpmem->dwAvailPageFile += free;
1216             }
1217         }
1218         fclose( f );
1219
1220         if (lpmem->dwTotalPhys)
1221         {
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;
1227         }
1228     }
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;
1238 }