Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Port some CoreRT Threading classes to Mono #47333

Merged
merged 36 commits into from
Mar 13, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
36 commits
Select commit Hold shift + click to select a range
ac37cf0
Remove appropriate icalls from Mono
CoffeeFlux Jan 21, 2021
b58f7c3
Wire up the build
CoffeeFlux Jan 22, 2021
515a552
Remove old Mono managed implementations
CoffeeFlux Jan 22, 2021
549cb47
Miscellaneous additions and changes needed for porting
CoffeeFlux Jan 22, 2021
4591f0f
Add Thread._waitInfo and switch over usage
CoffeeFlux Jan 22, 2021
ccb76f4
Attempt to annotate the new files
CoffeeFlux Jan 22, 2021
64c4abf
Fix todo
CoffeeFlux Feb 9, 2021
f53dc2c
Fix Windows build
CoffeeFlux Feb 9, 2021
8add4e0
Back to WaitInfo
CoffeeFlux Feb 10, 2021
13e5c80
Annotation fixes
CoffeeFlux Feb 10, 2021
990efa1
Add WaitHandle.Windows.cs
CoffeeFlux Feb 10, 2021
64c3af0
Rename to just FeatureManagedThreading and add WaitHandle.Windows.cs
CoffeeFlux Feb 10, 2021
8d1d8b0
Thread down stack size as part of thread creation
CoffeeFlux Feb 10, 2021
1e910a4
No separate feature flag
CoffeeFlux Feb 11, 2021
f5c3654
Expose property correctly
CoffeeFlux Feb 11, 2021
04d486a
Add Windows Interop files
CoffeeFlux Feb 11, 2021
b6bf424
Disable reentrant wait functionality
CoffeeFlux Feb 11, 2021
b24af36
Attempt to fix wasm
CoffeeFlux Feb 16, 2021
051fd47
Fix ifdefs
CoffeeFlux Feb 16, 2021
100c14a
Switch bool to BOOL for interop
CoffeeFlux Feb 16, 2021
1a865ce
Always create _waitInfo
CoffeeFlux Feb 24, 2021
aed3aac
Some exclusions
CoffeeFlux Feb 24, 2021
942b575
Re-enable the tests and disable the name check
CoffeeFlux Feb 26, 2021
616188c
Remove thread_interrupt_requested
CoffeeFlux Feb 26, 2021
61de05a
Correctly abandon mutexes
CoffeeFlux Feb 26, 2021
2a12e3f
Disable tests again
CoffeeFlux Feb 26, 2021
b84385f
Uncomment unsupported name exception
CoffeeFlux Feb 26, 2021
17ba865
Excise a lot more runtime code
CoffeeFlux Feb 26, 2021
bb3ae83
Disable another test
CoffeeFlux Feb 26, 2021
696fc10
Windows build fix
CoffeeFlux Feb 26, 2021
65801bd
Disable InterruptTest on Windows
CoffeeFlux Mar 12, 2021
3472b0b
Add link to issue on reentrant wait support for Windows
CoffeeFlux Mar 12, 2021
def05ab
Move mutex abandoning to the managed Thread object's finalizer
CoffeeFlux Mar 12, 2021
891987b
Rethrow with InvalidOperationException when called from WaitHandle
CoffeeFlux Mar 12, 2021
a9dd5c3
Another ActiveIssue on Windows
CoffeeFlux Mar 12, 2021
cc14788
Linker exclusion no longer needed
CoffeeFlux Mar 12, 2021
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

using System.Runtime.InteropServices;

