diff --git a/Src/Libraries/Builtins/FileOps.cs b/Src/Libraries/Builtins/FileOps.cs
index 72fcbe93..6194d887 100644
--- a/Src/Libraries/Builtins/FileOps.cs
+++ b/Src/Libraries/Builtins/FileOps.cs
@@ -1098,7 +1098,7 @@ internal static int GetNativeFileDescriptor(RubyIO/*!*/ io) {
[RubyMethod("flock", BuildConfig = "FEATURE_FILESYSTEM")]
public static object FileLock(RubyFile/*!*/ self, [DefaultProtocol]int operation) {
self.RequireInitialized();
- if (!Posix.IsAvailable) {
+ if (!Posix.IsFlockAvailable) {
throw new IronRuby.Builtins.NotImplementedError("flock() function is unimplemented on this machine");
}
@@ -1118,7 +1118,7 @@ public static object FileLock(RubyFile/*!*/ self, [DefaultProtocol]int operation
if (Posix.Flock(fd, operation | Posix.LOCK_NB, out errno) == 0) {
return 0;
}
- if (errno != Posix.EWOULDBLOCK) {
+ if (errno != Posix.EWouldBlock) {
throw Posix.Error(errno, self.Path);
}
if (nonBlocking) {
diff --git a/Src/Libraries/Builtins/Posix.cs b/Src/Libraries/Builtins/Posix.cs
index 5f0195cc..197adc86 100644
--- a/Src/Libraries/Builtins/Posix.cs
+++ b/Src/Libraries/Builtins/Posix.cs
@@ -25,6 +25,29 @@ internal static class Posix {
System.IO.Path.DirectorySeparatorChar == '/' &&
!RuntimeInformation.IsOSPlatform(OSPlatform.OSX);
+ ///
+ /// flock(2) is the same call with the same operation bits on every Unix, so it is
+ /// offered on macOS too, where the rest of this class (statx, Linux errno numbers)
+ /// is not. RubyGems takes a lock on every binstub it writes, so without this
+ /// `gem install` of anything with an executable failed on a Mac.
+ ///
+ internal static readonly bool IsFlockAvailable = System.IO.Path.DirectorySeparatorChar == '/';
+
+ ///
+ /// errno for "would block" on this platform: EAGAIN is 11 on Linux and 35 on macOS and
+ /// the other BSDs, whose errno numbering macOS inherited. IsFlockAvailable lets every
+ /// Unix in, so a BSD has to get 35 too, or a contended LOCK_NB raises instead of
+ /// returning false and a blocking lock never retries.
+ ///
+ internal static readonly int EWouldBlock = IsBsdErrno() ? 35 : EWOULDBLOCK;
+
+ private static bool IsBsdErrno() {
+ return RuntimeInformation.IsOSPlatform(OSPlatform.OSX) ||
+ RuntimeInformation.IsOSPlatform(OSPlatform.FreeBSD) ||
+ RuntimeInformation.IsOSPlatform(OSPlatform.Create("NETBSD")) ||
+ RuntimeInformation.IsOSPlatform(OSPlatform.Create("OPENBSD"));
+ }
+
#region errno numbers
internal const int EPERM = 1;