Release 970914
[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 "module.h"
21 #include "options.h"
22 #include "stddebug.h"
23 #include "debug.h"
24 #include "winerror.h"
25
26   /* Global arena block */
27 typedef struct
28 {
29     DWORD     base;          /* Base address (0 if discarded) */
30     DWORD     size;          /* Size in bytes (0 indicates a free block) */
31     HGLOBAL16 handle;        /* Handle for this block */
32     HGLOBAL16 hOwner;        /* Owner of this block */
33     BYTE      lockCount;     /* Count of GlobalFix() calls */
34     BYTE      pageLockCount; /* Count of GlobalPageLock() calls */
35     BYTE      flags;         /* Allocation flags */
36     BYTE      selCount;      /* Number of selectors allocated for this block */
37 #ifdef CONFIG_IPC
38     int       shmid;
39 #endif
40 } GLOBALARENA;
41
42   /* Flags definitions */
43 #define GA_MOVEABLE     0x02  /* same as GMEM_MOVEABLE */
44 #define GA_DGROUP       0x04
45 #define GA_DISCARDABLE  0x08
46 #define GA_IPCSHARE     0x10  /* same as GMEM_DDESHARE */
47
48   /* Arena array */
49 static GLOBALARENA *pGlobalArena = NULL;
50 static int globalArenaSize = 0;
51
52 #define GLOBAL_MAX_ALLOC_SIZE 0x00ff0000  /* Largest allocation is 16M - 64K */
53
54 #define GET_ARENA_PTR(handle)  (pGlobalArena + ((handle) >> __AHSHIFT))
55
56 /***********************************************************************
57  *           GLOBAL_GetArena
58  *
59  * Return the arena for a given selector, growing the arena array if needed.
60  */
61 static GLOBALARENA *GLOBAL_GetArena( WORD sel, WORD selcount )
62 {
63     if (((sel >> __AHSHIFT) + selcount) > globalArenaSize)
64     {
65         int newsize = ((sel >> __AHSHIFT) + selcount + 0xff) & ~0xff;
66         GLOBALARENA *pNewArena = realloc( pGlobalArena,
67                                           newsize * sizeof(GLOBALARENA) );
68         if (!pNewArena) return 0;
69         pGlobalArena = pNewArena;
70         memset( pGlobalArena + globalArenaSize, 0,
71                 (newsize - globalArenaSize) * sizeof(GLOBALARENA) );
72         globalArenaSize = newsize;
73     }
74     return pGlobalArena + (sel >> __AHSHIFT);
75 }
76
77
78 void debug_handles()
79 {
80     int printed=0;
81     int i;
82     for (i = globalArenaSize-1 ; i>=0 ; i--) {
83         if (pGlobalArena[i].size!=0 && (pGlobalArena[i].handle & 0x8000)){
84             printed=1;
85             printf("0x%08x, ",pGlobalArena[i].handle);
86         }
87     }
88     if (printed)
89         printf("\n");
90 }
91
92
93 /***********************************************************************
94  *           GLOBAL_CreateBlock
95  *
96  * Create a global heap block for a fixed range of linear memory.
97  */
98 HGLOBAL16 GLOBAL_CreateBlock( WORD flags, const void *ptr, DWORD size,
99                               HGLOBAL16 hOwner, BOOL16 isCode,
100                               BOOL16 is32Bit, BOOL16 isReadOnly,
101                               SHMDATA *shmdata  )
102 {
103     WORD sel, selcount;
104     GLOBALARENA *pArena;
105
106       /* Allocate the selector(s) */
107
108     sel = SELECTOR_AllocBlock( ptr, size,
109                               isCode ? SEGMENT_CODE : SEGMENT_DATA,
110                               is32Bit, isReadOnly );
111     
112     if (!sel) return 0;
113     selcount = (size + 0xffff) / 0x10000;
114
115     if (!(pArena = GLOBAL_GetArena( sel, selcount )))
116     {
117         SELECTOR_FreeBlock( sel, selcount );
118         return 0;
119     }
120
121       /* Fill the arena block */
122
123     pArena->base = (DWORD)ptr;
124     pArena->size = GET_SEL_LIMIT(sel) + 1;
125
126 #ifdef CONFIG_IPC
127     if ((flags & GMEM_DDESHARE) && Options.ipc)
128     {
129         pArena->handle = shmdata->handle;
130         pArena->shmid  = shmdata->shmid;
131         shmdata->sel   = sel;
132     }
133     else
134     {
135         pArena->handle = (flags & GMEM_MOVEABLE) ? sel - 1 : sel;
136         pArena->shmid  = 0;
137     }
138 #else
139     pArena->handle = (flags & GMEM_MOVEABLE) ? sel - 1 : sel;
140 #endif
141     pArena->hOwner = hOwner;
142     pArena->lockCount = 0;
143     pArena->pageLockCount = 0;
144     pArena->flags = flags & GA_MOVEABLE;
145     if (flags & GMEM_DISCARDABLE) pArena->flags |= GA_DISCARDABLE;
146     if (flags & GMEM_DDESHARE) pArena->flags |= GA_IPCSHARE;
147     if (!isCode) pArena->flags |= GA_DGROUP;
148     pArena->selCount = selcount;
149     if (selcount > 1)  /* clear the next arena blocks */
150         memset( pArena + 1, 0, (selcount - 1) * sizeof(GLOBALARENA) );
151
152     return pArena->handle;
153 }
154
155
156 /***********************************************************************
157  *           GLOBAL_FreeBlock
158  *
159  * Free a block allocated by GLOBAL_CreateBlock, without touching
160  * the associated linear memory range.
161  */
162 BOOL16 GLOBAL_FreeBlock( HGLOBAL16 handle )
163 {
164     WORD sel;
165     GLOBALARENA *pArena;
166
167     if (!handle) return TRUE;
168     sel = GlobalHandleToSel( handle ); 
169     pArena = GET_ARENA_PTR(sel);
170     SELECTOR_FreeBlock( sel, (pArena->size + 0xffff) / 0x10000 );
171     memset( pArena, 0, sizeof(GLOBALARENA) );
172     return TRUE;
173 }
174
175
176 /***********************************************************************
177  *           GLOBAL_Alloc
178  *
179  * Implementation of GlobalAlloc16()
180  */
181 HGLOBAL16 GLOBAL_Alloc( UINT16 flags, DWORD size, HGLOBAL16 hOwner,
182                         BOOL16 isCode, BOOL16 is32Bit, BOOL16 isReadOnly )
183 {
184     void *ptr;
185     HGLOBAL16 handle;
186     SHMDATA shmdata;
187
188     dprintf_global( stddeb, "GlobalAlloc: %ld flags=%04x\n", size, flags );
189
190     /* If size is 0, create a discarded block */
191
192     if (size == 0) return GLOBAL_CreateBlock( flags, NULL, 1, hOwner, isCode,
193                                               is32Bit, isReadOnly, NULL );
194
195     /* Fixup the size */
196
197     if (size >= GLOBAL_MAX_ALLOC_SIZE - 0x1f) return 0;
198     size = (size + 0x1f) & ~0x1f;
199
200       /* Allocate the linear memory */
201
202 #ifdef CONFIG_IPC
203     if ((flags & GMEM_DDESHARE) && Options.ipc)
204         ptr = DDE_malloc(flags, size, &shmdata);
205     else 
206 #endif  /* CONFIG_IPC */
207     {
208         ptr = HeapAlloc( SystemHeap, 0, size );
209     }
210       /* FIXME: free discardable blocks and try again? */
211     if (!ptr) return 0;
212
213       /* Allocate the selector(s) */
214
215     handle = GLOBAL_CreateBlock( flags, ptr, size, hOwner,
216                                 isCode, is32Bit, isReadOnly, &shmdata);
217     if (!handle)
218     {
219         HeapFree( SystemHeap, 0, ptr );
220         return 0;
221     }
222
223     if (flags & GMEM_ZEROINIT) memset( ptr, 0, size );
224     return handle;
225 }
226
227
228 #ifdef CONFIG_IPC
229 /***********************************************************************
230  *           GLOBAL_FindArena
231  *
232  * Find the arena  for a given handle
233  * (when handle is not serial - e.g. DDE)
234  */
235 static GLOBALARENA *GLOBAL_FindArena( HGLOBAL16 handle)
236 {
237     int i;
238     for (i = globalArenaSize-1 ; i>=0 ; i--) {
239         if (pGlobalArena[i].size!=0 && pGlobalArena[i].handle == handle)
240             return ( &pGlobalArena[i] );
241     }
242     return NULL;
243 }
244
245
246 /***********************************************************************
247  *           DDE_GlobalHandleToSel
248  */
249
250 WORD DDE_GlobalHandleToSel( HGLOBAL16 handle )
251 {
252     GLOBALARENA *pArena;
253     SEGPTR segptr;
254     
255     pArena= GLOBAL_FindArena(handle);
256     if (pArena) {
257         int ArenaIdx = pArena - pGlobalArena;
258
259         /* See if synchronized to the shared memory  */
260         return DDE_SyncHandle(handle, ( ArenaIdx << __AHSHIFT) | 7);
261     }
262
263     /* attach the block */
264     DDE_AttachHandle(handle, &segptr);
265
266     return SELECTOROF( segptr );
267 }
268 #endif  /* CONFIG_IPC */
269
270
271 /***********************************************************************
272  *           GlobalAlloc16   (KERNEL.15)
273  */
274 HGLOBAL16 WINAPI GlobalAlloc16( UINT16 flags, DWORD size )
275 {
276     HANDLE16 owner = GetCurrentPDB();
277
278     if (flags & GMEM_DDESHARE)
279         owner = MODULE_HANDLEtoHMODULE16(owner);  /* Make it a module handle */
280     return GLOBAL_Alloc( flags, size, owner, FALSE, FALSE, FALSE );
281 }
282
283
284 /***********************************************************************
285  *           GlobalReAlloc16   (KERNEL.16)
286  */
287 HGLOBAL16 WINAPI GlobalReAlloc16( HGLOBAL16 handle, DWORD size, UINT16 flags )
288 {
289     WORD selcount;
290     DWORD oldsize;
291     void *ptr;
292     GLOBALARENA *pArena, *pNewArena;
293     WORD sel = GlobalHandleToSel( handle );
294
295     dprintf_global( stddeb, "GlobalReAlloc16: %04x %ld flags=%04x\n",
296                     handle, size, flags );
297     if (!handle) return 0;
298     
299 #ifdef CONFIG_IPC
300     if (Options.ipc && (flags & GMEM_DDESHARE || is_dde_handle(handle))) {
301         fprintf(stdnimp,
302                "GlobalReAlloc16: shared memory reallocating unimplemented\n"); 
303         return 0;
304     }
305 #endif  /* CONFIG_IPC */
306
307     pArena = GET_ARENA_PTR( handle );
308
309       /* Discard the block if requested */
310
311     if ((size == 0) && (flags & GMEM_MOVEABLE) && !(flags & GMEM_MODIFY))
312     {
313         if (!(pArena->flags & GA_MOVEABLE) ||
314             !(pArena->flags & GA_DISCARDABLE) ||
315             (pArena->lockCount > 0) || (pArena->pageLockCount > 0)) return 0;
316         HeapFree( SystemHeap, 0, (void *)pArena->base );
317         pArena->base = 0;
318
319         /* Note: we rely on the fact that SELECTOR_ReallocBlock won't 
320          * change the selector if we are shrinking the block.
321          * FIXME: shouldn't we keep selectors until the block is deleted?
322          */
323         SELECTOR_ReallocBlock( sel, 0, 1, SEGMENT_DATA, 0, 0 );
324         return handle;
325     }
326
327       /* Fixup the size */
328
329     if (size > GLOBAL_MAX_ALLOC_SIZE - 0x20) return 0;
330     if (size == 0) size = 0x20;
331     else size = (size + 0x1f) & ~0x1f;
332
333       /* Change the flags */
334
335     if (flags & GMEM_MODIFY)
336     {
337           /* Change the flags, leaving GA_DGROUP alone */
338         pArena->flags = (pArena->flags & GA_DGROUP) | (flags & GA_MOVEABLE);
339         if (flags & GMEM_DISCARDABLE) pArena->flags |= GA_DISCARDABLE;
340         return handle;
341     }
342
343       /* Reallocate the linear memory */
344
345     ptr = (void *)pArena->base;
346     oldsize = pArena->size;
347     dprintf_global(stddeb,"oldsize %08lx\n",oldsize);
348     if (ptr && (size == oldsize)) return handle;  /* Nothing to do */
349
350     ptr = HeapReAlloc( SystemHeap, 0, ptr, size );
351     if (!ptr)
352     {
353         SELECTOR_FreeBlock( sel, (oldsize + 0xffff) / 0x10000 );
354         memset( pArena, 0, sizeof(GLOBALARENA) );
355         return 0;
356     }
357
358       /* Reallocate the selector(s) */
359
360     sel = SELECTOR_ReallocBlock( sel, ptr, size, SEGMENT_DATA, 0, 0 );
361     if (!sel)
362     {
363         HeapFree( SystemHeap, 0, ptr );
364         memset( pArena, 0, sizeof(GLOBALARENA) );
365         return 0;
366     }
367     selcount = (size + 0xffff) / 0x10000;
368
369     if (!(pNewArena = GLOBAL_GetArena( sel, selcount )))
370     {
371         HeapFree( SystemHeap, 0, ptr );
372         SELECTOR_FreeBlock( sel, selcount );
373         return 0;
374     }
375
376       /* Fill the new arena block */
377
378     if (pNewArena != pArena) memcpy( pNewArena, pArena, sizeof(GLOBALARENA) );
379     pNewArena->base = (DWORD)ptr;
380     pNewArena->size = GET_SEL_LIMIT(sel) + 1;
381     pNewArena->selCount = selcount;
382     pNewArena->handle = (pNewArena->flags & GA_MOVEABLE) ? sel - 1 : sel;
383
384     if (selcount > 1)  /* clear the next arena blocks */
385         memset( pNewArena + 1, 0, (selcount - 1) * sizeof(GLOBALARENA) );
386
387     if ((oldsize < size) && (flags & GMEM_ZEROINIT))
388         memset( (char *)ptr + oldsize, 0, size - oldsize );
389     return pNewArena->handle;
390 }
391
392
393 /***********************************************************************
394  *           GlobalFree16   (KERNEL.17)
395  */
396 HGLOBAL16 WINAPI GlobalFree16( HGLOBAL16 handle )
397 {
398     void *ptr = GlobalLock16( handle );
399
400     dprintf_global( stddeb, "GlobalFree16: %04x\n", handle );
401     if (!GLOBAL_FreeBlock( handle )) return handle;  /* failed */
402 #ifdef CONFIG_IPC
403     if (is_dde_handle(handle)) return DDE_GlobalFree(handle);
404 #endif  /* CONFIG_IPC */
405     if (ptr) HeapFree( SystemHeap, 0, ptr );
406     return 0;
407 }
408
409
410 /***********************************************************************
411  *           WIN16_GlobalLock16   (KERNEL.18)
412  *
413  * This is the GlobalLock16() function used by 16-bit code.
414  */
415 SEGPTR WINAPI WIN16_GlobalLock16( HGLOBAL16 handle )
416 {
417     dprintf_global( stddeb, "WIN16_GlobalLock16(%04x) -> %08lx\n",
418                     handle, MAKELONG( 0, GlobalHandleToSel(handle)) );
419     if (handle)
420     {
421         if (handle == (HGLOBAL16)-1) handle = CURRENT_DS;
422
423 #ifdef CONFIG_IPC
424         if (is_dde_handle(handle))
425             return PTR_SEG_OFF_TO_SEGPTR( DDE_GlobalHandleToSel(handle), 0 );
426 #endif  /* CONFIG_IPC */
427
428         if (!GET_ARENA_PTR(handle)->base) return (SEGPTR)0;
429         return PTR_SEG_OFF_TO_SEGPTR( GlobalHandleToSel(handle), 0 );
430         /* FIXME: put segment value in CX as well */
431     }
432     return (SEGPTR)0;
433 }
434
435
436 /***********************************************************************
437  *           GlobalLock16   (KERNEL.18)
438  *
439  * This is the GlobalLock16() function used by 32-bit code.
440  */
441 LPVOID WINAPI GlobalLock16( HGLOBAL16 handle )
442 {
443     if (!handle) return 0;
444 #ifdef CONFIG_IPC
445     if (is_dde_handle(handle)) return DDE_AttachHandle(handle, NULL);
446 #endif
447     return (LPVOID)GET_ARENA_PTR(handle)->base;
448 }
449
450
451 /***********************************************************************
452  *           GlobalUnlock16   (KERNEL.19)
453  */
454 BOOL16 WINAPI GlobalUnlock16( HGLOBAL16 handle )
455 {
456     dprintf_global( stddeb, "GlobalUnlock16: %04x\n", handle );
457     return 0;
458 }
459
460
461 /***********************************************************************
462  *           GlobalSize16   (KERNEL.20)
463  */
464 DWORD WINAPI GlobalSize16( HGLOBAL16 handle )
465 {
466     dprintf_global( stddeb, "GlobalSize16: %04x\n", handle );
467     if (!handle) return 0;
468     return GET_ARENA_PTR(handle)->size;
469 }
470
471
472 /***********************************************************************
473  *           GlobalHandle16   (KERNEL.21)
474  */
475 DWORD WINAPI GlobalHandle16( WORD sel )
476 {
477     dprintf_global( stddeb, "GlobalHandle16: %04x\n", sel );
478     return MAKELONG( GET_ARENA_PTR(sel)->handle, GlobalHandleToSel(sel) );
479 }
480
481
482 /***********************************************************************
483  *           GlobalFlags16   (KERNEL.22)
484  */
485 UINT16 WINAPI GlobalFlags16( HGLOBAL16 handle )
486 {
487     GLOBALARENA *pArena;
488
489     dprintf_global( stddeb, "GlobalFlags16: %04x\n", handle );
490     pArena = GET_ARENA_PTR(handle);
491     return pArena->lockCount |
492            ((pArena->flags & GA_DISCARDABLE) ? GMEM_DISCARDABLE : 0) |
493            ((pArena->base == 0) ? GMEM_DISCARDED : 0);
494 }
495
496
497 /***********************************************************************
498  *           LockSegment16   (KERNEL.23)
499  */
500 HGLOBAL16 WINAPI LockSegment16( HGLOBAL16 handle )
501 {
502     dprintf_global( stddeb, "LockSegment: %04x\n", handle );
503     if (handle == (HGLOBAL16)-1) handle = CURRENT_DS;
504     GET_ARENA_PTR(handle)->lockCount++;
505     return handle;
506 }
507
508
509 /***********************************************************************
510  *           UnlockSegment16   (KERNEL.24)
511  */
512 void WINAPI UnlockSegment16( HGLOBAL16 handle )
513 {
514     dprintf_global( stddeb, "UnlockSegment: %04x\n", handle );
515     if (handle == (HGLOBAL16)-1) handle = CURRENT_DS;
516     GET_ARENA_PTR(handle)->lockCount--;
517     /* FIXME: this ought to return the lock count in CX (go figure...) */
518 }
519
520
521 /***********************************************************************
522  *           GlobalCompact16   (KERNEL.25)
523  */
524 DWORD WINAPI GlobalCompact16( DWORD desired )
525 {
526     return GLOBAL_MAX_ALLOC_SIZE;
527 }
528
529
530 /***********************************************************************
531  *           GlobalFreeAll   (KERNEL.26)
532  */
533 void WINAPI GlobalFreeAll( HGLOBAL16 owner )
534 {
535     DWORD i;
536     GLOBALARENA *pArena;
537
538     pArena = pGlobalArena;
539     for (i = 0; i < globalArenaSize; i++, pArena++)
540     {
541         if ((pArena->size != 0) && (pArena->hOwner == owner))
542             GlobalFree16( pArena->handle );
543     }
544 }
545
546
547 /***********************************************************************
548  *           GlobalWire16   (KERNEL.111)
549  */
550 SEGPTR WINAPI GlobalWire16( HGLOBAL16 handle )
551 {
552     return WIN16_GlobalLock16( handle );
553 }
554
555
556 /***********************************************************************
557  *           GlobalUnWire16   (KERNEL.112)
558  */
559 BOOL16 WINAPI GlobalUnWire16( HGLOBAL16 handle )
560 {
561     return GlobalUnlock16( handle );
562 }
563
564
565 /***********************************************************************
566  *           SetSwapAreaSize   (KERNEL.106)
567  */
568 LONG WINAPI SetSwapAreaSize( WORD size )
569 {
570     dprintf_global(stdnimp, "STUB: SetSwapAreaSize(%d)\n", size );
571     return MAKELONG( size, 0xffff );
572 }
573
574
575 /***********************************************************************
576  *           GlobalLRUOldest   (KERNEL.163)
577  */
578 HGLOBAL16 WINAPI GlobalLRUOldest( HGLOBAL16 handle )
579 {
580     dprintf_global( stddeb, "GlobalLRUOldest: %04x\n", handle );
581     if (handle == (HGLOBAL16)-1) handle = CURRENT_DS;
582     return handle;
583 }
584
585
586 /***********************************************************************
587  *           GlobalLRUNewest   (KERNEL.164)
588  */
589 HGLOBAL16 WINAPI GlobalLRUNewest( HGLOBAL16 handle )
590 {
591     dprintf_global( stddeb, "GlobalLRUNewest: %04x\n", handle );
592     if (handle == (HGLOBAL16)-1) handle = CURRENT_DS;
593     return handle;
594 }
595
596
597 /***********************************************************************
598  *           GetFreeSpace16   (KERNEL.169)
599  */
600 DWORD WINAPI GetFreeSpace16( UINT16 wFlags )
601 {
602     MEMORYSTATUS ms;
603     GlobalMemoryStatus( &ms );
604     return ms.dwAvailVirtual;
605 }
606
607 /***********************************************************************
608  *           GlobalDOSAlloc   (KERNEL.184)
609  */
610 DWORD WINAPI GlobalDOSAlloc(DWORD size)
611 {
612    UINT16    uParagraph;
613    LPVOID    lpBlock = DOSMEM_GetBlock( size, &uParagraph );
614    
615    if( lpBlock )
616    {
617        HMODULE16 hModule = GetModuleHandle16("KERNEL");
618        WORD      wSelector;
619    
620        wSelector = GLOBAL_CreateBlock(GMEM_FIXED, lpBlock, size, 
621                                       hModule, 0, 0, 0, NULL );
622        return MAKELONG(wSelector,uParagraph);
623    }
624    return 0;
625 }
626
627 /***********************************************************************
628  *           GlobalDOSFree      (KERNEL.185)
629  */
630 WORD WINAPI GlobalDOSFree(WORD sel)
631 {
632    DWORD   block = GetSelectorBase(sel);
633
634    if( block && block < 0x100000 ) 
635    {
636        LPVOID lpBlock = DOSMEM_MapDosToLinear( block );
637        if( DOSMEM_FreeBlock( lpBlock ) )
638            GLOBAL_FreeBlock( sel );
639        sel = 0;
640    }
641    return sel;
642 }
643
644 /***********************************************************************
645  *           GlobalPageLock   (KERNEL.191)
646  */
647 WORD WINAPI GlobalPageLock( HGLOBAL16 handle )
648 {
649     dprintf_global( stddeb, "GlobalPageLock: %04x\n", handle );
650     return ++(GET_ARENA_PTR(handle)->pageLockCount);
651 }
652
653
654 /***********************************************************************
655  *           GlobalPageUnlock   (KERNEL.192)
656  */
657 WORD WINAPI GlobalPageUnlock( HGLOBAL16 handle )
658 {
659     dprintf_global( stddeb, "GlobalPageUnlock: %04x\n", handle );
660     return --(GET_ARENA_PTR(handle)->pageLockCount);
661 }
662
663
664 /***********************************************************************
665  *           GlobalFix16   (KERNEL.197)
666  */
667 void WINAPI GlobalFix16( HGLOBAL16 handle )
668 {
669     dprintf_global( stddeb, "GlobalFix16: %04x\n", handle );
670     GET_ARENA_PTR(handle)->lockCount++;
671 }
672
673
674 /***********************************************************************
675  *           GlobalUnfix16   (KERNEL.198)
676  */
677 void WINAPI GlobalUnfix16( HGLOBAL16 handle )
678 {
679     dprintf_global( stddeb, "GlobalUnfix16: %04x\n", handle );
680     GET_ARENA_PTR(handle)->lockCount--;
681 }
682
683
684 /***********************************************************************
685  *           FarSetOwner   (KERNEL.403)
686  */
687 void WINAPI FarSetOwner( HGLOBAL16 handle, HANDLE16 hOwner )
688 {
689     GET_ARENA_PTR(handle)->hOwner = hOwner;
690 }
691
692
693 /***********************************************************************
694  *           FarGetOwner   (KERNEL.404)
695  */
696 HANDLE16 WINAPI FarGetOwner( HGLOBAL16 handle )
697 {
698     return GET_ARENA_PTR(handle)->hOwner;
699 }
700
701
702 /***********************************************************************
703  *           GlobalHandleToSel   (TOOLHELP.50)
704  */
705 WORD WINAPI GlobalHandleToSel( HGLOBAL16 handle )
706 {
707     dprintf_toolhelp( stddeb, "GlobalHandleToSel: %04x\n", handle );
708     if (!handle) return 0;
709 #ifdef CONFIG_IPC
710     if (is_dde_handle(handle)) return DDE_GlobalHandleToSel(handle);
711 #endif
712     if (!(handle & 7))
713     {
714         fprintf( stderr, "Program attempted invalid selector conversion\n" );
715         return handle - 1;
716     }
717     return handle | 7;
718 }
719
720
721 /***********************************************************************
722  *           GlobalFirst   (TOOLHELP.51)
723  */
724 BOOL16 WINAPI GlobalFirst( GLOBALENTRY *pGlobal, WORD wFlags )
725 {
726     if (wFlags == GLOBAL_LRU) return FALSE;
727     pGlobal->dwNext = 0;
728     return GlobalNext( pGlobal, wFlags );
729 }
730
731
732 /***********************************************************************
733  *           GlobalNext   (TOOLHELP.52)
734  */
735 BOOL16 WINAPI GlobalNext( GLOBALENTRY *pGlobal, WORD wFlags)
736 {
737     GLOBALARENA *pArena;
738
739     if (pGlobal->dwNext >= globalArenaSize) return FALSE;
740     pArena = pGlobalArena + pGlobal->dwNext;
741     if (wFlags == GLOBAL_FREE)  /* only free blocks */
742     {
743         int i;
744         for (i = pGlobal->dwNext; i < globalArenaSize; i++, pArena++)
745             if (pArena->size == 0) break;  /* block is free */
746         if (i >= globalArenaSize) return FALSE;
747         pGlobal->dwNext = i;
748     }
749
750     pGlobal->dwAddress    = pArena->base;
751     pGlobal->dwBlockSize  = pArena->size;
752     pGlobal->hBlock       = pArena->handle;
753     pGlobal->wcLock       = pArena->lockCount;
754     pGlobal->wcPageLock   = pArena->pageLockCount;
755     pGlobal->wFlags       = (GetCurrentPDB() == pArena->hOwner);
756     pGlobal->wHeapPresent = FALSE;
757     pGlobal->hOwner       = pArena->hOwner;
758     pGlobal->wType        = GT_UNKNOWN;
759     pGlobal->wData        = 0;
760     pGlobal->dwNext++;
761     return TRUE;
762 }
763
764
765 /***********************************************************************
766  *           GlobalInfo   (TOOLHELP.53)
767  */
768 BOOL16 WINAPI GlobalInfo( GLOBALINFO *pInfo )
769 {
770     int i;
771     GLOBALARENA *pArena;
772
773     pInfo->wcItems = globalArenaSize;
774     pInfo->wcItemsFree = 0;
775     pInfo->wcItemsLRU = 0;
776     for (i = 0, pArena = pGlobalArena; i < globalArenaSize; i++, pArena++)
777         if (pArena->size == 0) pInfo->wcItemsFree++;
778     return TRUE;
779 }
780
781
782 /***********************************************************************
783  *           GlobalEntryHandle   (TOOLHELP.54)
784  */
785 BOOL16 WINAPI GlobalEntryHandle( GLOBALENTRY *pGlobal, HGLOBAL16 hItem )
786 {
787     return FALSE;
788 }
789
790
791 /***********************************************************************
792  *           GlobalEntryModule   (TOOLHELP.55)
793  */
794 BOOL16 WINAPI GlobalEntryModule( GLOBALENTRY *pGlobal, HMODULE16 hModule,
795                                  WORD wSeg )
796 {
797     return FALSE;
798 }
799
800
801 /***********************************************************************
802  *           MemManInfo   (TOOLHELP.72)
803  */
804 BOOL16 WINAPI MemManInfo( MEMMANINFO *info )
805 {
806     MEMORYSTATUS status;
807
808     /*
809      * Not unsurprisingly although the documention says you 
810      * _must_ provide the size in the dwSize field, this function
811      * (under Windows) always fills the structure and returns true.
812      */
813     GlobalMemoryStatus( &status );
814 #ifdef __svr4__
815     info->wPageSize            = sysconf(_SC_PAGESIZE);
816 #else
817     info->wPageSize            = getpagesize();
818 #endif
819     info->dwLargestFreeBlock   = status.dwAvailVirtual;
820     info->dwMaxPagesAvailable  = info->dwLargestFreeBlock / info->wPageSize;
821     info->dwMaxPagesLockable   = info->dwMaxPagesAvailable;
822     info->dwTotalLinearSpace   = status.dwTotalVirtual / info->wPageSize;
823     info->dwTotalUnlockedPages = info->dwTotalLinearSpace;
824     info->dwFreePages          = info->dwMaxPagesAvailable;
825     info->dwTotalPages         = info->dwTotalLinearSpace;
826     info->dwFreeLinearSpace    = info->dwMaxPagesAvailable;
827     info->dwSwapFilePages      = status.dwTotalPageFile / info->wPageSize;
828     return TRUE;
829 }
830
831 /*
832  * Win32 Global heap functions (GlobalXXX).
833  * These functions included in Win32 for compatibility with 16 bit Windows
834  * Especially the moveable blocks and handles are oldish. 
835  * But the ability to directly allocate memory with GPTR and LPTR is widely
836  * used.
837  *
838  * The handle stuff looks horrible, but it's implemented almost like Win95
839  * does it. 
840  *
841  */
842
843 #define MAGIC_GLOBAL_USED 0x5342
844 #define GLOBAL_LOCK_MAX   0xFF
845 #define HANDLE_TO_INTERN(h)  (PGLOBAL32_INTERN)(((char *)(h))-2)
846 #define INTERN_TO_HANDLE(i)  ((HGLOBAL32) &((i)->Pointer))
847 #define POINTER_TO_HANDLE(p) (*(((HGLOBAL32 *)(p))-1))
848 #define ISHANDLE(h)          (((DWORD)(h)&2)!=0)
849 #define ISPOINTER(h)         (((DWORD)(h)&2)==0)
850
851 typedef struct __GLOBAL32_INTERN
852 {
853    WORD         Magic;
854    LPVOID       Pointer WINE_PACKED;
855    BYTE         Flags;
856    BYTE         LockCount;
857 } GLOBAL32_INTERN, *PGLOBAL32_INTERN;
858
859
860 /***********************************************************************
861  *           GlobalAlloc32   (KERNEL32.315)
862  */
863 HGLOBAL32 WINAPI GlobalAlloc32(UINT32 flags, DWORD size)
864 {
865    PGLOBAL32_INTERN     pintern;
866    DWORD                hpflags;
867    LPVOID               palloc;
868
869    if(flags&GMEM_ZEROINIT)
870       hpflags=HEAP_ZERO_MEMORY;
871    else
872       hpflags=0;
873    
874    if((flags & GMEM_MOVEABLE)==0) /* POINTER */
875    {
876       palloc=HeapAlloc(GetProcessHeap(), hpflags, size);
877       return (HGLOBAL32) palloc;
878    }
879    else  /* HANDLE */
880    {
881       /* HeapLock(GetProcessHeap()); */
882
883       pintern=HeapAlloc(GetProcessHeap(), 0,  sizeof(GLOBAL32_INTERN));
884       if(size)
885       {
886          palloc=HeapAlloc(GetProcessHeap(), hpflags, size+sizeof(HGLOBAL32));
887          *(HGLOBAL32 *)palloc=INTERN_TO_HANDLE(pintern);
888          pintern->Pointer=palloc+sizeof(HGLOBAL32);
889       }
890       else
891          pintern->Pointer=NULL;
892       pintern->Magic=MAGIC_GLOBAL_USED;
893       pintern->Flags=flags>>8;
894       pintern->LockCount=0;
895       
896       /* HeapUnlock(GetProcessHeap()); */
897        
898       return INTERN_TO_HANDLE(pintern);
899    }
900 }
901
902
903 /***********************************************************************
904  *           GlobalLock32   (KERNEL32.326)
905  */
906 LPVOID WINAPI GlobalLock32(HGLOBAL32 hmem)
907 {
908    PGLOBAL32_INTERN pintern;
909    LPVOID           palloc;
910
911    if(ISPOINTER(hmem))
912       return (LPVOID) hmem;
913
914    /* HeapLock(GetProcessHeap()); */
915    
916    pintern=HANDLE_TO_INTERN(hmem);
917    if(pintern->Magic==MAGIC_GLOBAL_USED)
918    {
919       if(pintern->LockCount<GLOBAL_LOCK_MAX)
920          pintern->LockCount++;
921       palloc=pintern->Pointer;
922    }
923    else
924    {
925       dprintf_global(stddeb, "GlobalLock32: invalid handle\n");
926       palloc=(LPVOID) NULL;
927    }
928    /* HeapUnlock(GetProcessHeap()); */;
929    return palloc;
930 }
931
932
933 /***********************************************************************
934  *           GlobalUnlock32   (KERNEL32.332)
935  */
936 BOOL32 WINAPI GlobalUnlock32(HGLOBAL32 hmem)
937 {
938    PGLOBAL32_INTERN       pintern;
939    BOOL32                 locked;
940
941    if(ISPOINTER(hmem))
942       return FALSE;
943
944    /* HeapLock(GetProcessHeap()); */
945    pintern=HANDLE_TO_INTERN(hmem);
946    
947    if(pintern->Magic==MAGIC_GLOBAL_USED)
948    {
949       if((pintern->LockCount<GLOBAL_LOCK_MAX)&&(pintern->LockCount>0))
950          pintern->LockCount--;
951
952       locked=(pintern->LockCount==0) ? FALSE : TRUE;
953    }
954    else
955    {
956       dprintf_global(stddeb, "GlobalUnlock32: invalid handle\n");
957       locked=FALSE;
958    }
959    /* HeapUnlock(GetProcessHeap()); */
960    return locked;
961 }
962
963
964 /***********************************************************************
965  *           GlobalHandle32   (KERNEL32.325)
966  */
967 HGLOBAL32 WINAPI GlobalHandle32(LPCVOID pmem)
968 {
969    return (HGLOBAL32) POINTER_TO_HANDLE(pmem);
970 }
971
972
973 /***********************************************************************
974  *           GlobalReAlloc32   (KERNEL32.328)
975  */
976 HGLOBAL32 WINAPI GlobalReAlloc32(HGLOBAL32 hmem, DWORD size, UINT32 flags)
977 {
978    LPVOID               palloc;
979    HGLOBAL32            hnew;
980    PGLOBAL32_INTERN     pintern;
981
982    hnew=NULL;
983    /* HeapLock(GetProcessHeap()); */
984    if(flags & GMEM_MODIFY) /* modify flags */
985    {
986       if( ISPOINTER(hmem) && (flags & GMEM_MOVEABLE))
987       {
988          /* make a fixed block moveable
989           * actually only NT is able to do this. But it's soo simple
990           */
991          size=HeapSize(GetProcessHeap(), 0, (LPVOID) hmem);
992          hnew=GlobalAlloc32( flags, size);
993          palloc=GlobalLock32(hnew);
994          memcpy(palloc, (LPVOID) hmem, size);
995          GlobalUnlock32(hnew);
996          GlobalFree32(hmem);
997       }
998       else if( ISPOINTER(hmem) &&(flags & GMEM_DISCARDABLE))
999       {
1000          /* change the flags to make our block "discardable" */
1001          pintern=HANDLE_TO_INTERN(hmem);
1002          pintern->Flags = pintern->Flags | (GMEM_DISCARDABLE >> 8);
1003          hnew=hmem;
1004       }
1005       else
1006       {
1007          SetLastError(ERROR_INVALID_PARAMETER);
1008          hnew=NULL;
1009       }
1010    }
1011    else
1012    {
1013       if(ISPOINTER(hmem))
1014       {
1015          /* reallocate fixed memory */
1016          hnew=(HGLOBAL32)HeapReAlloc(GetProcessHeap(), 0, (LPVOID) hmem, size);
1017       }
1018       else
1019       {
1020          /* reallocate a moveable block */
1021          pintern=HANDLE_TO_INTERN(hmem);
1022          if(pintern->LockCount!=0)
1023             SetLastError(ERROR_INVALID_HANDLE);
1024          else if(size!=0)
1025          {
1026             hnew=hmem;
1027             if(pintern->Pointer)
1028             {
1029                palloc=HeapReAlloc(GetProcessHeap(), 0,
1030                                   pintern->Pointer-sizeof(HGLOBAL32),
1031                                   size+sizeof(HGLOBAL32) );
1032                pintern->Pointer=palloc+sizeof(HGLOBAL32);
1033             }
1034             else
1035             {
1036                palloc=HeapAlloc(GetProcessHeap(), 0, size+sizeof(HGLOBAL32));
1037                *(HGLOBAL32 *)palloc=hmem;
1038                pintern->Pointer=palloc+sizeof(HGLOBAL32);
1039             }
1040          }
1041          else
1042          {
1043             if(pintern->Pointer)
1044             {
1045                HeapFree(GetProcessHeap(), 0, pintern->Pointer-sizeof(HGLOBAL32));
1046                pintern->Pointer=NULL;
1047             }
1048          }
1049       }
1050    }
1051    /* HeapUnlock(GetProcessHeap()); */
1052    return hnew;
1053 }
1054
1055
1056 /***********************************************************************
1057  *           GlobalFree32   (KERNEL32.322)
1058  */
1059 HGLOBAL32 WINAPI GlobalFree32(HGLOBAL32 hmem)
1060 {
1061    PGLOBAL32_INTERN pintern;
1062    HGLOBAL32        hreturned=NULL;
1063    
1064    if(ISPOINTER(hmem)) /* POINTER */
1065    {
1066       if(!HeapFree(GetProcessHeap(), 0, (LPVOID) hmem))
1067          hmem=NULL;
1068    }
1069    else  /* HANDLE */
1070    {
1071       /* HeapLock(GetProcessHeap()); */      
1072       pintern=HANDLE_TO_INTERN(hmem);
1073       
1074       if(pintern->Magic==MAGIC_GLOBAL_USED)
1075       {  
1076          if(pintern->LockCount!=0)
1077             SetLastError(ERROR_INVALID_HANDLE);
1078          if(pintern->Pointer)
1079             if(!HeapFree(GetProcessHeap(), 0, 
1080                          (char *)(pintern->Pointer)-sizeof(HGLOBAL32)))
1081                hreturned=hmem;
1082          if(!HeapFree(GetProcessHeap(), 0, pintern)) 
1083             hreturned=hmem;
1084       }      
1085       /* HeapUnlock(GetProcessHeap()); */
1086    }
1087    return hreturned;
1088 }
1089
1090
1091 /***********************************************************************
1092  *           GlobalSize32   (KERNEL32.329)
1093  */
1094 DWORD WINAPI GlobalSize32(HGLOBAL32 hmem)
1095 {
1096    DWORD                retval;
1097    PGLOBAL32_INTERN     pintern;
1098
1099    if(ISPOINTER(hmem)) 
1100    {
1101       retval=HeapSize(GetProcessHeap(), 0,  (LPVOID) hmem);
1102    }
1103    else
1104    {
1105       /* HeapLock(GetProcessHeap()); */
1106       pintern=HANDLE_TO_INTERN(hmem);
1107       
1108       if(pintern->Magic==MAGIC_GLOBAL_USED)
1109       {
1110          retval=HeapSize(GetProcessHeap(), 0, 
1111                          (char *)(pintern->Pointer)-sizeof(HGLOBAL32))-4;
1112       }
1113       else
1114       {
1115          dprintf_global(stddeb, "GlobalSize32: invalid handle\n");
1116          retval=0;
1117       }
1118       /* HeapUnlock(GetProcessHeap()); */
1119    }
1120    return retval;
1121 }
1122
1123
1124 /***********************************************************************
1125  *           GlobalWire32   (KERNEL32.333)
1126  */
1127 LPVOID WINAPI GlobalWire32(HGLOBAL32 hmem)
1128 {
1129    return GlobalLock32( hmem );
1130 }
1131
1132
1133 /***********************************************************************
1134  *           GlobalUnWire32   (KERNEL32.330)
1135  */
1136 BOOL32 WINAPI GlobalUnWire32(HGLOBAL32 hmem)
1137 {
1138    return GlobalUnlock32( hmem);
1139 }
1140
1141
1142 /***********************************************************************
1143  *           GlobalFix32   (KERNEL32.320)
1144  */
1145 VOID WINAPI GlobalFix32(HGLOBAL32 hmem)
1146 {
1147     GlobalLock32( hmem );
1148 }
1149
1150
1151 /***********************************************************************
1152  *           GlobalUnfix32   (KERNEL32.331)
1153  */
1154 VOID WINAPI GlobalUnfix32(HGLOBAL32 hmem)
1155 {
1156    GlobalUnlock32( hmem);
1157 }
1158
1159
1160 /***********************************************************************
1161  *           GlobalFlags32   (KERNEL32.321)
1162  */
1163 UINT32 WINAPI GlobalFlags32(HGLOBAL32 hmem)
1164 {
1165    DWORD                retval;
1166    PGLOBAL32_INTERN     pintern;
1167    
1168    if(ISPOINTER(hmem))
1169    {
1170       retval=0;
1171    }
1172    else
1173    {
1174       /* HeapLock(GetProcessHeap()); */
1175       pintern=HANDLE_TO_INTERN(hmem);
1176       if(pintern->Magic==MAGIC_GLOBAL_USED)
1177       {               
1178          retval=pintern->LockCount + (pintern->Flags<<8);
1179          if(pintern->Pointer==0)
1180             retval|= GMEM_DISCARDED;
1181       }
1182       else
1183       {
1184          dprintf_global(stddeb,"GlobalFlags32: invalid handle\n");
1185          retval=0;
1186       }
1187       /* HeapUnlock(GetProcessHeap()); */
1188    }
1189    return retval;
1190 }
1191
1192
1193 /***********************************************************************
1194  *           GlobalCompact32   (KERNEL32.316)
1195  */
1196 DWORD WINAPI GlobalCompact32( DWORD minfree )
1197 {
1198     return 0;  /* GlobalCompact does nothing in Win32 */
1199 }
1200
1201
1202 /***********************************************************************
1203  *           GlobalMemoryStatus   (KERNEL32.327)
1204  */
1205 VOID WINAPI GlobalMemoryStatus( LPMEMORYSTATUS lpmem )
1206 {
1207 #ifdef linux
1208     FILE *f = fopen( "/proc/meminfo", "r" );
1209     if (f)
1210     {
1211         char buffer[256];
1212         int total, used, free;
1213
1214         lpmem->dwTotalPhys = lpmem->dwAvailPhys = 0;
1215         lpmem->dwTotalPageFile = lpmem->dwAvailPageFile = 0;
1216         while (fgets( buffer, sizeof(buffer), f ))
1217         {
1218             /* old style /proc/meminfo ... */
1219             if (sscanf( buffer, "Mem: %d %d %d", &total, &used, &free ))
1220             {
1221                 lpmem->dwTotalPhys += total;
1222                 lpmem->dwAvailPhys += free;
1223             }
1224             if (sscanf( buffer, "Swap: %d %d %d", &total, &used, &free ))
1225             {
1226                 lpmem->dwTotalPageFile += total;
1227                 lpmem->dwAvailPageFile += free;
1228             }
1229
1230             /* new style /proc/meminfo ... */
1231             if (sscanf(buffer, "MemTotal: %d", &total))
1232                 lpmem->dwTotalPhys = total*1024;
1233             if (sscanf(buffer, "MemFree: %d", &free))
1234                 lpmem->dwAvailPhys = free*1024;
1235             if (sscanf(buffer, "SwapTotal: %d", &total))
1236                 lpmem->dwTotalPageFile = total*1024;
1237             if (sscanf(buffer, "SwapFree: %d", &free))
1238                 lpmem->dwAvailPageFile = free*1024;
1239         }
1240         fclose( f );
1241
1242         if (lpmem->dwTotalPhys)
1243         {
1244             lpmem->dwTotalVirtual = lpmem->dwTotalPhys+lpmem->dwTotalPageFile;
1245             lpmem->dwAvailVirtual = lpmem->dwAvailPhys+lpmem->dwAvailPageFile;
1246             lpmem->dwMemoryLoad = (lpmem->dwTotalVirtual-lpmem->dwAvailVirtual)
1247                                       * 100 / lpmem->dwTotalVirtual;
1248             return;
1249         }
1250     }
1251 #endif
1252     /* FIXME: should do something for other systems */
1253     lpmem->dwMemoryLoad    = 0;
1254     lpmem->dwTotalPhys     = 16*1024*1024;
1255     lpmem->dwAvailPhys     = 16*1024*1024;
1256     lpmem->dwTotalPageFile = 16*1024*1024;
1257     lpmem->dwAvailPageFile = 16*1024*1024;
1258     lpmem->dwTotalVirtual  = 32*1024*1024;
1259     lpmem->dwAvailVirtual  = 32*1024*1024;
1260 }
1261
1262 /**********************************************************************
1263  *           WOWGlobalAllocLock (KERNEL32.62)
1264  *
1265  * Combined GlobalAlloc and GlobalLock.
1266  */
1267 SEGPTR WINAPI WOWGlobalAllocLock16(DWORD flags,DWORD cb,HGLOBAL16 *hmem)
1268 {
1269     HGLOBAL16 xhmem;
1270     xhmem = GlobalAlloc16(flags,cb);
1271     if (hmem) *hmem = xhmem;
1272     return WIN16_GlobalLock16(xhmem);
1273 }