[MethodImpl(MethodImplOptions.InternalCall)]
private static extern long GetPendingUnmanagedWorkItemCount();
- private static void RegisterWaitForSingleObjectCore(WaitHandle waitObject, RegisteredWaitHandle registeredWaitHandle)
+ private static RegisteredWaitHandle RegisterWaitForSingleObject(
+ WaitHandle? waitObject,
+ WaitOrTimerCallback? callBack,
+ object? state,
+ uint millisecondsTimeOutInterval,
+ bool executeOnlyOnce,
+ bool flowExecutionContext)
{
+
+ if (waitObject == null)
+ throw new ArgumentNullException(nameof(waitObject));
+
+ if (callBack == null)
+ throw new ArgumentNullException(nameof(callBack));
+
+ RegisteredWaitHandle registeredWaitHandle = new RegisteredWaitHandle(
+ waitObject,
+ new _ThreadPoolWaitOrTimerCallback(callBack, state, flowExecutionContext),
+ (int)millisecondsTimeOutInterval,
+ !executeOnlyOnce);
+
registeredWaitHandle.OnBeforeRegister();
if (UsePortableThreadPool)
{
PortableThreadPool.ThreadPoolInstance.RegisterWaitHandle(registeredWaitHandle);
- return;
+ }
+ else
+ {
+ IntPtr nativeRegisteredWaitHandle =
+ RegisterWaitForSingleObjectNative(
+ waitObject,
+ registeredWaitHandle.Callback,
+ (uint)registeredWaitHandle.TimeoutDurationMs,
+ !registeredWaitHandle.Repeating,
+ registeredWaitHandle);
+ registeredWaitHandle.SetNativeRegisteredWaitHandle(nativeRegisteredWaitHandle);
}
- IntPtr nativeRegisteredWaitHandle =
- RegisterWaitForSingleObjectNative(
- waitObject,
- registeredWaitHandle.Callback,
- (uint)registeredWaitHandle.TimeoutDurationMs,
- !registeredWaitHandle.Repeating,
- registeredWaitHandle);
- registeredWaitHandle.SetNativeRegisteredWaitHandle(nativeRegisteredWaitHandle);
+ return registeredWaitHandle;
}
internal static void UnsafeQueueWaitCompletion(CompleteWaitThreadPoolWorkItem completeWaitWorkItem)
return false;
}
+
+ public bool Any(Func<T, bool> func)
+ {
+ for (int i = 0; i < _count; i++)
+ {
+ if (func(_items[i]))
+ {
+ return true;
+ }
+ }
+
+ return false;
+ }
}
}
largestAlignmentRequirement = LayoutInt.Max(fieldSizeAndAlignment.Alignment, largestAlignmentRequirement);
- cumulativeInstanceFieldPos = AlignUpInstanceFieldOffset(type, cumulativeInstanceFieldPos, fieldSizeAndAlignment.Alignment, type.Context.Target
- , armAlignFromStartOfFields: true // In what appears to have been a bug in the design of the arm32 type layout code
- // this portion of the layout algorithm does not layout from the start of the object
+ cumulativeInstanceFieldPos = AlignUpInstanceFieldOffset(type, cumulativeInstanceFieldPos, fieldSizeAndAlignment.Alignment, type.Context.Target,
+ armAlignFromStartOfFields: true // In what appears to have been a bug in the design of the arm32 type layout code
+ // this portion of the layout algorithm does not layout from the start of the object
);
offsets[fieldOrdinal] = new FieldAndOffset(field, cumulativeInstanceFieldPos);
cumulativeInstanceFieldPos = checked(cumulativeInstanceFieldPos + fieldSizeAndAlignment.Size);
}
/// <summary>
- /// Determines whether an object of type '<paramref name="type"/>' requires 8-byte alignment on
+ /// Determines whether an object of type '<paramref name="type"/>' requires 8-byte alignment on
/// 32bit ARM or 32bit Wasm architectures.
/// </summary>
public static bool RequiresAlign8(this TypeDesc type)
GC.SuppressFinalize(this);
}
+#if DEBUG
+ public bool IsLocked
+ {
+ get
+ {
+ bool isLocked = _ownerThread == Thread.CurrentThread;
+ Debug.Assert(!isLocked || (_state & LockedMask) != 0);
+ return isLocked;
+ }
+ }
+#endif
+
[Conditional("DEBUG")]
public void VerifyIsLocked()
{
namespace System.Threading
{
+ /// <summary>
+ /// The info for a completed wait on a specific <see cref="RegisteredWaitHandle"/>.
+ /// </summary>
+ internal sealed partial class CompleteWaitThreadPoolWorkItem : IThreadPoolWorkItem
+ {
+ private RegisteredWaitHandle _registeredWaitHandle;
+ private bool _timedOut;
+
+ public CompleteWaitThreadPoolWorkItem(RegisteredWaitHandle registeredWaitHandle, bool timedOut)
+ {
+ _registeredWaitHandle = registeredWaitHandle;
+ _timedOut = timedOut;
+ }
+ }
+
internal partial class PortableThreadPool
{
/// <summary>
// The .NET Foundation licenses this file to you under the MIT license.
using System.Diagnostics;
+using System.Runtime.Versioning;
+using Microsoft.Win32.SafeHandles;
namespace System.Threading
{
+ /// <summary>
+ /// An object representing the registration of a <see cref="WaitHandle"/> via <see cref="ThreadPool.RegisterWaitForSingleObject"/>.
+ /// </summary>
+ [UnsupportedOSPlatform("browser")]
public sealed partial class RegisteredWaitHandle : MarshalByRefObject
{
+ internal RegisteredWaitHandle(WaitHandle waitHandle, _ThreadPoolWaitOrTimerCallback callbackHelper,
+ int millisecondsTimeout, bool repeating)
+ {
+ Handle = waitHandle.SafeWaitHandle;
+ Callback = callbackHelper;
+ TimeoutDurationMs = millisecondsTimeout;
+ Repeating = repeating;
+ if (!IsInfiniteTimeout)
+ {
+ RestartTimeout();
+ }
+ }
+
+ private static AutoResetEvent? s_cachedEvent;
+
+ private static AutoResetEvent RentEvent() =>
+ Interlocked.Exchange(ref s_cachedEvent, null) ??
+ new AutoResetEvent(false);
+
+ private static void ReturnEvent(AutoResetEvent resetEvent)
+ {
+ if (Interlocked.CompareExchange(ref s_cachedEvent, resetEvent, null) != null)
+ {
+ resetEvent.Dispose();
+ }
+ }
+
+ private static readonly LowLevelLock s_callbackLock = new LowLevelLock();
+
+ /// <summary>
+ /// The callback to execute when the wait on <see cref="Handle"/> either times out or completes.
+ /// </summary>
+ internal _ThreadPoolWaitOrTimerCallback Callback { get; }
+
+ /// <summary>
+ /// The <see cref="SafeWaitHandle"/> that was registered.
+ /// </summary>
+ internal SafeWaitHandle Handle { get; }
+
+ /// <summary>
+ /// The time this handle times out at in ms.
+ /// </summary>
+ internal int TimeoutTimeMs { get; private set; }
+
+ internal int TimeoutDurationMs { get; }
+
+ internal bool IsInfiniteTimeout => TimeoutDurationMs == -1;
+
+ internal void RestartTimeout()
+ {
+ Debug.Assert(!IsInfiniteTimeout);
+ TimeoutTimeMs = Environment.TickCount + TimeoutDurationMs;
+ }
+
+ /// <summary>
+ /// Whether or not the wait is a repeating wait.
+ /// </summary>
+ internal bool Repeating { get; }
+
+ /// <summary>
+ /// The <see cref="WaitHandle"/> the user passed in via <see cref="Unregister(WaitHandle)"/>.
+ /// </summary>
+ private SafeWaitHandle? UserUnregisterWaitHandle { get; set; }
+
+ private IntPtr UserUnregisterWaitHandleValue { get; set; }
+
+ private static IntPtr InvalidHandleValue => new IntPtr(-1);
+
+ internal bool IsBlocking => UserUnregisterWaitHandleValue == InvalidHandleValue;
+
+ /// <summary>
+ /// The number of callbacks that are currently queued on the Thread Pool or executing.
+ /// </summary>
+ private int _numRequestedCallbacks;
+
+ /// <summary>
+ /// Notes if we need to signal the user's unregister event after all callbacks complete.
+ /// </summary>
+ private bool _signalAfterCallbacksComplete;
+
+ private bool _unregisterCalled;
+
+ private bool _unregistered;
+
+ private AutoResetEvent? _callbacksComplete;
+
+ private AutoResetEvent? _removed;
+
/// <summary>
/// The <see cref="PortableThreadPool.WaitThread"/> this <see cref="RegisteredWaitHandle"/> was registered on.
/// </summary>
internal PortableThreadPool.WaitThread? WaitThread { get; set; }
+#if CORECLR
private bool UnregisterPortable(WaitHandle waitObject)
+#else
+ public bool Unregister(WaitHandle waitObject)
+#endif
{
// The registered wait handle must have been registered by this time, otherwise the instance is not handed out to
// the caller of the public variants of RegisterWaitForSingleObject
WaitThread!.UnregisterWait(this);
return true;
}
+
+ /// <summary>
+ /// Signal <see cref="UserUnregisterWaitHandle"/> if it has not been signaled yet and is a valid handle.
+ /// </summary>
+ private void SignalUserWaitHandle()
+ {
+ s_callbackLock.VerifyIsLocked();
+ SafeWaitHandle? handle = UserUnregisterWaitHandle;
+ IntPtr handleValue = UserUnregisterWaitHandleValue;
+ try
+ {
+ if (handleValue != IntPtr.Zero && handleValue != InvalidHandleValue)
+ {
+ Debug.Assert(handleValue == handle!.DangerousGetHandle());
+ EventWaitHandle.Set(handle);
+ }
+ }
+ finally
+ {
+ handle?.DangerousRelease();
+ _callbacksComplete?.Set();
+ _unregistered = true;
+ }
+ }
+
+ /// <summary>
+ /// Perform the registered callback if the <see cref="UserUnregisterWaitHandle"/> has not been signaled.
+ /// </summary>
+ /// <param name="timedOut">Whether or not the wait timed out.</param>
+ internal void PerformCallback(bool timedOut)
+ {
+#if DEBUG
+ s_callbackLock.Acquire();
+ try
+ {
+ Debug.Assert(_numRequestedCallbacks != 0);
+ }
+ finally
+ {
+ s_callbackLock.Release();
+ }
+#endif
+
+ _ThreadPoolWaitOrTimerCallback.PerformWaitOrTimerCallback(Callback, timedOut);
+ CompleteCallbackRequest();
+ }
+
+ /// <summary>
+ /// Tell this handle that there is a callback queued on the thread pool for this handle.
+ /// </summary>
+ internal void RequestCallback()
+ {
+ s_callbackLock.Acquire();
+ try
+ {
+ _numRequestedCallbacks++;
+ }
+ finally
+ {
+ s_callbackLock.Release();
+ }
+ }
+
+ /// <summary>
+ /// Called when the wait thread removes this handle registration. This will signal the user's event if there are no callbacks pending,
+ /// or note that the user's event must be signaled when the callbacks complete.
+ /// </summary>
+ internal void OnRemoveWait()
+ {
+ s_callbackLock.Acquire();
+ try
+ {
+ _removed?.Set();
+ if (_numRequestedCallbacks == 0)
+ {
+ SignalUserWaitHandle();
+ }
+ else
+ {
+ _signalAfterCallbacksComplete = true;
+ }
+ }
+ finally
+ {
+ s_callbackLock.Release();
+ }
+ }
+
+ /// <summary>
+ /// Reduces the number of callbacks requested. If there are no more callbacks and the user's handle is queued to be signaled, signal it.
+ /// </summary>
+ private void CompleteCallbackRequest()
+ {
+ s_callbackLock.Acquire();
+ try
+ {
+ --_numRequestedCallbacks;
+ if (_numRequestedCallbacks == 0 && _signalAfterCallbacksComplete)
+ {
+ SignalUserWaitHandle();
+ }
+ }
+ finally
+ {
+ s_callbackLock.Release();
+ }
+ }
+
+ /// <summary>
+ /// Wait for all queued callbacks and the full unregistration to complete.
+ /// </summary>
+ internal void WaitForCallbacks()
+ {
+ Debug.Assert(IsBlocking);
+ Debug.Assert(_unregisterCalled); // Should only be called when the wait is unregistered by the user.
+
+ _callbacksComplete!.WaitOne();
+ ReturnEvent(_callbacksComplete);
+ _callbacksComplete = null;
+ }
+
+ internal void WaitForRemoval()
+ {
+ Debug.Assert(!IsBlocking);
+ Debug.Assert(_unregisterCalled); // Should only be called when the wait is unregistered by the user.
+
+ _removed!.WaitOne();
+ ReturnEvent(_removed);
+ _removed = null;
+ }
}
}
// Portable implementation of ThreadPool
//
- public sealed partial class RegisteredWaitHandle : MarshalByRefObject
- {
- /// <summary>
- /// Unregisters this wait handle registration from the wait threads.
- /// </summary>
- /// <param name="waitObject">The event to signal when the handle is unregistered.</param>
- /// <returns>If the handle was successfully marked to be removed and the provided wait handle was set as the user provided event.</returns>
- /// <remarks>
- /// This method will only return true on the first call.
- /// Passing in a wait handle with a value of -1 will result in a blocking wait, where Unregister will not return until the full unregistration is completed.
- /// </remarks>
- public bool Unregister(WaitHandle waitObject) => UnregisterPortable(waitObject);
- }
-
internal sealed partial class CompleteWaitThreadPoolWorkItem : IThreadPoolWorkItem
{
void IThreadPoolWorkItem.Execute() => PortableThreadPool.CompleteWait(_registeredWaitHandle, _timedOut);
// does not yield the thread and instead processes time-sensitive work items queued by specific APIs periodically.
internal const bool SupportsTimeSensitiveWorkItems = true;
+#if CORERT
+ internal const bool EnableWorkerTracking = false;
+#else
internal static readonly bool EnableWorkerTracking =
AppContextConfigHelper.GetBooleanConfig("System.Threading.ThreadPool.EnableWorkerTracking", false);
+#endif
+
+ // Threadpool specific initialization of a new thread. Used by OS-provided threadpools. No-op for portable threadpool.
+ internal static void InitializeForThreadPoolThread() { }
internal static bool CanSetMinIOCompletionThreads(int ioCompletionThreads) => true;
internal static void SetMinIOCompletionThreads(int ioCompletionThreads) { }
internal static object GetOrCreateThreadLocalCompletionCountObject() =>
PortableThreadPool.ThreadPoolInstance.GetOrCreateThreadLocalCompletionCountObject();
- private static void RegisterWaitForSingleObjectCore(WaitHandle? waitObject, RegisteredWaitHandle registeredWaitHandle) =>
- PortableThreadPool.ThreadPoolInstance.RegisterWaitHandle(registeredWaitHandle);
+ private static RegisteredWaitHandle RegisterWaitForSingleObject(
+ WaitHandle? waitObject,
+ WaitOrTimerCallback? callBack,
+ object? state,
+ uint millisecondsTimeOutInterval,
+ bool executeOnlyOnce,
+ bool flowExecutionContext)
+ {
+ if (waitObject == null)
+ throw new ArgumentNullException(nameof(waitObject));
+
+ if (callBack == null)
+ throw new ArgumentNullException(nameof(callBack));
+
+ RegisteredWaitHandle registeredHandle = new RegisteredWaitHandle(
+ waitObject,
+ new _ThreadPoolWaitOrTimerCallback(callBack, state, flowExecutionContext),
+ (int)millisecondsTimeOutInterval,
+ !executeOnlyOnce);
+ PortableThreadPool.ThreadPoolInstance.RegisterWaitHandle(registeredHandle);
+ return registeredHandle;
+ }
internal static void UnsafeQueueWaitCompletion(CompleteWaitThreadPoolWorkItem completeWaitWorkItem) =>
UnsafeQueueUserWorkItemInternal(completeWaitWorkItem, preferLocal: false);
}
}
- /// <summary>
- /// An object representing the registration of a <see cref="WaitHandle"/> via <see cref="ThreadPool.RegisterWaitForSingleObject"/>.
- /// </summary>
- [UnsupportedOSPlatform("browser")]
- public sealed partial class RegisteredWaitHandle : MarshalByRefObject
- {
- internal RegisteredWaitHandle(WaitHandle waitHandle, _ThreadPoolWaitOrTimerCallback callbackHelper,
- int millisecondsTimeout, bool repeating)
- {
- Handle = waitHandle.SafeWaitHandle;
- Callback = callbackHelper;
- TimeoutDurationMs = millisecondsTimeout;
- Repeating = repeating;
- if (!IsInfiniteTimeout)
- {
- RestartTimeout();
- }
- }
-
- private static AutoResetEvent? s_cachedEvent;
-
- private static AutoResetEvent RentEvent()
- {
- AutoResetEvent? resetEvent = Interlocked.Exchange(ref s_cachedEvent, (AutoResetEvent?)null);
- if (resetEvent == null)
- {
- resetEvent = new AutoResetEvent(false);
- }
- return resetEvent;
- }
-
- private static void ReturnEvent(AutoResetEvent resetEvent)
- {
- if (Interlocked.CompareExchange(ref s_cachedEvent, resetEvent, null) != null)
- {
- resetEvent.Dispose();
- }
- }
-
- private static readonly LowLevelLock s_callbackLock = new LowLevelLock();
-
- /// <summary>
- /// The callback to execute when the wait on <see cref="Handle"/> either times out or completes.
- /// </summary>
- internal _ThreadPoolWaitOrTimerCallback Callback { get; }
-
-
- /// <summary>
- /// The <see cref="SafeWaitHandle"/> that was registered.
- /// </summary>
- internal SafeWaitHandle Handle { get; }
-
- /// <summary>
- /// The time this handle times out at in ms.
- /// </summary>
- internal int TimeoutTimeMs { get; private set; }
-
- internal int TimeoutDurationMs { get; }
-
- internal bool IsInfiniteTimeout => TimeoutDurationMs == -1;
-
- internal void RestartTimeout()
- {
- Debug.Assert(!IsInfiniteTimeout);
- TimeoutTimeMs = Environment.TickCount + TimeoutDurationMs;
- }
-
- /// <summary>
- /// Whether or not the wait is a repeating wait.
- /// </summary>
- internal bool Repeating { get; }
-
- /// <summary>
- /// The <see cref="WaitHandle"/> the user passed in via <see cref="Unregister(WaitHandle)"/>.
- /// </summary>
- private SafeWaitHandle? UserUnregisterWaitHandle { get; set; }
-
- private IntPtr UserUnregisterWaitHandleValue { get; set; }
-
- private static IntPtr InvalidHandleValue => new IntPtr(-1);
-
- internal bool IsBlocking => UserUnregisterWaitHandleValue == InvalidHandleValue;
-
- /// <summary>
- /// The number of callbacks that are currently queued on the Thread Pool or executing.
- /// </summary>
- private int _numRequestedCallbacks;
-
- /// <summary>
- /// Notes if we need to signal the user's unregister event after all callbacks complete.
- /// </summary>
- private bool _signalAfterCallbacksComplete;
-
- private bool _unregisterCalled;
-
-#pragma warning disable CS0414 // The field is assigned but its value is never used. Some runtimes may not support registered wait handles.
- private bool _unregistered;
-#pragma warning restore CS0414
-
- private AutoResetEvent? _callbacksComplete;
-
- private AutoResetEvent? _removed;
-
- /// <summary>
- /// Signal <see cref="UserUnregisterWaitHandle"/> if it has not been signaled yet and is a valid handle.
- /// </summary>
- private void SignalUserWaitHandle()
- {
- s_callbackLock.VerifyIsLocked();
- SafeWaitHandle? handle = UserUnregisterWaitHandle;
- IntPtr handleValue = UserUnregisterWaitHandleValue;
- try
- {
- if (handleValue != IntPtr.Zero && handleValue != InvalidHandleValue)
- {
- Debug.Assert(handleValue == handle!.DangerousGetHandle());
- EventWaitHandle.Set(handle);
- }
- }
- finally
- {
- handle?.DangerousRelease();
- _callbacksComplete?.Set();
- _unregistered = true;
- }
- }
-
- /// <summary>
- /// Perform the registered callback if the <see cref="UserUnregisterWaitHandle"/> has not been signaled.
- /// </summary>
- /// <param name="timedOut">Whether or not the wait timed out.</param>
- internal void PerformCallback(bool timedOut)
- {
-#if DEBUG
- s_callbackLock.Acquire();
- try
- {
- Debug.Assert(_numRequestedCallbacks != 0);
- }
- finally
- {
- s_callbackLock.Release();
- }
-#endif
-
- _ThreadPoolWaitOrTimerCallback.PerformWaitOrTimerCallback(Callback, timedOut);
- CompleteCallbackRequest();
- }
-
- /// <summary>
- /// Tell this handle that there is a callback queued on the thread pool for this handle.
- /// </summary>
- internal void RequestCallback()
- {
- s_callbackLock.Acquire();
- try
- {
- _numRequestedCallbacks++;
- }
- finally
- {
- s_callbackLock.Release();
- }
- }
-
- /// <summary>
- /// Called when the wait thread removes this handle registration. This will signal the user's event if there are no callbacks pending,
- /// or note that the user's event must be signaled when the callbacks complete.
- /// </summary>
- internal void OnRemoveWait()
- {
- s_callbackLock.Acquire();
- try
- {
- _removed?.Set();
- if (_numRequestedCallbacks == 0)
- {
- SignalUserWaitHandle();
- }
- else
- {
- _signalAfterCallbacksComplete = true;
- }
- }
- finally
- {
- s_callbackLock.Release();
- }
- }
-
- /// <summary>
- /// Reduces the number of callbacks requested. If there are no more callbacks and the user's handle is queued to be signaled, signal it.
- /// </summary>
- private void CompleteCallbackRequest()
- {
- s_callbackLock.Acquire();
- try
- {
- --_numRequestedCallbacks;
- if (_numRequestedCallbacks == 0 && _signalAfterCallbacksComplete)
- {
- SignalUserWaitHandle();
- }
- }
- finally
- {
- s_callbackLock.Release();
- }
- }
-
- /// <summary>
- /// Wait for all queued callbacks and the full unregistration to complete.
- /// </summary>
- internal void WaitForCallbacks()
- {
- Debug.Assert(IsBlocking);
- Debug.Assert(_unregisterCalled); // Should only be called when the wait is unregistered by the user.
-
- _callbacksComplete!.WaitOne();
- ReturnEvent(_callbacksComplete);
- _callbacksComplete = null;
- }
-
- internal void WaitForRemoval()
- {
- Debug.Assert(!IsBlocking);
- Debug.Assert(_unregisterCalled); // Should only be called when the wait is unregistered by the user.
-
- _removed!.WaitOne();
- ReturnEvent(_removed);
- _removed = null;
- }
- }
-
- /// <summary>
- /// The info for a completed wait on a specific <see cref="RegisteredWaitHandle"/>.
- /// </summary>
- internal sealed partial class CompleteWaitThreadPoolWorkItem : IThreadPoolWorkItem
- {
- private RegisteredWaitHandle _registeredWaitHandle;
- private bool _timedOut;
-
- public CompleteWaitThreadPoolWorkItem(RegisteredWaitHandle registeredWaitHandle, bool timedOut)
- {
- _registeredWaitHandle = registeredWaitHandle;
- _timedOut = timedOut;
- }
- }
-
public static partial class ThreadPool
{
internal const string WorkerThreadName = ".NET ThreadPool Worker";
return RegisterWaitForSingleObject(waitObject, callBack, state, (uint)tm, executeOnlyOnce, false);
}
- private static RegisteredWaitHandle RegisterWaitForSingleObject(
- WaitHandle? waitObject,
- WaitOrTimerCallback? callBack,
- object? state,
- uint millisecondsTimeOutInterval,
- bool executeOnlyOnce,
- bool flowExecutionContext)
- {
- if (waitObject == null)
- throw new ArgumentNullException(nameof(waitObject));
-
- if (callBack == null)
- throw new ArgumentNullException(nameof(callBack));
-
- RegisteredWaitHandle registeredHandle = new RegisteredWaitHandle(
- waitObject,
- new _ThreadPoolWaitOrTimerCallback(callBack, state, flowExecutionContext),
- (int)millisecondsTimeOutInterval,
- !executeOnlyOnce);
- RegisterWaitForSingleObjectCore(waitObject, registeredHandle);
- return registeredHandle;
- }
-
public static bool QueueUserWorkItem(WaitCallback callBack) =>
QueueUserWorkItem(callBack, null);
using System.Diagnostics;
using System.Collections.Generic;
using System.Runtime.CompilerServices;
+using System.Runtime.Versioning;
using System.Diagnostics.CodeAnalysis;
using Microsoft.Win32.SafeHandles;
namespace System.Threading
{
- public sealed partial class RegisteredWaitHandle : MarshalByRefObject
+ [UnsupportedOSPlatform("browser")]
+ public sealed class RegisteredWaitHandle : MarshalByRefObject
{
- public bool Unregister(WaitHandle? waitObject)
+ internal RegisteredWaitHandle()
{
- throw new PlatformNotSupportedException();
}
- }
- internal sealed partial class CompleteWaitThreadPoolWorkItem : IThreadPoolWorkItem
- {
- void IThreadPoolWorkItem.Execute()
+ public bool Unregister(WaitHandle? waitObject)
{
- Debug.Fail("Registered wait handles are currently not supported");
+ throw new PlatformNotSupportedException();
}
}
public static partial class ThreadPool
{
- // Time-senstiive work items are those that may need to run ahead of normal work items at least periodically. For a
+ // Time-sensitive work items are those that may need to run ahead of normal work items at least periodically. For a
// runtime that does not support time-sensitive work items on the managed side, the thread pool yields the thread to the
// runtime periodically (by exiting the dispatch loop) so that the runtime may use that thread for processing
// any time-sensitive work. For a runtime that supports time-sensitive work items on the managed side, the thread pool
internal static object? GetOrCreateThreadLocalCompletionCountObject() => null;
- private static void RegisterWaitForSingleObjectCore(WaitHandle? waitObject, RegisteredWaitHandle registeredWaitHandle) =>
+ private static RegisteredWaitHandle RegisterWaitForSingleObject(
+ WaitHandle? waitObject,
+ WaitOrTimerCallback? callBack,
+ object? state,
+ uint millisecondsTimeOutInterval,
+ bool executeOnlyOnce,
+ bool flowExecutionContext)
+ {
throw new PlatformNotSupportedException();
+ }
[DynamicDependency("Callback")]
[DynamicDependency("PumpThreadPool")]
using System.Globalization;
using System.Reflection;
using System.Runtime.InteropServices;
-using System.Runtime.InteropServices.Expando;
using TestLibrary;
-using Console = Internal.Console;
-
namespace PInvokeTests
{
static class CustomMarshalersNative
<PropertyGroup>
<OutputType>exe</OutputType>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
- <ReferenceSystemPrivateCoreLib>true</ReferenceSystemPrivateCoreLib>
<!-- CustomMarshalers unsupported outside of windows -->
<CLRTestTargetUnsupported Condition="'$(TargetsWindows)' != 'true'">true</CLRTestTargetUnsupported>
</PropertyGroup>