Skip to content
This repository was archived by the owner on Jan 23, 2023. It is now read-only.

Conversation

@wfurt
Copy link
Member

@wfurt wfurt commented Sep 11, 2019

When even stream is created it needs to be properly cleaned up in order to close associated file handles and associated resources.
https://developer.apple.com/library/archive/documentation/Darwin/Conceptual/FSEvents_ProgGuide/UsingtheFSEventsFramework/UsingtheFSEventsFramework.html

We need to call FSEventStreamInvalidate and FSEventStreamRelease. Conveniently, it seems like this is all encapsulated in SafeEventStreamHandle's ReleaseHandle.

I run repro code from #40888 in loop and I did not see any descriptor leak. (The leak was pretty obvious without the fix)
I may spent more time tomorrow thinking if there is some good way how to add test but it may be tricky to verify OS resources.

fixes #40888

@Therzok
Copy link
Contributor

Therzok commented Sep 11, 2019

You can probably use CFGetRetainCount before releasing the last ref to validate it's 1.

@Therzok
Copy link
Contributor

Therzok commented Sep 11, 2019

Can confirm, mono side is fixed too 🎉

@danmoseley danmoseley added this to the 5.0 milestone Sep 12, 2019
@danmoseley
Copy link
Member

For 2.2 we'll need the usual PR with template, and mail to netcoreship. Thanks @wfurt.

@wfurt
Copy link
Member Author

wfurt commented Sep 16, 2019

test failures in System.Security.Cryptography are unrelated. Please let me know if there is anything outstanding @JeremyKuhne and @stephentoub.
I would like to get this into master and work on 2.x port.

@danmoseley
Copy link
Member

@carlossanlop perhaps you can review?

{
_cancellation = null;
token.Cancel();
token.Dispose();
Copy link

@carlossanlop carlossanlop Sep 27, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@wfurt I have a question: why do we only cancel and dispose the token here? The RunningInstance class received a copy of this token in its constructor, so why not perform these two actions inside CancellationCallback too? (follow up of Marius' question).

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

CancellationCallback() did not do anything with the token. It is StartRaisingEvents() where token was created and symmetrically StopRaisingEvents() where token is destroyed. Existing _cancellation = null should be sufficient IMHO to dispose token. I only add explicit Dispose() call to make it explicit and not wait for GC. I did not want to introduce different life cycle for the token and worry about what changed.

Copy link

@carlossanlop carlossanlop left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Left a question.
Would it make sense to add unit tests to verify this change?
The build failed. Do you know what was the cause?

@stephentoub
Copy link
Member

@wfurt, what's the status of this PR? Can it be made ready to merge, or closed?

@wfurt
Copy link
Member Author

wfurt commented Oct 21, 2019

Tests are failing in System.Security.Cryptography on OSX and x86 Windows. That seems unrelated to this change.

As far as the test I could not come up with one I would like. Best I think I can do is to create and destroy watcher in loop and make loop count bigger than default handle limit. But CI does manipulate limits AFAIK and well as that may differ across systems. Also tests trying to exhaust system resources are potentially dangerous. Let me know @carlossanlop if you have suggestions.

@carlossanlop
Copy link

As far as the test I could not come up with one I would like. Best I think I can do is to create and destroy watcher in loop and make loop count bigger than default handle limit. But CI does manipulate limits AFAIK and well as that may differ across systems. Also tests trying to exhaust system resources are potentially dangerous. Let me know @carlossanlop if you have suggestions.

I noticed the original issue #40888 has a small file watcher test here: https://github.com/mrward/test-file-watcher-dispose/blob/master/Program.cs

Would it make sense to write a unit test that looks somewhat like in that code, or would we encounter the CI limit you mentioned, @wfurt ?

@Therzok
Copy link
Contributor

Therzok commented Oct 24, 2019

I know this is icky, but what if we had something like:

var streamHandle = // use reflection to get the native handle
var ref = new WeakReference (streamHandle);
...
// do the test

Assert.AreEqual (1, CFRetainCount (streamHandle.Handle));

// dispose the watcher and wait for GC to run

Assert.IsNull (ref.Target);

@wfurt
Copy link
Member Author

wfurt commented Oct 24, 2019

I added test and verified it fails in CI without the fix same way as #40888
https://helix.dot.net/api/2019-06-17/jobs/7d88982f-e479-45e6-b82f-36c65c3e89bd/workitems/System.IO.FileSystem.Watcher.Tests/console

   System.IO.Tests.FileSystemWatcherTests_Unix.Watcher_Usage_DoesNotLeak [STARTING]
Limits are 10240 and 18446744073709551615
File open failed at 10067 with Too many open files
    System.IO.Tests.FileSystemWatcherTests_Unix.Watcher_Usage_DoesNotLeak [FINISHED] Time: 0.6855082s

I use new trick to push test to the and making sure that it does not run with any other tests.
That allows to use XUnit output helper . (which is not available for "remote" exec in separate process.

@wfurt
Copy link
Member Author

wfurt commented Oct 24, 2019

/azp run

@azure-pipelines
Copy link

Azure Pipelines successfully started running 4 pipeline(s).

Copy link

@carlossanlop carlossanlop left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@wfurt I left a small nit comment.
Also, there were failures in musl and in outerloop. Would you mind taking a look?

@wfurt
Copy link
Member Author

wfurt commented Nov 4, 2019

/azp run

@azure-pipelines
Copy link

Azure Pipelines successfully started running 4 pipeline(s).

@wfurt
Copy link
Member Author

wfurt commented Nov 5, 2019

/azp run

@azure-pipelines
Copy link

Azure Pipelines successfully started running 4 pipeline(s).

@wfurt
Copy link
Member Author

wfurt commented Nov 5, 2019

System.Runtime tests failures are unrelated. They also fail in master. The Musl run did not producer any reasonable output., That seems like infrastructure problem.

@maryamariyan
Copy link

Thank you for your contribution. As announced in dotnet/coreclr#27549 this repository will be moving to dotnet/runtime on November 13. If you would like to continue working on this PR after this date, the easiest way to move the change to dotnet/runtime is:

  1. In your corefx repository clone, create patch by running git format-patch origin
  2. In your runtime repository clone, apply the patch by running git apply --directory src/corefx <path to the patch created in step 1>

Copy link

@carlossanlop carlossanlop left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for checking the unit tests. I don't have any more input.

@wfurt wfurt merged commit dd4fa0d into dotnet:master Nov 7, 2019
@wfurt wfurt deleted the watcher_40888 branch November 7, 2019 02:09
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Disposing the FileSystemWatcher does not close associated file descriptors

7 participants