Release 961215
[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 "dde_mem.h"
18 #include "stackframe.h"
19 #include "options.h"
20 #include "stddebug.h"
21 #include "debug.h"
22
23   /* Global arena block */
24 typedef struct
25 {
26     DWORD     base;          /* Base address (0 if discarded) */
27     DWORD     size;          /* Size in bytes (0 indicates a free block) */
28     HGLOBAL16 handle;        /* Handle for this block */
29     HGLOBAL16 hOwner;        /* Owner of this block */
30     BYTE      lockCount;     /* Count of GlobalFix() calls */
31     BYTE      pageLockCount; /* Count of GlobalPageLock() calls */
32     BYTE      flags;         /* Allocation flags */
33     BYTE      selCount;      /* Number of selectors allocated for this block */
34 #ifdef CONFIG_IPC
35     int       shmid;
36 #endif
37 } GLOBALARENA;
38
39   /* Flags definitions */
40 #define GA_MOVEABLE     0x02  /* same as GMEM_MOVEABLE */
41 #define GA_DGROUP       0x04
42 #define GA_DISCARDABLE  0x08
43 #define GA_IPCSHARE     0x10  /* same as GMEM_DDESHARE */
44
45   /* Arena array */
46 static GLOBALARENA *pGlobalArena = NULL;
47 static int globalArenaSize = 0;
48
49 #define GLOBAL_MAX_ALLOC_SIZE 0x00ff0000  /* Largest allocation is 16M - 64K */
50
51 #define GET_ARENA_PTR(handle)  (pGlobalArena + ((handle) >> __AHSHIFT))
52
53 /***********************************************************************
54  *           GLOBAL_GetArena
55  *
56  * Return the arena for a given selector, growing the arena array if needed.
57  */
58 static GLOBALARENA *GLOBAL_GetArena( WORD sel, WORD selcount )
59 {
60     if (((sel >> __AHSHIFT) + selcount) > globalArenaSize)
61     {
62         int newsize = ((sel >> __AHSHIFT) + selcount + 0xff) & ~0xff;
63         GLOBALARENA *pNewArena = realloc( pGlobalArena,
64                                           newsize * sizeof(GLOBALARENA) );
65         if (!pNewArena) return 0;
66         pGlobalArena = pNewArena;
67         memset( pGlobalArena + globalArenaSize, 0,
68                 (newsize - globalArenaSize) * sizeof(GLOBALARENA) );
69         globalArenaSize = newsize;
70     }
71     return pGlobalArena + (sel >> __AHSHIFT);
72 }
73
74
75 void debug_handles()
76 {
77     int printed=0;
78     int i;
79     for (i = globalArenaSize-1 ; i>=0 ; i--) {
80         if (pGlobalArena[i].size!=0 && (pGlobalArena[i].handle & 0x8000)){
81             printed=1;
82             printf("0x%08x, ",pGlobalArena[i].handle);
83         }
84     }
85     if (printed)
86         printf("\n");
87 }
88
89
90 /***********************************************************************
91  *           GLOBAL_CreateBlock
92  *
93  * Create a global heap block for a fixed range of linear memory.
94  */
95 HGLOBAL16 GLOBAL_CreateBlock( WORD flags, const void *ptr, DWORD size,
96                               HGLOBAL16 hOwner, BOOL16 isCode,
97                               BOOL16 is32Bit, BOOL16 isReadOnly,
98                               SHMDATA *shmdata  )
99 {
100     WORD sel, selcount;
101     GLOBALARENA *pArena;
102
103       /* Allocate the selector(s) */
104
105     sel = SELECTOR_AllocBlock( ptr, size,
106                               isCode ? SEGMENT_CODE : SEGMENT_DATA,
107                               is32Bit, isReadOnly );
108     
109     if (!sel) return 0;
110     selcount = (size + 0xffff) / 0x10000;
111
112     if (!(pArena = GLOBAL_GetArena( sel, selcount )))
113     {
114         SELECTOR_FreeBlock( sel, selcount );
115         return 0;
116     }
117
118       /* Fill the arena block */
119
120     pArena->base = (DWORD)ptr;
121     pArena->size = GET_SEL_LIMIT(sel) + 1;
122
123 #ifdef CONFIG_IPC
124     if ((flags & GMEM_DDESHARE) && Options.ipc)
125     {
126         pArena->handle = shmdata->handle;
127         pArena->shmid  = shmdata->shmid;
128         shmdata->sel   = sel;
129     }
130     else
131     {
132         pArena->handle = (flags & GMEM_MOVEABLE) ? sel - 1 : sel;
133         pArena->shmid  = 0;
134     }
135 #else
136     pArena->handle = (flags & GMEM_MOVEABLE) ? sel - 1 : sel;
137 #endif
138     pArena->hOwner = hOwner;
139     pArena->lockCount = 0;
140     pArena->pageLockCount = 0;
141     pArena->flags = flags & GA_MOVEABLE;
142     if (flags & GMEM_DISCARDABLE) pArena->flags |= GA_DISCARDABLE;
143     if (flags & GMEM_DDESHARE) pArena->flags |= GA_IPCSHARE;
144     if (!isCode) pArena->flags |= GA_DGROUP;
145     pArena->selCount = selcount;
146     if (selcount > 1)  /* clear the next arena blocks */
147         memset( pArena + 1, 0, (selcount - 1) * sizeof(GLOBALARENA) );
148
149     return pArena->handle;
150 }
151
152
153 /***********************************************************************
154  *           GLOBAL_FreeBlock
155  *
156  * Free a block allocated by GLOBAL_CreateBlock, without touching
157  * the associated linear memory range.
158  */
159 BOOL16 GLOBAL_FreeBlock( HGLOBAL16 handle )
160 {
161     WORD sel;
162     GLOBALARENA *pArena;
163
164     if (!handle) return TRUE;
165     sel = GlobalHandleToSel( handle ); 
166     pArena = GET_ARENA_PTR(sel);
167     SELECTOR_FreeBlock( sel, (pArena->size + 0xffff) / 0x10000 );
168     memset( pArena, 0, sizeof(GLOBALARENA) );
169     return TRUE;
170 }
171
172
173 /***********************************************************************
174  *           GLOBAL_Alloc
175  *
176  * Implementation of GlobalAlloc16()
177  */
178 HGLOBAL16 GLOBAL_Alloc( UINT16 flags, DWORD size, HGLOBAL16 hOwner,
179                         BOOL16 isCode, BOOL16 is32Bit, BOOL16 isReadOnly )
180 {
181     void *ptr;
182     HGLOBAL16 handle;
183     SHMDATA shmdata;
184
185     dprintf_global( stddeb, "GlobalAlloc: %ld flags=%04x\n", size, flags );
186
187     /* If size is 0, create a discarded block */
188
189     if (size == 0) return GLOBAL_CreateBlock( flags, NULL, 1, hOwner, isCode,
190                                               is32Bit, isReadOnly, NULL );
191
192     /* Fixup the size */
193
194     if (size >= GLOBAL_MAX_ALLOC_SIZE - 0x1f) return 0;
195     size = (size + 0x1f) & ~0x1f;
196
197       /* Allocate the linear memory */
198
199 #ifdef CONFIG_IPC
200     if ((flags & GMEM_DDESHARE) && Options.ipc)
201         ptr = DDE_malloc(flags, size, &shmdata);
202     else 
203 #endif  /* CONFIG_IPC */
204     {
205         ptr = HeapAlloc( SystemHeap, 0, size );
206     }
207     if (!ptr) return 0;
208
209       /* Allocate the selector(s) */
210
211     handle = GLOBAL_CreateBlock( flags, ptr, size, hOwner,
212                                 isCode, is32Bit, isReadOnly, &shmdata);
213     if (!handle)
214     {
215         HeapFree( SystemHeap, 0, ptr );
216         return 0;
217     }
218
219     if (flags & GMEM_ZEROINIT) memset( ptr, 0, size );
220     return handle;
221 }
222
223
224 #ifdef CONFIG_IPC
225 /***********************************************************************
226  *           GLOBAL_FindArena
227  *
228  * Find the arena  for a given handle
229  * (when handle is not serial - e.g. DDE)
230  */
231 static GLOBALARENA *GLOBAL_FindArena( HGLOBAL16 handle)
232 {
233     int i;
234     for (i = globalArenaSize-1 ; i>=0 ; i--) {
235         if (pGlobalArena[i].size!=0 && pGlobalArena[i].handle == handle)
236             return ( &pGlobalArena[i] );
237     }
238     return NULL;
239 }
240
241
242 /***********************************************************************
243  *           DDE_GlobalHandleToSel
244  */
245
246 WORD DDE_GlobalHandleToSel( HGLOBAL16 handle )
247 {
248     GLOBALARENA *pArena;
249     SEGPTR segptr;
250     
251     pArena= GLOBAL_FindArena(handle);
252     if (pArena) {
253         int ArenaIdx = pArena - pGlobalArena;
254
255         /* See if synchronized to the shared memory  */
256         return DDE_SyncHandle(handle, ( ArenaIdx << __AHSHIFT) | 7);
257     }
258
259     /* attach the block */
260     DDE_AttachHandle(handle, &segptr);
261
262     return SELECTOROF( segptr );
263 }
264 #endif  /* CONFIG_IPC */
265
266
267 /***********************************************************************
268  *           GlobalAlloc16   (KERNEL.15)
269  */
270 HGLOBAL16 GlobalAlloc16( UINT16 flags, DWORD size )
271 {
272     HANDLE16 owner = GetCurrentPDB();
273
274     if (flags & GMEM_DDESHARE)
275         owner = GetExePtr(owner);  /* Make it a module handle */
276     return GLOBAL_Alloc( flags, size, owner, FALSE, FALSE, FALSE );
277 }
278
279
280 /***********************************************************************
281  *           GlobalReAlloc16   (KERNEL.16)
282  */
283 HGLOBAL16 GlobalReAlloc16( HGLOBAL16 handle, DWORD size, UINT16 flags )
284 {
285     WORD selcount;
286     DWORD oldsize;
287     void *ptr;
288     GLOBALARENA *pArena, *pNewArena;
289     WORD sel = GlobalHandleToSel( handle );
290
291     dprintf_global( stddeb, "GlobalReAlloc16: %04x %ld flags=%04x\n",
292                     handle, size, flags );
293     if (!handle) return 0;
294     
295 #ifdef CONFIG_IPC
296     if (Options.ipc && (flags & GMEM_DDESHARE || is_dde_handle(handle))) {
297         fprintf(stdnimp,
298                "GlobalReAlloc16: shared memory reallocating unimplemented\n"); 
299         return 0;
300     }
301 #endif  /* CONFIG_IPC */
302
303     pArena = GET_ARENA_PTR( handle );
304
305       /* Discard the block if requested */
306
307     if ((size == 0) && (flags & GMEM_MOVEABLE) && !(flags & GMEM_MODIFY))
308     {
309         if (!(pArena->flags & GA_MOVEABLE) ||
310             !(pArena->flags & GA_DISCARDABLE) ||
311             (pArena->lockCount > 0) || (pArena->pageLockCount > 0)) return 0;
312         HeapFree( SystemHeap, 0, (void *)pArena->base );
313         pArena->base = 0;
314         /* Note: we rely on the fact that SELECTOR_ReallocBlock won't */
315         /* change the selector if we are shrinking the block */
316         SELECTOR_ReallocBlock( sel, 0, 1, SEGMENT_DATA, 0, 0 );
317         return handle;
318     }
319
320       /* Fixup the size */
321
322     if (size > GLOBAL_MAX_ALLOC_SIZE - 0x20) return 0;
323     if (size == 0) size = 0x20;
324     else size = (size + 0x1f) & ~0x1f;
325
326       /* Change the flags */
327
328     if (flags & GMEM_MODIFY)
329     {
330           /* Change the flags, leaving GA_DGROUP alone */
331         pArena->flags = (pArena->flags & GA_DGROUP) | (flags & GA_MOVEABLE);
332         if (flags & GMEM_DISCARDABLE) pArena->flags |= GA_DISCARDABLE;
333         return handle;
334     }
335
336       /* Reallocate the linear memory */
337
338     ptr = (void *)pArena->base;
339     oldsize = pArena->size;
340     dprintf_global(stddeb,"oldsize %08lx\n",oldsize);
341     if (ptr && (size == oldsize)) return handle;  /* Nothing to do */
342
343     ptr = HeapReAlloc( SystemHeap, 0, ptr, size );
344     if (!ptr)
345     {
346         SELECTOR_FreeBlock( sel, (oldsize + 0xffff) / 0x10000 );
347         memset( pArena, 0, sizeof(GLOBALARENA) );
348         return 0;
349     }
350
351       /* Reallocate the selector(s) */
352
353     sel = SELECTOR_ReallocBlock( sel, ptr, size, SEGMENT_DATA, 0, 0 );
354     if (!sel)
355     {
356         HeapFree( SystemHeap, 0, ptr );
357         memset( pArena, 0, sizeof(GLOBALARENA) );
358         return 0;
359     }
360     selcount = (size + 0xffff) / 0x10000;
361
362     if (!(pNewArena = GLOBAL_GetArena( sel, selcount )))
363     {
364         HeapFree( SystemHeap, 0, ptr );
365         SELECTOR_FreeBlock( sel, selcount );
366         return 0;
367     }
368
369       /* Fill the new arena block */
370
371     if (pNewArena != pArena) memcpy( pNewArena, pArena, sizeof(GLOBALARENA) );
372     pNewArena->base = (DWORD)ptr;
373     pNewArena->size = GET_SEL_LIMIT(sel) + 1;
374     pNewArena->selCount = selcount;
375     pNewArena->handle = (pNewArena->flags & GA_MOVEABLE) ? sel - 1 : sel;
376
377     if (selcount > 1)  /* clear the next arena blocks */
378         memset( pNewArena + 1, 0, (selcount - 1) * sizeof(GLOBALARENA) );
379
380     if ((oldsize < size) && (flags & GMEM_ZEROINIT))
381         memset( (char *)ptr + oldsize, 0, size - oldsize );
382     return pNewArena->handle;
383 }
384
385
386 /***********************************************************************
387  *           GlobalFree16   (KERNEL.17)
388  */
389 HGLOBAL16 GlobalFree16( HGLOBAL16 handle )
390 {
391     void *ptr = GlobalLock16( handle );
392
393     dprintf_global( stddeb, "GlobalFree16: %04x\n", handle );
394     if (!GLOBAL_FreeBlock( handle )) return handle;  /* failed */
395 #ifdef CONFIG_IPC
396     if (is_dde_handle(handle)) return DDE_GlobalFree(handle);
397 #endif  /* CONFIG_IPC */
398     if (ptr) HeapFree( SystemHeap, 0, ptr );
399     return 0;
400 }
401
402
403 /***********************************************************************
404  *           WIN16_GlobalLock16   (KERNEL.18)
405  *
406  * This is the GlobalLock16() function used by 16-bit code.
407  */
408 SEGPTR WIN16_GlobalLock16( HGLOBAL16 handle )
409 {
410     dprintf_global( stddeb, "WIN16_GlobalLock16(%04x) -> %08lx\n",
411                     handle, MAKELONG( 0, GlobalHandleToSel(handle)) );
412     if (!handle) return 0;
413
414 #ifdef CONFIG_IPC
415     if (is_dde_handle(handle))
416         return PTR_SEG_OFF_TO_SEGPTR( DDE_GlobalHandleToSel(handle), 0 );
417 #endif  /* CONFIG_IPC */
418
419     if (!GET_ARENA_PTR(handle)->base) return (SEGPTR)0;
420     return PTR_SEG_OFF_TO_SEGPTR( GlobalHandleToSel(handle), 0 );
421 }
422
423
424 /***********************************************************************
425  *           GlobalLock16   (KERNEL.18)
426  *
427  * This is the GlobalLock16() function used by 32-bit code.
428  */
429 LPVOID GlobalLock16( HGLOBAL16 handle )
430 {
431     if (!handle) return 0;
432 #ifdef CONFIG_IPC
433     if (is_dde_handle(handle)) return DDE_AttachHandle(handle, NULL);
434 #endif
435     return (LPVOID)GET_ARENA_PTR(handle)->base;
436 }
437
438
439 /***********************************************************************
440  *           GlobalUnlock16   (KERNEL.19)
441  */
442 BOOL16 GlobalUnlock16( HGLOBAL16 handle )
443 {
444     dprintf_global( stddeb, "GlobalUnlock16: %04x\n", handle );
445     return 0;
446 }
447
448
449 /***********************************************************************
450  *           GlobalSize16   (KERNEL.20)
451  */
452 DWORD GlobalSize16( HGLOBAL16 handle )
453 {
454     dprintf_global( stddeb, "GlobalSize16: %04x\n", handle );
455     if (!handle) return 0;
456     return GET_ARENA_PTR(handle)->size;
457 }
458
459
460 /***********************************************************************
461  *           GlobalHandle16   (KERNEL.21)
462  */
463 DWORD GlobalHandle16( WORD sel )
464 {
465     dprintf_global( stddeb, "GlobalHandle16: %04x\n", sel );
466     return MAKELONG( GET_ARENA_PTR(sel)->handle, GlobalHandleToSel(sel) );
467 }
468
469
470 /***********************************************************************
471  *           GlobalFlags16   (KERNEL.22)
472  */
473 UINT16 GlobalFlags16( HGLOBAL16 handle )
474 {
475     GLOBALARENA *pArena;
476
477     dprintf_global( stddeb, "GlobalFlags16: %04x\n", handle );
478     pArena = GET_ARENA_PTR(handle);
479     return pArena->lockCount |
480            ((pArena->flags & GA_DISCARDABLE) ? GMEM_DISCARDABLE : 0) |
481            ((pArena->base == 0) ? GMEM_DISCARDED : 0);
482 }
483
484
485 /***********************************************************************
486  *           LockSegment16   (KERNEL.23)
487  */
488 HGLOBAL16 LockSegment16( HGLOBAL16 handle )
489 {
490     dprintf_global( stddeb, "LockSegment: %04x\n", handle );
491     if (handle == (HGLOBAL16)-1) handle = CURRENT_DS;
492     GET_ARENA_PTR(handle)->lockCount++;
493     return handle;
494 }
495
496
497 /***********************************************************************
498  *           UnlockSegment16   (KERNEL.24)
499  */
500 void UnlockSegment16( HGLOBAL16 handle )
501 {
502     dprintf_global( stddeb, "UnlockSegment: %04x\n", handle );
503     if (handle == (HGLOBAL16)-1) handle = CURRENT_DS;
504     GET_ARENA_PTR(handle)->lockCount--;
505     /* FIXME: this ought to return the lock count in CX (go figure...) */
506 }
507
508
509 /***********************************************************************
510  *           GlobalCompact16   (KERNEL.25)
511  */
512 DWORD GlobalCompact16( DWORD desired )
513 {
514     return GLOBAL_MAX_ALLOC_SIZE;
515 }
516
517
518 /***********************************************************************
519  *           GlobalFreeAll   (KERNEL.26)
520  */
521 void GlobalFreeAll( HGLOBAL16 owner )
522 {
523     DWORD i;
524     GLOBALARENA *pArena;
525
526     pArena = pGlobalArena;
527     for (i = 0; i < globalArenaSize; i++, pArena++)
528     {
529         if ((pArena->size != 0) && (pArena->hOwner == owner))
530             GlobalFree16( pArena->handle );
531     }
532 }
533
534
535 /***********************************************************************
536  *           GlobalWire   (KERNEL.111)
537  */
538 SEGPTR GlobalWire( HGLOBAL16 handle )
539 {
540     return WIN16_GlobalLock16( handle );
541 }
542
543
544 /***********************************************************************
545  *           GlobalUnWire   (KERNEL.112)
546  */
547 BOOL16 GlobalUnWire( HGLOBAL16 handle )
548 {
549     return GlobalUnlock16( handle );
550 }
551
552
553 /***********************************************************************
554  *           SetSwapAreaSize   (KERNEL.106)
555  */
556 LONG SetSwapAreaSize( WORD size )
557 {
558     dprintf_global(stdnimp, "STUB: SetSwapAreaSize(%d)\n", size );
559     return MAKELONG( size, 0xffff );
560 }
561
562
563 /***********************************************************************
564  *           GlobalLRUOldest   (KERNEL.163)
565  */
566 HGLOBAL16 GlobalLRUOldest( HGLOBAL16 handle )
567 {
568     dprintf_global( stddeb, "GlobalLRUOldest: %04x\n", handle );
569     if (handle == (HGLOBAL16)-1) handle = CURRENT_DS;
570     return handle;
571 }
572
573
574 /***********************************************************************
575  *           GlobalLRUNewest   (KERNEL.164)
576  */
577 HGLOBAL16 GlobalLRUNewest( HGLOBAL16 handle )
578 {
579     dprintf_global( stddeb, "GlobalLRUNewest: %04x\n", handle );
580     if (handle == (HGLOBAL16)-1) handle = CURRENT_DS;
581     return handle;
582 }
583
584
585 /***********************************************************************
586  *           GetFreeSpace   (KERNEL.169)
587  */
588 DWORD GetFreeSpace( UINT16 wFlags )
589 {
590     MEMORYSTATUS        ms;
591
592     GlobalMemoryStatus( &ms );
593     return ms.dwAvailVirtual;
594 }
595
596
597 /***********************************************************************
598  *           GlobalPageLock   (KERNEL.191)
599  */
600 WORD GlobalPageLock( HGLOBAL16 handle )
601 {
602     dprintf_global( stddeb, "GlobalPageLock: %04x\n", handle );
603     return ++(GET_ARENA_PTR(handle)->pageLockCount);
604 }
605
606
607 /***********************************************************************
608  *           GlobalPageUnlock   (KERNEL.192)
609  */
610 WORD GlobalPageUnlock( HGLOBAL16 handle )
611 {
612     dprintf_global( stddeb, "GlobalPageUnlock: %04x\n", handle );
613     return --(GET_ARENA_PTR(handle)->pageLockCount);
614 }
615
616
617 /***********************************************************************
618  *           GlobalFix   (KERNEL.197)
619  */
620 void GlobalFix( HGLOBAL16 handle )
621 {
622     dprintf_global( stddeb, "GlobalFix: %04x\n", handle );
623     GET_ARENA_PTR(handle)->lockCount++;
624 }
625
626
627 /***********************************************************************
628  *           GlobalUnfix   (KERNEL.198)
629  */
630 void GlobalUnfix( HGLOBAL16 handle )
631 {
632     dprintf_global( stddeb, "GlobalUnfix: %04x\n", handle );
633     GET_ARENA_PTR(handle)->lockCount--;
634 }
635
636
637 /***********************************************************************
638  *           FarSetOwner   (KERNEL.403)
639  */
640 void FarSetOwner( HGLOBAL16 handle, HANDLE16 hOwner )
641 {
642     GET_ARENA_PTR(handle)->hOwner = hOwner;
643 }
644
645
646 /***********************************************************************
647  *           FarGetOwner   (KERNEL.404)
648  */
649 HANDLE16 FarGetOwner( HGLOBAL16 handle )
650 {
651     return GET_ARENA_PTR(handle)->hOwner;
652 }
653
654
655 /***********************************************************************
656  *           GlobalHandleToSel   (TOOLHELP.50)
657  */
658 WORD GlobalHandleToSel( HGLOBAL16 handle )
659 {
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))
666     {
667         fprintf( stderr, "Program attempted invalid selector conversion\n" );
668         return handle - 1;
669     }
670     return handle | 7;
671 }
672
673
674 /***********************************************************************
675  *           GlobalFirst   (TOOLHELP.51)
676  */
677 BOOL16 GlobalFirst( GLOBALENTRY *pGlobal, WORD wFlags )
678 {
679     if (wFlags == GLOBAL_LRU) return FALSE;
680     pGlobal->dwNext = 0;
681     return GlobalNext( pGlobal, wFlags );
682 }
683
684
685 /***********************************************************************
686  *           GlobalNext   (TOOLHELP.52)
687  */
688 BOOL16 GlobalNext( GLOBALENTRY *pGlobal, WORD wFlags)
689 {
690     GLOBALARENA *pArena;
691
692     if (pGlobal->dwNext >= globalArenaSize) return FALSE;
693     pArena = pGlobalArena + pGlobal->dwNext;
694     if (wFlags == GLOBAL_FREE)  /* only free blocks */
695     {
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;
701     }
702
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;
715 }
716
717
718 /***********************************************************************
719  *           GlobalInfo   (TOOLHELP.53)
720  */
721 BOOL16 GlobalInfo( GLOBALINFO *pInfo )
722 {
723     int i;
724     GLOBALARENA *pArena;
725
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;
732 }
733
734
735 /***********************************************************************
736  *           GlobalEntryHandle   (TOOLHELP.54)
737  */
738 BOOL16 GlobalEntryHandle( GLOBALENTRY *pGlobal, HGLOBAL16 hItem )
739 {
740     return FALSE;
741 }
742
743
744 /***********************************************************************
745  *           GlobalEntryModule   (TOOLHELP.55)
746  */
747 BOOL16 GlobalEntryModule( GLOBALENTRY *pGlobal, HMODULE16 hModule, WORD wSeg )
748 {
749     return FALSE;
750 }
751
752
753 /***********************************************************************
754  *           MemManInfo   (TOOLHELP.72)
755  */
756 BOOL16 MemManInfo( MEMMANINFO *info )
757 {
758     MEMORYSTATUS status;
759
760     if (info->dwSize < sizeof(MEMMANINFO)) return FALSE;
761     GlobalMemoryStatus( &status );
762     info->wPageSize            = getpagesize();
763     info->dwLargestFreeBlock   = status.dwAvailVirtual;
764     info->dwMaxPagesAvailable  = info->dwLargestFreeBlock / info->wPageSize;
765     info->dwMaxPagesLockable   = info->dwMaxPagesAvailable;
766     info->dwTotalLinearSpace   = status.dwTotalVirtual / info->wPageSize;
767     info->dwTotalUnlockedPages = info->dwTotalLinearSpace;
768     info->dwFreePages          = info->dwMaxPagesAvailable;
769     info->dwTotalPages         = info->dwTotalLinearSpace;
770     info->dwFreeLinearSpace    = info->dwMaxPagesAvailable;
771     info->dwSwapFilePages      = status.dwTotalPageFile / info->wPageSize;
772     return TRUE;
773 }
774
775
776 /***********************************************************************
777  *           GlobalAlloc32   (KERNEL32.315)
778  */
779 HGLOBAL32 GlobalAlloc32( UINT32 flags, DWORD size )
780 {
781     DWORD heapFlags = 0;
782
783     if (flags & GMEM_MOVEABLE)
784         fprintf( stderr, "GlobalAlloc32: unimplemented flag GMEM_MOVEABLE\n" );
785
786     if (flags & GMEM_ZEROINIT) heapFlags |= HEAP_ZERO_MEMORY;
787     return (HGLOBAL32)HeapAlloc( GetProcessHeap(), heapFlags, size );
788 }
789
790
791 /***********************************************************************
792  *           GlobalCompact32   (KERNEL32.316)
793  */
794 DWORD GlobalCompact32( DWORD minfree )
795 {
796     return 0;  /* GlobalCompact does nothing in Win32 */
797 }
798
799
800 /***********************************************************************
801  *           GlobalFlags32   (KERNEL32.321)
802  */
803 UINT32 GlobalFlags32( HGLOBAL32 handle )
804 {
805     return 0;
806 }
807
808
809 /***********************************************************************
810  *           GlobalFree32   (KERNEL32.322)
811  */
812 HGLOBAL32 GlobalFree32( HGLOBAL32 handle )
813 {
814     return HeapFree( GetProcessHeap(), 0, (LPVOID)handle ) ? 0 : handle;
815 }
816
817
818 /***********************************************************************
819  *           GlobalHandle32   (KERNEL32.325)
820  */
821 HGLOBAL32 GlobalHandle32( LPCVOID ptr )
822 {
823     return (HGLOBAL32)ptr;
824 }
825
826
827 /***********************************************************************
828  *           GlobalLock32   (KERNEL32.326)
829  */
830 LPVOID GlobalLock32( HGLOBAL32 handle )
831 {
832     return (LPVOID)handle;
833 }
834
835
836 /***********************************************************************
837  *           GlobalReAlloc32   (KERNEL32.328)
838  */
839 HGLOBAL32 GlobalReAlloc32( HGLOBAL32 handle, DWORD size, UINT32 flags )
840 {
841     if (flags & GMEM_MODIFY)
842     {
843         fprintf( stderr, "GlobalReAlloc32: GMEM_MODIFY not supported\n" );
844         return 0;
845     }
846
847     return (HGLOBAL32)HeapReAlloc( GetProcessHeap(), 0, (LPVOID)handle, size );
848 }
849
850
851 /***********************************************************************
852  *           GlobalSize32   (KERNEL32.329)
853  */
854 DWORD GlobalSize32( HGLOBAL32 handle )
855 {
856     return HeapSize( GetProcessHeap(), 0, (LPVOID)handle );
857 }
858
859
860 /***********************************************************************
861  *           GlobalUnlock32   (KERNEL32.332)
862  */
863 BOOL32 GlobalUnlock32( HGLOBAL32 handle )
864 {
865     return TRUE;
866 }
867
868
869 /***********************************************************************
870  *           GlobalMemoryStatus   (KERNEL32.327)
871  */
872 VOID GlobalMemoryStatus( LPMEMORYSTATUS lpmem )
873 {
874 #ifdef linux
875     FILE *f = fopen( "/proc/meminfo", "r" );
876     if (f)
877     {
878         char buffer[256];
879         int total, used, free;
880
881         lpmem->dwTotalPhys = lpmem->dwAvailPhys = 0;
882         lpmem->dwTotalPageFile = lpmem->dwAvailPageFile = 0;
883         while (fgets( buffer, sizeof(buffer), f ))
884         {
885             if (sscanf( buffer, "Mem: %d %d %d", &total, &used, &free ))
886             {
887                 lpmem->dwTotalPhys += total;
888                 lpmem->dwAvailPhys += free;
889             }
890             else if (sscanf( buffer, "Swap: %d %d %d", &total, &used, &free ))
891             {
892                 lpmem->dwTotalPageFile += total;
893                 lpmem->dwAvailPageFile += free;
894             }
895         }
896         fclose( f );
897
898         if (lpmem->dwTotalPhys)
899         {
900             lpmem->dwTotalVirtual = lpmem->dwTotalPhys+lpmem->dwTotalPageFile;
901             lpmem->dwAvailVirtual = lpmem->dwAvailPhys+lpmem->dwAvailPageFile;
902             lpmem->dwMemoryLoad = (lpmem->dwTotalVirtual-lpmem->dwAvailVirtual)
903                                       * 100 / lpmem->dwTotalVirtual;
904             return;
905         }
906     }
907 #endif
908     /* FIXME: should do something for other systems */
909     lpmem->dwMemoryLoad    = 0;
910     lpmem->dwTotalPhys     = 16*1024*1024;
911     lpmem->dwAvailPhys     = 16*1024*1024;
912     lpmem->dwTotalPageFile = 16*1024*1024;
913     lpmem->dwAvailPageFile = 16*1024*1024;
914     lpmem->dwTotalVirtual  = 32*1024*1024;
915     lpmem->dwAvailVirtual  = 32*1024*1024;
916 }