diff --git a/src/coreclr/System.Private.CoreLib/System.Private.CoreLib.csproj b/src/coreclr/System.Private.CoreLib/System.Private.CoreLib.csproj
index adf2908c581ab9..036936d4f58f9d 100644
--- a/src/coreclr/System.Private.CoreLib/System.Private.CoreLib.csproj
+++ b/src/coreclr/System.Private.CoreLib/System.Private.CoreLib.csproj
@@ -143,7 +143,7 @@
-
+
@@ -333,9 +333,9 @@
+ Outputs="@(EventingSourceFile)"
+ DependsOnTargets="FindPython"
+ BeforeTargets="BeforeCompile">
diff --git a/src/coreclr/System.Private.CoreLib/src/System/GC.cs b/src/coreclr/System.Private.CoreLib/src/System/GC.CoreCLR.cs
similarity index 100%
rename from src/coreclr/System.Private.CoreLib/src/System/GC.cs
rename to src/coreclr/System.Private.CoreLib/src/System/GC.CoreCLR.cs
diff --git a/src/coreclr/nativeaot/System.Private.CoreLib/src/System.Private.CoreLib.csproj b/src/coreclr/nativeaot/System.Private.CoreLib/src/System.Private.CoreLib.csproj
index 523b6b8c3a814d..2b562e55213dbc 100644
--- a/src/coreclr/nativeaot/System.Private.CoreLib/src/System.Private.CoreLib.csproj
+++ b/src/coreclr/nativeaot/System.Private.CoreLib/src/System.Private.CoreLib.csproj
@@ -169,7 +169,7 @@
-
+
diff --git a/src/coreclr/nativeaot/System.Private.CoreLib/src/System/GC.cs b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/GC.CoreRT.cs
similarity index 99%
rename from src/coreclr/nativeaot/System.Private.CoreLib/src/System/GC.cs
rename to src/coreclr/nativeaot/System.Private.CoreLib/src/System/GC.CoreRT.cs
index c9578dfee08036..783f75f41ef6a4 100644
--- a/src/coreclr/nativeaot/System.Private.CoreLib/src/System/GC.cs
+++ b/src/coreclr/nativeaot/System.Private.CoreLib/src/System/GC.CoreRT.cs
@@ -58,7 +58,7 @@ internal enum EndNoGCRegionStatus
AllocationExceeded = 3
}
- public static class GC
+ public static partial class GC
{
public static int GetGeneration(object obj)
{
diff --git a/src/libraries/System.ComponentModel.Annotations/ref/System.ComponentModel.Annotations.cs b/src/libraries/System.ComponentModel.Annotations/ref/System.ComponentModel.Annotations.cs
index cc7dfb6120ef18..c6a9b98a8eba03 100644
--- a/src/libraries/System.ComponentModel.Annotations/ref/System.ComponentModel.Annotations.cs
+++ b/src/libraries/System.ComponentModel.Annotations/ref/System.ComponentModel.Annotations.cs
@@ -237,6 +237,7 @@ public partial class RegularExpressionAttribute : System.ComponentModel.DataAnno
{
public RegularExpressionAttribute([System.Diagnostics.CodeAnalysis.StringSyntaxAttribute(System.Diagnostics.CodeAnalysis.StringSyntaxAttribute.Regex)] string pattern) { }
public int MatchTimeoutInMilliseconds { get { throw null; } set { } }
+ public System.TimeSpan MatchTimeout { get { throw null; } }
public string Pattern { get { throw null; } }
public override string FormatErrorMessage(string name) { throw null; }
public override bool IsValid(object? value) { throw null; }
diff --git a/src/libraries/System.ComponentModel.Annotations/src/System/ComponentModel/DataAnnotations/RegularExpressionAttribute.cs b/src/libraries/System.ComponentModel.Annotations/src/System/ComponentModel/DataAnnotations/RegularExpressionAttribute.cs
index cf2ec8a7697c20..b21d843d060f7d 100644
--- a/src/libraries/System.ComponentModel.Annotations/src/System/ComponentModel/DataAnnotations/RegularExpressionAttribute.cs
+++ b/src/libraries/System.ComponentModel.Annotations/src/System/ComponentModel/DataAnnotations/RegularExpressionAttribute.cs
@@ -31,6 +31,11 @@ public RegularExpressionAttribute([StringSyntax(StringSyntaxAttribute.Regex)] st
///
public int MatchTimeoutInMilliseconds { get; set; }
+ ///
+ /// Gets the timeout to use when matching the regular expression pattern
+ ///
+ public TimeSpan MatchTimeout => TimeSpan.FromMilliseconds(MatchTimeoutInMilliseconds);
+
///
/// Gets the regular expression pattern to use
///
diff --git a/src/libraries/System.ComponentModel.Annotations/tests/System.ComponentModel.Annotations.Tests.csproj b/src/libraries/System.ComponentModel.Annotations/tests/System.ComponentModel.Annotations.Tests.csproj
index d4e20cee535409..ea79a73bf74a66 100644
--- a/src/libraries/System.ComponentModel.Annotations/tests/System.ComponentModel.Annotations.Tests.csproj
+++ b/src/libraries/System.ComponentModel.Annotations/tests/System.ComponentModel.Annotations.Tests.csproj
@@ -28,6 +28,7 @@
+
diff --git a/src/libraries/System.ComponentModel.Annotations/tests/System/ComponentModel/DataAnnotations/RegularExpressionAttributeTests.Core.cs b/src/libraries/System.ComponentModel.Annotations/tests/System/ComponentModel/DataAnnotations/RegularExpressionAttributeTests.Core.cs
new file mode 100644
index 00000000000000..78bb2e5e028fd6
--- /dev/null
+++ b/src/libraries/System.ComponentModel.Annotations/tests/System/ComponentModel/DataAnnotations/RegularExpressionAttributeTests.Core.cs
@@ -0,0 +1,20 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+
+using System.ComponentModel.DataAnnotations;
+using Xunit;
+
+namespace System.ComponentModel.Annotations.Tests.System.ComponentModel.DataAnnotations
+{
+ public sealed partial class RegularExpressionAttributeTests
+ {
+ [Theory]
+ [InlineData(12345)]
+ [InlineData(-1)]
+ public static void MatchTimeout_Get_ReturnsExpected(int newValue)
+ {
+ var attribute = new RegularExpressionAttribute("SomePattern") { MatchTimeoutInMilliseconds = newValue };
+ Assert.Equal(TimeSpan.FromMilliseconds(newValue), attribute.MatchTimeout);
+ }
+ }
+}
diff --git a/src/libraries/System.ComponentModel.Annotations/tests/System/ComponentModel/DataAnnotations/RegularExpressionAttributeTests.cs b/src/libraries/System.ComponentModel.Annotations/tests/System/ComponentModel/DataAnnotations/RegularExpressionAttributeTests.cs
index 78ac307027f371..45a9da9712f262 100644
--- a/src/libraries/System.ComponentModel.Annotations/tests/System/ComponentModel/DataAnnotations/RegularExpressionAttributeTests.cs
+++ b/src/libraries/System.ComponentModel.Annotations/tests/System/ComponentModel/DataAnnotations/RegularExpressionAttributeTests.cs
@@ -7,7 +7,7 @@
namespace System.ComponentModel.DataAnnotations.Tests
{
- public class RegularExpressionAttributeTests : ValidationAttributeTestBase
+ public sealed partial class RegularExpressionAttributeTests : ValidationAttributeTestBase
{
protected override IEnumerable ValidValues()
{
diff --git a/src/libraries/System.ComponentModel.TypeConverter/ref/System.ComponentModel.TypeConverter.cs b/src/libraries/System.ComponentModel.TypeConverter/ref/System.ComponentModel.TypeConverter.cs
index f1a8f6f698f15c..04d75256cb4384 100644
--- a/src/libraries/System.ComponentModel.TypeConverter/ref/System.ComponentModel.TypeConverter.cs
+++ b/src/libraries/System.ComponentModel.TypeConverter/ref/System.ComponentModel.TypeConverter.cs
@@ -2338,6 +2338,7 @@ public partial class Timer : System.ComponentModel.Component, System.ComponentMo
{
public Timer() { }
public Timer(double interval) { }
+ public Timer(System.TimeSpan interval) { }
[System.ComponentModel.DefaultValueAttribute(true)]
public bool AutoReset { get { throw null; } set { } }
[System.ComponentModel.DefaultValueAttribute(false)]
diff --git a/src/libraries/System.ComponentModel.TypeConverter/src/System/Timers/Timer.cs b/src/libraries/System.ComponentModel.TypeConverter/src/System/Timers/Timer.cs
index 0dc77a54ccda65..826257de2e7cf0 100644
--- a/src/libraries/System.ComponentModel.TypeConverter/src/System/Timers/Timer.cs
+++ b/src/libraries/System.ComponentModel.TypeConverter/src/System/Timers/Timer.cs
@@ -59,6 +59,13 @@ public Timer(double interval) : this()
_interval = (int)roundedInterval;
}
+ ///
+ /// Initializes a new instance of the class, setting the property to the specified period.
+ ///
+ public Timer(TimeSpan interval) : this(interval.TotalMilliseconds)
+ {
+ }
+
///
/// Gets or sets a value indicating whether the Timer raises the Tick event each time the specified
/// Interval has elapsed, when Enabled is set to true.
diff --git a/src/libraries/System.Diagnostics.Process/ref/System.Diagnostics.Process.cs b/src/libraries/System.Diagnostics.Process/ref/System.Diagnostics.Process.cs
index d6975bd7274153..5dcecba7702110 100644
--- a/src/libraries/System.Diagnostics.Process/ref/System.Diagnostics.Process.cs
+++ b/src/libraries/System.Diagnostics.Process/ref/System.Diagnostics.Process.cs
@@ -168,9 +168,11 @@ public void Refresh() { }
public override string ToString() { throw null; }
public void WaitForExit() { }
public bool WaitForExit(int milliseconds) { throw null; }
+ public bool WaitForExit(System.TimeSpan timeout) { throw null; }
public System.Threading.Tasks.Task WaitForExitAsync(System.Threading.CancellationToken cancellationToken = default(System.Threading.CancellationToken)) { throw null; }
public bool WaitForInputIdle() { throw null; }
public bool WaitForInputIdle(int milliseconds) { throw null; }
+ public bool WaitForInputIdle(System.TimeSpan timeout) { throw null; }
}
[System.ComponentModel.DesignerAttribute("System.Diagnostics.Design.ProcessModuleDesigner, System.Design, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a")]
public partial class ProcessModule : System.ComponentModel.Component
diff --git a/src/libraries/System.Diagnostics.Process/src/System/Diagnostics/Process.cs b/src/libraries/System.Diagnostics.Process/src/System/Diagnostics/Process.cs
index 2aeee088c509e9..7e4c4953f4d057 100644
--- a/src/libraries/System.Diagnostics.Process/src/System/Diagnostics/Process.cs
+++ b/src/libraries/System.Diagnostics.Process/src/System/Diagnostics/Process.cs
@@ -826,6 +826,39 @@ public bool WaitForInputIdle(int milliseconds)
return WaitForInputIdleCore(milliseconds);
}
+ ///
+ /// Causes the component to wait the specified for the associated process to enter an idle state.
+ /// This overload applies only to processes with a user interface and, therefore, a message loop.
+ ///
+ /// The amount of time, in milliseconds, to wait for the associated process to become idle.
+ /// if the associated process has reached an idle state; otherwise, .
+ ///
+ /// The process does not have a graphical interface.
+ ///
+ /// -or-
+ ///
+ /// An unknown error occurred. The process failed to enter an idle state.
+ ///
+ /// -or-
+ ///
+ /// The process has already exited.
+ ///
+ /// -or-
+ ///
+ /// No process is associated with this object.
+ ///
+ ///
+ /// Use to force the processing of your application
+ /// to wait until the message loop has returned to the idle state.
+ /// When a process with a user interface is executing, its message loop executes every time
+ /// a Windows message is sent to the process by the operating system.
+ /// The process then returns to the message loop. A process is said to be in an idle state
+ /// when it is waiting for messages inside of a message loop.
+ /// This state is useful, for example, when your application needs to wait for a starting process
+ /// to finish creating its main window before the application communicates with that window.
+ ///
+ public bool WaitForInputIdle(TimeSpan timeout) => WaitForInputIdle(ToTimeoutMilliseconds(timeout));
+
public ISynchronizeInvoke? SynchronizingObject { get; set; }
///
@@ -1414,6 +1447,22 @@ public bool WaitForExit(int milliseconds)
return exited;
}
+ ///
+ /// Instructs the Process component to wait the specified number of milliseconds for
+ /// the associated process to exit.
+ ///
+ public bool WaitForExit(TimeSpan timeout) => WaitForExit(ToTimeoutMilliseconds(timeout));
+
+ private static int ToTimeoutMilliseconds(TimeSpan timeout)
+ {
+ long totalMilliseconds = (long)timeout.TotalMilliseconds;
+ if (totalMilliseconds < -1 || totalMilliseconds > int.MaxValue)
+ {
+ throw new ArgumentOutOfRangeException(nameof(timeout));
+ }
+ return (int)totalMilliseconds;
+ }
+
///
/// Instructs the Process component to wait for the associated process to exit, or
/// for the to be canceled.
diff --git a/src/libraries/System.Diagnostics.Process/tests/ProcessTests.cs b/src/libraries/System.Diagnostics.Process/tests/ProcessTests.cs
index 441036b8380fe2..90dc6a8b4ba8f6 100644
--- a/src/libraries/System.Diagnostics.Process/tests/ProcessTests.cs
+++ b/src/libraries/System.Diagnostics.Process/tests/ProcessTests.cs
@@ -74,6 +74,15 @@ private void AssertNonZeroAllZeroDarwin(long value)
}
}
+ [Theory]
+ [InlineData(-2)]
+ [InlineData((long)int.MaxValue + 1)]
+ public void TestWaitForExitValidation(long milliseconds)
+ {
+ CreateDefaultProcess();
+ Assert.Throws("timeout", () => _process.WaitForExit(TimeSpan.FromMilliseconds(milliseconds)));
+ }
+
[ConditionalFact(typeof(RemoteExecutor), nameof(RemoteExecutor.IsSupported))]
[PlatformSpecific(TestPlatforms.Windows)] // Expected behavior varies on Windows and Unix
public void TestBasePriorityOnWindows()
diff --git a/src/libraries/System.IO.FileSystem.Watcher/ref/System.IO.FileSystem.Watcher.cs b/src/libraries/System.IO.FileSystem.Watcher/ref/System.IO.FileSystem.Watcher.cs
index 1f926bff17f315..d640d89cfe3888 100644
--- a/src/libraries/System.IO.FileSystem.Watcher/ref/System.IO.FileSystem.Watcher.cs
+++ b/src/libraries/System.IO.FileSystem.Watcher/ref/System.IO.FileSystem.Watcher.cs
@@ -50,6 +50,7 @@ protected void OnError(System.IO.ErrorEventArgs e) { }
protected void OnRenamed(System.IO.RenamedEventArgs e) { }
public System.IO.WaitForChangedResult WaitForChanged(System.IO.WatcherChangeTypes changeType) { throw null; }
public System.IO.WaitForChangedResult WaitForChanged(System.IO.WatcherChangeTypes changeType, int timeout) { throw null; }
+ public System.IO.WaitForChangedResult WaitForChanged(System.IO.WatcherChangeTypes changeType, System.TimeSpan timeout) { throw null; }
}
public partial class InternalBufferOverflowException : System.SystemException
{
diff --git a/src/libraries/System.IO.FileSystem.Watcher/src/System/IO/FileSystemWatcher.cs b/src/libraries/System.IO.FileSystem.Watcher/src/System/IO/FileSystemWatcher.cs
index fd9c2ce4fa6baf..654bd3ab856c8f 100644
--- a/src/libraries/System.IO.FileSystem.Watcher/src/System/IO/FileSystemWatcher.cs
+++ b/src/libraries/System.IO.FileSystem.Watcher/src/System/IO/FileSystemWatcher.cs
@@ -618,6 +618,19 @@ public WaitForChangedResult WaitForChanged(WatcherChangeTypes changeType, int ti
WaitForChangedResult.TimedOutResult;
}
+ public WaitForChangedResult WaitForChanged(WatcherChangeTypes changeType, TimeSpan timeout) =>
+ WaitForChanged(changeType, ToTimeoutMilliseconds(timeout));
+
+ private static int ToTimeoutMilliseconds(TimeSpan timeout)
+ {
+ long totalMilliseconds = (long)timeout.TotalMilliseconds;
+ if (totalMilliseconds < -1 || totalMilliseconds > int.MaxValue)
+ {
+ throw new ArgumentOutOfRangeException(nameof(timeout));
+ }
+ return (int)totalMilliseconds;
+ }
+
///
/// Stops and starts this object.
///
diff --git a/src/libraries/System.IO.FileSystem.Watcher/tests/FileSystemWatcher.WaitForChanged.cs b/src/libraries/System.IO.FileSystem.Watcher/tests/FileSystemWatcher.WaitForChanged.cs
index cce5f54469f2dd..f2558953d26086 100644
--- a/src/libraries/System.IO.FileSystem.Watcher/tests/FileSystemWatcher.WaitForChanged.cs
+++ b/src/libraries/System.IO.FileSystem.Watcher/tests/FileSystemWatcher.WaitForChanged.cs
@@ -76,50 +76,73 @@ public static void WaitForChangedResult_TimedOut_Roundtrip()
}
[Theory]
- [InlineData(false)]
- [InlineData(true)]
- public void ZeroTimeout_TimesOut(bool enabledBeforeWait)
+ [InlineData(-2)]
+ [InlineData((long)int.MaxValue + 1)]
+ public void TimeSpan_ArgumentValidation(long milliseconds)
+ {
+ TimeSpan timeout = TimeSpan.FromMilliseconds(milliseconds);
+ using var testDirectory = new TempDirectory(GetTestFilePath());
+ using var _ = new TempDirectory(Path.Combine(testDirectory.Path, GetTestFileName()));
+ using var fsw = new FileSystemWatcher(testDirectory.Path);
+
+ Assert.Throws("timeout", () => fsw.WaitForChanged(WatcherChangeTypes.All, timeout));
+ }
+
+ [Theory]
+ [InlineData(false, true)]
+ [InlineData(true, false)]
+ public void ZeroTimeout_TimesOut(bool enabledBeforeWait, bool useTimeSpan)
{
using (var testDirectory = new TempDirectory(GetTestFilePath()))
using (var dir = new TempDirectory(Path.Combine(testDirectory.Path, GetTestFileName())))
using (var fsw = new FileSystemWatcher(testDirectory.Path))
{
if (enabledBeforeWait) fsw.EnableRaisingEvents = true;
- AssertTimedOut(fsw.WaitForChanged(WatcherChangeTypes.All, 0));
+
+ const int timeoutMilliseconds = 0;
+ AssertTimedOut(useTimeSpan
+ ? fsw.WaitForChanged(WatcherChangeTypes.All, TimeSpan.FromMilliseconds(timeoutMilliseconds))
+ : fsw.WaitForChanged(WatcherChangeTypes.All, timeoutMilliseconds));
Assert.Equal(enabledBeforeWait, fsw.EnableRaisingEvents);
}
}
[Theory]
- [InlineData(false)]
- [InlineData(true)]
- public void NonZeroTimeout_NoEvents_TimesOut(bool enabledBeforeWait)
+ [InlineData(false, false)]
+ [InlineData(true, true)]
+ public void NonZeroTimeout_NoEvents_TimesOut(bool enabledBeforeWait, bool useTimeSpan)
{
using (var testDirectory = new TempDirectory(GetTestFilePath()))
using (var dir = new TempDirectory(Path.Combine(testDirectory.Path, GetTestFileName())))
using (var fsw = new FileSystemWatcher(testDirectory.Path))
{
if (enabledBeforeWait) fsw.EnableRaisingEvents = true;
- AssertTimedOut(fsw.WaitForChanged(0, 1));
+ const int timeoutMilliseconds = 1;
+ AssertTimedOut(useTimeSpan
+ ? fsw.WaitForChanged(0, TimeSpan.FromMilliseconds(timeoutMilliseconds))
+ : fsw.WaitForChanged(0, timeoutMilliseconds));
Assert.Equal(enabledBeforeWait, fsw.EnableRaisingEvents);
}
}
[Theory]
- [InlineData(WatcherChangeTypes.Deleted, false)]
- [InlineData(WatcherChangeTypes.Created, true)]
- [InlineData(WatcherChangeTypes.Changed, false)]
- [InlineData(WatcherChangeTypes.Renamed, true)]
- [InlineData(WatcherChangeTypes.All, true)]
+ [InlineData(WatcherChangeTypes.Deleted, false, true)]
+ [InlineData(WatcherChangeTypes.Created, true, false)]
+ [InlineData(WatcherChangeTypes.Changed, false, true)]
+ [InlineData(WatcherChangeTypes.Renamed, true, false)]
+ [InlineData(WatcherChangeTypes.All, true, true)]
[ActiveIssue("https://github.com/dotnet/runtime/issues/58418", typeof(PlatformDetection), nameof(PlatformDetection.IsMacCatalyst), nameof(PlatformDetection.IsArm64Process))]
- public void NonZeroTimeout_NoActivity_TimesOut(WatcherChangeTypes changeType, bool enabledBeforeWait)
+ public void NonZeroTimeout_NoActivity_TimesOut(WatcherChangeTypes changeType, bool enabledBeforeWait, bool useTimeSpan)
{
using (var testDirectory = new TempDirectory(GetTestFilePath()))
using (var dir = new TempDirectory(Path.Combine(testDirectory.Path, GetTestFileName())))
using (var fsw = new FileSystemWatcher(testDirectory.Path))
{
if (enabledBeforeWait) fsw.EnableRaisingEvents = true;
- AssertTimedOut(fsw.WaitForChanged(changeType, 1));
+ const int timeoutMilliseconds = 1;
+ AssertTimedOut(useTimeSpan
+ ? fsw.WaitForChanged(changeType, TimeSpan.FromMilliseconds(timeoutMilliseconds))
+ : fsw.WaitForChanged(changeType, timeoutMilliseconds));
Assert.Equal(enabledBeforeWait, fsw.EnableRaisingEvents);
}
}
diff --git a/src/libraries/System.IO.Pipes/ref/System.IO.Pipes.cs b/src/libraries/System.IO.Pipes/ref/System.IO.Pipes.cs
index 3966988ecad2d1..a7432dbc5a2177 100644
--- a/src/libraries/System.IO.Pipes/ref/System.IO.Pipes.cs
+++ b/src/libraries/System.IO.Pipes/ref/System.IO.Pipes.cs
@@ -54,9 +54,11 @@ public sealed partial class NamedPipeClientStream : System.IO.Pipes.PipeStream
protected internal override void CheckPipePropertyOperations() { }
public void Connect() { }
public void Connect(int timeout) { }
+ public void Connect(System.TimeSpan timeout) { }
public System.Threading.Tasks.Task ConnectAsync() { throw null; }
public System.Threading.Tasks.Task ConnectAsync(int timeout) { throw null; }
public System.Threading.Tasks.Task ConnectAsync(int timeout, System.Threading.CancellationToken cancellationToken) { throw null; }
+ public System.Threading.Tasks.Task ConnectAsync(System.TimeSpan timeout, System.Threading.CancellationToken cancellationToken) { throw null; }
public System.Threading.Tasks.Task ConnectAsync(System.Threading.CancellationToken cancellationToken) { throw null; }
~NamedPipeClientStream() { }
}
diff --git a/src/libraries/System.IO.Pipes/src/System/IO/Pipes/NamedPipeClientStream.cs b/src/libraries/System.IO.Pipes/src/System/IO/Pipes/NamedPipeClientStream.cs
index 8a7a9213a76ffa..1667631bda0f67 100644
--- a/src/libraries/System.IO.Pipes/src/System/IO/Pipes/NamedPipeClientStream.cs
+++ b/src/libraries/System.IO.Pipes/src/System/IO/Pipes/NamedPipeClientStream.cs
@@ -125,6 +125,8 @@ public void Connect(int timeout)
ConnectInternal(timeout, CancellationToken.None, Environment.TickCount);
}
+ public void Connect(TimeSpan timeout) => Connect(ToTimeoutMilliseconds(timeout));
+
private void ConnectInternal(int timeout, CancellationToken cancellationToken, int startTime)
{
// This is the main connection loop. It will loop until the timeout expires.
@@ -193,6 +195,19 @@ public Task ConnectAsync(int timeout, CancellationToken cancellationToken)
return Task.Run(() => ConnectInternal(timeout, cancellationToken, startTime), cancellationToken);
}
+ public Task ConnectAsync(TimeSpan timeout, CancellationToken cancellationToken = default) =>
+ ConnectAsync(ToTimeoutMilliseconds(timeout), cancellationToken);
+
+ private static int ToTimeoutMilliseconds(TimeSpan timeout)
+ {
+ long totalMilliseconds = (long)timeout.TotalMilliseconds;
+ if (totalMilliseconds < -1 || totalMilliseconds > int.MaxValue)
+ {
+ throw new ArgumentOutOfRangeException(nameof(timeout));
+ }
+ return (int)totalMilliseconds;
+ }
+
// override because named pipe clients can't get/set properties when waiting to connect
// or broken
protected internal override void CheckPipePropertyOperations()
diff --git a/src/libraries/System.IO.Pipes/tests/NamedPipeTests/NamedPipeTest.CurrentUserOnly.Windows.cs b/src/libraries/System.IO.Pipes/tests/NamedPipeTests/NamedPipeTest.CurrentUserOnly.Windows.cs
index 439454502655d8..e4f9a045759a7c 100644
--- a/src/libraries/System.IO.Pipes/tests/NamedPipeTests/NamedPipeTest.CurrentUserOnly.Windows.cs
+++ b/src/libraries/System.IO.Pipes/tests/NamedPipeTests/NamedPipeTest.CurrentUserOnly.Windows.cs
@@ -162,12 +162,14 @@ public void Connection_UnderDifferentUsers_BehavesAsExpected(
}
[OuterLoop]
- [ConditionalFact(nameof(IsAdminOnSupportedWindowsVersions))]
- public void Allow_Connection_UnderDifferentUsers_ForClientReading()
+ [ConditionalTheory(nameof(IsAdminOnSupportedWindowsVersions))]
+ [InlineData(false)]
+ [InlineData(true)]
+ public void Allow_Connection_UnderDifferentUsers_ForClientReading(bool useTimeSpan)
{
string name = PipeStreamConformanceTests.GetUniquePipeName();
using (var server = new NamedPipeServerStream(
- name, PipeDirection.InOut, 1, PipeTransmissionMode.Byte, PipeOptions.Asynchronous))
+ name, PipeDirection.InOut, 1, PipeTransmissionMode.Byte, PipeOptions.Asynchronous))
{
Task serverTask = server.WaitForConnectionAsync(CancellationToken.None);
@@ -175,7 +177,14 @@ public void Allow_Connection_UnderDifferentUsers_ForClientReading()
{
using (var client = new NamedPipeClientStream(".", name, PipeDirection.In))
{
- client.Connect(10_000);
+ if (useTimeSpan)
+ {
+ client.Connect(TimeSpan.FromMilliseconds(10_000));
+ }
+ else
+ {
+ client.Connect(10_000);
+ }
}
});
diff --git a/src/libraries/System.IO.Pipes/tests/NamedPipeTests/NamedPipeTest.Specific.cs b/src/libraries/System.IO.Pipes/tests/NamedPipeTests/NamedPipeTest.Specific.cs
index 220be9d65ca8a8..64744e5a4e4fbb 100644
--- a/src/libraries/System.IO.Pipes/tests/NamedPipeTests/NamedPipeTest.Specific.cs
+++ b/src/libraries/System.IO.Pipes/tests/NamedPipeTests/NamedPipeTest.Specific.cs
@@ -23,6 +23,10 @@ public void InvalidConnectTimeout_Throws_ArgumentOutOfRangeException()
{
AssertExtensions.Throws("timeout", () => client.Connect(-111));
AssertExtensions.Throws("timeout", () => { client.ConnectAsync(-111); });
+ AssertExtensions.Throws("timeout", () => client.Connect(TimeSpan.FromMilliseconds(-2)));
+ AssertExtensions.Throws("timeout", () => { client.ConnectAsync(TimeSpan.FromMilliseconds(-2), default); });
+ AssertExtensions.Throws("timeout", () => client.Connect(TimeSpan.FromMilliseconds((long)int.MaxValue + 1)));
+ AssertExtensions.Throws("timeout", () => { client.ConnectAsync(TimeSpan.FromMilliseconds((long)int.MaxValue + 1), default); });
}
}
@@ -32,9 +36,12 @@ public async Task ConnectToNonExistentServer_Throws_TimeoutException()
using (NamedPipeClientStream client = new NamedPipeClientStream(".", "notthere"))
{
var ctx = new CancellationTokenSource();
- Assert.Throws(() => client.Connect(60)); // 60 to be over internal 50 interval
- await Assert.ThrowsAsync(() => client.ConnectAsync(50));
- await Assert.ThrowsAsync(() => client.ConnectAsync(60, ctx.Token)); // testing Token overload; ctx is not canceled in this test
+ Assert.Throws(() =>
+ client.Connect(TimeSpan.FromMilliseconds(60))); // 60 to be over internal 50 interval
+ await Assert.ThrowsAsync(() => client.ConnectAsync(TimeSpan.FromMilliseconds(50), default));
+ await Assert.ThrowsAsync(() =>
+ client.ConnectAsync(TimeSpan.FromMilliseconds(60),
+ ctx.Token)); // testing Token overload; ctx is not canceled in this test
}
}
@@ -611,7 +618,8 @@ public async Task ClientConnectAsync_Throws_Timeout_When_Pipe_Not_Found(Cancella
string pipeName = PipeStreamConformanceTests.GetUniquePipeName();
using (NamedPipeClientStream client = new NamedPipeClientStream(pipeName))
{
- Task waitingClient = client.ConnectAsync(92, cancellationToken);
+ TimeSpan timeout = TimeSpan.FromMilliseconds(92);
+ Task waitingClient = client.ConnectAsync(timeout, cancellationToken);
await Assert.ThrowsAsync(() => { return waitingClient; });
}
}
@@ -626,16 +634,18 @@ public void ClientConnect_Throws_Timeout_When_Pipe_Busy()
using (NamedPipeClientStream firstClient = new NamedPipeClientStream(pipeName))
using (NamedPipeClientStream secondClient = new NamedPipeClientStream(pipeName))
{
- const int timeout = 10_000;
+ var ctx = new CancellationTokenSource();
+ TimeSpan timeout = TimeSpan.FromMilliseconds(10_000);
Task[] clientAndServerTasks = new[]
{
- firstClient.ConnectAsync(timeout),
+ firstClient.ConnectAsync(timeout, ctx.Token),
Task.Run(() => server.WaitForConnection())
};
Assert.True(Task.WaitAll(clientAndServerTasks, timeout));
- Assert.Throws(() => secondClient.Connect(93));
+ TimeSpan connectionTimeout = TimeSpan.FromMilliseconds(93);
+ Assert.Throws(() => secondClient.Connect(connectionTimeout));
}
}
@@ -650,16 +660,17 @@ public async Task ClientConnectAsync_With_Cancellation_Throws_Timeout_When_Pipe_
using (NamedPipeClientStream firstClient = new NamedPipeClientStream(pipeName))
using (NamedPipeClientStream secondClient = new NamedPipeClientStream(pipeName))
{
- const int timeout = 10_000;
+ TimeSpan timeout = TimeSpan.FromMilliseconds(10_000);
Task[] clientAndServerTasks = new[]
{
- firstClient.ConnectAsync(timeout),
+ firstClient.ConnectAsync(timeout, cancellationToken),
Task.Run(() => server.WaitForConnection())
};
Assert.True(Task.WaitAll(clientAndServerTasks, timeout));
- Task waitingClient = secondClient.ConnectAsync(94, cancellationToken);
+ TimeSpan connectionTimeout = TimeSpan.FromMilliseconds(94);
+ Task waitingClient = secondClient.ConnectAsync(connectionTimeout, cancellationToken);
await Assert.ThrowsAsync(() => { return waitingClient; });
}
}
diff --git a/src/libraries/System.Net.Ping/ref/System.Net.Ping.cs b/src/libraries/System.Net.Ping/ref/System.Net.Ping.cs
index 82dcd06b86b9b7..71d2e314241d63 100644
--- a/src/libraries/System.Net.Ping/ref/System.Net.Ping.cs
+++ b/src/libraries/System.Net.Ping/ref/System.Net.Ping.cs
@@ -47,6 +47,8 @@ protected void OnPingCompleted(System.Net.NetworkInformation.PingCompletedEventA
public System.Net.NetworkInformation.PingReply Send(string hostNameOrAddress, int timeout) { throw null; }
public System.Net.NetworkInformation.PingReply Send(string hostNameOrAddress, int timeout, byte[] buffer) { throw null; }
public System.Net.NetworkInformation.PingReply Send(string hostNameOrAddress, int timeout, byte[] buffer, System.Net.NetworkInformation.PingOptions? options) { throw null; }
+ public System.Net.NetworkInformation.PingReply Send(System.Net.IPAddress address, System.TimeSpan timeout, byte[]? buffer, System.Net.NetworkInformation.PingOptions? options) { throw null; }
+ public System.Net.NetworkInformation.PingReply Send(string hostNameOrAddress, System.TimeSpan timeout, byte[]? buffer, System.Net.NetworkInformation.PingOptions? options) { throw null; }
public void SendAsync(System.Net.IPAddress address, int timeout, byte[] buffer, System.Net.NetworkInformation.PingOptions? options, object? userToken) { }
public void SendAsync(System.Net.IPAddress address, int timeout, byte[] buffer, object? userToken) { }
public void SendAsync(System.Net.IPAddress address, int timeout, object? userToken) { }
@@ -64,6 +66,8 @@ public void SendAsyncCancel() { }
public System.Threading.Tasks.Task SendPingAsync(string hostNameOrAddress, int timeout) { throw null; }
public System.Threading.Tasks.Task SendPingAsync(string hostNameOrAddress, int timeout, byte[] buffer) { throw null; }
public System.Threading.Tasks.Task SendPingAsync(string hostNameOrAddress, int timeout, byte[] buffer, System.Net.NetworkInformation.PingOptions? options) { throw null; }
+ public System.Threading.Tasks.Task SendPingAsync(System.Net.IPAddress address, System.TimeSpan timeout, byte[]? buffer, System.Net.NetworkInformation.PingOptions? options, System.Threading.CancellationToken cancellationToken) { throw null; }
+ public System.Threading.Tasks.Task SendPingAsync(string hostNameOrAddress, System.TimeSpan timeout, byte[]? buffer, System.Net.NetworkInformation.PingOptions? options, System.Threading.CancellationToken cancellationToken) { throw null; }
}
public partial class PingCompletedEventArgs : System.ComponentModel.AsyncCompletedEventArgs
{
diff --git a/src/libraries/System.Net.Ping/src/System/Net/NetworkInformation/Ping.cs b/src/libraries/System.Net.Ping/src/System/Net/NetworkInformation/Ping.cs
index 125f793c98c962..106501c913642c 100644
--- a/src/libraries/System.Net.Ping/src/System/Net/NetworkInformation/Ping.cs
+++ b/src/libraries/System.Net.Ping/src/System/Net/NetworkInformation/Ping.cs
@@ -231,6 +231,12 @@ public PingReply Send(IPAddress address, int timeout, byte[] buffer, PingOptions
}
}
+ public PingReply Send(IPAddress address, TimeSpan timeout, byte[]? buffer = null, PingOptions? options = null) =>
+ Send(address, ToTimeoutMilliseconds(timeout), buffer ?? DefaultSendBuffer, options);
+
+ public PingReply Send(string hostNameOrAddress, TimeSpan timeout, byte[]? buffer = null,
+ PingOptions? options = null) => Send(hostNameOrAddress, ToTimeoutMilliseconds(timeout), buffer ?? DefaultSendBuffer, options);
+
public void SendAsync(string hostNameOrAddress, object? userToken)
{
SendAsync(hostNameOrAddress, DefaultTimeout, DefaultSendBuffer, userToken);
@@ -318,6 +324,24 @@ public Task SendPingAsync(IPAddress address, int timeout, byte[] buff
return SendPingAsyncInternal(address, timeout, buffer, options);
}
+ public Task SendPingAsync(IPAddress address, TimeSpan timeout, byte[]? buffer = null,
+ PingOptions? options = null, CancellationToken cancellationToken = default)
+ {
+ cancellationToken.ThrowIfCancellationRequested();
+ Task task = SendPingAsync(address, ToTimeoutMilliseconds(timeout), buffer ?? DefaultSendBuffer, options);
+
+ return task.WaitAsync(cancellationToken);
+ }
+
+ public Task SendPingAsync(string hostNameOrAddress, TimeSpan timeout, byte[]? buffer = null,
+ PingOptions? options = null, CancellationToken cancellationToken = default)
+ {
+ cancellationToken.ThrowIfCancellationRequested();
+ Task task = SendPingAsync(hostNameOrAddress, ToTimeoutMilliseconds(timeout), buffer ?? DefaultSendBuffer, options);
+
+ return task.WaitAsync(cancellationToken);
+ }
+
private async Task SendPingAsyncInternal(IPAddress address, int timeout, byte[] buffer, PingOptions? options)
{
// Need to snapshot the address here, so we're sure that it's not changed between now
@@ -357,6 +381,16 @@ public Task SendPingAsync(string hostNameOrAddress, int timeout, byte
return GetAddressAndSendAsync(hostNameOrAddress, timeout, buffer, options);
}
+ private static int ToTimeoutMilliseconds(TimeSpan timeout)
+ {
+ long totalMilliseconds = (long)timeout.TotalMilliseconds;
+ if (totalMilliseconds < -1 || totalMilliseconds > int.MaxValue)
+ {
+ throw new ArgumentOutOfRangeException(nameof(timeout));
+ }
+ return (int)totalMilliseconds;
+ }
+
public void SendAsyncCancel()
{
lock (_lockObject)
diff --git a/src/libraries/System.Net.Ping/tests/FunctionalTests/PingTest.cs b/src/libraries/System.Net.Ping/tests/FunctionalTests/PingTest.cs
index c506643f9c8f56..1e1d1568943b63 100644
--- a/src/libraries/System.Net.Ping/tests/FunctionalTests/PingTest.cs
+++ b/src/libraries/System.Net.Ping/tests/FunctionalTests/PingTest.cs
@@ -3,6 +3,7 @@
using Microsoft.DotNet.XUnitExtensions;
using System.Diagnostics;
+using System.Globalization;
using System.Linq;
using System.Net.Sockets;
using System.Net.Test.Common;
@@ -47,7 +48,7 @@ public PingTest(ITestOutputHelper output)
private void PingResultValidator(PingReply pingReply, IPAddress[] localIpAddresses) => PingResultValidator(pingReply, localIpAddresses, null);
- private static void PingResultValidator(PingReply pingReply, IPAddress[] localIpAddresses, ITestOutputHelper output)
+ private static void PingResultValidator(PingReply pingReply, IPAddress[] localIpAddresses, ITestOutputHelper? output)
{
Assert.Equal(IPStatus.Success, pingReply.Status);
if (localIpAddresses.Any(addr => pingReply.Address.Equals(addr)))
@@ -105,10 +106,18 @@ public async Task SendPingAsync_InvalidArgs()
// Negative timeout
AssertExtensions.Throws("timeout", () => { p.SendPingAsync(localIpAddress, -1); });
AssertExtensions.Throws("timeout", () => { p.SendPingAsync(TestSettings.LocalHost, -1); });
+ AssertExtensions.Throws("timeout", () => { p.SendPingAsync(localIpAddress, TimeSpan.FromMilliseconds(-1), default, default, default); });
+ AssertExtensions.Throws("timeout", () => { p.SendPingAsync(TestSettings.LocalHost, TimeSpan.FromMilliseconds(-1), default, default, default); });
+ AssertExtensions.Throws("timeout", () => { p.SendPingAsync(localIpAddress, TimeSpan.FromMilliseconds((long)int.MaxValue + 1), default, default, default); });
+ AssertExtensions.Throws("timeout", () => { p.SendPingAsync(TestSettings.LocalHost, TimeSpan.FromMilliseconds((long)int.MaxValue + 1), default, default, default); });
AssertExtensions.Throws("timeout", () => { p.SendAsync(localIpAddress, -1, null); });
AssertExtensions.Throws("timeout", () => { p.SendAsync(TestSettings.LocalHost, -1, null); });
AssertExtensions.Throws("timeout", () => { p.Send(localIpAddress, -1); });
AssertExtensions.Throws("timeout", () => { p.Send(TestSettings.LocalHost, -1); });
+ AssertExtensions.Throws("timeout", () => { p.Send(localIpAddress, TimeSpan.FromMilliseconds(-1), default, default); });
+ AssertExtensions.Throws("timeout", () => { p.Send(TestSettings.LocalHost, TimeSpan.FromMilliseconds(-1), default, default); });
+ AssertExtensions.Throws("timeout", () => { p.Send(localIpAddress, TimeSpan.FromMilliseconds((long)int.MaxValue + 1), default, default); });
+ AssertExtensions.Throws("timeout", () => { p.Send(TestSettings.LocalHost, TimeSpan.FromMilliseconds((long)int.MaxValue + 1), default, default); });
// Null byte[]
AssertExtensions.Throws("buffer", () => { p.SendPingAsync(localIpAddress, 0, null); });
@@ -814,17 +823,15 @@ public void SendPing_LocaleEnvVarsMustBeIgnored(AddressFamily addressFamily, str
public void SendPingAsync_LocaleEnvVarsMustBeIgnored(AddressFamily addressFamily, string envVar_LANG, string envVar_LC_MESSAGES, string envVar_LC_ALL)
{
IPAddress localIpAddress = TestSettings.GetLocalIPAddress(addressFamily);
- if (localIpAddress == null)
- {
- // No local address for given address family.
- return;
- }
-
- var remoteInvokeStartInfo = new ProcessStartInfo();
- remoteInvokeStartInfo.EnvironmentVariables["LANG"] = envVar_LANG;
- remoteInvokeStartInfo.EnvironmentVariables["LC_MESSAGES"] = envVar_LC_MESSAGES;
- remoteInvokeStartInfo.EnvironmentVariables["LC_ALL"] = envVar_LC_ALL;
+ var remoteInvokeStartInfo = new ProcessStartInfo {
+ EnvironmentVariables =
+ {
+ ["LANG"] = envVar_LANG,
+ ["LC_MESSAGES"] = envVar_LC_MESSAGES,
+ ["LC_ALL"] = envVar_LC_ALL
+ }
+ };
RemoteExecutor.Invoke(async address =>
{
diff --git a/src/libraries/System.Net.Sockets/ref/System.Net.Sockets.cs b/src/libraries/System.Net.Sockets/ref/System.Net.Sockets.cs
index e813cca044ee04..3eec205b412966 100644
--- a/src/libraries/System.Net.Sockets/ref/System.Net.Sockets.cs
+++ b/src/libraries/System.Net.Sockets/ref/System.Net.Sockets.cs
@@ -136,6 +136,7 @@ public NetworkStream(System.Net.Sockets.Socket socket, System.IO.FileAccess acce
public override System.IAsyncResult BeginRead(byte[] buffer, int offset, int count, System.AsyncCallback? callback, object? state) { throw null; }
public override System.IAsyncResult BeginWrite(byte[] buffer, int offset, int count, System.AsyncCallback? callback, object? state) { throw null; }
public void Close(int timeout) { }
+ public void Close(System.TimeSpan timeout) { }
protected override void Dispose(bool disposing) { }
public override int EndRead(System.IAsyncResult asyncResult) { throw null; }
public override void EndWrite(System.IAsyncResult asyncResult) { }
@@ -371,6 +372,7 @@ public void GetSocketOption(System.Net.Sockets.SocketOptionLevel optionLevel, Sy
public void Listen() { }
public void Listen(int backlog) { }
public bool Poll(int microSeconds, System.Net.Sockets.SelectMode mode) { throw null; }
+ public bool Poll(System.TimeSpan timeout, System.Net.Sockets.SelectMode mode) { throw null; }
public int Receive(byte[] buffer) { throw null; }
public int Receive(byte[] buffer, int offset, int size, System.Net.Sockets.SocketFlags socketFlags) { throw null; }
public int Receive(byte[] buffer, int offset, int size, System.Net.Sockets.SocketFlags socketFlags, out System.Net.Sockets.SocketError errorCode) { throw null; }
@@ -408,6 +410,7 @@ public void Listen(int backlog) { }
public System.Threading.Tasks.ValueTask ReceiveMessageFromAsync(System.Memory buffer, System.Net.Sockets.SocketFlags socketFlags, System.Net.EndPoint remoteEndPoint, System.Threading.CancellationToken cancellationToken = default) { throw null; }
public bool ReceiveMessageFromAsync(System.Net.Sockets.SocketAsyncEventArgs e) { throw null; }
public static void Select(System.Collections.IList? checkRead, System.Collections.IList? checkWrite, System.Collections.IList? checkError, int microSeconds) { }
+ public static void Select(System.Collections.IList? checkRead, System.Collections.IList? checkWrite, System.Collections.IList? checkError, System.TimeSpan timeout) { }
public int Send(byte[] buffer) { throw null; }
public int Send(byte[] buffer, int offset, int size, System.Net.Sockets.SocketFlags socketFlags) { throw null; }
public int Send(byte[] buffer, int offset, int size, System.Net.Sockets.SocketFlags socketFlags, out System.Net.Sockets.SocketError errorCode) { throw null; }
diff --git a/src/libraries/System.Net.Sockets/src/System/Net/Sockets/NetworkStream.cs b/src/libraries/System.Net.Sockets/src/System/Net/Sockets/NetworkStream.cs
index 6e57472a199f08..299091bf28f3dd 100644
--- a/src/libraries/System.Net.Sockets/src/System/Net/Sockets/NetworkStream.cs
+++ b/src/libraries/System.Net.Sockets/src/System/Net/Sockets/NetworkStream.cs
@@ -337,6 +337,18 @@ public void Close(int timeout)
Dispose();
}
+ public void Close(TimeSpan timeout) => Close(ToTimeoutSeconds(timeout));
+
+ private static int ToTimeoutSeconds(TimeSpan timeout)
+ {
+ long totalSeconds = (long)timeout.TotalSeconds;
+ if (totalSeconds < -1 || totalSeconds > int.MaxValue)
+ {
+ throw new ArgumentOutOfRangeException(nameof(timeout));
+ }
+ return (int)totalSeconds;
+ }
+
protected override void Dispose(bool disposing)
{
if (Interlocked.Exchange(ref _disposed, 1) != 0)
diff --git a/src/libraries/System.Net.Sockets/src/System/Net/Sockets/Socket.cs b/src/libraries/System.Net.Sockets/src/System/Net/Sockets/Socket.cs
index ea137810083a8e..d0478278b83277 100644
--- a/src/libraries/System.Net.Sockets/src/System/Net/Sockets/Socket.cs
+++ b/src/libraries/System.Net.Sockets/src/System/Net/Sockets/Socket.cs
@@ -2138,6 +2138,9 @@ public bool Poll(int microSeconds, SelectMode mode)
return status;
}
+ public bool Poll(TimeSpan timeout, SelectMode mode) =>
+ Poll(ToTimeoutMicroseconds(timeout), mode);
+
// Determines the status of a socket.
public static void Select(IList? checkRead, IList? checkWrite, IList? checkError, int microSeconds)
{
@@ -2171,6 +2174,18 @@ public static void Select(IList? checkRead, IList? checkWrite, IList? checkError
}
}
+ public static void Select(IList? checkRead, IList? checkWrite, IList? checkError, TimeSpan timeout) => Select(checkRead, checkWrite, checkError, ToTimeoutMicroseconds(timeout));
+
+ private static int ToTimeoutMicroseconds(TimeSpan timeout)
+ {
+ long totalMicroseconds = timeout.Ticks / 10;
+ if (totalMicroseconds < -1 || totalMicroseconds > int.MaxValue)
+ {
+ throw new ArgumentOutOfRangeException(nameof(timeout));
+ }
+ return (int)totalMicroseconds;
+ }
+
public IAsyncResult BeginConnect(EndPoint remoteEP, AsyncCallback? callback, object? state) =>
TaskToApm.Begin(ConnectAsync(remoteEP), callback, state);
diff --git a/src/libraries/System.Net.Sockets/tests/FunctionalTests/ArgumentValidationTests.cs b/src/libraries/System.Net.Sockets/tests/FunctionalTests/ArgumentValidationTests.cs
index 41fe74b0c4f757..31da90800351ab 100644
--- a/src/libraries/System.Net.Sockets/tests/FunctionalTests/ArgumentValidationTests.cs
+++ b/src/libraries/System.Net.Sockets/tests/FunctionalTests/ArgumentValidationTests.cs
@@ -355,6 +355,22 @@ public void Select_NullOrEmptyLists_Throws_ArgumentNull()
Assert.Throws(() => Socket.Select(emptyList, emptyList, emptyList, -1));
}
+ [Fact]
+ public void Select_NullOrEmptyLists_Throws_ArgumentNull_TimeSpan()
+ {
+ TimeSpan nonInfinity = TimeSpan.FromMilliseconds(1);
+ var emptyList = new List();
+
+ Assert.Throws(() => Socket.Select(null, null, null, nonInfinity));
+ Assert.Throws(() => Socket.Select(emptyList, null, null, nonInfinity));
+ Assert.Throws(() => Socket.Select(null, emptyList, null, nonInfinity));
+ Assert.Throws(() => Socket.Select(emptyList, emptyList, null, nonInfinity));
+ Assert.Throws(() => Socket.Select(null, null, emptyList, nonInfinity));
+ Assert.Throws(() => Socket.Select(emptyList, null, emptyList, nonInfinity));
+ Assert.Throws(() => Socket.Select(null, emptyList, emptyList, nonInfinity));
+ Assert.Throws(() => Socket.Select(emptyList, emptyList, emptyList, nonInfinity));
+ }
+
[Fact]
public void Select_LargeList_Throws_ArgumentOutOfRange()
{
@@ -365,6 +381,22 @@ public void Select_LargeList_Throws_ArgumentOutOfRange()
Assert.Throws(() => Socket.Select(null, null, largeList, -1));
}
+ [Fact]
+ public void Select_LargeList_Throws_ArgumentOutOfRange_TimeSpan()
+ {
+ var largeList = new LargeList();
+
+ TimeSpan infinity = Timeout.InfiniteTimeSpan;
+ Assert.Throws(() => Socket.Select(largeList, null, null, infinity));
+ Assert.Throws(() => Socket.Select(null, largeList, null, infinity));
+ Assert.Throws(() => Socket.Select(null, null, largeList, infinity));
+
+ TimeSpan negative = TimeSpan.FromMilliseconds(-1);
+ Assert.Throws(() => Socket.Select(largeList, null, null, negative));
+ Assert.Throws(() => Socket.Select(null, largeList, null, negative));
+ Assert.Throws(() => Socket.Select(null, null, largeList, negative));
+ }
+
[Fact]
public void AcceptAsync_NullAsyncEventArgs_Throws_ArgumentNull()
{
diff --git a/src/libraries/System.Net.Sockets/tests/FunctionalTests/Connect.cs b/src/libraries/System.Net.Sockets/tests/FunctionalTests/Connect.cs
index 39506cee57fdaf..954e70fa7fe980 100644
--- a/src/libraries/System.Net.Sockets/tests/FunctionalTests/Connect.cs
+++ b/src/libraries/System.Net.Sockets/tests/FunctionalTests/Connect.cs
@@ -341,8 +341,10 @@ public async Task ConnectHostNameAndPort_CancelDuringConnect_Throws()
}
}
- [Fact]
- public async Task FailedConnect_ConnectedReturnsFalse()
+ [Theory]
+ [InlineData(false)]
+ [InlineData(true)]
+ public async Task FailedConnect_ConnectedReturnsFalse(bool useTimeSpan)
{
using Socket socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
@@ -354,7 +356,14 @@ public async Task FailedConnect_ConnectedReturnsFalse()
Assert.Equal(SocketError.WouldBlock, se.SocketErrorCode);
// Give the non-blocking connect some time to complete.
- socket.Poll(5_000_000 /* microSeconds */, SelectMode.SelectWrite);
+ if (useTimeSpan)
+ {
+ socket.Poll(TimeSpan.FromMilliseconds(5000), SelectMode.SelectWrite);
+ }
+ else
+ {
+ socket.Poll(5_000_000 /* microSeconds */, SelectMode.SelectWrite);
+ }
}
Assert.False(socket.Connected);
diff --git a/src/libraries/System.Private.CoreLib/src/System.Private.CoreLib.Shared.projitems b/src/libraries/System.Private.CoreLib/src/System.Private.CoreLib.Shared.projitems
index 3a846e7828eab4..8889b675d14f9c 100644
--- a/src/libraries/System.Private.CoreLib/src/System.Private.CoreLib.Shared.projitems
+++ b/src/libraries/System.Private.CoreLib/src/System.Private.CoreLib.Shared.projitems
@@ -309,6 +309,7 @@
+
diff --git a/src/libraries/System.Private.CoreLib/src/System/GC.cs b/src/libraries/System.Private.CoreLib/src/System/GC.cs
new file mode 100644
index 00000000000000..de53aa1296c5a3
--- /dev/null
+++ b/src/libraries/System.Private.CoreLib/src/System/GC.cs
@@ -0,0 +1,28 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+
+using System.Threading;
+
+namespace System
+{
+ public static partial class GC
+ {
+ ///
+ /// Returns, in a specified time-out period, the status of a registered notification for determining whether a full,
+ /// blocking garbage collection by the common language runtime is imminent.
+ ///
+ /// The timeout on waiting for a full GC approach
+ /// The status of a registered full GC notification
+ public static GCNotificationStatus WaitForFullGCApproach(TimeSpan timeout)
+ => WaitForFullGCApproach(WaitHandle.ToTimeoutMilliseconds(timeout));
+
+ ///
+ /// Returns the status of a registered notification about whether a blocking garbage collection
+ /// has completed. May wait indefinitely for a full collection.
+ ///
+ /// The timeout on waiting for a full collection
+ /// The status of a registered full GC notification
+ public static GCNotificationStatus WaitForFullGCComplete(TimeSpan timeout)
+ => WaitForFullGCComplete(WaitHandle.ToTimeoutMilliseconds(timeout));
+ }
+}
diff --git a/src/libraries/System.Private.CoreLib/src/System/Threading/Tasks/Task.cs b/src/libraries/System.Private.CoreLib/src/System/Threading/Tasks/Task.cs
index 421af0e5034b0e..f3aa1a57fd48aa 100644
--- a/src/libraries/System.Private.CoreLib/src/System/Threading/Tasks/Task.cs
+++ b/src/libraries/System.Private.CoreLib/src/System/Threading/Tasks/Task.cs
@@ -2637,15 +2637,41 @@ public void Wait()
/// infinite time-out -or- timeout is greater than
/// .
///
- public bool Wait(TimeSpan timeout)
+ public bool Wait(TimeSpan timeout) => Wait(timeout, default);
+
+ ///
+ /// Waits for the to complete execution.
+ ///
+ /// The time to wait, or to wait indefinitely
+ ///
+ /// A to observe while waiting for the task to complete.
+ ///
+ ///
+ /// true if the completed execution within the allotted time; otherwise, false.
+ ///
+ ///
+ /// The was canceled -or- an exception was thrown during the execution of the .
+ ///
+ ///
+ /// is a negative number other than -1 milliseconds, which represents an
+ /// infinite time-out -or- timeout is greater than
+ /// .
+ ///
+ ///
+ /// The was canceled.
+ ///
+ public bool Wait(TimeSpan timeout, CancellationToken cancellationToken)
{
+ cancellationToken.ThrowIfCancellationRequested();
+
long totalMilliseconds = (long)timeout.TotalMilliseconds;
if (totalMilliseconds < -1 || totalMilliseconds > int.MaxValue)
{
ThrowHelper.ThrowArgumentOutOfRangeException(ExceptionArgument.timeout);
}
- return Wait((int)totalMilliseconds, default);
+ return Wait((int)totalMilliseconds, cancellationToken);
}
///
diff --git a/src/libraries/System.Runtime/ref/System.Runtime.cs b/src/libraries/System.Runtime/ref/System.Runtime.cs
index bf155afc8500ff..73e14973650f63 100644
--- a/src/libraries/System.Runtime/ref/System.Runtime.cs
+++ b/src/libraries/System.Runtime/ref/System.Runtime.cs
@@ -2437,8 +2437,10 @@ public static void SuppressFinalize(object obj) { }
public static bool TryStartNoGCRegion(long totalSize, long lohSize, bool disallowFullBlockingGC) { throw null; }
public static System.GCNotificationStatus WaitForFullGCApproach() { throw null; }
public static System.GCNotificationStatus WaitForFullGCApproach(int millisecondsTimeout) { throw null; }
+ public static System.GCNotificationStatus WaitForFullGCApproach(System.TimeSpan timeout) { throw null; }
public static System.GCNotificationStatus WaitForFullGCComplete() { throw null; }
public static System.GCNotificationStatus WaitForFullGCComplete(int millisecondsTimeout) { throw null; }
+ public static System.GCNotificationStatus WaitForFullGCComplete(System.TimeSpan timeout) { throw null; }
public static void WaitForPendingFinalizers() { }
}
public enum GCCollectionMode
@@ -13356,6 +13358,7 @@ public void Wait() { }
public bool Wait(int millisecondsTimeout, System.Threading.CancellationToken cancellationToken) { throw null; }
public void Wait(System.Threading.CancellationToken cancellationToken) { }
public bool Wait(System.TimeSpan timeout) { throw null; }
+ public bool Wait(System.TimeSpan timeout, System.Threading.CancellationToken cancellationToken) { throw null; }
[System.Runtime.Versioning.UnsupportedOSPlatformAttribute("browser")]
public static void WaitAll(params System.Threading.Tasks.Task[] tasks) { }
[System.Runtime.Versioning.UnsupportedOSPlatformAttribute("browser")]
diff --git a/src/libraries/System.ServiceProcess.ServiceController/ref/System.ServiceProcess.ServiceController.netcoreapp.cs b/src/libraries/System.ServiceProcess.ServiceController/ref/System.ServiceProcess.ServiceController.netcoreapp.cs
index 1298a7c23d6909..42be0a6c2c64f1 100644
--- a/src/libraries/System.ServiceProcess.ServiceController/ref/System.ServiceProcess.ServiceController.netcoreapp.cs
+++ b/src/libraries/System.ServiceProcess.ServiceController/ref/System.ServiceProcess.ServiceController.netcoreapp.cs
@@ -6,6 +6,10 @@
namespace System.ServiceProcess
{
+ public partial class ServiceBase : System.ComponentModel.Component
+ {
+ public void RequestAdditionalTime(System.TimeSpan time) { }
+ }
public partial class ServiceController : System.ComponentModel.Component
{
public void Stop(bool stopDependentServices) { }
diff --git a/src/libraries/System.ServiceProcess.ServiceController/src/System/ServiceProcess/ServiceBase.cs b/src/libraries/System.ServiceProcess.ServiceController/src/System/ServiceProcess/ServiceBase.cs
index c8dcaa55b8936c..74e95338d51a73 100644
--- a/src/libraries/System.ServiceProcess.ServiceController/src/System/ServiceProcess/ServiceBase.cs
+++ b/src/libraries/System.ServiceProcess.ServiceController/src/System/ServiceProcess/ServiceBase.cs
@@ -72,6 +72,26 @@ public unsafe void RequestAdditionalTime(int milliseconds)
}
}
+#if NETCOREAPP
+ ///
+ /// When this method is called from OnStart, OnStop, OnPause or OnContinue,
+ /// the specified wait hint is passed to the
+ /// Service Control Manager to avoid having the service marked as not responding.
+ ///
+ /// The requested additional time
+ public void RequestAdditionalTime(TimeSpan time) => RequestAdditionalTime(ToIntMilliseconds(time));
+
+ private static int ToIntMilliseconds(TimeSpan time)
+ {
+ long totalMilliseconds = (long)time.TotalMilliseconds;
+ if (totalMilliseconds < -1 || totalMilliseconds > int.MaxValue)
+ {
+ throw new ArgumentOutOfRangeException(nameof(time));
+ }
+ return (int)totalMilliseconds;
+ }
+#endif
+
///
/// Indicates whether to report Start, Stop, Pause, and Continue commands in the event.
///
diff --git a/src/libraries/System.ServiceProcess.ServiceController/tests/ServiceBaseTests.cs b/src/libraries/System.ServiceProcess.ServiceController/tests/ServiceBaseTests.cs
index 247d600b86c768..67954fda143349 100644
--- a/src/libraries/System.ServiceProcess.ServiceController/tests/ServiceBaseTests.cs
+++ b/src/libraries/System.ServiceProcess.ServiceController/tests/ServiceBaseTests.cs
@@ -72,6 +72,18 @@ private void Cleanup()
}
}
+#if NETCOREAPP
+ [Theory]
+ [InlineData(-2)]
+ [InlineData((long)int.MaxValue + 1)]
+ public void RequestAdditionalTime_Throws_ArgumentOutOfRangeException(long milliseconds)
+ {
+ TimeSpan time = TimeSpan.FromMilliseconds(milliseconds);
+ using var serviceBase = new ServiceBase();
+ Assert.Throws("time", () => serviceBase.RequestAdditionalTime(time));
+ }
+#endif
+
[ConditionalFact(nameof(IsProcessElevated))]
public void TestOnStartThenStop()
{
diff --git a/src/libraries/System.Threading.Tasks/tests/System.Threading.Tasks.Tests.csproj b/src/libraries/System.Threading.Tasks/tests/System.Threading.Tasks.Tests.csproj
index 2253b5e87e79d9..ca9d7b875714f1 100644
--- a/src/libraries/System.Threading.Tasks/tests/System.Threading.Tasks.Tests.csproj
+++ b/src/libraries/System.Threading.Tasks/tests/System.Threading.Tasks.Tests.csproj
@@ -7,6 +7,7 @@
+
diff --git a/src/libraries/System.Threading.Tasks/tests/Task/TaskArgumentValidationTests.cs b/src/libraries/System.Threading.Tasks/tests/Task/TaskArgumentValidationTests.cs
new file mode 100644
index 00000000000000..99892193107546
--- /dev/null
+++ b/src/libraries/System.Threading.Tasks/tests/Task/TaskArgumentValidationTests.cs
@@ -0,0 +1,20 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+
+using Xunit;
+
+namespace System.Threading.Tasks.Tests
+{
+ public sealed class TaskArgumentValidationTests
+ {
+ [Theory]
+ [InlineData(-2)]
+ [InlineData((long)int.MaxValue + 1)]
+ public void Task_Wait_ArgumentOutOfRange(long milliseconds)
+ {
+ TimeSpan timeout = TimeSpan.FromMilliseconds(milliseconds);
+ Task task = Task.Run(static () => {});
+ Assert.Throws("timeout", () => task.Wait(timeout));
+ }
+ }
+}
diff --git a/src/libraries/System.Threading.Tasks/tests/Task/TaskContinueWithTests.cs b/src/libraries/System.Threading.Tasks/tests/Task/TaskContinueWithTests.cs
index 35f7917eba9b50..11d2e326bcc6f8 100644
--- a/src/libraries/System.Threading.Tasks/tests/Task/TaskContinueWithTests.cs
+++ b/src/libraries/System.Threading.Tasks/tests/Task/TaskContinueWithTests.cs
@@ -256,8 +256,10 @@ public static void RunContinueWithParamsTest_IllegalArgs()
}
// Test what happens when you cancel a task in the middle of a continuation chain.
- [ConditionalFact(typeof(PlatformDetection), nameof(PlatformDetection.IsThreadingSupported))]
- public static void RunContinuationCancelTest()
+ [ConditionalTheory(typeof(PlatformDetection), nameof(PlatformDetection.IsThreadingSupported))]
+ [InlineData(false)]
+ [InlineData(true)]
+ public static void RunContinuationCancelTest(bool useTimeSpan)
{
bool t1Ran = false;
bool t3Ran = false;
@@ -266,9 +268,9 @@ public static void RunContinuationCancelTest()
CancellationTokenSource ctsForT2 = new CancellationTokenSource();
Task t2 = t1.ContinueWith((ContinuedTask) =>
- {
- Assert.True(false, string.Format("RunContinuationCancelTest: > Failed! t2 should not have run."));
- }, ctsForT2.Token);
+ {
+ Assert.True(false, string.Format("RunContinuationCancelTest: > Failed! t2 should not have run."));
+ }, ctsForT2.Token);
Task t3 = t2.ContinueWith((ContinuedTask) =>
{
@@ -281,8 +283,17 @@ public static void RunContinuationCancelTest()
// Start the first task in the chain. Should hold off from kicking off (canceled) t2.
t1.Start();
- t1.Wait(5000); // should be more than enough time for either of these
- t3.Wait(5000);
+ if (useTimeSpan)
+ {
+ TimeSpan timeout = TimeSpan.FromMilliseconds(5000);
+ t1.Wait(timeout);
+ t3.Wait(timeout);
+ }
+ else
+ {
+ t1.Wait(5000); // should be more than enough time for either of these
+ t3.Wait(5000);
+ }
if (!t1Ran)
{