- msvcrt: the file descriptors are now inherited between parent/child
[wine] / dlls / kernel / global16.c
1 /*
2  * Global heap functions
3  *
4  * Copyright 1995 Alexandre Julliard
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Lesser General Public
8  * License as published by the Free Software Foundation; either
9  * version 2.1 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Lesser General Public License for more details.
15  *
16  * You should have received a copy of the GNU Lesser General Public
17  * License along with this library; if not, write to the Free Software
18  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19  */
20 /* 0xffff sometimes seems to mean: CURRENT_DS */
21
22 #include "config.h"
23 #include "wine/port.h"
24
25 #include <sys/types.h>
26 #include <stdlib.h>
27 #include <time.h>
28 #include <stdio.h>
29 #ifdef HAVE_UNISTD_H
30 # include <unistd.h>
31 #endif
32 #include <string.h>
33 #ifdef HAVE_SYS_PARAM_H
34 #include <sys/param.h>
35 #endif
36 #ifdef HAVE_SYS_SYSCTL_H
37 #include <sys/sysctl.h>
38 #endif
39
40 #include "wine/winbase16.h"
41 #include "ntstatus.h"
42 #include "toolhelp.h"
43 #include "miscemu.h"
44 #include "stackframe.h"
45 #include "kernel_private.h"
46 #include "wine/debug.h"
47 #include "winerror.h"
48
49 WINE_DEFAULT_DEBUG_CHANNEL(global);
50
51   /* Global arena block */
52 typedef struct
53 {
54     DWORD     base;          /* Base address (0 if discarded) */
55     DWORD     size;          /* Size in bytes (0 indicates a free block) */
56     HGLOBAL16 handle;        /* Handle for this block */
57     HGLOBAL16 hOwner;        /* Owner of this block */
58     BYTE      lockCount;     /* Count of GlobalFix() calls */
59     BYTE      pageLockCount; /* Count of GlobalPageLock() calls */
60     BYTE      flags;         /* Allocation flags */
61     BYTE      selCount;      /* Number of selectors allocated for this block */
62 } GLOBALARENA;
63
64   /* Flags definitions */
65 #define GA_MOVEABLE     0x02  /* same as GMEM_MOVEABLE */
66 #define GA_DGROUP       0x04
67 #define GA_DISCARDABLE  0x08
68 #define GA_IPCSHARE     0x10  /* same as GMEM_DDESHARE */
69 #define GA_DOSMEM       0x20
70
71 /* Arena array (FIXME) */
72 static GLOBALARENA *pGlobalArena;
73 static int globalArenaSize;
74
75 #define GLOBAL_MAX_ALLOC_SIZE 0x00ff0000  /* Largest allocation is 16M - 64K */
76
77 #define VALID_HANDLE(handle) (((handle)>>__AHSHIFT)<globalArenaSize)
78 #define GET_ARENA_PTR(handle)  (pGlobalArena + ((handle) >> __AHSHIFT))
79
80
81 /***********************************************************************
82  *           GLOBAL_GetArena
83  *
84  * Return the arena for a given selector, growing the arena array if needed.
85  */
86 static GLOBALARENA *GLOBAL_GetArena( WORD sel, WORD selcount )
87 {
88     if (((sel >> __AHSHIFT) + selcount) > globalArenaSize)
89     {
90         int newsize = ((sel >> __AHSHIFT) + selcount + 0xff) & ~0xff;
91         GLOBALARENA *pNewArena = realloc( pGlobalArena,
92                                           newsize * sizeof(GLOBALARENA) );
93         if (!pNewArena) return 0;
94         pGlobalArena = pNewArena;
95         memset( pGlobalArena + globalArenaSize, 0,
96                 (newsize - globalArenaSize) * sizeof(GLOBALARENA) );
97         globalArenaSize = newsize;
98     }
99     return pGlobalArena + (sel >> __AHSHIFT);
100 }
101
102 void debug_handles(void)
103 {
104     int printed=0;
105     int i;
106     for (i = globalArenaSize-1 ; i>=0 ; i--) {
107         if (pGlobalArena[i].size!=0 && (pGlobalArena[i].handle & 0x8000)){
108             printed=1;
109             DPRINTF("0x%08x, ",pGlobalArena[i].handle);
110         }
111     }
112     if (printed)
113         DPRINTF("\n");
114 }
115
116
117 /***********************************************************************
118  *           GLOBAL_CreateBlock
119  *
120  * Create a global heap block for a fixed range of linear memory.
121  */
122 HGLOBAL16 GLOBAL_CreateBlock( WORD flags, const void *ptr, DWORD size,
123                               HGLOBAL16 hOwner, unsigned char selflags )
124 {
125     WORD sel, selcount;
126     GLOBALARENA *pArena;
127
128       /* Allocate the selector(s) */
129
130     sel = SELECTOR_AllocBlock( ptr, size, selflags );
131     if (!sel) return 0;
132     selcount = (size + 0xffff) / 0x10000;
133
134     if (!(pArena = GLOBAL_GetArena( sel, selcount )))
135     {
136         SELECTOR_FreeBlock( sel );
137         return 0;
138     }
139
140       /* Fill the arena block */
141
142     pArena->base = (DWORD)ptr;
143     pArena->size = GetSelectorLimit16(sel) + 1;
144     pArena->handle = (flags & GMEM_MOVEABLE) ? sel - 1 : sel;
145     pArena->hOwner = hOwner;
146     pArena->lockCount = 0;
147     pArena->pageLockCount = 0;
148     pArena->flags = flags & GA_MOVEABLE;
149     if (flags & GMEM_DISCARDABLE) pArena->flags |= GA_DISCARDABLE;
150     if (flags & GMEM_DDESHARE) pArena->flags |= GA_IPCSHARE;
151     if (!(selflags & (WINE_LDT_FLAGS_CODE^WINE_LDT_FLAGS_DATA))) pArena->flags |= GA_DGROUP;
152     pArena->selCount = selcount;
153     if (selcount > 1)  /* clear the next arena blocks */
154         memset( pArena + 1, 0, (selcount - 1) * sizeof(GLOBALARENA) );
155
156     return pArena->handle;
157 }
158
159
160 /***********************************************************************
161  *           GLOBAL_FreeBlock
162  *
163  * Free a block allocated by GLOBAL_CreateBlock, without touching
164  * the associated linear memory range.
165  */
166 BOOL16 GLOBAL_FreeBlock( HGLOBAL16 handle )
167 {
168     WORD sel;
169     GLOBALARENA *pArena;
170
171     if (!handle) return TRUE;
172     sel = GlobalHandleToSel16( handle );
173     if (!VALID_HANDLE(sel)) return FALSE;
174     pArena = GET_ARENA_PTR(sel);
175     SELECTOR_FreeBlock( sel );
176     memset( pArena, 0, sizeof(GLOBALARENA) );
177     return TRUE;
178 }
179
180 /***********************************************************************
181  *           GLOBAL_MoveBlock
182  */
183 BOOL16 GLOBAL_MoveBlock( HGLOBAL16 handle, const void *ptr, DWORD size )
184 {
185     WORD sel;
186     GLOBALARENA *pArena;
187
188     if (!handle) return TRUE;
189     sel = GlobalHandleToSel16( handle );
190     if (!VALID_HANDLE(sel)) return FALSE;
191     pArena = GET_ARENA_PTR(sel);
192     if (pArena->selCount != 1)
193         return FALSE;
194
195     pArena->base = (DWORD)ptr;
196     pArena->size = size;
197     SELECTOR_ReallocBlock( sel, ptr, size );
198     return TRUE;
199 }
200
201 /***********************************************************************
202  *           GLOBAL_Alloc
203  *
204  * Implementation of GlobalAlloc16()
205  */
206 HGLOBAL16 GLOBAL_Alloc( UINT16 flags, DWORD size, HGLOBAL16 hOwner, unsigned char selflags )
207 {
208     void *ptr;
209     HGLOBAL16 handle;
210
211     TRACE("%ld flags=%04x\n", size, flags );
212
213     /* If size is 0, create a discarded block */
214
215     if (size == 0) return GLOBAL_CreateBlock( flags, NULL, 1, hOwner, selflags );
216
217     /* Fixup the size */
218
219     if (size >= GLOBAL_MAX_ALLOC_SIZE - 0x1f) return 0;
220     size = (size + 0x1f) & ~0x1f;
221
222     /* Allocate the linear memory */
223     ptr = HeapAlloc( GetProcessHeap(), 0, size );
224       /* FIXME: free discardable blocks and try again? */
225     if (!ptr) return 0;
226
227       /* Allocate the selector(s) */
228
229     handle = GLOBAL_CreateBlock( flags, ptr, size, hOwner, selflags );
230     if (!handle)
231     {
232         HeapFree( GetProcessHeap(), 0, ptr );
233         return 0;
234     }
235
236     if (flags & GMEM_ZEROINIT) memset( ptr, 0, size );
237     return handle;
238 }
239
240 /***********************************************************************
241  *           GlobalAlloc     (KERNEL.15)
242  *           GlobalAlloc16   (KERNEL32.24)
243  * RETURNS
244  *      Handle: Success
245  *      NULL: Failure
246  */
247 HGLOBAL16 WINAPI GlobalAlloc16(
248                  UINT16 flags, /* [in] Object allocation attributes */
249                  DWORD size    /* [in] Number of bytes to allocate */
250 ) {
251     HANDLE16 owner = GetCurrentPDB16();
252
253     if (flags & GMEM_DDESHARE)
254         owner = GetExePtr(owner);  /* Make it a module handle */
255     return GLOBAL_Alloc( flags, size, owner, WINE_LDT_FLAGS_DATA );
256 }
257
258
259 /***********************************************************************
260  *           GlobalReAlloc     (KERNEL.16)
261  * RETURNS
262  *      Handle: Success
263  *      NULL: Failure
264  */
265 HGLOBAL16 WINAPI GlobalReAlloc16(
266                  HGLOBAL16 handle, /* [in] Handle of global memory object */
267                  DWORD size,       /* [in] New size of block */
268                  UINT16 flags      /* [in] How to reallocate object */
269 ) {
270     WORD selcount;
271     DWORD oldsize;
272     void *ptr, *newptr;
273     GLOBALARENA *pArena, *pNewArena;
274     WORD sel = GlobalHandleToSel16( handle );
275
276     TRACE("%04x %ld flags=%04x\n",
277                     handle, size, flags );
278     if (!handle) return 0;
279
280     if (!VALID_HANDLE(handle))
281     {
282         WARN("Invalid handle 0x%04x!\n", handle);
283         return 0;
284     }
285     pArena = GET_ARENA_PTR( handle );
286
287       /* Discard the block if requested */
288
289     if ((size == 0) && (flags & GMEM_MOVEABLE) && !(flags & GMEM_MODIFY))
290     {
291         if (!(pArena->flags & GA_MOVEABLE) ||
292             !(pArena->flags & GA_DISCARDABLE) ||
293             (pArena->lockCount > 0) || (pArena->pageLockCount > 0)) return 0;
294         if (pArena->flags & GA_DOSMEM)
295             DOSMEM_FreeBlock( (void *)pArena->base );
296         else
297             HeapFree( GetProcessHeap(), 0, (void *)pArena->base );
298         pArena->base = 0;
299
300         /* Note: we rely on the fact that SELECTOR_ReallocBlock won't
301          * change the selector if we are shrinking the block.
302          * FIXME: shouldn't we keep selectors until the block is deleted?
303          */
304         SELECTOR_ReallocBlock( sel, 0, 1 );
305         return handle;
306     }
307
308       /* Fixup the size */
309
310     if (size > GLOBAL_MAX_ALLOC_SIZE - 0x20) return 0;
311     if (size == 0) size = 0x20;
312     else size = (size + 0x1f) & ~0x1f;
313
314       /* Change the flags */
315
316     if (flags & GMEM_MODIFY)
317     {
318           /* Change the flags, leaving GA_DGROUP alone */
319         pArena->flags = (pArena->flags & GA_DGROUP) | (flags & GA_MOVEABLE);
320         if (flags & GMEM_DISCARDABLE) pArena->flags |= GA_DISCARDABLE;
321         return handle;
322     }
323
324       /* Reallocate the linear memory */
325
326     ptr = (void *)pArena->base;
327     oldsize = pArena->size;
328     TRACE("oldbase %p oldsize %08lx newsize %08lx\n", ptr,oldsize,size);
329     if (ptr && (size == oldsize)) return handle;  /* Nothing to do */
330
331     if (pArena->flags & GA_DOSMEM)
332     {
333         if (DOSMEM_ResizeBlock(ptr, size, TRUE) == size) 
334             newptr = ptr;
335         else if(pArena->pageLockCount > 0)
336             newptr = 0;
337         else
338         {
339             newptr = DOSMEM_GetBlock( size, 0 );
340             if (newptr)
341             {
342                 memcpy( newptr, ptr, oldsize );
343                 DOSMEM_FreeBlock( ptr );
344             }
345         }
346     }
347     else
348     {
349         /*
350          * if more than one reader (e.g. some pointer has been 
351          * given out by GetVDMPointer32W16),
352          * only try to realloc in place
353          */
354
355         if (ptr)
356             newptr = HeapReAlloc( GetProcessHeap(),
357                 (pArena->pageLockCount > 0) ? HEAP_REALLOC_IN_PLACE_ONLY : 0, 
358                               ptr, size );
359         else
360             newptr = HeapAlloc( GetProcessHeap(),
361                 (pArena->pageLockCount > 0) ? HEAP_REALLOC_IN_PLACE_ONLY : 0, 
362                               size );
363
364     }
365
366     if (!newptr)
367     {
368         FIXME("Realloc failed lock %d\n",pArena->pageLockCount);
369         if (pArena->pageLockCount <1)
370         {
371             if (pArena->flags & GA_DOSMEM)
372                 DOSMEM_FreeBlock( (void *)pArena->base );
373             else
374                 HeapFree( GetProcessHeap(), 0, ptr );
375             SELECTOR_FreeBlock( sel );
376             memset( pArena, 0, sizeof(GLOBALARENA) );
377         }
378         return 0;
379     }
380     ptr = newptr;
381
382       /* Reallocate the selector(s) */
383
384     sel = SELECTOR_ReallocBlock( sel, ptr, size );
385     if (!sel)
386     {
387         if (pArena->flags & GA_DOSMEM)
388             DOSMEM_FreeBlock( (void *)pArena->base );
389         else
390             HeapFree( GetProcessHeap(), 0, ptr );
391         memset( pArena, 0, sizeof(GLOBALARENA) );
392         return 0;
393     }
394     selcount = (size + 0xffff) / 0x10000;
395
396     if (!(pNewArena = GLOBAL_GetArena( sel, selcount )))
397     {        
398         if (pArena->flags & GA_DOSMEM)
399             DOSMEM_FreeBlock( (void *)pArena->base );
400         else
401             HeapFree( GetProcessHeap(), 0, ptr );
402         SELECTOR_FreeBlock( sel );
403         return 0;
404     }
405
406       /* Fill the new arena block
407          As we may have used HEAP_REALLOC_IN_PLACE_ONLY, areas may overlap*/
408
409     if (pNewArena != pArena) memmove( pNewArena, pArena, sizeof(GLOBALARENA) );
410     pNewArena->base = (DWORD)ptr;
411     pNewArena->size = GetSelectorLimit16(sel) + 1;
412     pNewArena->selCount = selcount;
413     pNewArena->handle = (pNewArena->flags & GA_MOVEABLE) ? sel - 1 : sel;
414
415     if (selcount > 1)  /* clear the next arena blocks */
416         memset( pNewArena + 1, 0, (selcount - 1) * sizeof(GLOBALARENA) );
417
418     if ((oldsize < size) && (flags & GMEM_ZEROINIT))
419         memset( (char *)ptr + oldsize, 0, size - oldsize );
420     return pNewArena->handle;
421 }
422
423
424 /***********************************************************************
425  *           GlobalFree     (KERNEL.17)
426  *           GlobalFree16   (KERNEL32.31)
427  * RETURNS
428  *      NULL: Success
429  *      Handle: Failure
430  */
431 HGLOBAL16 WINAPI GlobalFree16(
432                  HGLOBAL16 handle /* [in] Handle of global memory object */
433 ) {
434     void *ptr;
435
436     if (!VALID_HANDLE(handle))
437     {
438         WARN("Invalid handle 0x%04x passed to GlobalFree16!\n",handle);
439         return 0;
440     }
441     ptr = (void *)GET_ARENA_PTR(handle)->base;
442
443     TRACE("%04x\n", handle );
444     if (!GLOBAL_FreeBlock( handle )) return handle;  /* failed */
445     if (ptr) HeapFree( GetProcessHeap(), 0, ptr );
446     return 0;
447 }
448
449
450 /**********************************************************************
451  *           K32WOWGlobalLock16         (KERNEL32.60)
452  */
453 SEGPTR WINAPI K32WOWGlobalLock16( HGLOBAL16 handle )
454 {
455     WORD sel = GlobalHandleToSel16( handle );
456     TRACE("(%04x) -> %08lx\n", handle, MAKELONG( 0, sel ) );
457
458     if (handle)
459     {
460         if (handle == (HGLOBAL16)-1) handle = CURRENT_DS;
461
462         if (!VALID_HANDLE(handle)) {
463             WARN("Invalid handle 0x%04x passed to WIN16_GlobalLock16!\n",handle);
464             sel = 0;
465         }
466         else if (!GET_ARENA_PTR(handle)->base)
467             sel = 0;
468         else
469             GET_ARENA_PTR(handle)->lockCount++;
470     }
471
472     return MAKESEGPTR( sel, 0 );
473
474 }
475
476
477 /***********************************************************************
478  *           GlobalLock   (KERNEL.18)
479  *
480  * This is the GlobalLock16() function used by 16-bit code.
481  */
482 SEGPTR WINAPI WIN16_GlobalLock16( HGLOBAL16 handle )
483 {
484     SEGPTR ret = K32WOWGlobalLock16( handle );
485     CURRENT_STACK16->ecx = SELECTOROF(ret);  /* selector must be returned in CX as well */
486     return ret;
487 }
488
489
490 /***********************************************************************
491  *           GlobalLock16   (KERNEL32.25)
492  *
493  * This is the GlobalLock16() function used by 32-bit code.
494  *
495  * RETURNS
496  *      Pointer to first byte of memory block
497  *      NULL: Failure
498  */
499 LPVOID WINAPI GlobalLock16(
500               HGLOBAL16 handle /* [in] Handle of global memory object */
501 ) {
502     if (!handle) return 0;
503     if (!VALID_HANDLE(handle))
504         return 0;
505     GET_ARENA_PTR(handle)->lockCount++;
506     return (LPVOID)GET_ARENA_PTR(handle)->base;
507 }
508
509
510 /***********************************************************************
511  *           GlobalUnlock     (KERNEL.19)
512  *           GlobalUnlock16   (KERNEL32.26)
513  * NOTES
514  *      Should the return values be cast to booleans?
515  *
516  * RETURNS
517  *      TRUE: Object is still locked
518  *      FALSE: Object is unlocked
519  */
520 BOOL16 WINAPI GlobalUnlock16(
521               HGLOBAL16 handle /* [in] Handle of global memory object */
522 ) {
523     GLOBALARENA *pArena = GET_ARENA_PTR(handle);
524     if (!VALID_HANDLE(handle)) {
525         WARN("Invalid handle 0x%04x passed to GlobalUnlock16!\n",handle);
526         return 0;
527     }
528     TRACE("%04x\n", handle );
529     if (pArena->lockCount) pArena->lockCount--;
530     return pArena->lockCount;
531 }
532
533 /***********************************************************************
534  *     GlobalChangeLockCount               (KERNEL.365)
535  *
536  * This is declared as a register function as it has to preserve
537  * *all* registers, even AX/DX !
538  *
539  */
540 void WINAPI GlobalChangeLockCount16( HGLOBAL16 handle, INT16 delta,
541                                      CONTEXT86 *context )
542 {
543     if ( delta == 1 )
544         GlobalLock16( handle );
545     else if ( delta == -1 )
546         GlobalUnlock16( handle );
547     else
548         ERR("(%04X, %d): strange delta value\n", handle, delta );
549 }
550
551 /***********************************************************************
552  *           GlobalSize     (KERNEL.20)
553  *           GlobalSize16   (KERNEL32.32)
554  * RETURNS
555  *      Size in bytes of object
556  *      0: Failure
557  */
558 DWORD WINAPI GlobalSize16(
559              HGLOBAL16 handle /* [in] Handle of global memory object */
560 ) {
561     TRACE("%04x\n", handle );
562     if (!handle) return 0;
563     if (!VALID_HANDLE(handle))
564         return 0;
565     return GET_ARENA_PTR(handle)->size;
566 }
567
568
569 /***********************************************************************
570  *           GlobalHandle   (KERNEL.21)
571  * NOTES
572  *      Why is GlobalHandleToSel used here with the sel as input?
573  *
574  * RETURNS
575  *      Handle: Success
576  *      NULL: Failure
577  */
578 DWORD WINAPI GlobalHandle16(
579              WORD sel /* [in] Address of global memory block */
580 ) {
581     TRACE("%04x\n", sel );
582     if (!VALID_HANDLE(sel)) {
583         WARN("Invalid handle 0x%04x passed to GlobalHandle16!\n",sel);
584         return 0;
585     }
586     return MAKELONG( GET_ARENA_PTR(sel)->handle, GlobalHandleToSel16(sel) );
587 }
588
589 /***********************************************************************
590  *           GlobalHandleNoRIP   (KERNEL.159)
591  */
592 DWORD WINAPI GlobalHandleNoRIP16( WORD sel )
593 {
594     int i;
595     for (i = globalArenaSize-1 ; i>=0 ; i--) {
596         if (pGlobalArena[i].size!=0 && pGlobalArena[i].handle == sel)
597                 return MAKELONG( GET_ARENA_PTR(sel)->handle, GlobalHandleToSel16(sel) );
598     }
599     return 0;
600 }
601
602
603 /***********************************************************************
604  *           GlobalFlags     (KERNEL.22)
605  *
606  * NOTES
607  *      Should this return GMEM_INVALID_HANDLE instead of 0 on invalid
608  *      handle?
609  *
610  * RETURNS
611  *      Value specifying flags and lock count
612  *      GMEM_INVALID_HANDLE: Invalid handle
613  */
614 UINT16 WINAPI GlobalFlags16(
615               HGLOBAL16 handle /* [in] Handle of global memory object */
616 ) {
617     GLOBALARENA *pArena;
618
619     TRACE("%04x\n", handle );
620     if (!VALID_HANDLE(handle)) {
621         WARN("Invalid handle 0x%04x passed to GlobalFlags16!\n",handle);
622         return 0;
623     }
624     pArena = GET_ARENA_PTR(handle);
625     return pArena->lockCount |
626            ((pArena->flags & GA_DISCARDABLE) ? GMEM_DISCARDABLE : 0) |
627            ((pArena->base == 0) ? GMEM_DISCARDED : 0);
628 }
629
630
631 /***********************************************************************
632  *           LockSegment   (KERNEL.23)
633  */
634 HGLOBAL16 WINAPI LockSegment16( HGLOBAL16 handle )
635 {
636     TRACE("%04x\n", handle );
637     if (handle == (HGLOBAL16)-1) handle = CURRENT_DS;
638     if (!VALID_HANDLE(handle)) {
639         WARN("Invalid handle 0x%04x passed to LockSegment16!\n",handle);
640         return 0;
641     }
642     GET_ARENA_PTR(handle)->lockCount++;
643     return handle;
644 }
645
646
647 /***********************************************************************
648  *           UnlockSegment   (KERNEL.24)
649  */
650 void WINAPI UnlockSegment16( HGLOBAL16 handle )
651 {
652     TRACE("%04x\n", handle );
653     if (handle == (HGLOBAL16)-1) handle = CURRENT_DS;
654     if (!VALID_HANDLE(handle)) {
655         WARN("Invalid handle 0x%04x passed to UnlockSegment16!\n",handle);
656         return;
657     }
658     GET_ARENA_PTR(handle)->lockCount--;
659     /* FIXME: this ought to return the lock count in CX (go figure...) */
660 }
661
662
663 /***********************************************************************
664  *           GlobalCompact   (KERNEL.25)
665  */
666 DWORD WINAPI GlobalCompact16( DWORD desired )
667 {
668     return GLOBAL_MAX_ALLOC_SIZE;
669 }
670
671
672 /***********************************************************************
673  *           GlobalFreeAll   (KERNEL.26)
674  */
675 void WINAPI GlobalFreeAll16( HGLOBAL16 owner )
676 {
677     int i;
678     GLOBALARENA *pArena;
679
680     pArena = pGlobalArena;
681     for (i = 0; i < globalArenaSize; i++, pArena++)
682     {
683         if ((pArena->size != 0) && (pArena->hOwner == owner))
684             GlobalFree16( pArena->handle );
685     }
686 }
687
688
689 /***********************************************************************
690  *           GlobalWire     (KERNEL.111)
691  *           GlobalWire16   (KERNEL32.29)
692  */
693 SEGPTR WINAPI GlobalWire16( HGLOBAL16 handle )
694 {
695     return WIN16_GlobalLock16( handle );
696 }
697
698
699 /***********************************************************************
700  *           GlobalUnWire     (KERNEL.112)
701  *           GlobalUnWire16   (KERNEL32.30)
702  */
703 BOOL16 WINAPI GlobalUnWire16( HGLOBAL16 handle )
704 {
705     return !GlobalUnlock16( handle );
706 }
707
708
709 /***********************************************************************
710  *           SetSwapAreaSize   (KERNEL.106)
711  */
712 LONG WINAPI SetSwapAreaSize16( WORD size )
713 {
714     FIXME("(%d) - stub!\n", size );
715     return MAKELONG( size, 0xffff );
716 }
717
718
719 /***********************************************************************
720  *           GlobalLRUOldest   (KERNEL.163)
721  */
722 HGLOBAL16 WINAPI GlobalLRUOldest16( HGLOBAL16 handle )
723 {
724     TRACE("%04x\n", handle );
725     if (handle == (HGLOBAL16)-1) handle = CURRENT_DS;
726     return handle;
727 }
728
729
730 /***********************************************************************
731  *           GlobalLRUNewest   (KERNEL.164)
732  */
733 HGLOBAL16 WINAPI GlobalLRUNewest16( HGLOBAL16 handle )
734 {
735     TRACE("%04x\n", handle );
736     if (handle == (HGLOBAL16)-1) handle = CURRENT_DS;
737     return handle;
738 }
739
740
741 /***********************************************************************
742  *           GetFreeSpace   (KERNEL.169)
743  */
744 DWORD WINAPI GetFreeSpace16( UINT16 wFlags )
745 {
746     MEMORYSTATUS ms;
747     GlobalMemoryStatus( &ms );
748     return ms.dwAvailVirtual;
749 }
750
751 /***********************************************************************
752  *           GlobalDOSAlloc   (KERNEL.184)
753  * RETURNS
754  *      Address (HW=Paragraph segment; LW=Selector)
755  */
756 DWORD WINAPI GlobalDOSAlloc16(
757              DWORD size /* [in] Number of bytes to be allocated */
758 ) {
759    UINT16    uParagraph;
760    LPVOID    lpBlock = DOSMEM_GetBlock( size, &uParagraph );
761
762    if( lpBlock )
763    {
764        HMODULE16 hModule = GetModuleHandle16("KERNEL");
765        WORD      wSelector;
766        GLOBALARENA *pArena;
767
768        wSelector = GLOBAL_CreateBlock(GMEM_FIXED, lpBlock, size, hModule, WINE_LDT_FLAGS_DATA );
769        pArena = GET_ARENA_PTR(wSelector);
770        pArena->flags |= GA_DOSMEM;
771        return MAKELONG(wSelector,uParagraph);
772    }
773    return 0;
774 }
775
776
777 /***********************************************************************
778  *           GlobalDOSFree      (KERNEL.185)
779  * RETURNS
780  *      NULL: Success
781  *      sel: Failure
782  */
783 WORD WINAPI GlobalDOSFree16(
784             WORD sel /* [in] Selector */
785 ) {
786    DWORD   block = GetSelectorBase(sel);
787
788    if( block && block < 0x100000 )
789    {
790        LPVOID lpBlock = DOSMEM_MapDosToLinear( block );
791        if( DOSMEM_FreeBlock( lpBlock ) )
792            GLOBAL_FreeBlock( sel );
793        sel = 0;
794    }
795    return sel;
796 }
797
798
799 /***********************************************************************
800  *           GlobalPageLock   (KERNEL.191)
801  *           GlobalSmartPageLock(KERNEL.230)
802  */
803 WORD WINAPI GlobalPageLock16( HGLOBAL16 handle )
804 {
805     TRACE("%04x\n", handle );
806     if (!VALID_HANDLE(handle)) {
807         WARN("Invalid handle 0x%04x passed to GlobalPageLock!\n",handle);
808         return 0;
809     }
810     return ++(GET_ARENA_PTR(handle)->pageLockCount);
811 }
812
813
814 /***********************************************************************
815  *           GlobalPageUnlock   (KERNEL.192)
816  *           GlobalSmartPageUnlock(KERNEL.231)
817  */
818 WORD WINAPI GlobalPageUnlock16( HGLOBAL16 handle )
819 {
820     TRACE("%04x\n", handle );
821     if (!VALID_HANDLE(handle)) {
822         WARN("Invalid handle 0x%04x passed to GlobalPageUnlock!\n",handle);
823         return 0;
824     }
825     return --(GET_ARENA_PTR(handle)->pageLockCount);
826 }
827
828
829 /***********************************************************************
830  *           GlobalFix     (KERNEL.197)
831  *           GlobalFix16   (KERNEL32.27)
832  */
833 WORD WINAPI GlobalFix16( HGLOBAL16 handle )
834 {
835     TRACE("%04x\n", handle );
836     if (!VALID_HANDLE(handle)) {
837         WARN("Invalid handle 0x%04x passed to GlobalFix16!\n",handle);
838         return 0;
839     }
840     GET_ARENA_PTR(handle)->lockCount++;
841
842     return GlobalHandleToSel16(handle);
843 }
844
845
846 /***********************************************************************
847  *           GlobalUnfix     (KERNEL.198)
848  *           GlobalUnfix16   (KERNEL32.28)
849  */
850 void WINAPI GlobalUnfix16( HGLOBAL16 handle )
851 {
852     TRACE("%04x\n", handle );
853     if (!VALID_HANDLE(handle)) {
854         WARN("Invalid handle 0x%04x passed to GlobalUnfix16!\n",handle);
855         return;
856     }
857     GET_ARENA_PTR(handle)->lockCount--;
858 }
859
860
861 /***********************************************************************
862  *           FarSetOwner   (KERNEL.403)
863  */
864 void WINAPI FarSetOwner16( HGLOBAL16 handle, HANDLE16 hOwner )
865 {
866     if (!VALID_HANDLE(handle)) {
867         WARN("Invalid handle 0x%04x passed to FarSetOwner!\n",handle);
868         return;
869     }
870     GET_ARENA_PTR(handle)->hOwner = hOwner;
871 }
872
873
874 /***********************************************************************
875  *           FarGetOwner   (KERNEL.404)
876  */
877 HANDLE16 WINAPI FarGetOwner16( HGLOBAL16 handle )
878 {
879     if (!VALID_HANDLE(handle)) {
880         WARN("Invalid handle 0x%04x passed to FarGetOwner!\n",handle);
881         return 0;
882     }
883     return GET_ARENA_PTR(handle)->hOwner;
884 }
885
886
887 /***********************************************************************
888  *           GlobalHandleToSel   (TOOLHELP.50)
889  */
890 WORD WINAPI GlobalHandleToSel16( HGLOBAL16 handle )
891 {
892     if (!handle) return 0;
893     if (!VALID_HANDLE(handle)) {
894         WARN("Invalid handle 0x%04x passed to GlobalHandleToSel!\n",handle);
895         return 0;
896     }
897     if (!(handle & 7))
898     {
899         WARN("Program attempted invalid selector conversion\n" );
900         return handle - 1;
901     }
902     return handle | 7;
903 }
904
905
906 /***********************************************************************
907  *           GlobalFirst   (TOOLHELP.51)
908  */
909 BOOL16 WINAPI GlobalFirst16( GLOBALENTRY *pGlobal, WORD wFlags )
910 {
911     if (wFlags == GLOBAL_LRU) return FALSE;
912     pGlobal->dwNext = 0;
913     return GlobalNext16( pGlobal, wFlags );
914 }
915
916
917 /***********************************************************************
918  *           GlobalNext   (TOOLHELP.52)
919  */
920 BOOL16 WINAPI GlobalNext16( GLOBALENTRY *pGlobal, WORD wFlags)
921 {
922     GLOBALARENA *pArena;
923
924     if (pGlobal->dwNext >= globalArenaSize) return FALSE;
925     pArena = pGlobalArena + pGlobal->dwNext;
926     if (wFlags == GLOBAL_FREE)  /* only free blocks */
927     {
928         int i;
929         for (i = pGlobal->dwNext; i < globalArenaSize; i++, pArena++)
930             if (pArena->size == 0) break;  /* block is free */
931         if (i >= globalArenaSize) return FALSE;
932         pGlobal->dwNext = i;
933     }
934
935     pGlobal->dwAddress    = pArena->base;
936     pGlobal->dwBlockSize  = pArena->size;
937     pGlobal->hBlock       = pArena->handle;
938     pGlobal->wcLock       = pArena->lockCount;
939     pGlobal->wcPageLock   = pArena->pageLockCount;
940     pGlobal->wFlags       = (GetCurrentPDB16() == pArena->hOwner);
941     pGlobal->wHeapPresent = FALSE;
942     pGlobal->hOwner       = pArena->hOwner;
943     pGlobal->wType        = GT_UNKNOWN;
944     pGlobal->wData        = 0;
945     pGlobal->dwNext++;
946     return TRUE;
947 }
948
949
950 /***********************************************************************
951  *           GlobalInfo   (TOOLHELP.53)
952  */
953 BOOL16 WINAPI GlobalInfo16( GLOBALINFO *pInfo )
954 {
955     int i;
956     GLOBALARENA *pArena;
957
958     pInfo->wcItems = globalArenaSize;
959     pInfo->wcItemsFree = 0;
960     pInfo->wcItemsLRU = 0;
961     for (i = 0, pArena = pGlobalArena; i < globalArenaSize; i++, pArena++)
962         if (pArena->size == 0) pInfo->wcItemsFree++;
963     return TRUE;
964 }
965
966
967 /***********************************************************************
968  *           GlobalEntryHandle   (TOOLHELP.54)
969  */
970 BOOL16 WINAPI GlobalEntryHandle16( GLOBALENTRY *pGlobal, HGLOBAL16 hItem )
971 {
972     GLOBALARENA *pArena = GET_ARENA_PTR(hItem);
973
974     pGlobal->dwAddress    = pArena->base;
975     pGlobal->dwBlockSize  = pArena->size;
976     pGlobal->hBlock       = pArena->handle;
977     pGlobal->wcLock       = pArena->lockCount;
978     pGlobal->wcPageLock   = pArena->pageLockCount;
979     pGlobal->wFlags       = (GetCurrentPDB16() == pArena->hOwner);
980     pGlobal->wHeapPresent = FALSE;
981     pGlobal->hOwner       = pArena->hOwner;
982     pGlobal->wType        = GT_UNKNOWN;
983     pGlobal->wData        = 0;
984     pGlobal->dwNext++;
985     return TRUE;
986 }
987
988
989 /***********************************************************************
990  *           GlobalEntryModule   (TOOLHELP.55)
991  */
992 BOOL16 WINAPI GlobalEntryModule16( GLOBALENTRY *pGlobal, HMODULE16 hModule,
993                                  WORD wSeg )
994 {
995     FIXME("(%p, 0x%04x, 0x%04x), stub.\n", pGlobal, hModule, wSeg);
996     return FALSE;
997 }
998
999
1000 /***********************************************************************
1001  *           MemManInfo   (TOOLHELP.72)
1002  */
1003 BOOL16 WINAPI MemManInfo16( MEMMANINFO *info )
1004 {
1005     MEMORYSTATUS status;
1006
1007     /*
1008      * Not unsurprisingly although the documention says you
1009      * _must_ provide the size in the dwSize field, this function
1010      * (under Windows) always fills the structure and returns true.
1011      */
1012     GlobalMemoryStatus( &status );
1013     info->wPageSize            = getpagesize();
1014     info->dwLargestFreeBlock   = status.dwAvailVirtual;
1015     info->dwMaxPagesAvailable  = info->dwLargestFreeBlock / info->wPageSize;
1016     info->dwMaxPagesLockable   = info->dwMaxPagesAvailable;
1017     info->dwTotalLinearSpace   = status.dwTotalVirtual / info->wPageSize;
1018     info->dwTotalUnlockedPages = info->dwTotalLinearSpace;
1019     info->dwFreePages          = info->dwMaxPagesAvailable;
1020     info->dwTotalPages         = info->dwTotalLinearSpace;
1021     info->dwFreeLinearSpace    = info->dwMaxPagesAvailable;
1022     info->dwSwapFilePages      = status.dwTotalPageFile / info->wPageSize;
1023     return TRUE;
1024 }
1025
1026 /***********************************************************************
1027  *           GetFreeMemInfo   (KERNEL.316)
1028  */
1029 DWORD WINAPI GetFreeMemInfo16(void)
1030 {
1031     MEMMANINFO info;
1032     MemManInfo16( &info );
1033     return MAKELONG( info.dwTotalLinearSpace, info.dwMaxPagesAvailable );
1034 }
1035
1036 /***********************************************************************
1037  *           A20Proc   (KERNEL.165)
1038  *           A20_Proc  (SYSTEM.20)
1039  */
1040 void WINAPI A20Proc16( WORD unused )
1041 {
1042     /* this is also a NOP in Windows */
1043 }
1044
1045 /***********************************************************************
1046  *           LimitEMSPages   (KERNEL.156)
1047  */
1048 DWORD WINAPI LimitEMSPages16( DWORD unused )
1049 {
1050     return 0;
1051 }