public void FileSystemWatcher_Unix_DoesNotLeak() { Interop.Sys.GetRLimit(Interop.Sys.RlimitResources.RLIMIT_NOFILE, out Interop.Sys.RLimit limits); _output.WriteLine("File descriptor limit is {0}", limits.CurrentLimit); _output.WriteLine($"Starting 100/200 test on {TestDirectory}"); RemoteInvokeOptions options = new RemoteInvokeOptions { TimeOut = 600_000 }; RemoteExecutor.Invoke(testDirectory => { ulong maxFd = 200; int count = 100; Interop.Sys.RLimit limits = new Interop.Sys.RLimit { CurrentLimit = maxFd, MaximumLimit = maxFd }; // Set open file limit to given value. Assert.Equal(0, Interop.Sys.SetRLimit(Interop.Sys.RlimitResources.RLIMIT_NOFILE, ref limits)); Assert.Equal(0, Interop.Sys.GetRLimit(Interop.Sys.RlimitResources.RLIMIT_NOFILE, out limits)); Assert.Equal(maxFd, limits.CurrentLimit); try { for (int i = 0; i < count; i++) { using (var watcher = new FileSystemWatcher(testDirectory)) { watcher.Created += (s, e) => { }; watcher.EnableRaisingEvents = true; } } } catch (Exception e) { // If we use all handles we may not have luck writing out errors. // Try our best here. _output is not available within RemoteExec(). // When we run out of fd, exception may be weird from OutOfMem to "unable load type". Console.WriteLine($"Test failed for count={count}, limit={maxFd} and path='{testDirectory}'."); Console.WriteLine(e.Message); return(1); } return(RemoteExecutor.SuccessExitCode); }, TestDirectory, options).Dispose(); }
/// <summary>Sets one or both of the minimum and maximum working set limits.</summary> /// <param name="newMin">The new minimum working set limit, or null not to change it.</param> /// <param name="newMax">The new maximum working set limit, or null not to change it.</param> /// <param name="resultingMin">The resulting minimum working set limit after any changes applied.</param> /// <param name="resultingMax">The resulting maximum working set limit after any changes applied.</param> private void SetWorkingSetLimitsCore(IntPtr?newMin, IntPtr?newMax, out IntPtr resultingMin, out IntPtr resultingMax) { // We can only do this for the current process on OS X if (_processId != Environment.ProcessId) { throw new PlatformNotSupportedException(SR.OsxExternalProcessWorkingSetNotSupported); } // There isn't a way to set the minimum working set, so throw an exception here if (newMin.HasValue) { throw new PlatformNotSupportedException(SR.MinimumWorkingSetNotSupported); } // The minimum resident set will always be 0, default the resulting max to 0 until we set it (to make the compiler happy) resultingMin = IntPtr.Zero; resultingMax = IntPtr.Zero; // The default hard upper limit is absurdly high (over 9000PB) so just change the soft limit...especially since // if you aren't root and move the upper limit down, you need root to move it back up if (newMax.HasValue) { Interop.Sys.RLimit limits = new Interop.Sys.RLimit() { CurrentLimit = (ulong)newMax.Value.ToInt64() }; int result = Interop.Sys.SetRLimit(Interop.Sys.RlimitResources.RLIMIT_RSS, ref limits); if (result != 0) { throw new System.ComponentModel.Win32Exception(SR.RUsageFailure); } // Try to grab the actual value, in case the OS decides to fudge the numbers result = Interop.Sys.GetRLimit(Interop.Sys.RlimitResources.RLIMIT_RSS, out limits); if (result == 0) { resultingMax = new IntPtr((long)limits.CurrentLimit); } } }
/// <summary>Sets one or both of the minimum and maximum working set limits.</summary> /// <param name="newMin">The new minimum working set limit, or null not to change it.</param> /// <param name="newMax">The new maximum working set limit, or null not to change it.</param> /// <param name="resultingMin">The resulting minimum working set limit after any changes applied.</param> /// <param name="resultingMax">The resulting maximum working set limit after any changes applied.</param> private void SetWorkingSetLimitsCore(IntPtr? newMin, IntPtr? newMax, out IntPtr resultingMin, out IntPtr resultingMax) { // We can only do this for the current process on OS X if (_processId != Interop.Sys.GetPid()) throw new PlatformNotSupportedException(SR.OsxExternalProcessWorkingSetNotSupported); // There isn't a way to set the minimum working set, so throw an exception here if (newMin.HasValue) { throw new PlatformNotSupportedException(SR.MinimumWorkingSetNotSupported); } // The minimum resident set will always be 0, default the resulting max to 0 until we set it (to make the compiler happy) resultingMin = IntPtr.Zero; resultingMax = IntPtr.Zero; // The default hard upper limit is absurdly high (over 9000PB) so just change the soft limit...especially since // if you aren't root and move the upper limit down, you need root to move it back up if (newMax.HasValue) { Interop.Sys.RLimit limits = new Interop.Sys.RLimit() { CurrentLimit = (ulong)newMax.Value.ToInt64() }; int result = Interop.Sys.SetRLimit(Interop.Sys.RlimitResources.RLIMIT_RSS, ref limits); if (result != 0) { throw new System.ComponentModel.Win32Exception(SR.RUsageFailure); } // Try to grab the actual value, in case the OS decides to fudge the numbers result = Interop.Sys.GetRLimit(Interop.Sys.RlimitResources.RLIMIT_RSS, out limits); if (result == 0) resultingMax = new IntPtr((long)limits.CurrentLimit); } }