runtime: Getting file descriptor count on macOS throws
Description
A known way to get the file descriptor count on macOS is by using /dev/fd
. Here is an example implementation in Rust.
The problem is that some file descriptors listed under /dev/fd
are not stat
-able, so they will fail when queried. One example is kqueue
s.
Reproduction Steps
Directory.EnumerateFileSystemEntries("/dev/fd").Count();
on macOS.
Expected behavior
The number of open file descriptors.
Actual behavior
C# > Directory.EnumerateFileSystemEntries("/dev/fd").Count();
╭─❌─────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╮
│ System.UnauthorizedAccessException: Access to the path '/dev/fd/5' is denied. │
│ ---> System.IO.IOException: Bad file descriptor │
│ --- End of inner exception stack trace --- │
│ at System.IO.FileStatus.ThrowOnCacheInitializationError(ReadOnlySpan`1 path) │
│ at System.IO.Enumeration.FileSystemEntry.get_IsSymbolicLink() │
│ at System.IO.Enumeration.FileSystemEntry.Initialize(FileSystemEntry& entry, DirectoryEntry directoryEntry, ReadOnlySpan`1 │
│ directory, ReadOnlySpan`1 rootDirectory, ReadOnlySpan`1 originalRootDirectory, Span`1 pathBuffer) │
│ at System.IO.Enumeration.FileSystemEnumerator`1.MoveNext() │
│ at System.Linq.Enumerable.Count[TSource](IEnumerable`1 source) │
│ at Submission#3.<<Initialize>>d__0.MoveNext() │
│ --- End of stack trace from previous location --- │
│ at Microsoft.CodeAnalysis.Scripting.ScriptExecutionState.RunSubmissionsAsync[TResult](ImmutableArray`1 precedingExecutors, Func`2 │
│ currentExecutor, StrongBox`1 exceptionHolderOpt, Func`2 catchExceptionOpt, CancellationToken cancellationToken) │
╰────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────╯
Regression?
Not sure if it’s a regression.
Known Workarounds
Manually PInvoke opendir
and then iterate with readdir
.
Configuration
dotnet 6.0.101, macOS 10.14+, x64 and arm64
Other information
No response
About this issue
- Original URL
- State: closed
- Created 2 years ago
- Comments: 20 (19 by maintainers)
Thank you, @Therzok. Since you have the (albeit unfortunate) workaround in place are are unblocked, and the backport isn’t 100% straightforward/contained, I’m not inclined to backport the fix. If others report the same issue in a way that they are blocked, that would encourage the backport though.
Hey @jeffhandley , thanks for the response!
I work on Visual Studio for Mac. We use this API to check whether we are close to hitting the ridiculously low limit of open file handles (256). There currently is a workaround in place where we count filescriptors in C - did not have one at the time.
I’m not sure if publishing a release on top of .NET 7.0 is an option right now.
Testing on net7
Console.WriteLine(Directory.EnumerateFileSystemEntries("/dev/fd").Count());
Yields
38
which is correct and matcheslsof -p
.lsof -p output
Closing as we added a workaround on our end, but having this API work in net6 would be nice.
It was introduced in https://github.com/dotnet/runtime/pull/52235
Yes, and also specific to the special directory of
/dev/fd
which represents the open file descriptors of the process. One of these file descriptors doesn’t supportstat
probably because its something special that is not ordinarily found in a real file system.https://github.com/dotnet/runtime/pull/60214 is a bugfix PR, it doesn’t do much refactoring. There are little things to be left out. I think you should take it as a whole.
There was a separate PR to refactor some things: https://github.com/dotnet/runtime/pull/62721.
Yes, this was refactored (and fixed) in https://github.com/dotnet/runtime/pull/60214. One thing that was missing is
continueOnError: true
forIsSymbolicLink
which is the cause for this exception.