diff --git a/winsup/cygwin/ChangeLog b/winsup/cygwin/ChangeLog index cb6dcb549..eb1382e37 100644 --- a/winsup/cygwin/ChangeLog +++ b/winsup/cygwin/ChangeLog @@ -1,3 +1,25 @@ +2005-10-18 Corinna Vinschen + + * autoload.cc (NtLockVirtualMemory): Import. + (NtUnlockVirtualMemory): Import. + (GetProcessWorkingSetSize): Import. + (SetProcessWorkingSetSize): Import. + * cygwin.din (mlock): Export. + (munlock): Export. + * mmap.cc (mlock): New function. + (munlock): Ditto. + * ntdll.h (STATUS_WORKING_SET_QUOTA): Define. + (LOCK_VM_IN_WSL): Define. + (LOCK_VM_IN_RAM): Define. + (NtLockVirtualMemory): Declare. + (NtUnlockVirtualMemory): Declare. + * sysconf.cc (sysconf): Implement _SC_MEMLOCK_RANGE. + * wincap.h: Implement has_working_virtual_lock throughout. + * wincap.cc: Ditto. + * include/cygwin/version.h: Bump API minor version. + * include/sys/mman.h (mlock): Declare, + (munlock): Declare. + 2005-10-18 Christopher Faylor * sigproc.cc (child_info::sync): Use correct name when closing to diff --git a/winsup/cygwin/autoload.cc b/winsup/cygwin/autoload.cc index 8ac707edb..87564f5cd 100644 --- a/winsup/cygwin/autoload.cc +++ b/winsup/cygwin/autoload.cc @@ -379,6 +379,7 @@ LoadDLLfunc (NetWkstaUserGetInfo, 12, netapi32) LoadDLLfuncEx (NtCreateFile, 44, ntdll, 1) LoadDLLfuncEx (NtCreateToken, 52, ntdll, 1) +LoadDLLfuncEx (NtLockVirtualMemory, 16, ntdll, 1) LoadDLLfuncEx (NtMapViewOfSection, 40, ntdll, 1) LoadDLLfuncEx (NtOpenFile, 24, ntdll, 1) LoadDLLfuncEx (NtOpenSection, 12, ntdll, 1) @@ -390,6 +391,7 @@ LoadDLLfuncEx (NtQuerySecurityObject, 20, ntdll, 1) LoadDLLfuncEx (NtQueryVirtualMemory, 24, ntdll, 1) LoadDLLfuncEx (NtQueryVolumeInformationFile, 20, ntdll, 1) LoadDLLfuncEx (NtSetSecurityObject, 12, ntdll, 1) +LoadDLLfuncEx (NtUnlockVirtualMemory, 16, ntdll, 1) LoadDLLfuncEx (NtUnmapViewOfSection, 8, ntdll, 1) LoadDLLfuncEx (RtlInitUnicodeString, 8, ntdll, 1) LoadDLLfuncEx (RtlNtStatusToDosError, 4, ntdll, 1) @@ -508,6 +510,7 @@ LoadDLLfuncEx2 (GetCompressedFileSizeA, 8, kernel32, 1, 0xffffffff) LoadDLLfuncEx (GetConsoleWindow, 0, kernel32, 1) LoadDLLfuncEx (GetDiskFreeSpaceEx, 16, kernel32, 1) LoadDLLfuncEx (GetNativeSystemInfo, 4, kernel32, 1) +LoadDLLfuncEx (GetProcessWorkingSetSize, 12, kernel32, 1) LoadDLLfuncEx (GetSystemTimes, 12, kernel32, 1) LoadDLLfuncEx (GetVolumeNameForVolumeMountPointA, 12, kernel32, 1) LoadDLLfuncEx2 (IsDebuggerPresent, 0, kernel32, 1, 1) @@ -516,6 +519,7 @@ LoadDLLfuncEx (IsWow64Process, 8, kernel32, 1); LoadDLLfuncEx (Process32First, 8, kernel32, 1) LoadDLLfuncEx (Process32Next, 8, kernel32, 1) LoadDLLfuncEx (RegisterServiceProcess, 8, kernel32, 1) +LoadDLLfuncEx (SetProcessWorkingSetSize, 12, kernel32, 1) LoadDLLfuncEx (SignalObjectAndWait, 16, kernel32, 1) LoadDLLfuncEx (SwitchToThread, 0, kernel32, 1) diff --git a/winsup/cygwin/cygwin.din b/winsup/cygwin/cygwin.din index 4543352ad..f172f1415 100644 --- a/winsup/cygwin/cygwin.din +++ b/winsup/cygwin/cygwin.din @@ -953,6 +953,8 @@ _modff = modff NOSIGFE mount SIGFE _mount = mount SIGFE mprotect SIGFE +mlock SIGFE +munlock SIGFE mrand48 NOSIGFE msgctl SIGFE msgget SIGFE diff --git a/winsup/cygwin/include/cygwin/version.h b/winsup/cygwin/include/cygwin/version.h index 32dfa413c..9edd89856 100644 --- a/winsup/cygwin/include/cygwin/version.h +++ b/winsup/cygwin/include/cygwin/version.h @@ -277,12 +277,13 @@ details. */ 138: Export readdir_r. 139: Start using POSIX definition of struct msghdr and WinSock2 IPPROTO_IP values. + 140: Export mlock, munlock. */ /* Note that we forgot to bump the api for ualarm, strtoll, strtoull */ #define CYGWIN_VERSION_API_MAJOR 0 -#define CYGWIN_VERSION_API_MINOR 139 +#define CYGWIN_VERSION_API_MINOR 140 /* There is also a compatibity version number associated with the shared memory regions. It is incremented when incompatible diff --git a/winsup/cygwin/include/sys/mman.h b/winsup/cygwin/include/sys/mman.h index 21bf6976d..5290a62d9 100644 --- a/winsup/cygwin/include/sys/mman.h +++ b/winsup/cygwin/include/sys/mman.h @@ -49,6 +49,8 @@ extern void *mmap (void *__addr, size_t __len, int __prot, int __flags, int __fd extern int munmap (void *__addr, size_t __len); extern int mprotect (void *__addr, size_t __len, int __prot); extern int msync (void *__addr, size_t __len, int __flags); +extern int mlock (const void *__addr, size_t __len); +extern int munlock (const void *__addr, size_t __len); #ifdef __cplusplus }; diff --git a/winsup/cygwin/mmap.cc b/winsup/cygwin/mmap.cc index d85186f8e..ad47cb907 100644 --- a/winsup/cygwin/mmap.cc +++ b/winsup/cygwin/mmap.cc @@ -977,6 +977,98 @@ mprotect (void *addr, size_t len, int prot) return 0; } +extern "C" int +mlock (const void *addr, size_t len) +{ + if (!wincap.has_working_virtual_lock ()) + return 0; + + int ret = -1; + + /* Instead of using VirtualLock, which does not guarantee that the pages + aren't swapped out when the process is inactive, we're using + ZwLockVirtualMemory with the LOCK_VM_IN_RAM flag to do what mlock on + POSIX systems does. On NT, this requires SeLockMemoryPrivilege, + which is given only to SYSTEM by default. */ + + push_thread_privilege (SE_LOCK_MEMORY_PRIV, true); + + /* Align address and length values to page size. */ + PVOID base = (PVOID) ((uintptr_t) addr & ~(getpagesize () - 1)); + ULONG size = ((uintptr_t) addr - (uintptr_t) base) + len; + size = (size + getpagesize () - 1) & ~(getpagesize () - 1); + NTSTATUS status = 0; + do + { + status = NtLockVirtualMemory (hMainProc, &base, &size, LOCK_VM_IN_RAM); + if (status == STATUS_WORKING_SET_QUOTA) + { + /* The working set is too small, try to increase it so that the + requested locking region fits in. Unfortunately I don't know + any function which would return the currently locked pages of + a process (no go with NtQueryVirtualMemory). + + So, except for the border cases, what we do here is something + really embarrassing. We raise the working set by 64K at a time + and retry, until either we fail to raise the working set size + further, or until NtLockVirtualMemory returns successfully (or + with another error). */ + ULONG min, max; + if (!GetProcessWorkingSetSize (hMainProc, &min, &max)) + { + set_errno (ENOMEM); + break; + } + if (min < size) + min = size + 12 * getpagesize (); /* Evaluated by testing */ + else if (size < 65536) + min += size; + else + min += 65536; + if (max < min) + max = min; + if (!SetProcessWorkingSetSize (hMainProc, min, max)) + { + set_errno (ENOMEM); + break; + } + } + else if (!NT_SUCCESS (status)) + __seterrno_from_nt_status (status); + else + ret = 0; + } + while (status == STATUS_WORKING_SET_QUOTA); + + pop_thread_privilege (); + + return ret; +} + +extern "C" int +munlock (const void *addr, size_t len) +{ + if (!wincap.has_working_virtual_lock ()) + return 0; + + int ret = -1; + + push_thread_privilege (SE_LOCK_MEMORY_PRIV, true); + + PVOID base = (PVOID) addr; + ULONG size = len; + NTSTATUS status = NtUnlockVirtualMemory (hMainProc, &base, &size, + LOCK_VM_IN_RAM); + if (!NT_SUCCESS (status)) + __seterrno_from_nt_status (status); + else + ret = 0; + + pop_thread_privilege (); + + return ret; +} + /* * Base implementation: * diff --git a/winsup/cygwin/ntdll.h b/winsup/cygwin/ntdll.h index 5a43df538..26ae8ff59 100644 --- a/winsup/cygwin/ntdll.h +++ b/winsup/cygwin/ntdll.h @@ -10,6 +10,7 @@ #define STATUS_INFO_LENGTH_MISMATCH ((NTSTATUS) 0xc0000004) #define STATUS_BUFFER_TOO_SMALL ((NTSTATUS) 0xc0000023) +#define STATUS_WORKING_SET_QUOTA ((NTSTATUS) 0xc00000a1L) #define PDI_MODULES 0x01 #define PDI_HEAPS 0x04 #define LDRP_IMAGE_DLL 0x00000004 @@ -25,6 +26,9 @@ #define AT_ROUND_TO_PAGE 0x40000000 +#define LOCK_VM_IN_WSL 1 +#define LOCK_VM_IN_RAM 2 + typedef ULONG KAFFINITY; typedef enum _SYSTEM_INFORMATION_CLASS @@ -480,6 +484,7 @@ extern "C" PTOKEN_GROUPS, PTOKEN_PRIVILEGES, PTOKEN_OWNER, PTOKEN_PRIMARY_GROUP, PTOKEN_DEFAULT_DACL, PTOKEN_SOURCE); + NTSTATUS NTAPI NtLockVirtualMemory (HANDLE, PVOID *, ULONG *, ULONG); NTSTATUS NTAPI NtMapViewOfSection (HANDLE, HANDLE, PVOID *, ULONG, ULONG, PLARGE_INTEGER, PULONG, SECTION_INHERIT, ULONG, ULONG); @@ -503,6 +508,7 @@ extern "C" FS_INFORMATION_CLASS); NTSTATUS NTAPI NtSetSecurityObject (HANDLE, SECURITY_INFORMATION, PSECURITY_DESCRIPTOR); + NTSTATUS NTAPI NtUnlockVirtualMemory (HANDLE, PVOID *, ULONG *, ULONG); NTSTATUS NTAPI NtUnmapViewOfSection (HANDLE, PVOID); VOID NTAPI RtlInitUnicodeString (PUNICODE_STRING, PCWSTR); ULONG NTAPI RtlNtStatusToDosError (NTSTATUS); diff --git a/winsup/cygwin/sysconf.cc b/winsup/cygwin/sysconf.cc index b50688fd4..7bd8cb618 100644 --- a/winsup/cygwin/sysconf.cc +++ b/winsup/cygwin/sysconf.cc @@ -123,6 +123,8 @@ sysconf (int in) return RTSIG_MAX; case _SC_TTY_NAME_MAX: return TTY_NAME_MAX; + case _SC_MEMLOCK_RANGE: + return _POSIX_MEMLOCK_RANGE; } /* Invalid input or unimplemented sysconf name */ diff --git a/winsup/cygwin/wincap.cc b/winsup/cygwin/wincap.cc index 2cfffc2d6..955a620c5 100644 --- a/winsup/cygwin/wincap.cc +++ b/winsup/cygwin/wincap.cc @@ -60,7 +60,8 @@ static NO_COPY wincaps wincap_unknown = { has_guid_volumes:false, detect_win16_exe:true, has_null_console_handler_routine:false, - has_disk_ex_ioctls:false + has_disk_ex_ioctls:false, + has_working_virtual_lock:false }; static NO_COPY wincaps wincap_95 = { @@ -112,7 +113,8 @@ static NO_COPY wincaps wincap_95 = { has_guid_volumes:false, detect_win16_exe:true, has_null_console_handler_routine:false, - has_disk_ex_ioctls:false + has_disk_ex_ioctls:false, + has_working_virtual_lock:false }; static NO_COPY wincaps wincap_95osr2 = { @@ -164,7 +166,8 @@ static NO_COPY wincaps wincap_95osr2 = { has_guid_volumes:false, detect_win16_exe:true, has_null_console_handler_routine:false, - has_disk_ex_ioctls:false + has_disk_ex_ioctls:false, + has_working_virtual_lock:false }; static NO_COPY wincaps wincap_98 = { @@ -216,7 +219,8 @@ static NO_COPY wincaps wincap_98 = { has_guid_volumes:false, detect_win16_exe:true, has_null_console_handler_routine:false, - has_disk_ex_ioctls:false + has_disk_ex_ioctls:false, + has_working_virtual_lock:false }; static NO_COPY wincaps wincap_98se = { @@ -268,7 +272,8 @@ static NO_COPY wincaps wincap_98se = { has_guid_volumes:false, detect_win16_exe:true, has_null_console_handler_routine:false, - has_disk_ex_ioctls:false + has_disk_ex_ioctls:false, + has_working_virtual_lock:false }; static NO_COPY wincaps wincap_me = { @@ -320,7 +325,8 @@ static NO_COPY wincaps wincap_me = { has_guid_volumes:false, detect_win16_exe:true, has_null_console_handler_routine:false, - has_disk_ex_ioctls:false + has_disk_ex_ioctls:false, + has_working_virtual_lock:false }; static NO_COPY wincaps wincap_nt3 = { @@ -372,7 +378,8 @@ static NO_COPY wincaps wincap_nt3 = { has_guid_volumes:false, detect_win16_exe:false, has_null_console_handler_routine:true, - has_disk_ex_ioctls:false + has_disk_ex_ioctls:false, + has_working_virtual_lock:true }; static NO_COPY wincaps wincap_nt4 = { @@ -424,7 +431,8 @@ static NO_COPY wincaps wincap_nt4 = { has_guid_volumes:false, detect_win16_exe:false, has_null_console_handler_routine:true, - has_disk_ex_ioctls:false + has_disk_ex_ioctls:false, + has_working_virtual_lock:true }; static NO_COPY wincaps wincap_nt4sp4 = { @@ -476,7 +484,8 @@ static NO_COPY wincaps wincap_nt4sp4 = { has_guid_volumes:false, detect_win16_exe:false, has_null_console_handler_routine:true, - has_disk_ex_ioctls:false + has_disk_ex_ioctls:false, + has_working_virtual_lock:true }; static NO_COPY wincaps wincap_2000 = { @@ -528,7 +537,8 @@ static NO_COPY wincaps wincap_2000 = { has_guid_volumes:true, detect_win16_exe:false, has_null_console_handler_routine:true, - has_disk_ex_ioctls:false + has_disk_ex_ioctls:false, + has_working_virtual_lock:true }; static NO_COPY wincaps wincap_xp = { @@ -580,7 +590,8 @@ static NO_COPY wincaps wincap_xp = { has_guid_volumes:true, detect_win16_exe:false, has_null_console_handler_routine:true, - has_disk_ex_ioctls:true + has_disk_ex_ioctls:true, + has_working_virtual_lock:true }; static NO_COPY wincaps wincap_2003 = { @@ -632,7 +643,8 @@ static NO_COPY wincaps wincap_2003 = { has_guid_volumes:true, detect_win16_exe:false, has_null_console_handler_routine:true, - has_disk_ex_ioctls:true + has_disk_ex_ioctls:true, + has_working_virtual_lock:true }; static NO_COPY wincaps wincap_vista = { @@ -684,7 +696,8 @@ static NO_COPY wincaps wincap_vista = { has_guid_volumes:true, detect_win16_exe:false, has_null_console_handler_routine:true, - has_disk_ex_ioctls:true + has_disk_ex_ioctls:true, + has_working_virtual_lock:true }; wincapc wincap; diff --git a/winsup/cygwin/wincap.h b/winsup/cygwin/wincap.h index 7bc3d5ca7..02c1fa48c 100644 --- a/winsup/cygwin/wincap.h +++ b/winsup/cygwin/wincap.h @@ -62,6 +62,7 @@ struct wincaps unsigned detect_win16_exe : 1; unsigned has_null_console_handler_routine : 1; unsigned has_disk_ex_ioctls : 1; + unsigned has_working_virtual_lock : 1; }; class wincapc @@ -128,6 +129,7 @@ public: bool IMPLEMENT (detect_win16_exe) bool IMPLEMENT (has_null_console_handler_routine) bool IMPLEMENT (has_disk_ex_ioctls) + bool IMPLEMENT (has_working_virtual_lock) #undef IMPLEMENT };