internal partial class Interop
{
internal partial class Kernel32
{
[DllImport(Libraries.Kernel32)]
[SuppressGCTransition]
internal static extern int GetLastError();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

using Microsoft.Win32.SafeHandles;
using System;
using System.Runtime.InteropServices;

internal static partial class Interop
{
internal static partial class Kernel32
{
internal const int WAIT_FAILED = unchecked((int)0xFFFFFFFF);

[DllImport(Libraries.Kernel32)]
internal static extern uint WaitForMultipleObjectsEx(uint nCount, IntPtr lpHandles, BOOL bWaitAll, uint dwMilliseconds, BOOL bAlertable);

[DllImport(Libraries.Kernel32)]
internal static extern uint WaitForSingleObject(IntPtr hHandle, uint dwMilliseconds);

[DllImport(Libraries.Kernel32)]
internal static extern uint SignalObjectAndWait(IntPtr hObjectToSignal, IntPtr hObjectToWaitOn, uint dwMilliseconds, BOOL bAlertable);

[DllImport(Libraries.Kernel32)]
internal static extern void Sleep(uint milliseconds);

internal const uint CREATE_SUSPENDED = 0x00000004;
internal const uint STACK_SIZE_PARAM_IS_A_RESERVATION = 0x00010000;

[DllImport(Libraries.Kernel32)]
internal static extern unsafe SafeWaitHandle CreateThread(
IntPtr lpThreadAttributes,
IntPtr dwStackSize,
delegate* unmanaged<IntPtr, uint> lpStartAddress,
IntPtr lpParameter,
uint dwCreationFlags,
out uint lpThreadId);

[DllImport(Libraries.Kernel32)]
internal static extern uint ResumeThread(SafeWaitHandle hThread);

[DllImport(Libraries.Kernel32)]
internal static extern IntPtr GetCurrentThread();

internal const int DUPLICATE_SAME_ACCESS = 2;

[DllImport(Libraries.Kernel32, SetLastError = true)]
internal static extern bool DuplicateHandle(
IntPtr hSourceProcessHandle,
IntPtr hSourceHandle,
IntPtr hTargetProcessHandle,
out SafeWaitHandle lpTargetHandle,
uint dwDesiredAccess,
bool bInheritHandle,
uint dwOptions);

internal enum ThreadPriority : int
{
Idle = -15,
Lowest = -2,
BelowNormal = -1,
Normal = 0,
AboveNormal = 1,
Highest = 2,
TimeCritical = 15,

ErrorReturn = 0x7FFFFFFF
}

[DllImport(Libraries.Kernel32)]
internal static extern ThreadPriority GetThreadPriority(SafeWaitHandle hThread);

[DllImport(Libraries.Kernel32)]
internal static extern bool SetThreadPriority(SafeWaitHandle hThread, int nPriority);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -8,4 +8,5 @@
// create unique identities for every test to allow every test to have
// it's own store.
[assembly: CollectionBehavior(CollectionBehavior.CollectionPerAssembly, DisableTestParallelization = true)]
[assembly: ActiveIssue("https://github.com/dotnet/runtime/issues/48720", TestPlatforms.AnyUnix, TargetFrameworkMonikers.Netcoreapp, TestRuntimes.Mono)]
[assembly: SkipOnMono("System.IO.IsolatedStorage is not supported on Browser", TestPlatforms.Browser)]
Original file line number Diff line number Diff line change
Expand Up @@ -2998,6 +2998,9 @@
<data name="Overflow_Int64" xml:space="preserve">
<value>Value was either too large or too small for an Int64.</value>
</data>
<data name="Overflow_MutexReacquireCount" xml:space="preserve">
<value>The current thread attempted to reacquire a mutex that has reached its maximum acquire count.</value>
</data>
<data name="Overflow_NegateTwosCompNum" xml:space="preserve">
<value>Negating the minimum value of a twos complement number is invalid.</value>
</data>
Expand Down Expand Up @@ -3577,6 +3580,9 @@
<data name="InvalidOperation_InvalidComUnRegFunctionSig" xml:space="preserve">
<value>COM unregister function must have a System.Type parameter and a void return type.</value>
</data>
<data name="InvalidOperation_InvalidHandle" xml:space="preserve">
<value>The handle is invalid.</value>
</data>
<data name="InvalidOperation_MultipleComRegFunctions" xml:space="preserve">
<value>Type '{0}' has more than one COM registration function.</value>
</data>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1980,4 +1980,24 @@
<Compile Include="$(MSBuildThisFileDirectory)System\Threading\LowLevelLifoSemaphore.Windows.cs" Condition="'$(TargetsWindows)' == 'true'" />
<Compile Include="$(MSBuildThisFileDirectory)System\Threading\RegisteredWaitHandle.Portable.cs" />
</ItemGroup>
<ItemGroup Condition="'$(FeatureCoreCLR)' != 'true' and ('$(TargetsUnix)' == 'true' or '$(TargetsBrowser)' == 'true')">
<Compile Include="$(MSBuildThisFileDirectory)Microsoft\Win32\SafeHandles\SafeWaitHandle.Unix.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\Threading\EventWaitHandle.Unix.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\Threading\Mutex.Unix.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\Threading\Semaphore.Unix.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\Threading\WaitHandle.Unix.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\Threading\WaitSubsystem.HandleManager.Unix.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\Threading\WaitSubsystem.ThreadWaitInfo.Unix.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\Threading\WaitSubsystem.Unix.cs" />
<Compile Include="$(MSBuildThisFileDirectory)System\Threading\WaitSubsystem.WaitableObject.Unix.cs" />
</ItemGroup>
<ItemGroup Condition="'$(FeatureCoreCLR)' != 'true' and '$(TargetsWindows)' == 'true'">
<Compile Include="$(MSBuildThisFileDirectory)System\Threading\WaitHandle.Windows.cs" />
<Compile Include="$(CommonPath)\Interop\Windows\Kernel32\Interop.GetLastError.cs">
<Link>Interop\Windows\Kernel32\Interop.GetLastError.cs</Link>
</Compile>
<Compile Include="$(CommonPath)\Interop\Windows\Kernel32\Interop.Threading.cs">
<Link>Interop\Windows\Kernel32\Interop.Threading.cs</Link>
</Compile>
</ItemGroup>
</Project>
Original file line number Diff line number Diff line change
Expand Up @@ -161,6 +161,13 @@ public void DangerousAddRef(ref bool success)
success = true;
}

// Used by internal callers to avoid declaring a bool to pass by ref
internal void DangerousAddRef()
{
bool success = false;
DangerousAddRef(ref success);
}

public void DangerousRelease() => InternalRelease(disposeOrFinalizeOperation: false);

private void InternalRelease(bool disposeOrFinalizeOperation)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ namespace System.Threading
{
public partial class EventWaitHandle
{
private void CreateEventCore(bool initialState, EventResetMode mode, string name, out bool createdNew)
private void CreateEventCore(bool initialState, EventResetMode mode, string? name, out bool createdNew)
{
if (name != null)
throw new PlatformNotSupportedException(SR.PlatformNotSupported_NamedSynchronizationPrimitives);
Expand All @@ -19,7 +19,7 @@ private void CreateEventCore(bool initialState, EventResetMode mode, string name
createdNew = true;
}

private static OpenExistingResult OpenExistingWorker(string name, out EventWaitHandle result)
private static OpenExistingResult OpenExistingWorker(string name, out EventWaitHandle? result)
Copy link
Contributor

Choose a reason for hiding this comment

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

This might be better to move to the caller. It seems to do always do some error checking which is Windows specific

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I think we have to match the Windows equivalent here, since otherwise you end up with a bunch of weird platform-specific code at a higher level? Maybe I'm misunderstanding.

Copy link
Contributor

Choose a reason for hiding this comment

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

I was referring to code patterns like

public static EventWaitHandle OpenExisting(string name)
{
switch (OpenExistingWorker(name, out EventWaitHandle? result))
{
case OpenExistingResult.NameNotFound:
throw new WaitHandleCannotBeOpenedException();
case OpenExistingResult.NameInvalid:
throw new WaitHandleCannotBeOpenedException(SR.Format(SR.Threading_WaitHandleCannotBeOpenedException_InvalidHandle, name));
case OpenExistingResult.PathNotFound:
throw new DirectoryNotFoundException(SR.Format(SR.IO_PathNotFound_Path, name));
default:
Debug.Assert(result != null, "result should be non-null on success");
return result;
}
. The API is windows only and on Unix will have never reached error handling.

{
throw new PlatformNotSupportedException(SR.PlatformNotSupported_NamedSynchronizationPrimitives);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,19 @@ private void WaitCore()
Interop.Sys.LowLevelMonitor_Wait(_nativeMonitor);
}

private bool WaitCore(int timeoutMilliseconds)
{
Debug.Assert(timeoutMilliseconds >= -1);

if (timeoutMilliseconds < 0)
{
WaitCore();
return true;
}

return Interop.Sys.LowLevelMonitor_TimedWait(_nativeMonitor, timeoutMilliseconds);
}

private void Signal_ReleaseCore()
{
Interop.Sys.LowLevelMonitor_Signal_Release(_nativeMonitor);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,16 @@ public void Wait()
SetOwnerThreadToCurrent();
}

public bool Wait(int timeoutMilliseconds)
{
Debug.Assert(timeoutMilliseconds >= -1);

ResetOwnerThread();
bool waitResult = WaitCore(timeoutMilliseconds);
SetOwnerThreadToCurrent();
return waitResult;
}

public void Signal_Release()
{
ResetOwnerThread();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,9 @@ namespace System.Threading
{
public sealed partial class Mutex
{
private void CreateMutexCore(bool initiallyOwned, string name, out bool createdNew)
private void CreateMutexCore(bool initiallyOwned, string? name, out bool createdNew)
{
// See https://github.com/dotnet/runtime/issues/48720
if (name != null)
{
throw new PlatformNotSupportedException(SR.PlatformNotSupported_NamedSynchronizationPrimitives);
Expand All @@ -21,7 +22,7 @@ private void CreateMutexCore(bool initiallyOwned, string name, out bool createdN
createdNew = true;
}

private static OpenExistingResult OpenExistingWorker(string name, out Mutex result)
private static OpenExistingResult OpenExistingWorker(string name, out Mutex? result)
{
throw new PlatformNotSupportedException(SR.PlatformNotSupported_NamedSynchronizationPrimitives);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ namespace System.Threading
{
public sealed partial class Semaphore
{
private void CreateSemaphoreCore(int initialCount, int maximumCount, string name, out bool createdNew)
private void CreateSemaphoreCore(int initialCount, int maximumCount, string? name, out bool createdNew)
{
if (name != null)
{
Expand All @@ -21,7 +21,7 @@ private void CreateSemaphoreCore(int initialCount, int maximumCount, string name
createdNew = true;
}

private static OpenExistingResult OpenExistingWorker(string name, out Semaphore result)
private static OpenExistingResult OpenExistingWorker(string name, out Semaphore? result)
{
throw new PlatformNotSupportedException(SR.PlatformNotSupported_NamedSynchronizationPrimitives);
}
Expand Down
Loading