7
7
using System . Text ;
8
8
using System . Threading ;
9
9
using System . Threading . Tasks ;
10
- using System . Runtime . InteropServices ;
11
10
12
11
namespace System . IO
13
12
{
@@ -299,7 +298,10 @@ private WatchedDirectory AddDirectoryWatchUnlocked(WatchedDirectory parent, stri
299
298
300
299
// Add a watch for the full path. If the path is already being watched, this will return
301
300
// the existing descriptor. This works even in the case of a rename.
302
- int wd = ( int ) SysCall ( fd => Interop . libc . inotify_add_watch ( fd , fullPath , ( uint ) _notifyFilters ) ) ;
301
+ int wd = ( int ) SysCall (
302
+ ( fd , path , thisRef ) => Interop . libc . inotify_add_watch ( fd , path , ( uint ) thisRef . _notifyFilters ) ,
303
+ fullPath ,
304
+ this ) ;
303
305
304
306
// Then store the path information into our map.
305
307
WatchedDirectory directoryEntry ;
@@ -401,15 +403,15 @@ private void RemoveWatchedDirectoryUnlocked(WatchedDirectory directoryEntry, boo
401
403
// And if the caller has requested, remove the associated inotify watch.
402
404
if ( removeInotify )
403
405
{
404
- SysCall ( fd =>
406
+ SysCall ( ( fd , dirEntry , _ ) =>
405
407
{
406
408
// Remove the inotify watch. This could fail if our state has become inconsistent
407
409
// with the state of the world (e.g. due to lost events). So we don't want failures
408
410
// to throw exceptions, but we do assert to detect coding problems during debugging.
409
- long result = Interop . libc . inotify_rm_watch ( fd , directoryEntry . WatchDescriptor ) ;
411
+ long result = Interop . libc . inotify_rm_watch ( fd , dirEntry . WatchDescriptor ) ;
410
412
Debug . Assert ( result >= 0 ) ;
411
413
return 0 ;
412
- } ) ;
414
+ } , directoryEntry , 0 ) ;
413
415
}
414
416
}
415
417
@@ -423,14 +425,14 @@ private void CancellationCallback()
423
425
{
424
426
// Remove all watches (inotiy_rm_watch) and clear out the map.
425
427
// No additional watches will be added after this point.
426
- SysCall ( fd => {
427
- foreach ( int wd in _wdToPathMap . Keys )
428
+ SysCall ( ( fd , thisRef , _ ) => {
429
+ foreach ( int wd in thisRef . _wdToPathMap . Keys )
428
430
{
429
431
int result = Interop . libc . inotify_rm_watch ( fd , wd ) ;
430
432
Debug . Assert ( result >= 0 ) ; // ignore errors; they're non-fatal, but they also shouldn't happen
431
433
}
432
434
return 0 ;
433
- } ) ;
435
+ } , this , 0 ) ;
434
436
_wdToPathMap . Clear ( ) ;
435
437
}
436
438
}
@@ -628,15 +630,15 @@ private bool TryReadEvent(out NotifyEvent notifyEvent)
628
630
{
629
631
try
630
632
{
631
- _bufferAvailable = ( int ) SysCall ( fd => {
633
+ _bufferAvailable = ( int ) SysCall ( ( fd , thisRef , _ ) => {
632
634
long result ;
633
- fixed ( byte * buf = _buffer )
635
+ fixed ( byte * buf = thisRef . _buffer )
634
636
{
635
- result = ( long ) Interop . libc . read ( fd , buf , ( IntPtr ) _buffer . Length ) ;
637
+ result = ( long ) Interop . libc . read ( fd , buf , ( IntPtr ) thisRef . _buffer . Length ) ;
636
638
}
637
- Debug . Assert ( result <= _buffer . Length ) ;
639
+ Debug . Assert ( result <= thisRef . _buffer . Length ) ;
638
640
return result ;
639
- } ) ;
641
+ } , this , 0 ) ;
640
642
}
641
643
catch ( ArgumentException )
642
644
{
@@ -710,10 +712,15 @@ private string ReadName(int position, int nameLength)
710
712
/// and less than zero on failure. In the case of failure, errno is expected to
711
713
/// be set to the relevant error code.
712
714
/// </summary>
713
- /// <param name="handle">The SafeFileHandle that wraps the file descriptor to use with the system call.</param>
714
715
/// <param name="sysCall">A delegate that invokes the system call. It's passed the associated file descriptor and should return the result.</param>
716
+ /// <param name="arg1">The first argument to be passed to the system call, after the file descriptor.</param>
717
+ /// <param name="arg2">The second argument to be passed to the system call.</param>
715
718
/// <returns>The return value of the system call.</returns>
716
- private long SysCall ( Func < int , long > sysCall )
719
+ /// <remarks>
720
+ /// Arguments are expected to be passed via <paramref name="arg1"/> and <paramref name="arg2"/>
721
+ /// so as to avoid delegate and closure allocations at the call sites.
722
+ /// </remarks>
723
+ private long SysCall < TArg1 , TArg2 > ( Func < int , TArg1 , TArg2 , long > sysCall , TArg1 arg1 , TArg2 arg2 )
717
724
{
718
725
bool gotRefOnHandle = false ;
719
726
try
@@ -726,7 +733,7 @@ private long SysCall(Func<int, long> sysCall)
726
733
Debug . Assert ( fd >= 0 ) ;
727
734
728
735
long result ;
729
- while ( Interop . CheckIo ( result = sysCall ( fd ) , isDirectory : true ) ) ;
736
+ while ( Interop . CheckIo ( result = sysCall ( fd , arg1 , arg2 ) , isDirectory : true ) ) ;
730
737
return result ;
731
738
}
732
739
finally
0 commit comments