diff options
author | Steffen Kieß <s-kiess@web.de> | 2019-08-30 20:13:33 +0300 |
---|---|---|
committer | Alexander Köplinger <alex.koeplinger@outlook.com> | 2019-08-30 20:13:33 +0300 |
commit | 80b7813d54bbf7e3e20361228e109b2b9abcccb5 (patch) | |
tree | 9a5b9ae122973b64ffacfac92fbc7429bbfc50cf /mcs/class/Mono.Posix | |
parent | c8707c6e84ed5978fb21be3c2dd4fe678b904c9c (diff) |
[Mono.Posix] Add FcntlCommand.F_OFD_{GETLK,SETLK,SETLKW} (#16571)
Add F_OFD_GETLK, F_OFD_SETLK and F_OFD_SETLKW to FcntlCommand. These
commmands are similar to F_GETLK, F_SETLK and F_SETLKW but operate on a
per-open-file-description lock instead of a per-process lock and avoid the
problem that the locks are released when close(dup(fd)) is called. See
https://lwn.net/Articles/586904/ for more information.
This commit also reruns create-native-map but keeps manual changes from
ed892ccf27849c082ce6ca46fa8b96d86ca7c329,
b522eab5ff5466debaacf9e971e26cfc464ebba5 and
22b6b9581418260397b701c17b16c3eb55136de7.
In [create-native-map.diff.txt](https://github.com/mono/mono/files/3557077/create-native-map.diff.txt) you can see the difference between the commited `map.[ch]` and the one `create-native-map.exe` wants to create:
- Manually inserted changes for NetBSD (`MAYMOVE` is turned into a negated `FIXED`)
- `Mono_Posix_ToSockaddrIn6()` and friends get skipped for `HOST_WIN32` (not sure why, when `sockaddr_in6` exists then `Mono_Posix_ToSockaddrIn6()` should work)
- At the bottom of `map.h` some functions are reordered and the parameters change (`const char*` vs. `char*`)
Running create-native-map.exe also moved some O_NOATIME-related stuff (from 8b9033e4d24115190c06f775d18ef3a40cbca876) to the correct position and added it to Mono_Posix_ToOpenFlags(), which I kept in the commit.
Diffstat (limited to 'mcs/class/Mono.Posix')
-rw-r--r-- | mcs/class/Mono.Posix/Mono.Posix_test.dll.sources | 1 | ||||
-rw-r--r-- | mcs/class/Mono.Posix/Mono.Unix.Native/Syscall.cs | 35 | ||||
-rw-r--r-- | mcs/class/Mono.Posix/Test/Mono.Unix.Native/OFDLockTest.cs | 133 |
3 files changed, 153 insertions, 16 deletions
diff --git a/mcs/class/Mono.Posix/Mono.Posix_test.dll.sources b/mcs/class/Mono.Posix/Mono.Posix_test.dll.sources index a2f290f8656..5aee212abe7 100644 --- a/mcs/class/Mono.Posix/Mono.Posix_test.dll.sources +++ b/mcs/class/Mono.Posix/Mono.Posix_test.dll.sources @@ -9,6 +9,7 @@ Mono.Unix/UnixPathTest.cs Mono.Unix/UnixSignalTest.cs Mono.Unix/UnixUserTest.cs Mono.Unix.Android/TestHelper.cs +Mono.Unix.Native/OFDLockTest.cs Mono.Unix.Native/RealTimeSignumTests.cs Mono.Unix.Native/SocketTest.cs Mono.Unix.Native/StdlibTest.cs diff --git a/mcs/class/Mono.Posix/Mono.Unix.Native/Syscall.cs b/mcs/class/Mono.Posix/Mono.Unix.Native/Syscall.cs index 6cc67dda4b8..c9eb750d222 100644 --- a/mcs/class/Mono.Posix/Mono.Unix.Native/Syscall.cs +++ b/mcs/class/Mono.Posix/Mono.Unix.Native/Syscall.cs @@ -212,22 +212,25 @@ namespace Mono.Unix.Native { [CLSCompliant (false)] public enum FcntlCommand : int { // Form /usr/include/bits/fcntl.h - F_DUPFD = 0, // Duplicate file descriptor. - F_GETFD = 1, // Get file descriptor flags. - F_SETFD = 2, // Set file descriptor flags. - F_GETFL = 3, // Get file status flags. - F_SETFL = 4, // Set file status flags. - F_GETLK = 12, // Get record locking info. [64] - F_SETLK = 13, // Set record locking info (non-blocking). [64] - F_SETLKW = 14, // Set record locking info (blocking). [64] - F_SETOWN = 8, // Set owner of socket (receiver of SIGIO). - F_GETOWN = 9, // Get owner of socket (receiver of SIGIO). - F_SETSIG = 10, // Set number of signal to be sent. - F_GETSIG = 11, // Get number of signal to be sent. - F_NOCACHE = 48, // OSX: turn data caching off/on for this fd. - F_SETLEASE = 1024, // Set a lease. - F_GETLEASE = 1025, // Enquire what lease is active. - F_NOTIFY = 1026, // Required notifications on a directory + F_DUPFD = 0, // Duplicate file descriptor. + F_GETFD = 1, // Get file descriptor flags. + F_SETFD = 2, // Set file descriptor flags. + F_GETFL = 3, // Get file status flags. + F_SETFL = 4, // Set file status flags. + F_GETLK = 12, // Get record locking info. [64] + F_SETLK = 13, // Set record locking info (non-blocking). [64] + F_SETLKW = 14, // Set record locking info (blocking). [64] + F_OFD_GETLK = 36, // Get open file description locking info. + F_OFD_SETLK = 37, // Set open file description locking info (non-blocking). + F_OFD_SETLKW = 38, // Set open file description locking info (blocking). + F_SETOWN = 8, // Set owner of socket (receiver of SIGIO). + F_GETOWN = 9, // Get owner of socket (receiver of SIGIO). + F_SETSIG = 10, // Set number of signal to be sent. + F_GETSIG = 11, // Get number of signal to be sent. + F_NOCACHE = 48, // OSX: turn data caching off/on for this fd. + F_SETLEASE = 1024, // Set a lease. + F_GETLEASE = 1025, // Enquire what lease is active. + F_NOTIFY = 1026, // Required notifications on a directory } [Map] diff --git a/mcs/class/Mono.Posix/Test/Mono.Unix.Native/OFDLockTest.cs b/mcs/class/Mono.Posix/Test/Mono.Unix.Native/OFDLockTest.cs new file mode 100644 index 00000000000..44f45fe0187 --- /dev/null +++ b/mcs/class/Mono.Posix/Test/Mono.Unix.Native/OFDLockTest.cs @@ -0,0 +1,133 @@ +// +// Tests for FcntlCommand.F_OFD_{GETLK,SETLK,SETLKW} +// +// Authors: +// Steffen Kiess (kiess@ki4.de) +// +// Copyright (C) 2019 Steffen Kiess +// + +using System; +using System.IO; +using System.Net; +using System.Net.Sockets; +using System.Runtime.InteropServices; + +using Mono.Unix; +using Mono.Unix.Native; + +using NUnit.Framework; + +namespace MonoTests.Mono.Unix.Native +{ + [TestFixture, Category ("NotDotNet"), Category ("NotOnWindows"), Category ("NotOnMac")] + public class OFDLockTest { + + string TempFolder; + + [SetUp] + public void SetUp () + { + TempFolder = Path.Combine (Path.GetTempPath (), this.GetType ().FullName); + + if (Directory.Exists (TempFolder)) + Directory.Delete (TempFolder, true); + + Directory.CreateDirectory (TempFolder); + } + + [TearDown] + public void TearDown() + { + if (Directory.Exists (TempFolder)) + Directory.Delete (TempFolder, true); + } + + [Test] + public void TestOFDLock () + { + int fd1 = Syscall.open (TempFolder + "/testfile", OpenFlags.O_RDWR | OpenFlags.O_CREAT | OpenFlags.O_EXCL, FilePermissions.DEFFILEMODE); + if (fd1 < 0) + UnixMarshal.ThrowExceptionForLastError (); + int fd2 = Syscall.open (TempFolder + "/testfile", OpenFlags.O_RDWR); + if (fd2 < 0) + UnixMarshal.ThrowExceptionForLastError (); + int fd3 = Syscall.open (TempFolder + "/testfile", OpenFlags.O_RDWR); + if (fd3 < 0) + UnixMarshal.ThrowExceptionForLastError (); + + // Get read lock for first 100 bytes on fd1 + var flock1 = new Flock { + l_type = LockType.F_RDLCK, + l_whence = SeekFlags.SEEK_SET, + l_start = 0, + l_len = 100, + }; + if (Syscall.fcntl (fd1, FcntlCommand.F_OFD_SETLKW, ref flock1) < 0) { + // Old kernels and non-linux systems should return EINVAL + if (Stdlib.GetLastError () == Errno.EINVAL) + Assert.Ignore ("F_OFD_SETLKW does not seem to be supported."); + UnixMarshal.ThrowExceptionForLastError (); + } + + // Get read lock for first 100 bytes on fd2 + var flock2 = new Flock { + l_type = LockType.F_RDLCK, + l_whence = SeekFlags.SEEK_SET, + l_start = 0, + l_len = 100, + }; + if (Syscall.fcntl (fd2, FcntlCommand.F_OFD_SETLK, ref flock2) < 0) + UnixMarshal.ThrowExceptionForLastError (); + + // Get write lock for remaining bytes on fd1 + var flock3 = new Flock { + l_type = LockType.F_WRLCK, + l_whence = SeekFlags.SEEK_SET, + l_start = 100, + l_len = 0, + }; + if (Syscall.fcntl (fd1, FcntlCommand.F_OFD_SETLK, ref flock3) < 0) + UnixMarshal.ThrowExceptionForLastError (); + + // Close fd3, should not release lock + if (Syscall.close (fd3) < 0) + UnixMarshal.ThrowExceptionForLastError (); + + // Get lock status for byte 150 from fd2 + var flock4 = new Flock { + l_type = LockType.F_RDLCK, + l_whence = SeekFlags.SEEK_SET, + l_start = 150, + l_len = 1, + }; + if (Syscall.fcntl (fd2, FcntlCommand.F_OFD_GETLK, ref flock4) < 0) + UnixMarshal.ThrowExceptionForLastError (); + // There should be a conflicting write lock + Assert.AreEqual (LockType.F_WRLCK, flock4.l_type); + + // Get write byte 0 on fd1, should fail with EAGAIN + var flock5 = new Flock { + l_type = LockType.F_WRLCK, + l_whence = SeekFlags.SEEK_SET, + l_start = 0, + l_len = 1, + }; + var res = Syscall.fcntl (fd1, FcntlCommand.F_OFD_SETLK, ref flock5); + Assert.AreEqual (-1, res); + Assert.AreEqual (Errno.EAGAIN, Stdlib.GetLastError ()); + + if (Syscall.close (fd1) < 0) + UnixMarshal.ThrowExceptionForLastError (); + if (Syscall.close (fd2) < 0) + UnixMarshal.ThrowExceptionForLastError (); + } + } +} + +// vim: noexpandtab +// Local Variables: +// tab-width: 4 +// c-basic-offset: 4 +// indent-tabs-mode: t +// End: |