Skip to content

Commit

Permalink
[API Implementation]: Use TimeSpan everywhere we use an int for secon…
Browse files Browse the repository at this point in the history
…ds, milliseconds, and timeouts (Group 1/3) (#64860)
  • Loading branch information
deeprobin authored Mar 28, 2022
1 parent 071e772 commit bda94ca
Show file tree
Hide file tree
Showing 39 changed files with 470 additions and 59 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -143,7 +143,7 @@
<Compile Include="$(BclSourcesRoot)\System\Enum.CoreCLR.cs" />
<Compile Include="$(BclSourcesRoot)\System\Environment.CoreCLR.cs" />
<Compile Include="$(BclSourcesRoot)\System\Exception.CoreCLR.cs" />
<Compile Include="$(BclSourcesRoot)\System\GC.cs" />
<Compile Include="$(BclSourcesRoot)\System\GC.CoreCLR.cs" />
<Compile Include="$(BclSourcesRoot)\System\IO\FileLoadException.CoreCLR.cs" />
<Compile Include="$(BclSourcesRoot)\System\IO\FileNotFoundException.CoreCLR.cs" />
<Compile Include="$(BclSourcesRoot)\System\Math.CoreCLR.cs" />
Expand Down Expand Up @@ -331,9 +331,9 @@

<Target Name="GenerateEventingFiles"
Inputs="@(EventingGenerationScript);@(EventManifestFile)"
Outputs="@(EventingSourceFile)"
DependsOnTargets="FindPython"
BeforeTargets="BeforeCompile">
Outputs="@(EventingSourceFile)"
DependsOnTargets="FindPython"
BeforeTargets="BeforeCompile">

<Error Condition="'$(PYTHON)' == ''" Text="Unable to locate Python. NativeRuntimeEventSource.CoreCLR.cs cannot be generated without Python installed on the machine. Either install Python in your path or point to it with the PYTHON environment variable." />
<PropertyGroup>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -169,7 +169,7 @@
<Compile Include="System\Diagnostics\StackTrace.CoreRT.cs" />
<Compile Include="System\Enum.CoreRT.cs" />
<Compile Include="System\Environment.CoreRT.cs" />
<Compile Include="System\GC.cs" />
<Compile Include="System\GC.CoreRT.cs" />
<Compile Include="System\Helpers.cs" />
<Compile Include="System\Math.CoreRT.cs" />
<Compile Include="System\MathF.CoreRT.cs" />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ internal enum EndNoGCRegionStatus
AllocationExceeded = 3
}

public static class GC
public static partial class GC
{
public static int GetGeneration(object obj)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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; }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,11 @@ public RegularExpressionAttribute([StringSyntax(StringSyntaxAttribute.Regex)] st
/// </summary>
public int MatchTimeoutInMilliseconds { get; set; }

/// <summary>
/// Gets the timeout to use when matching the regular expression pattern
/// </summary>
public TimeSpan MatchTimeout => TimeSpan.FromMilliseconds(MatchTimeoutInMilliseconds);

/// <summary>
/// Gets the regular expression pattern to use
/// </summary>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
<Compile Include="System\ComponentModel\DataAnnotations\PhoneAttributeTests.cs" />
<Compile Include="System\ComponentModel\DataAnnotations\RangeAttributeTests.cs" Condition="'$(TargetFramework)' == '$(NetCoreAppCurrent)'" />
<Compile Include="System\ComponentModel\DataAnnotations\RegularExpressionAttributeTests.cs" />
<Compile Include="System\ComponentModel\DataAnnotations\RegularExpressionAttributeTests.Core.cs" Condition="'$(TargetFramework)' == '$(NetCoreAppCurrent)'" />
<Compile Include="System\ComponentModel\DataAnnotations\RequiredAttributeTests.cs" />
<Compile Include="System\ComponentModel\DataAnnotations\ScaffoldColumnAttributeTests.cs" />
<Compile Include="System\ComponentModel\DataAnnotations\Schema\ColumnAttributeTests.cs" />
Expand Down
Original file line number Diff line number Diff line change
@@ -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);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@

namespace System.ComponentModel.DataAnnotations.Tests
{
public class RegularExpressionAttributeTests : ValidationAttributeTestBase
public sealed partial class RegularExpressionAttributeTests : ValidationAttributeTestBase
{
protected override IEnumerable<TestCase> ValidValues()
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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)]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,13 @@ public Timer(double interval) : this()
_interval = (int)roundedInterval;
}

/// <summary>
/// Initializes a new instance of the <see cref='Timer'/> class, setting the <see cref='Interval'/> property to the specified period.
/// </summary>
public Timer(TimeSpan interval) : this(interval.TotalMilliseconds)
{
}

/// <summary>
/// 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.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -826,6 +826,39 @@ public bool WaitForInputIdle(int milliseconds)
return WaitForInputIdleCore(milliseconds);
}

/// <summary>
/// Causes the <see cref="Process"/> component to wait the specified <paramref name="timeout"/> for the associated process to enter an idle state.
/// This overload applies only to processes with a user interface and, therefore, a message loop.
/// </summary>
/// <param name="timeout">The amount of time, in milliseconds, to wait for the associated process to become idle.</param>
/// <returns><see langword="true"/> if the associated process has reached an idle state; otherwise, <see langword="false"/>.</returns>
/// <exception cref="InvalidOperationException">
/// 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 <see cref="Process"/> object.
/// </exception>
/// <remarks>
/// Use <see cref="WaitForInputIdle(TimeSpan)"/> 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.
/// </remarks>
public bool WaitForInputIdle(TimeSpan timeout) => WaitForInputIdle(ToTimeoutMilliseconds(timeout));

public ISynchronizeInvoke? SynchronizingObject { get; set; }

/// <devdoc>
Expand Down Expand Up @@ -1414,6 +1447,22 @@ public bool WaitForExit(int milliseconds)
return exited;
}

/// <summary>
/// Instructs the Process component to wait the specified number of milliseconds for
/// the associated process to exit.
/// </summary>
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;
}

/// <summary>
/// Instructs the Process component to wait for the associated process to exit, or
/// for the <paramref name="cancellationToken"/> to be canceled.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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<ArgumentOutOfRangeException>("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()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}

/// <devdoc>
/// Stops and starts this object.
/// </devdoc>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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<ArgumentOutOfRangeException>("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);
}
}
Expand Down
2 changes: 2 additions & 0 deletions src/libraries/System.IO.Pipes/ref/System.IO.Pipes.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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() { }
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down Expand Up @@ -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()
Expand Down
Loading

0 comments on commit bda94ca

Please sign in to comment.