4 * Copyright 1995, 1996 Alexandre Julliard
5 * Copyright 1996 Huw Davies
6 * Copyright 1998 Ulrich Weigand
8 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public
10 * License as published by the Free Software Foundation; either
11 * version 2.1 of the License, or (at your option) any later version.
13 * This library is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Lesser General Public License for more details.
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with this library; if not, write to the Free Software
20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
24 #include "wine/port.h"
31 #include <sys/types.h>
33 #ifdef HAVE_SYS_PARAM_H
34 #include <sys/param.h>
36 #ifdef HAVE_SYS_SYSCTL_H
37 #include <sys/sysctl.h>
44 /* FIXME: Unfortunately swapctl can't be used with largefile.... */
45 # undef _FILE_OFFSET_BITS
46 # define _FILE_OFFSET_BITS 32
47 # include <sys/resource.h>
48 # ifdef HAVE_SYS_STAT_H
49 # include <sys/stat.h>
51 # include <sys/swap.h>
61 #include "wine/exception.h"
62 #include "wine/debug.h"
64 WINE_DEFAULT_DEBUG_CHANNEL(heap);
66 /* address where we try to map the system heap */
67 #define SYSTEM_HEAP_BASE ((void*)0x80000000)
68 #define SYSTEM_HEAP_SIZE 0x1000000 /* Default heap size = 16Mb */
70 static HANDLE systemHeap; /* globally shared heap */
74 /* filter for page-fault exceptions */
75 /* It is possible for a bogus global pointer to cause a */
76 /* page zero reference, so I include EXCEPTION_PRIV_INSTRUCTION too. */
77 static WINE_EXCEPTION_FILTER(page_fault)
79 switch (GetExceptionCode()) {
80 case (EXCEPTION_ACCESS_VIOLATION):
81 case (EXCEPTION_PRIV_INSTRUCTION):
82 return EXCEPTION_EXECUTE_HANDLER;
84 return EXCEPTION_CONTINUE_SEARCH;
88 /***********************************************************************
89 * HEAP_CreateSystemHeap
91 * Create the system heap.
93 inline static HANDLE HEAP_CreateSystemHeap(void)
99 /* create the system heap event first */
100 event = CreateEventA( NULL, TRUE, FALSE, "__wine_system_heap_event" );
102 if (!(map = CreateFileMappingA( INVALID_HANDLE_VALUE, NULL, SEC_COMMIT | PAGE_READWRITE,
103 0, SYSTEM_HEAP_SIZE, "__wine_system_heap" ))) return 0;
104 created = (GetLastError() != ERROR_ALREADY_EXISTS);
106 if (!(base = MapViewOfFileEx( map, FILE_MAP_ALL_ACCESS, 0, 0, 0, SYSTEM_HEAP_BASE )))
108 /* pre-defined address not available */
109 ERR( "system heap base address %p not available\n", SYSTEM_HEAP_BASE );
113 if (created) /* newly created heap */
115 systemHeap = RtlCreateHeap( HEAP_SHARED, base, SYSTEM_HEAP_SIZE,
116 SYSTEM_HEAP_SIZE, NULL, NULL );
121 /* wait for the heap to be initialized */
122 WaitForSingleObject( event, INFINITE );
123 systemHeap = (HANDLE)base;
130 /***********************************************************************
131 * HeapCreate (KERNEL32.@)
133 * Create a heap object.
136 * Handle of heap: Success
139 HANDLE WINAPI HeapCreate(
140 DWORD flags, /* [in] Heap allocation flag */
141 SIZE_T initialSize, /* [in] Initial heap size */
142 SIZE_T maxSize /* [in] Maximum heap size */
146 if ( flags & HEAP_SHARED )
148 if (!systemHeap) HEAP_CreateSystemHeap();
149 else WARN( "Shared Heap requested, returning system heap.\n" );
154 ret = RtlCreateHeap( flags, NULL, maxSize, initialSize, NULL, NULL );
155 if (!ret) SetLastError( ERROR_NOT_ENOUGH_MEMORY );
161 /***********************************************************************
162 * HeapDestroy (KERNEL32.@)
164 * Destroy a heap object.
170 BOOL WINAPI HeapDestroy( HANDLE heap /* [in] Handle of heap */ )
172 if (heap == systemHeap)
174 WARN( "attempt to destroy system heap, returning TRUE!\n" );
177 if (!RtlDestroyHeap( heap )) return TRUE;
178 SetLastError( ERROR_INVALID_HANDLE );
183 /***********************************************************************
184 * HeapCompact (KERNEL32.@)
186 SIZE_T WINAPI HeapCompact( HANDLE heap, DWORD flags )
188 return RtlCompactHeap( heap, flags );
192 /***********************************************************************
193 * HeapValidate (KERNEL32.@)
194 * Validates a specified heap.
203 BOOL WINAPI HeapValidate(
204 HANDLE heap, /* [in] Handle to the heap */
205 DWORD flags, /* [in] Bit flags that control access during operation */
206 LPCVOID block /* [in] Optional pointer to memory block to validate */
208 return RtlValidateHeap( heap, flags, block );
212 /***********************************************************************
213 * HeapWalk (KERNEL32.@)
214 * Enumerates the memory blocks in a specified heap.
217 * - handling of PROCESS_HEAP_ENTRY_MOVEABLE and
218 * PROCESS_HEAP_ENTRY_DDESHARE (needs heap.c support)
224 BOOL WINAPI HeapWalk(
225 HANDLE heap, /* [in] Handle to heap to enumerate */
226 LPPROCESS_HEAP_ENTRY entry /* [out] Pointer to structure of enumeration info */
228 NTSTATUS ret = RtlWalkHeap( heap, entry );
229 if (ret) SetLastError( RtlNtStatusToDosError(ret) );
234 /***********************************************************************
235 * HeapLock (KERNEL32.@)
236 * Attempts to acquire the critical section object for a specified heap.
242 BOOL WINAPI HeapLock(
243 HANDLE heap /* [in] Handle of heap to lock for exclusive access */
245 return RtlLockHeap( heap );
249 /***********************************************************************
250 * HeapUnlock (KERNEL32.@)
251 * Releases ownership of the critical section object.
257 BOOL WINAPI HeapUnlock(
258 HANDLE heap /* [in] Handle to the heap to unlock */
260 return RtlUnlockHeap( heap );
264 /***********************************************************************
265 * GetProcessHeap (KERNEL32.@)
267 HANDLE WINAPI GetProcessHeap(void)
269 return NtCurrentTeb()->Peb->ProcessHeap;
273 /***********************************************************************
274 * GetProcessHeaps (KERNEL32.@)
276 DWORD WINAPI GetProcessHeaps( DWORD count, HANDLE *heaps )
278 return RtlGetProcessHeaps( count, heaps );
282 /* These are needed so that we can call the functions from inside kernel itself */
284 LPVOID WINAPI HeapAlloc( HANDLE heap, DWORD flags, SIZE_T size )
286 return RtlAllocateHeap( heap, flags, size );
289 BOOL WINAPI HeapFree( HANDLE heap, DWORD flags, LPVOID ptr )
291 return RtlFreeHeap( heap, flags, ptr );
294 LPVOID WINAPI HeapReAlloc( HANDLE heap, DWORD flags, LPVOID ptr, SIZE_T size )
296 return RtlReAllocateHeap( heap, flags, ptr, size );
299 SIZE_T WINAPI HeapSize( HANDLE heap, DWORD flags, LPVOID ptr )
301 return RtlSizeHeap( heap, flags, ptr );
305 * Win32 Global heap functions (GlobalXXX).
306 * These functions included in Win32 for compatibility with 16 bit Windows
307 * Especially the moveable blocks and handles are oldish.
308 * But the ability to directly allocate memory with GPTR and LPTR is widely
311 * The handle stuff looks horrible, but it's implemented almost like Win95
316 #define MAGIC_GLOBAL_USED 0x5342
317 #define GLOBAL_LOCK_MAX 0xFF
318 #define HANDLE_TO_INTERN(h) ((PGLOBAL32_INTERN)(((char *)(h))-2))
319 #define INTERN_TO_HANDLE(i) ((HGLOBAL) &((i)->Pointer))
320 #define POINTER_TO_HANDLE(p) (*(((HGLOBAL *)(p))-2))
321 #define ISHANDLE(h) (((ULONG_PTR)(h)&2)!=0)
322 #define ISPOINTER(h) (((ULONG_PTR)(h)&2)==0)
323 /* align the storage needed for the HGLOBAL on an 8byte boundary thus
324 * GlobalAlloc/GlobalReAlloc'ing with GMEM_MOVEABLE of memory with
325 * size = 8*k, where k=1,2,3,... alloc's exactly the given size.
326 * The Minolta DiMAGE Image Viewer heavily relies on this, corrupting
327 * the output jpeg's > 1 MB if not */
328 #define HGLOBAL_STORAGE 8 /* sizeof(HGLOBAL)*2 */
330 #include "pshpack1.h"
332 typedef struct __GLOBAL32_INTERN
338 } GLOBAL32_INTERN, *PGLOBAL32_INTERN;
342 /***********************************************************************
343 * GlobalAlloc (KERNEL32.@)
345 * Allocate a global memory object.
351 HGLOBAL WINAPI GlobalAlloc(
352 UINT flags, /* [in] Object allocation attributes */
353 SIZE_T size /* [in] Number of bytes to allocate */
355 PGLOBAL32_INTERN pintern;
359 if(flags&GMEM_ZEROINIT)
360 hpflags=HEAP_ZERO_MEMORY;
364 TRACE("() flags=%04x\n", flags );
366 if((flags & GMEM_MOVEABLE)==0) /* POINTER */
368 palloc=HeapAlloc(GetProcessHeap(), hpflags, size);
369 return (HGLOBAL) palloc;
373 RtlLockHeap(GetProcessHeap());
375 pintern = HeapAlloc(GetProcessHeap(), 0, sizeof(GLOBAL32_INTERN));
378 pintern->Magic = MAGIC_GLOBAL_USED;
379 pintern->Flags = flags >> 8;
380 pintern->LockCount = 0;
384 palloc = HeapAlloc(GetProcessHeap(), hpflags, size+HGLOBAL_STORAGE);
387 HeapFree(GetProcessHeap(), 0, pintern);
392 *(HGLOBAL *)palloc = INTERN_TO_HANDLE(pintern);
393 pintern->Pointer = (char *)palloc + HGLOBAL_STORAGE;
397 pintern->Pointer = NULL;
400 RtlUnlockHeap(GetProcessHeap());
401 return pintern ? INTERN_TO_HANDLE(pintern) : 0;
406 /***********************************************************************
407 * GlobalLock (KERNEL32.@)
409 * Lock a global memory object.
412 * Pointer to first byte of block
415 LPVOID WINAPI GlobalLock(
416 HGLOBAL hmem /* [in] Handle of global memory object */
419 PGLOBAL32_INTERN pintern;
423 return IsBadReadPtr(hmem, 1) ? NULL : hmem;
425 RtlLockHeap(GetProcessHeap());
428 pintern = HANDLE_TO_INTERN(hmem);
429 if (pintern->Magic == MAGIC_GLOBAL_USED)
431 if (pintern->LockCount < GLOBAL_LOCK_MAX)
432 pintern->LockCount++;
433 palloc = pintern->Pointer;
437 WARN("invalid handle %p\n", hmem);
439 SetLastError(ERROR_INVALID_HANDLE);
444 WARN("page fault on %p\n", hmem);
446 SetLastError(ERROR_INVALID_HANDLE);
449 RtlUnlockHeap(GetProcessHeap());
454 /***********************************************************************
455 * GlobalUnlock (KERNEL32.@)
457 * Unlock a global memory object.
460 * TRUE: Object is still locked
461 * FALSE: Object is unlocked
463 BOOL WINAPI GlobalUnlock(
464 HGLOBAL hmem /* [in] Handle of global memory object */
466 PGLOBAL32_INTERN pintern;
469 if (ISPOINTER(hmem)) return FALSE;
471 RtlLockHeap(GetProcessHeap());
474 pintern=HANDLE_TO_INTERN(hmem);
475 if(pintern->Magic==MAGIC_GLOBAL_USED)
477 if((pintern->LockCount<GLOBAL_LOCK_MAX)&&(pintern->LockCount>0))
478 pintern->LockCount--;
480 locked = (pintern->LockCount != 0);
481 if (!locked) SetLastError(NO_ERROR);
485 WARN("invalid handle\n");
486 SetLastError(ERROR_INVALID_HANDLE);
492 ERR("page fault occurred ! Caused by bug ?\n");
493 SetLastError( ERROR_INVALID_PARAMETER );
497 RtlUnlockHeap(GetProcessHeap());
502 /***********************************************************************
503 * GlobalHandle (KERNEL32.@)
505 * Get the handle associated with the pointer to a global memory block.
511 HGLOBAL WINAPI GlobalHandle(
512 LPCVOID pmem /* [in] Pointer to global memory block */
515 PGLOBAL32_INTERN maybe_intern;
520 SetLastError( ERROR_INVALID_PARAMETER );
524 RtlLockHeap(GetProcessHeap());
529 /* note that if pmem is a pointer to a a block allocated by */
530 /* GlobalAlloc with GMEM_MOVEABLE then magic test in HeapValidate */
532 if (ISPOINTER(pmem)) {
533 if (HeapValidate( GetProcessHeap(), 0, pmem )) {
534 handle = (HGLOBAL)pmem; /* valid fixed block */
537 handle = POINTER_TO_HANDLE(pmem);
539 handle = (HGLOBAL)pmem;
541 /* Now test handle either passed in or retrieved from pointer */
542 maybe_intern = HANDLE_TO_INTERN( handle );
543 if (maybe_intern->Magic == MAGIC_GLOBAL_USED) {
544 test = maybe_intern->Pointer;
545 if (HeapValidate( GetProcessHeap(), 0, (const char *)test - HGLOBAL_STORAGE ) && /* obj(-handle) valid arena? */
546 HeapValidate( GetProcessHeap(), 0, maybe_intern )) /* intern valid arena? */
547 break; /* valid moveable block */
550 SetLastError( ERROR_INVALID_HANDLE );
554 SetLastError( ERROR_INVALID_HANDLE );
558 RtlUnlockHeap(GetProcessHeap());
564 /***********************************************************************
565 * GlobalReAlloc (KERNEL32.@)
567 * Change the size or attributes of a global memory object.
573 HGLOBAL WINAPI GlobalReAlloc(
574 HGLOBAL hmem, /* [in] Handle of global memory object */
575 SIZE_T size, /* [in] New size of block */
576 UINT flags /* [in] How to reallocate object */
580 PGLOBAL32_INTERN pintern;
581 DWORD heap_flags = (flags & GMEM_ZEROINIT) ? HEAP_ZERO_MEMORY : 0;
584 RtlLockHeap(GetProcessHeap());
585 if(flags & GMEM_MODIFY) /* modify flags */
587 if( ISPOINTER(hmem) && (flags & GMEM_MOVEABLE))
589 /* make a fixed block moveable
590 * actually only NT is able to do this. But it's soo simple
594 WARN("GlobalReAlloc with null handle!\n");
595 SetLastError( ERROR_NOACCESS );
600 size = HeapSize(GetProcessHeap(), 0, (LPVOID)hmem);
601 hnew = GlobalAlloc(flags, size);
602 palloc = GlobalLock(hnew);
603 memcpy(palloc, (LPVOID)hmem, size);
608 else if( ISPOINTER(hmem) &&(flags & GMEM_DISCARDABLE))
610 /* change the flags to make our block "discardable" */
611 pintern=HANDLE_TO_INTERN(hmem);
612 pintern->Flags = pintern->Flags | (GMEM_DISCARDABLE >> 8);
617 SetLastError(ERROR_INVALID_PARAMETER);
625 /* reallocate fixed memory */
626 hnew=HeapReAlloc(GetProcessHeap(), heap_flags, hmem, size);
630 /* reallocate a moveable block */
631 pintern=HANDLE_TO_INTERN(hmem);
634 /* Apparently Windows doesn't care whether the handle is locked at this point */
635 /* See also the same comment in GlobalFree() */
636 if(pintern->LockCount>1) {
637 ERR("handle 0x%08lx is still locked, cannot realloc!\n",(DWORD)hmem);
638 SetLastError(ERROR_INVALID_HANDLE);
646 if((palloc = HeapReAlloc(GetProcessHeap(), heap_flags,
647 (char *) pintern->Pointer-HGLOBAL_STORAGE,
648 size+HGLOBAL_STORAGE)) == NULL)
649 hnew = 0; /* Block still valid */
651 pintern->Pointer = (char *)palloc+HGLOBAL_STORAGE;
655 if((palloc=HeapAlloc(GetProcessHeap(), heap_flags, size+HGLOBAL_STORAGE))
660 *(HGLOBAL *)palloc = hmem;
661 pintern->Pointer = (char *)palloc + HGLOBAL_STORAGE;
669 HeapFree(GetProcessHeap(), 0, (char *) pintern->Pointer-HGLOBAL_STORAGE);
670 pintern->Pointer=NULL;
675 RtlUnlockHeap(GetProcessHeap());
680 /***********************************************************************
681 * GlobalFree (KERNEL32.@)
683 * Free a global memory object.
689 HGLOBAL WINAPI GlobalFree(
690 HGLOBAL hmem /* [in] Handle of global memory object */
692 PGLOBAL32_INTERN pintern;
695 RtlLockHeap(GetProcessHeap());
699 if(ISPOINTER(hmem)) /* POINTER */
701 if(!HeapFree(GetProcessHeap(), 0, (LPVOID) hmem)) hmem = 0;
705 pintern=HANDLE_TO_INTERN(hmem);
707 if(pintern->Magic==MAGIC_GLOBAL_USED)
710 /* WIN98 does not make this test. That is you can free a */
711 /* block you have not unlocked. Go figure!! */
712 /* if(pintern->LockCount!=0) */
713 /* SetLastError(ERROR_INVALID_HANDLE); */
716 if(!HeapFree(GetProcessHeap(), 0, (char *)(pintern->Pointer)-HGLOBAL_STORAGE))
718 if(!HeapFree(GetProcessHeap(), 0, pintern))
725 ERR("page fault occurred ! Caused by bug ?\n");
726 SetLastError( ERROR_INVALID_PARAMETER );
730 RtlUnlockHeap(GetProcessHeap());
735 /***********************************************************************
736 * GlobalSize (KERNEL32.@)
738 * Get the size of a global memory object.
741 * Size in bytes of the global memory object
744 SIZE_T WINAPI GlobalSize(
745 HGLOBAL hmem /* [in] Handle of global memory object */
748 PGLOBAL32_INTERN pintern;
754 retval=HeapSize(GetProcessHeap(), 0, (LPVOID) hmem);
758 RtlLockHeap(GetProcessHeap());
759 pintern=HANDLE_TO_INTERN(hmem);
761 if(pintern->Magic==MAGIC_GLOBAL_USED)
763 if (!pintern->Pointer) /* handle case of GlobalAlloc( ??,0) */
767 retval = HeapSize(GetProcessHeap(), 0,
768 (char *)(pintern->Pointer) - HGLOBAL_STORAGE );
769 if (retval != (DWORD)-1) retval -= HGLOBAL_STORAGE;
774 WARN("invalid handle\n");
777 RtlUnlockHeap(GetProcessHeap());
779 /* HeapSize returns 0xffffffff on failure */
780 if (retval == 0xffffffff) retval = 0;
785 /***********************************************************************
786 * GlobalWire (KERNEL32.@)
788 LPVOID WINAPI GlobalWire(HGLOBAL hmem)
790 return GlobalLock( hmem );
794 /***********************************************************************
795 * GlobalUnWire (KERNEL32.@)
797 BOOL WINAPI GlobalUnWire(HGLOBAL hmem)
799 return GlobalUnlock( hmem);
803 /***********************************************************************
804 * GlobalFix (KERNEL32.@)
806 VOID WINAPI GlobalFix(HGLOBAL hmem)
812 /***********************************************************************
813 * GlobalUnfix (KERNEL32.@)
815 VOID WINAPI GlobalUnfix(HGLOBAL hmem)
821 /***********************************************************************
822 * GlobalFlags (KERNEL32.@)
824 * Get information about a global memory object.
827 * Should this return GMEM_INVALID_HANDLE on invalid handle?
830 * Value specifying allocation flags and lock count
831 * GMEM_INVALID_HANDLE: Failure
833 UINT WINAPI GlobalFlags(
834 HGLOBAL hmem /* [in] Handle to global memory object */
837 PGLOBAL32_INTERN pintern;
845 RtlLockHeap(GetProcessHeap());
846 pintern=HANDLE_TO_INTERN(hmem);
847 if(pintern->Magic==MAGIC_GLOBAL_USED)
849 retval=pintern->LockCount + (pintern->Flags<<8);
850 if(pintern->Pointer==0)
851 retval|= GMEM_DISCARDED;
855 WARN("Invalid handle: %p\n", hmem);
858 RtlUnlockHeap(GetProcessHeap());
864 /***********************************************************************
865 * GlobalCompact (KERNEL32.@)
867 SIZE_T WINAPI GlobalCompact( DWORD minfree )
869 return 0; /* GlobalCompact does nothing in Win32 */
873 /***********************************************************************
874 * LocalAlloc (KERNEL32.@)
876 * Allocate a local memory object.
883 * Windows memory management does not provide a separate local heap
886 HLOCAL WINAPI LocalAlloc(
887 UINT flags, /* [in] Allocation attributes */
888 SIZE_T size /* [in] Number of bytes to allocate */
890 return (HLOCAL)GlobalAlloc( flags, size );
894 /***********************************************************************
895 * LocalCompact (KERNEL32.@)
897 SIZE_T WINAPI LocalCompact( UINT minfree )
899 return 0; /* LocalCompact does nothing in Win32 */
903 /***********************************************************************
904 * LocalFlags (KERNEL32.@)
906 * Get information about a local memory object.
909 * Value specifying allocation flags and lock count.
910 * LMEM_INVALID_HANDLE: Failure
913 * Windows memory management does not provide a separate local heap
916 UINT WINAPI LocalFlags(
917 HLOCAL handle /* [in] Handle of memory object */
919 return GlobalFlags( (HGLOBAL)handle );
923 /***********************************************************************
924 * LocalFree (KERNEL32.@)
926 * Free a local memory object.
933 * Windows memory management does not provide a separate local heap
936 HLOCAL WINAPI LocalFree(
937 HLOCAL handle /* [in] Handle of memory object */
939 return (HLOCAL)GlobalFree( (HGLOBAL)handle );
943 /***********************************************************************
944 * LocalHandle (KERNEL32.@)
946 * Get the handle associated with the pointer to a local memory block.
953 * Windows memory management does not provide a separate local heap
956 HLOCAL WINAPI LocalHandle(
957 LPCVOID ptr /* [in] Address of local memory block */
959 return (HLOCAL)GlobalHandle( ptr );
963 /***********************************************************************
964 * LocalLock (KERNEL32.@)
965 * Locks a local memory object and returns pointer to the first byte
966 * of the memory block.
973 * Windows memory management does not provide a separate local heap
976 LPVOID WINAPI LocalLock(
977 HLOCAL handle /* [in] Address of local memory object */
979 return GlobalLock( (HGLOBAL)handle );
983 /***********************************************************************
984 * LocalReAlloc (KERNEL32.@)
986 * Change the size or attributes of a local memory object.
993 * Windows memory management does not provide a separate local heap
996 HLOCAL WINAPI LocalReAlloc(
997 HLOCAL handle, /* [in] Handle of memory object */
998 SIZE_T size, /* [in] New size of block */
999 UINT flags /* [in] How to reallocate object */
1001 return (HLOCAL)GlobalReAlloc( (HGLOBAL)handle, size, flags );
1005 /***********************************************************************
1006 * LocalShrink (KERNEL32.@)
1008 SIZE_T WINAPI LocalShrink( HGLOBAL handle, UINT newsize )
1010 return 0; /* LocalShrink does nothing in Win32 */
1014 /***********************************************************************
1015 * LocalSize (KERNEL32.@)
1017 * Get the size of a local memory object.
1024 * Windows memory management does not provide a separate local heap
1027 SIZE_T WINAPI LocalSize(
1028 HLOCAL handle /* [in] Handle of memory object */
1030 return GlobalSize( (HGLOBAL)handle );
1034 /***********************************************************************
1035 * LocalUnlock (KERNEL32.@)
1037 * Unlock a local memory object.
1040 * TRUE: Object is still locked
1041 * FALSE: Object is unlocked
1044 * Windows memory management does not provide a separate local heap
1047 BOOL WINAPI LocalUnlock(
1048 HLOCAL handle /* [in] Handle of memory object */
1050 return GlobalUnlock( (HGLOBAL)handle );
1054 /**********************************************************************
1055 * AllocMappedBuffer (KERNEL32.38)
1057 * This is an undocumented KERNEL32 function that
1058 * SMapLS's a GlobalAlloc'ed buffer.
1061 * EDI register: pointer to buffer
1064 * The buffer is preceded by 8 bytes:
1067 * edi-4 SEGPTR to buffer
1068 * edi-8 some magic Win95 needs for SUnMapLS
1069 * (we use it for the memory handle)
1071 * The SEGPTR is used by the caller!
1073 void WINAPI __regs_AllocMappedBuffer(
1074 CONTEXT86 *context /* [in] EDI register: size of buffer to allocate */
1076 HGLOBAL handle = GlobalAlloc(0, context->Edi + 8);
1077 DWORD *buffer = (DWORD *)GlobalLock(handle);
1081 if (!(ptr = MapLS(buffer + 2)))
1083 GlobalUnlock(handle);
1088 context->Eax = context->Edi = 0;
1091 buffer[0] = (DWORD)handle;
1094 context->Eax = (DWORD) ptr;
1095 context->Edi = (DWORD)(buffer + 2);
1098 #ifdef DEFINE_REGS_ENTRYPOINT
1099 DEFINE_REGS_ENTRYPOINT( AllocMappedBuffer, 0, 0 );
1102 /**********************************************************************
1103 * FreeMappedBuffer (KERNEL32.39)
1105 * Free a buffer allocated by AllocMappedBuffer
1110 void WINAPI __regs_FreeMappedBuffer(
1111 CONTEXT86 *context /* [in] EDI register: pointer to buffer */
1115 DWORD *buffer = (DWORD *)context->Edi - 2;
1119 GlobalUnlock((HGLOBAL)buffer[0]);
1120 GlobalFree((HGLOBAL)buffer[0]);
1123 #ifdef DEFINE_REGS_ENTRYPOINT
1124 DEFINE_REGS_ENTRYPOINT( FreeMappedBuffer, 0, 0 );
1127 /***********************************************************************
1128 * GlobalMemoryStatusEx (KERNEL32.@)
1129 * A version of GlobalMemoryStatus that can deal with memory over 4GB
1134 BOOL WINAPI GlobalMemoryStatusEx( LPMEMORYSTATUSEX lpmemex )
1136 static MEMORYSTATUSEX cached_memstatus;
1137 static int cache_lastchecked = 0;
1142 #if defined(__FreeBSD__) || defined(__NetBSD__)
1145 int mib[2] = { CTL_HW };
1148 long pagesize,maxpages,freepages,swapspace,swapfree;
1149 struct anoninfo swapinf;
1153 if (time(NULL)==cache_lastchecked) {
1154 memcpy(lpmemex,&cached_memstatus,sizeof(*lpmemex));
1157 cache_lastchecked = time(NULL);
1159 lpmemex->dwLength = sizeof(*lpmemex);
1160 lpmemex->dwMemoryLoad = 0;
1161 lpmemex->ullTotalPhys = 16*1024*1024;
1162 lpmemex->ullAvailPhys = 16*1024*1024;
1163 lpmemex->ullTotalPageFile = 16*1024*1024;
1164 lpmemex->ullAvailPageFile = 16*1024*1024;
1167 f = fopen( "/proc/meminfo", "r" );
1171 int total, used, free, shared, buffers, cached;
1173 lpmemex->ullTotalPhys = lpmemex->ullAvailPhys = 0;
1174 lpmemex->ullTotalPageFile = lpmemex->ullAvailPageFile = 0;
1175 while (fgets( buffer, sizeof(buffer), f ))
1177 /* old style /proc/meminfo ... */
1178 if (sscanf( buffer, "Mem: %d %d %d %d %d %d", &total, &used, &free, &shared, &buffers, &cached ))
1180 lpmemex->ullTotalPhys += total;
1181 lpmemex->ullAvailPhys += free + buffers + cached;
1183 if (sscanf( buffer, "Swap: %d %d %d", &total, &used, &free ))
1185 lpmemex->ullTotalPageFile += total;
1186 lpmemex->ullAvailPageFile += free;
1189 /* new style /proc/meminfo ... */
1190 if (sscanf(buffer, "MemTotal: %d", &total))
1191 lpmemex->ullTotalPhys = total*1024;
1192 if (sscanf(buffer, "MemFree: %d", &free))
1193 lpmemex->ullAvailPhys = free*1024;
1194 if (sscanf(buffer, "SwapTotal: %d", &total))
1195 lpmemex->ullTotalPageFile = total*1024;
1196 if (sscanf(buffer, "SwapFree: %d", &free))
1197 lpmemex->ullAvailPageFile = free*1024;
1198 if (sscanf(buffer, "Buffers: %d", &buffers))
1199 lpmemex->ullAvailPhys += buffers*1024;
1200 if (sscanf(buffer, "Cached: %d", &cached))
1201 lpmemex->ullAvailPhys += cached*1024;
1205 if (lpmemex->ullTotalPhys)
1207 DWORDLONG TotalPhysical = lpmemex->ullTotalPhys+lpmemex->ullTotalPageFile;
1208 DWORDLONG AvailPhysical = lpmemex->ullAvailPhys+lpmemex->ullAvailPageFile;
1209 lpmemex->dwMemoryLoad = (TotalPhysical-AvailPhysical)
1210 / (TotalPhysical / 100);
1213 #elif defined(__FreeBSD__) || defined(__NetBSD__)
1214 mib[1] = HW_PHYSMEM;
1215 sysctl(mib, 2, NULL, &size_sys, NULL, 0);
1216 tmp = malloc(size_sys * sizeof(int));
1217 sysctl(mib, 2, tmp, &size_sys, NULL, 0);
1220 lpmemex->ullTotalPhys = *tmp;
1222 mib[1] = HW_USERMEM;
1223 sysctl(mib, 2, NULL, &size_sys, NULL, 0);
1224 tmp = malloc(size_sys * sizeof(int));
1225 sysctl(mib, 2, tmp, &size_sys, NULL, 0);
1228 lpmemex->ullAvailPhys = *tmp;
1229 lpmemex->ullTotalPageFile = *tmp;
1230 lpmemex->ullAvailPageFile = *tmp;
1231 lpmemex->dwMemoryLoad = lpmemex->ullTotalPhys - lpmemex->ullAvailPhys;
1234 lpmemex->ullAvailPhys = lpmemex->ullTotalPhys;
1235 lpmemex->ullTotalPageFile = lpmemex->ullTotalPhys;
1236 lpmemex->ullAvailPageFile = lpmemex->ullTotalPhys;
1237 lpmemex->dwMemoryLoad = 0;
1242 #elif defined ( sun )
1243 pagesize=sysconf(_SC_PAGESIZE);
1244 maxpages=sysconf(_SC_PHYS_PAGES);
1245 freepages=sysconf(_SC_AVPHYS_PAGES);
1246 rval=swapctl(SC_AINFO, &swapinf);
1249 swapspace=swapinf.ani_max*pagesize;
1250 swapfree=swapinf.ani_free*pagesize;
1254 WARN("Swap size cannot be determined , assuming equal to physical memory\n");
1255 swapspace=maxpages*pagesize;
1256 swapfree=maxpages*pagesize;
1258 lpmemex->ullTotalPhys=pagesize*maxpages;
1259 lpmemex->ullAvailPhys = pagesize*freepages;
1260 lpmemex->ullTotalPageFile = swapspace;
1261 lpmemex->ullAvailPageFile = swapfree;
1262 lpmemex->dwMemoryLoad = lpmemex->ullTotalPhys - lpmemex->ullAvailPhys;
1265 /* Project2k refuses to start if it sees less than 1Mb of free swap */
1266 if (lpmemex->ullTotalPageFile < lpmemex->ullTotalPhys)
1267 lpmemex->ullTotalPageFile = lpmemex->ullTotalPhys;
1268 if (lpmemex->ullAvailPageFile < lpmemex->ullAvailPhys)
1269 lpmemex->ullAvailPageFile = lpmemex->ullAvailPhys;
1271 /* FIXME: should do something for other systems */
1273 lpmemex->ullTotalVirtual = (char*)si.lpMaximumApplicationAddress-(char*)si.lpMinimumApplicationAddress;
1274 /* FIXME: we should track down all the already allocated VM pages and substract them, for now arbitrarily remove 64KB so that it matches NT */
1275 lpmemex->ullAvailVirtual = lpmemex->ullTotalVirtual-64*1024;
1277 /* MSDN says about AvailExtendedVirtual: Size of unreserved and uncommitted
1278 memory in the extended portion of the virtual address space of the calling
1280 However, I don't know what this means, so set it to zero :(
1282 lpmemex->ullAvailExtendedVirtual = 0;
1284 memcpy(&cached_memstatus,lpmemex,sizeof(*lpmemex));
1286 TRACE("<-- LPMEMORYSTATUSEX: dwLength %ld, dwMemoryLoad %ld, ullTotalPhys %s, ullAvailPhys %s,"
1287 " ullTotalPageFile %s, ullAvailPageFile %s, ullTotalVirtual %s, ullAvailVirtual %s\n",
1288 lpmemex->dwLength, lpmemex->dwMemoryLoad, wine_dbgstr_longlong(lpmemex->ullTotalPhys),
1289 wine_dbgstr_longlong(lpmemex->ullAvailPhys), wine_dbgstr_longlong(lpmemex->ullTotalPageFile),
1290 wine_dbgstr_longlong(lpmemex->ullAvailPageFile), wine_dbgstr_longlong(lpmemex->ullTotalVirtual),
1291 wine_dbgstr_longlong(lpmemex->ullAvailVirtual) );
1296 /***********************************************************************
1297 * GlobalMemoryStatus (KERNEL32.@)
1298 * Provides information about the status of the memory, so apps can tell
1299 * roughly how much they are able to allocate
1304 VOID WINAPI GlobalMemoryStatus( LPMEMORYSTATUS lpBuffer )
1306 MEMORYSTATUSEX memstatus;
1307 OSVERSIONINFOW osver;
1309 /* Because GlobalMemoryStatus is identical to GlobalMemoryStatusEX save
1310 for one extra field in the struct, and the lack of a bug, we simply
1311 call GlobalMemoryStatusEx and copy the values across. */
1312 GlobalMemoryStatusEx(&memstatus);
1314 lpBuffer->dwLength = sizeof(*lpBuffer);
1315 lpBuffer->dwMemoryLoad = memstatus.dwMemoryLoad;
1317 /* Windows 2000 and later report -1 when values are greater than 4 Gb.
1318 * NT reports values modulo 4 Gb.
1319 * Values between 2 Gb and 4 Gb are rounded down to 2 Gb.
1322 osver.dwOSVersionInfoSize = sizeof(osver);
1323 GetVersionExW(&osver);
1325 if ( osver.dwMajorVersion >= 5 )
1327 lpBuffer->dwTotalPhys = (memstatus.ullTotalPhys > MAXDWORD) ? MAXDWORD :
1328 (memstatus.ullTotalPhys > MAXLONG) ? MAXLONG : memstatus.ullTotalPhys;
1329 lpBuffer->dwAvailPhys = (memstatus.ullAvailPhys > MAXDWORD) ? MAXDWORD :
1330 (memstatus.ullAvailPhys > MAXLONG) ? MAXLONG : memstatus.ullAvailPhys;
1331 lpBuffer->dwTotalPageFile = (memstatus.ullTotalPageFile > MAXDWORD) ? MAXDWORD :
1332 (memstatus.ullTotalPageFile > MAXLONG) ? MAXLONG : memstatus.ullTotalPageFile;
1333 lpBuffer->dwAvailPageFile = (memstatus.ullAvailPageFile > MAXDWORD) ? MAXDWORD :
1334 (memstatus.ullAvailPageFile > MAXLONG) ? MAXLONG : memstatus.ullAvailPageFile;
1335 lpBuffer->dwTotalVirtual = (memstatus.ullTotalVirtual > MAXDWORD) ? MAXDWORD :
1336 (memstatus.ullTotalVirtual > MAXLONG) ? MAXLONG : memstatus.ullTotalVirtual;
1337 lpBuffer->dwAvailVirtual = (memstatus.ullAvailVirtual > MAXDWORD) ? MAXDWORD :
1338 (memstatus.ullAvailVirtual > MAXLONG) ? MAXLONG : memstatus.ullAvailVirtual;
1340 else /* duplicate NT bug */
1342 lpBuffer->dwTotalPhys = (memstatus.ullTotalPhys > MAXDWORD) ? memstatus.ullTotalPhys :
1343 (memstatus.ullTotalPhys > MAXLONG) ? MAXLONG : memstatus.ullTotalPhys;
1344 lpBuffer->dwAvailPhys = (memstatus.ullAvailPhys > MAXDWORD) ? memstatus.ullAvailPhys :
1345 (memstatus.ullAvailPhys > MAXLONG) ? MAXLONG : memstatus.ullAvailPhys;
1346 lpBuffer->dwTotalPageFile = (memstatus.ullTotalPageFile > MAXDWORD) ? memstatus.ullTotalPageFile :
1347 (memstatus.ullTotalPageFile > MAXLONG) ? MAXLONG : memstatus.ullTotalPageFile;
1348 lpBuffer->dwAvailPageFile = (memstatus.ullAvailPageFile > MAXDWORD) ? memstatus.ullAvailPageFile :
1349 (memstatus.ullAvailPageFile > MAXLONG) ? MAXLONG : memstatus.ullAvailPageFile;
1350 lpBuffer->dwTotalVirtual = (memstatus.ullTotalVirtual > MAXDWORD) ? memstatus.ullTotalVirtual :
1351 (memstatus.ullTotalVirtual > MAXLONG) ? MAXLONG : memstatus.ullTotalVirtual;
1352 lpBuffer->dwAvailVirtual = (memstatus.ullAvailVirtual > MAXDWORD) ? memstatus.ullAvailVirtual :
1353 (memstatus.ullAvailVirtual > MAXLONG) ? MAXLONG : memstatus.ullAvailVirtual;
1356 /* work around for broken photoshop 4 installer */
1357 if ( lpBuffer->dwAvailPhys + lpBuffer->dwAvailPageFile >= 2U*1024*1024*1024)
1358 lpBuffer->dwAvailPageFile = 2U*1024*1024*1024 - lpBuffer->dwAvailPhys - 1;