Welcome to mirror list, hosted at ThFree Co, Russian Federation.

cygwin.com/git/newlib-cygwin.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorCorinna Vinschen <corinna@vinschen.de>2005-10-18 22:51:33 +0400
committerCorinna Vinschen <corinna@vinschen.de>2005-10-18 22:51:33 +0400
commit1f5c3042d581783dfd8ed8495ef704e9ae325cd2 (patch)
tree4063c5b7fa5a74f1018847e1574f459c3fac4fd1 /winsup/cygwin/mmap.cc
parenta92822b74764fb7ff83517889cfa6b875c855250 (diff)
* 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.
Diffstat (limited to 'winsup/cygwin/mmap.cc')
-rw-r--r--winsup/cygwin/mmap.cc92
1 files changed, 92 insertions, 0 deletions
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:
*