You've already forked linux-packaging-mono
Imported Upstream version 6.4.0.137
Former-commit-id: 943baa9f16a098c33e129777827f3a9d20da00d6
This commit is contained in:
parent
e9207cf623
commit
ef583813eb
@@ -0,0 +1,87 @@
|
||||
using Microsoft.Win32.SafeHandles;
|
||||
using System.Runtime.CompilerServices;
|
||||
|
||||
namespace System.Threading
|
||||
{
|
||||
partial class EventWaitHandle
|
||||
{
|
||||
public bool Set ()
|
||||
{
|
||||
SafeWaitHandle handle = ValidateHandle (out bool release);
|
||||
|
||||
try {
|
||||
return SetEventInternal (handle.DangerousGetHandle ());
|
||||
} finally {
|
||||
if (release)
|
||||
handle.DangerousRelease ();
|
||||
}
|
||||
}
|
||||
|
||||
public bool Reset ()
|
||||
{
|
||||
SafeWaitHandle handle = ValidateHandle (out bool release);
|
||||
|
||||
try {
|
||||
return ResetEventInternal (handle.DangerousGetHandle ());
|
||||
} finally {
|
||||
if (release)
|
||||
handle.DangerousRelease ();
|
||||
}
|
||||
}
|
||||
|
||||
unsafe void CreateEventCore (bool initialState, EventResetMode mode, string name, out bool createdNew)
|
||||
{
|
||||
if (name != null)
|
||||
throw new PlatformNotSupportedException (SR.PlatformNotSupported_NamedSynchronizationPrimitives);
|
||||
|
||||
SafeWaitHandle handle = new SafeWaitHandle (CreateEventInternal (mode == EventResetMode.ManualReset, initialState, null, 0, out int errorCode), ownsHandle: true);
|
||||
if (errorCode != 0)
|
||||
throw new NotImplementedException ("errorCode");
|
||||
SafeWaitHandle = handle;
|
||||
|
||||
createdNew = true;
|
||||
}
|
||||
|
||||
static OpenExistingResult OpenExistingWorker (string name, out EventWaitHandle result)
|
||||
{
|
||||
throw new PlatformNotSupportedException (SR.PlatformNotSupported_NamedSynchronizationPrimitives);
|
||||
}
|
||||
|
||||
internal static bool Set (SafeWaitHandle waitHandle)
|
||||
{
|
||||
bool release = false;
|
||||
try {
|
||||
waitHandle.DangerousAddRef (ref release);
|
||||
return SetEventInternal (waitHandle.DangerousGetHandle ());
|
||||
} finally {
|
||||
if (release)
|
||||
waitHandle.DangerousRelease ();
|
||||
}
|
||||
}
|
||||
|
||||
SafeWaitHandle ValidateHandle (out bool success)
|
||||
{
|
||||
// The field value is modifiable via the public <see cref="WaitHandle.SafeWaitHandle"/> property, save it locally
|
||||
// to ensure that one instance is used in all places in this method
|
||||
SafeWaitHandle waitHandle = SafeWaitHandle;
|
||||
if (waitHandle.IsInvalid)
|
||||
{
|
||||
throw new InvalidOperationException ();
|
||||
}
|
||||
|
||||
success = false;
|
||||
waitHandle.DangerousAddRef (ref success);
|
||||
return waitHandle;
|
||||
}
|
||||
|
||||
[MethodImplAttribute (MethodImplOptions.InternalCall)]
|
||||
unsafe static extern IntPtr CreateEventInternal (bool manual, bool initialState, char *name, int name_length, out int errorCode);
|
||||
|
||||
[MethodImplAttribute (MethodImplOptions.InternalCall)]
|
||||
static extern bool ResetEventInternal (IntPtr handle);
|
||||
|
||||
[MethodImplAttribute (MethodImplOptions.InternalCall)]
|
||||
static extern bool SetEventInternal (IntPtr handle);
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,75 @@
|
||||
using System.Runtime.CompilerServices;
|
||||
|
||||
namespace System.Threading
|
||||
{
|
||||
public static class Interlocked
|
||||
{
|
||||
[MethodImplAttribute(MethodImplOptions.InternalCall)]
|
||||
public extern static int CompareExchange (ref int location1, int value, int comparand);
|
||||
|
||||
[MethodImplAttribute(MethodImplOptions.InternalCall)]
|
||||
public extern static object CompareExchange (ref object location1, object value, object comparand);
|
||||
|
||||
[MethodImplAttribute(MethodImplOptions.InternalCall)]
|
||||
public extern static float CompareExchange (ref float location1, float value, float comparand);
|
||||
|
||||
[MethodImplAttribute(MethodImplOptions.InternalCall)]
|
||||
public extern static int Decrement (ref int location);
|
||||
|
||||
[MethodImplAttribute(MethodImplOptions.InternalCall)]
|
||||
public extern static long Decrement (ref long location);
|
||||
|
||||
[MethodImplAttribute(MethodImplOptions.InternalCall)]
|
||||
public extern static int Increment (ref int location);
|
||||
|
||||
[MethodImplAttribute(MethodImplOptions.InternalCall)]
|
||||
public extern static long Increment (ref long location);
|
||||
|
||||
[MethodImplAttribute(MethodImplOptions.InternalCall)]
|
||||
public extern static int Exchange (ref int location1, int value);
|
||||
|
||||
[MethodImplAttribute(MethodImplOptions.InternalCall)]
|
||||
public extern static object Exchange (ref object location1, object value);
|
||||
|
||||
[MethodImplAttribute(MethodImplOptions.InternalCall)]
|
||||
public extern static float Exchange (ref float location1, float value);
|
||||
|
||||
[MethodImplAttribute(MethodImplOptions.InternalCall)]
|
||||
public extern static long CompareExchange (ref long location1, long value, long comparand);
|
||||
|
||||
[MethodImplAttribute(MethodImplOptions.InternalCall)]
|
||||
public extern static IntPtr CompareExchange (ref IntPtr location1, IntPtr value, IntPtr comparand);
|
||||
|
||||
[MethodImplAttribute(MethodImplOptions.InternalCall)]
|
||||
public extern static double CompareExchange (ref double location1, double value, double comparand);
|
||||
|
||||
[MethodImplAttribute(MethodImplOptions.InternalCall)]
|
||||
public extern static T CompareExchange<T> (ref T location1, T value, T comparand) where T : class;
|
||||
|
||||
[MethodImplAttribute(MethodImplOptions.InternalCall)]
|
||||
public extern static long Exchange (ref long location1, long value);
|
||||
|
||||
[MethodImplAttribute(MethodImplOptions.InternalCall)]
|
||||
public extern static IntPtr Exchange (ref IntPtr location1, IntPtr value);
|
||||
|
||||
[MethodImplAttribute(MethodImplOptions.InternalCall)]
|
||||
public extern static double Exchange (ref double location1, double value);
|
||||
|
||||
[MethodImplAttribute(MethodImplOptions.InternalCall)]
|
||||
public extern static T Exchange<T> (ref T location1, T value) where T : class;
|
||||
|
||||
[MethodImplAttribute(MethodImplOptions.InternalCall)]
|
||||
public extern static long Read (ref long location);
|
||||
|
||||
[MethodImplAttribute(MethodImplOptions.InternalCall)]
|
||||
public extern static int Add (ref int location1, int value);
|
||||
|
||||
[MethodImplAttribute(MethodImplOptions.InternalCall)]
|
||||
public extern static long Add (ref long location1, long value);
|
||||
|
||||
public static void MemoryBarrier () => Thread.MemoryBarrier ();
|
||||
|
||||
[MethodImplAttribute(MethodImplOptions.InternalCall)]
|
||||
public extern static void MemoryBarrierProcessWide ();
|
||||
}
|
||||
}
|
||||
173
mcs/class/System.Private.CoreLib/System.Threading/Monitor.cs
Normal file
173
mcs/class/System.Private.CoreLib/System.Threading/Monitor.cs
Normal file
@@ -0,0 +1,173 @@
|
||||
using System.Runtime.CompilerServices;
|
||||
|
||||
namespace System.Threading
|
||||
{
|
||||
public static partial class Monitor
|
||||
{
|
||||
[MethodImplAttribute (MethodImplOptions.InternalCall)]
|
||||
public static extern void Enter (object obj);
|
||||
|
||||
public static void Enter (object obj, ref bool lockTaken)
|
||||
{
|
||||
if (lockTaken)
|
||||
throw new ArgumentException (SR.Argument_MustBeFalse, nameof (lockTaken));
|
||||
|
||||
ReliableEnter (obj, ref lockTaken);
|
||||
}
|
||||
|
||||
[MethodImplAttribute (MethodImplOptions.InternalCall)]
|
||||
public static extern void Exit (object obj);
|
||||
|
||||
public static bool TryEnter (object obj)
|
||||
{
|
||||
bool lockTaken = false;
|
||||
TryEnter (obj, 0, ref lockTaken);
|
||||
return lockTaken;
|
||||
}
|
||||
|
||||
public static void TryEnter (object obj, ref bool lockTaken)
|
||||
{
|
||||
if (lockTaken)
|
||||
throw new ArgumentException (SR.Argument_MustBeFalse, nameof (lockTaken));
|
||||
|
||||
ReliableEnterTimeout (obj, 0, ref lockTaken);
|
||||
}
|
||||
|
||||
public static bool TryEnter (object obj, int millisecondsTimeout)
|
||||
{
|
||||
bool lockTaken = false;
|
||||
TryEnter (obj, millisecondsTimeout, ref lockTaken);
|
||||
return lockTaken;
|
||||
}
|
||||
|
||||
static int MillisecondsTimeoutFromTimeSpan (TimeSpan timeout)
|
||||
{
|
||||
long tm = (long) timeout.TotalMilliseconds;
|
||||
if (tm < -1 || tm > (long) int.MaxValue)
|
||||
throw new ArgumentOutOfRangeException (nameof (timeout), SR.ArgumentOutOfRange_NeedNonNegOrNegative1);
|
||||
return (int) tm;
|
||||
}
|
||||
|
||||
public static bool TryEnter (object obj, TimeSpan timeout)
|
||||
{
|
||||
return TryEnter (obj, MillisecondsTimeoutFromTimeSpan (timeout));
|
||||
}
|
||||
|
||||
public static void TryEnter (object obj, int millisecondsTimeout, ref bool lockTaken)
|
||||
{
|
||||
if (lockTaken)
|
||||
throw new ArgumentException (SR.Argument_MustBeFalse, nameof (lockTaken));
|
||||
ReliableEnterTimeout (obj, millisecondsTimeout, ref lockTaken);
|
||||
}
|
||||
|
||||
public static void TryEnter(object obj, TimeSpan timeout, ref bool lockTaken)
|
||||
{
|
||||
if (lockTaken)
|
||||
throw new ArgumentException (SR.Argument_MustBeFalse, nameof (lockTaken));
|
||||
ReliableEnterTimeout (obj, MillisecondsTimeoutFromTimeSpan (timeout), ref lockTaken);
|
||||
}
|
||||
|
||||
public static bool IsEntered (object obj)
|
||||
{
|
||||
if (obj == null)
|
||||
throw new ArgumentNullException (nameof (obj));
|
||||
return IsEnteredNative (obj);
|
||||
}
|
||||
|
||||
public static bool Wait (object obj, int millisecondsTimeout, bool exitContext)
|
||||
{
|
||||
if (obj == null)
|
||||
throw new ArgumentNullException (nameof (obj));
|
||||
return ObjWait (exitContext, millisecondsTimeout, obj);
|
||||
}
|
||||
|
||||
public static bool Wait (object obj, TimeSpan timeout, bool exitContext) => Wait (obj, MillisecondsTimeoutFromTimeSpan (timeout), exitContext);
|
||||
|
||||
public static bool Wait (object obj, int millisecondsTimeout) => Wait (obj, millisecondsTimeout, false);
|
||||
|
||||
public static bool Wait(object obj, TimeSpan timeout) => Wait (obj, MillisecondsTimeoutFromTimeSpan (timeout), false);
|
||||
|
||||
public static bool Wait(object obj) => Wait (obj, Timeout.Infinite, false);
|
||||
|
||||
public static void Pulse (object obj)
|
||||
{
|
||||
if (obj == null)
|
||||
throw new ArgumentNullException (nameof (obj));
|
||||
ObjPulse (obj);
|
||||
}
|
||||
|
||||
public static void PulseAll (object obj)
|
||||
{
|
||||
if (obj == null)
|
||||
throw new ArgumentNullException (nameof (obj));
|
||||
ObjPulseAll (obj);
|
||||
}
|
||||
|
||||
[MethodImplAttribute (MethodImplOptions.InternalCall)]
|
||||
extern static bool Monitor_test_synchronised (object obj);
|
||||
|
||||
[MethodImplAttribute (MethodImplOptions.InternalCall)]
|
||||
extern static void Monitor_pulse (object obj);
|
||||
|
||||
static void ObjPulse (object obj)
|
||||
{
|
||||
if (!Monitor_test_synchronised (obj))
|
||||
throw new SynchronizationLockException ("Object is not synchronized");
|
||||
|
||||
Monitor_pulse (obj);
|
||||
}
|
||||
|
||||
[MethodImplAttribute (MethodImplOptions.InternalCall)]
|
||||
extern static void Monitor_pulse_all (object obj);
|
||||
|
||||
static void ObjPulseAll (object obj)
|
||||
{
|
||||
if (!Monitor_test_synchronised (obj))
|
||||
throw new SynchronizationLockException ("Object is not synchronized");
|
||||
|
||||
Monitor_pulse_all (obj);
|
||||
}
|
||||
|
||||
[MethodImplAttribute (MethodImplOptions.InternalCall)]
|
||||
extern static bool Monitor_wait (object obj, int ms);
|
||||
|
||||
static bool ObjWait (bool exitContext, int millisecondsTimeout, object obj)
|
||||
{
|
||||
if (millisecondsTimeout < 0 && millisecondsTimeout != (int) Timeout.Infinite)
|
||||
throw new ArgumentOutOfRangeException ("millisecondsTimeout");
|
||||
if (!Monitor_test_synchronised (obj))
|
||||
throw new SynchronizationLockException ("Object is not synchronized");
|
||||
|
||||
return Monitor_wait (obj, millisecondsTimeout);
|
||||
}
|
||||
|
||||
[MethodImplAttribute (MethodImplOptions.InternalCall)]
|
||||
extern static void try_enter_with_atomic_var (object obj, int millisecondsTimeout, ref bool lockTaken);
|
||||
|
||||
static void ReliableEnterTimeout (object obj, int timeout, ref bool lockTaken)
|
||||
{
|
||||
if (obj == null)
|
||||
throw new ArgumentNullException (nameof (obj));
|
||||
|
||||
if (timeout < 0 && timeout != (int) Timeout.Infinite)
|
||||
throw new ArgumentOutOfRangeException (nameof (timeout));
|
||||
|
||||
try_enter_with_atomic_var (obj, timeout, ref lockTaken);
|
||||
}
|
||||
|
||||
static void ReliableEnter (object obj, ref bool lockTaken)
|
||||
{
|
||||
ReliableEnterTimeout (obj, (int) Timeout.Infinite, ref lockTaken);
|
||||
}
|
||||
|
||||
[MethodImplAttribute (MethodImplOptions.InternalCall)]
|
||||
extern static bool Monitor_test_owner (object obj);
|
||||
|
||||
static bool IsEnteredNative (object obj)
|
||||
{
|
||||
return Monitor_test_owner (obj);
|
||||
}
|
||||
|
||||
public static long LockContentionCount => throw new PlatformNotSupportedException ();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,68 @@
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.IO;
|
||||
|
||||
namespace System.Threading
|
||||
{
|
||||
partial class Mutex
|
||||
{
|
||||
Mutex (IntPtr handle) => Handle = handle;
|
||||
|
||||
public void ReleaseMutex ()
|
||||
{
|
||||
if (!ReleaseMutex_internal (Handle))
|
||||
throw new ApplicationException (SR.Arg_SynchronizationLockException);
|
||||
}
|
||||
|
||||
void CreateMutexCore (bool initiallyOwned, string name, out bool createdNew) =>
|
||||
Handle = CreateMutex_internal (initiallyOwned, name, out createdNew);
|
||||
|
||||
unsafe static IntPtr CreateMutex_internal (bool initiallyOwned, string name, out bool created)
|
||||
{
|
||||
fixed (char *fixed_name = name)
|
||||
return CreateMutex_icall (initiallyOwned, fixed_name,
|
||||
name?.Length ?? 0, out created);
|
||||
}
|
||||
|
||||
static OpenExistingResult OpenExistingWorker (string name, out Mutex result)
|
||||
{
|
||||
if (name == null)
|
||||
throw new ArgumentNullException (nameof (name));
|
||||
|
||||
result = null;
|
||||
if ((name.Length == 0) ||
|
||||
(name.Length > 260)) {
|
||||
return OpenExistingResult.NameInvalid;
|
||||
}
|
||||
|
||||
MonoIOError error;
|
||||
IntPtr handle = OpenMutex_internal (name, out error);
|
||||
if (handle == IntPtr.Zero) {
|
||||
if (error == MonoIOError.ERROR_FILE_NOT_FOUND) {
|
||||
return OpenExistingResult.NameNotFound;
|
||||
} else if (error == MonoIOError.ERROR_ACCESS_DENIED) {
|
||||
throw new UnauthorizedAccessException ();
|
||||
} else {
|
||||
return OpenExistingResult.PathNotFound;
|
||||
}
|
||||
}
|
||||
|
||||
result = new Mutex (handle);
|
||||
return OpenExistingResult.Success;
|
||||
}
|
||||
|
||||
unsafe static IntPtr OpenMutex_internal (string name, out MonoIOError error)
|
||||
{
|
||||
fixed (char *fixed_name = name)
|
||||
return OpenMutex_icall (fixed_name, name?.Length ?? 0, 0x000001 /* MutexRights.Modify */, out error);
|
||||
}
|
||||
|
||||
[MethodImplAttribute(MethodImplOptions.InternalCall)]
|
||||
private unsafe static extern IntPtr CreateMutex_icall (bool initiallyOwned, char *name, int name_length, out bool created);
|
||||
|
||||
[MethodImplAttribute(MethodImplOptions.InternalCall)]
|
||||
private unsafe static extern IntPtr OpenMutex_icall (char *name, int name_length, int rights, out MonoIOError error);
|
||||
|
||||
[MethodImplAttribute(MethodImplOptions.InternalCall)]
|
||||
private static extern bool ReleaseMutex_internal (IntPtr handle);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
namespace System.Threading
|
||||
{
|
||||
public class Overlapped
|
||||
{
|
||||
public Overlapped() { }
|
||||
[System.ObsoleteAttribute("This constructor is not 64-bit compatible. Use the constructor that takes an IntPtr for the event handle. https://go.microsoft.com/fwlink/?linkid=14202")]
|
||||
public Overlapped(int offsetLo, int offsetHi, int hEvent, System.IAsyncResult ar) { }
|
||||
public Overlapped(int offsetLo, int offsetHi, System.IntPtr hEvent, System.IAsyncResult ar) { }
|
||||
public System.IAsyncResult AsyncResult { get { throw null; } set { } }
|
||||
[System.ObsoleteAttribute("This property is not 64-bit compatible. Use EventHandleIntPtr instead. https://go.microsoft.com/fwlink/?linkid=14202")]
|
||||
public int EventHandle { get { throw null; } set { } }
|
||||
public System.IntPtr EventHandleIntPtr { get { throw null; } set { } }
|
||||
public int OffsetHigh { get { throw null; } set { } }
|
||||
public int OffsetLow { get { throw null; } set { } }
|
||||
[System.CLSCompliantAttribute(false)]
|
||||
public static unsafe void Free(System.Threading.NativeOverlapped* nativeOverlappedPtr) { }
|
||||
[System.CLSCompliantAttribute(false)]
|
||||
[System.ObsoleteAttribute("This method is not safe. Use Pack (iocb, userData) instead. https://go.microsoft.com/fwlink/?linkid=14202")]
|
||||
public unsafe System.Threading.NativeOverlapped* Pack(System.Threading.IOCompletionCallback iocb) { throw null; }
|
||||
[System.CLSCompliantAttribute(false)]
|
||||
public unsafe System.Threading.NativeOverlapped* Pack(System.Threading.IOCompletionCallback iocb, object userData) { throw null; }
|
||||
[System.CLSCompliantAttribute(false)]
|
||||
public static unsafe System.Threading.Overlapped Unpack(System.Threading.NativeOverlapped* nativeOverlappedPtr) { throw null; }
|
||||
[System.CLSCompliantAttribute(false)]
|
||||
[System.ObsoleteAttribute("This method is not safe. Use UnsafePack (iocb, userData) instead. https://go.microsoft.com/fwlink/?linkid=14202")]
|
||||
public unsafe System.Threading.NativeOverlapped* UnsafePack(System.Threading.IOCompletionCallback iocb) { throw null; }
|
||||
[System.CLSCompliantAttribute(false)]
|
||||
public unsafe System.Threading.NativeOverlapped* UnsafePack(System.Threading.IOCompletionCallback iocb, object userData) { throw null; }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
namespace System.Threading
|
||||
{
|
||||
public sealed class PreAllocatedOverlapped : System.IDisposable
|
||||
{
|
||||
[System.CLSCompliantAttribute(false)]
|
||||
public PreAllocatedOverlapped(System.Threading.IOCompletionCallback callback, object state, object pinData) { }
|
||||
public void Dispose() { }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,91 @@
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace System.Threading
|
||||
{
|
||||
public sealed class RegisteredWaitHandle : MarshalByRefObject
|
||||
{
|
||||
WaitHandle _waitObject;
|
||||
WaitOrTimerCallback _callback;
|
||||
object _state;
|
||||
WaitHandle _finalEvent;
|
||||
ManualResetEvent _cancelEvent;
|
||||
TimeSpan _timeout;
|
||||
int _callsInProcess;
|
||||
bool _executeOnlyOnce;
|
||||
bool _unregistered;
|
||||
|
||||
internal RegisteredWaitHandle (WaitHandle waitObject, WaitOrTimerCallback callback, object state, TimeSpan timeout, bool executeOnlyOnce)
|
||||
{
|
||||
_waitObject = waitObject;
|
||||
_callback = callback;
|
||||
_state = state;
|
||||
_timeout = timeout;
|
||||
_executeOnlyOnce = executeOnlyOnce;
|
||||
_cancelEvent = new ManualResetEvent (false);
|
||||
}
|
||||
|
||||
internal void Wait (object? state)
|
||||
{
|
||||
bool release = false;
|
||||
try {
|
||||
_waitObject.SafeWaitHandle.DangerousAddRef (ref release);
|
||||
try {
|
||||
WaitHandle[] waits = new WaitHandle[] {_waitObject, _cancelEvent};
|
||||
do {
|
||||
int signal = WaitHandle.WaitAny (waits, _timeout, false);
|
||||
if (!_unregistered) {
|
||||
lock (this) {
|
||||
_callsInProcess++;
|
||||
}
|
||||
ThreadPool.QueueUserWorkItem (new WaitCallback (DoCallBack), (signal == WaitHandle.WaitTimeout));
|
||||
}
|
||||
} while (!_unregistered && !_executeOnlyOnce);
|
||||
} catch {
|
||||
}
|
||||
|
||||
lock (this) {
|
||||
_unregistered = true;
|
||||
if (_callsInProcess == 0 && _finalEvent != null)
|
||||
throw new NotImplementedException ();
|
||||
}
|
||||
} catch (ObjectDisposedException) {
|
||||
// Can happen if we called Unregister before we had time to execute Wait
|
||||
if (release)
|
||||
throw;
|
||||
} finally {
|
||||
if (release)
|
||||
_waitObject.SafeWaitHandle.DangerousRelease ();
|
||||
}
|
||||
}
|
||||
|
||||
void DoCallBack (object? timedOut)
|
||||
{
|
||||
try {
|
||||
if (_callback != null)
|
||||
_callback (_state, (bool)timedOut!);
|
||||
} finally {
|
||||
lock (this) {
|
||||
_callsInProcess--;
|
||||
if (_unregistered && _callsInProcess == 0 && _finalEvent != null) {
|
||||
EventWaitHandle.Set (_finalEvent.SafeWaitHandle);
|
||||
_finalEvent = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public bool Unregister(WaitHandle waitObject)
|
||||
{
|
||||
lock (this) {
|
||||
if (_unregistered)
|
||||
return false;
|
||||
|
||||
_finalEvent = waitObject;
|
||||
_unregistered = true;
|
||||
_cancelEvent.Set();
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,98 @@
|
||||
using System.Runtime.CompilerServices;
|
||||
using Microsoft.Win32.SafeHandles;
|
||||
using System.IO;
|
||||
|
||||
namespace System.Threading
|
||||
{
|
||||
partial class Semaphore
|
||||
{
|
||||
const int MAX_PATH = 260;
|
||||
|
||||
Semaphore (SafeWaitHandle handle) => this.SafeWaitHandle = handle;
|
||||
|
||||
int ReleaseCore (int releaseCount)
|
||||
{
|
||||
if (!ReleaseSemaphore_internal (SafeWaitHandle.DangerousGetHandle (), releaseCount, out int previousCount))
|
||||
throw new SemaphoreFullException ();
|
||||
|
||||
return previousCount;
|
||||
}
|
||||
|
||||
static OpenExistingResult OpenExistingWorker (string name, out Semaphore result)
|
||||
{
|
||||
if (name == null)
|
||||
throw new ArgumentNullException (nameof (name));
|
||||
|
||||
if (name.Length == 0)
|
||||
throw new ArgumentException (SR.Argument_StringZeroLength, nameof (name));
|
||||
|
||||
if (name.Length > MAX_PATH)
|
||||
throw new ArgumentException (SR.Argument_WaitHandleNameTooLong);
|
||||
|
||||
var myHandle = new SafeWaitHandle (OpenSemaphore_internal (name,
|
||||
/*SemaphoreRights.Modify | SemaphoreRights.Synchronize*/ 0x000002 | 0x100000,
|
||||
out MonoIOError errorCode), true);
|
||||
|
||||
if (myHandle.IsInvalid) {
|
||||
result = null;
|
||||
switch (errorCode) {
|
||||
case MonoIOError.ERROR_FILE_NOT_FOUND:
|
||||
case MonoIOError.ERROR_INVALID_NAME:
|
||||
return OpenExistingResult.NameNotFound;
|
||||
case MonoIOError.ERROR_PATH_NOT_FOUND:
|
||||
return OpenExistingResult.PathNotFound;
|
||||
case MonoIOError.ERROR_INVALID_HANDLE when !string.IsNullOrEmpty (name):
|
||||
return OpenExistingResult.NameInvalid;
|
||||
default:
|
||||
//this is for passed through NativeMethods Errors
|
||||
throw new IOException ($"Unknown Error '{errorCode}'");
|
||||
}
|
||||
}
|
||||
|
||||
result = new Semaphore (myHandle);
|
||||
return OpenExistingResult.Success;
|
||||
}
|
||||
|
||||
void CreateSemaphoreCore (int initialCount, int maximumCount, string name, out bool createdNew)
|
||||
{
|
||||
if (name?.Length > MAX_PATH)
|
||||
throw new ArgumentException (SR.Argument_WaitHandleNameTooLong);
|
||||
|
||||
var myHandle = new SafeWaitHandle (CreateSemaphore_internal (initialCount, maximumCount, name, out MonoIOError errorCode), true);
|
||||
|
||||
if (myHandle.IsInvalid) {
|
||||
if (errorCode == MonoIOError.ERROR_INVALID_HANDLE && !string.IsNullOrEmpty (name))
|
||||
throw new WaitHandleCannotBeOpenedException (SR.Format (SR.Threading_WaitHandleCannotBeOpenedException_InvalidHandle, name));
|
||||
|
||||
throw new IOException ($"Unknown Error '{errorCode}'");
|
||||
}
|
||||
|
||||
this.SafeWaitHandle = myHandle;
|
||||
createdNew = errorCode != MonoIOError.ERROR_ALREADY_EXISTS;
|
||||
}
|
||||
|
||||
unsafe static IntPtr CreateSemaphore_internal (int initialCount, int maximumCount, string name, out MonoIOError errorCode)
|
||||
{
|
||||
// FIXME Check for embedded nuls in name.
|
||||
fixed (char *fixed_name = name)
|
||||
return CreateSemaphore_icall (initialCount, maximumCount,
|
||||
fixed_name, name?.Length ?? 0, out errorCode);
|
||||
}
|
||||
|
||||
unsafe static IntPtr OpenSemaphore_internal (string name, int rights, out MonoIOError errorCode)
|
||||
{
|
||||
// FIXME Check for embedded nuls in name.
|
||||
fixed (char *fixed_name = name)
|
||||
return OpenSemaphore_icall (fixed_name, name?.Length ?? 0, rights, out errorCode);
|
||||
}
|
||||
|
||||
[MethodImplAttribute (MethodImplOptions.InternalCall)]
|
||||
unsafe static extern IntPtr CreateSemaphore_icall (int initialCount, int maximumCount, char* name, int nameLength, out MonoIOError errorCode);
|
||||
|
||||
[MethodImplAttribute (MethodImplOptions.InternalCall)]
|
||||
unsafe static extern IntPtr OpenSemaphore_icall (char* name, int nameLength, int rights, out MonoIOError errorCode);
|
||||
|
||||
[MethodImplAttribute (MethodImplOptions.InternalCall)]
|
||||
static extern bool ReleaseSemaphore_internal (IntPtr handle, int releaseCount, out int previousCount);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
namespace System.Threading
|
||||
{
|
||||
// declaring a local var of this enum type and passing it by ref into a function that needs to do a
|
||||
// stack crawl will both prevent inlining of the calle and pass an ESP point to stack crawl to
|
||||
// Declaring these in EH clauses is illegal; they must declared in the main method body
|
||||
internal enum StackCrawlMark
|
||||
{
|
||||
LookForMe = 0,
|
||||
LookForMyCaller = 1,
|
||||
LookForMyCallersCaller = 2,
|
||||
LookForThread = 3
|
||||
}
|
||||
}
|
||||
316
mcs/class/System.Private.CoreLib/System.Threading/Thread.cs
Normal file
316
mcs/class/System.Private.CoreLib/System.Threading/Thread.cs
Normal file
@@ -0,0 +1,316 @@
|
||||
using System.Globalization;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace System.Threading
|
||||
{
|
||||
//
|
||||
// Under netcore, there is only one thread object per thread
|
||||
//
|
||||
[StructLayout (LayoutKind.Sequential)]
|
||||
partial class Thread
|
||||
{
|
||||
#pragma warning disable 169, 414, 649
|
||||
#region Sync with metadata/object-internals.h and InternalThread in mcs/class/corlib/System.Threading/Thread.cs
|
||||
int lock_thread_id;
|
||||
// stores a thread handle
|
||||
IntPtr handle;
|
||||
IntPtr native_handle; // used only on Win32
|
||||
IntPtr unused3;
|
||||
/* accessed only from unmanaged code */
|
||||
private IntPtr name;
|
||||
private int name_len;
|
||||
private ThreadState state;
|
||||
private object abort_exc;
|
||||
private int abort_state_handle;
|
||||
/* thread_id is only accessed from unmanaged code */
|
||||
internal Int64 thread_id;
|
||||
private IntPtr debugger_thread; // FIXME switch to bool as soon as CI testing with corlib version bump works
|
||||
private UIntPtr static_data; /* GC-tracked */
|
||||
private IntPtr runtime_thread_info;
|
||||
/* current System.Runtime.Remoting.Contexts.Context instance
|
||||
keep as an object to avoid triggering its class constructor when not needed */
|
||||
private object current_appcontext;
|
||||
private object root_domain_thread;
|
||||
internal byte[] _serialized_principal;
|
||||
internal int _serialized_principal_version;
|
||||
private IntPtr appdomain_refs;
|
||||
private int interruption_requested;
|
||||
private IntPtr longlived;
|
||||
internal bool threadpool_thread;
|
||||
private bool thread_interrupt_requested;
|
||||
/* These are used from managed code */
|
||||
internal int stack_size;
|
||||
internal byte apartment_state;
|
||||
internal volatile int critical_region_level;
|
||||
internal int managed_id;
|
||||
private int small_id;
|
||||
private IntPtr manage_callback;
|
||||
private IntPtr unused4;
|
||||
private IntPtr flags;
|
||||
private IntPtr thread_pinning_ref;
|
||||
private IntPtr abort_protected_block_count;
|
||||
private int priority;
|
||||
private IntPtr owned_mutex;
|
||||
private IntPtr suspended_event;
|
||||
private int self_suspended;
|
||||
private IntPtr thread_state;
|
||||
private Thread self;
|
||||
private object pending_exception;
|
||||
private object start_obj;
|
||||
|
||||
/* This is used only to check that we are in sync between the representation
|
||||
* of MonoInternalThread in native and InternalThread in managed
|
||||
*
|
||||
* DO NOT RENAME! DO NOT ADD FIELDS AFTER! */
|
||||
private IntPtr last;
|
||||
#endregion
|
||||
#pragma warning restore 169, 414, 649
|
||||
|
||||
string _name;
|
||||
Delegate m_start;
|
||||
object m_start_arg;
|
||||
CultureInfo culture, ui_culture;
|
||||
internal ExecutionContext _executionContext;
|
||||
internal SynchronizationContext _synchronizationContext;
|
||||
|
||||
Thread ()
|
||||
{
|
||||
InitInternal (this);
|
||||
}
|
||||
|
||||
~Thread ()
|
||||
{
|
||||
FreeInternal ();
|
||||
}
|
||||
|
||||
internal static ulong CurrentOSThreadId {
|
||||
get {
|
||||
throw new NotImplementedException ();
|
||||
}
|
||||
}
|
||||
|
||||
public bool IsAlive {
|
||||
get {
|
||||
var state = GetState (this);
|
||||
return (state & (ThreadState.Unstarted | ThreadState.Stopped | ThreadState.Aborted)) == 0;
|
||||
}
|
||||
}
|
||||
|
||||
public bool IsBackground {
|
||||
get {
|
||||
var state = ValidateThreadState ();
|
||||
return (state & ThreadState.Background) != 0;
|
||||
}
|
||||
set {
|
||||
ValidateThreadState ();
|
||||
if (value) {
|
||||
SetState (this, ThreadState.Background);
|
||||
} else {
|
||||
ClrState (this, ThreadState.Background);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public bool IsThreadPoolThread {
|
||||
get {
|
||||
ValidateThreadState ();
|
||||
return threadpool_thread;
|
||||
}
|
||||
}
|
||||
|
||||
public int ManagedThreadId => managed_id;
|
||||
|
||||
internal static int OptimalMaxSpinWaitsPerSpinIteration {
|
||||
get {
|
||||
// Default from coreclr (src/utilcode/yieldprocessornormalized.cpp)
|
||||
return 7;
|
||||
}
|
||||
}
|
||||
|
||||
public ThreadPriority Priority {
|
||||
get {
|
||||
ValidateThreadState ();
|
||||
return (ThreadPriority) priority;
|
||||
}
|
||||
set {
|
||||
// TODO: arguments check
|
||||
SetPriority (this, (int) value);
|
||||
}
|
||||
}
|
||||
|
||||
internal SynchronizationContext SynchronizationContext { get; set; }
|
||||
|
||||
public ThreadState ThreadState => GetState (this);
|
||||
|
||||
void Create (ThreadStart start) => SetStartHelper ((Delegate) start, 0); // 0 will setup Thread with default stackSize
|
||||
|
||||
void Create (ThreadStart start, int maxStackSize) => SetStartHelper ((Delegate) start, maxStackSize);
|
||||
|
||||
void Create (ParameterizedThreadStart start) => SetStartHelper ((Delegate) start, 0);
|
||||
|
||||
void Create (ParameterizedThreadStart start, int maxStackSize) => SetStartHelper ((Delegate) start, maxStackSize);
|
||||
|
||||
public ApartmentState GetApartmentState () => ApartmentState.Unknown;
|
||||
|
||||
public void DisableComObjectEagerCleanup ()
|
||||
{
|
||||
// no-op
|
||||
}
|
||||
|
||||
public static int GetCurrentProcessorId ()
|
||||
{
|
||||
// TODO: Implement correctly
|
||||
return Environment.CurrentManagedThreadId;
|
||||
}
|
||||
|
||||
public void Interrupt ()
|
||||
{
|
||||
InterruptInternal (this);
|
||||
}
|
||||
|
||||
public bool Join (int millisecondsTimeout)
|
||||
{
|
||||
if (millisecondsTimeout < Timeout.Infinite)
|
||||
throw new ArgumentOutOfRangeException (nameof (millisecondsTimeout), millisecondsTimeout, SR.ArgumentOutOfRange_NeedNonNegOrNegative1);
|
||||
return JoinInternal (this, millisecondsTimeout);
|
||||
}
|
||||
|
||||
public void ResetThreadPoolThread ()
|
||||
{
|
||||
}
|
||||
|
||||
void SetCultureOnUnstartedThreadNoCheck (CultureInfo value, bool uiCulture)
|
||||
{
|
||||
if (uiCulture)
|
||||
ui_culture = value;
|
||||
else
|
||||
culture = value;
|
||||
}
|
||||
|
||||
void SetStartHelper (Delegate start, int maxStackSize)
|
||||
{
|
||||
m_start = start;
|
||||
stack_size = maxStackSize;
|
||||
}
|
||||
|
||||
public static void SpinWait (int iterations)
|
||||
{
|
||||
if (iterations < 0)
|
||||
return;
|
||||
|
||||
while (iterations-- > 0)
|
||||
SpinWait_nop ();
|
||||
}
|
||||
|
||||
public static void Sleep (int millisecondsTimeout)
|
||||
{
|
||||
if (millisecondsTimeout < Timeout.Infinite)
|
||||
throw new ArgumentOutOfRangeException (nameof (millisecondsTimeout), millisecondsTimeout, SR.ArgumentOutOfRange_NeedNonNegOrNegative1);
|
||||
|
||||
SleepInternal (millisecondsTimeout);
|
||||
}
|
||||
|
||||
public void Start ()
|
||||
{
|
||||
StartInternal (this);
|
||||
}
|
||||
|
||||
public void Start (object parameter)
|
||||
{
|
||||
if (m_start is ThreadStart)
|
||||
throw new InvalidOperationException (SR.InvalidOperation_ThreadWrongThreadStart);
|
||||
|
||||
m_start_arg = parameter;
|
||||
StartInternal (this);
|
||||
}
|
||||
|
||||
// Called from the runtime
|
||||
internal void StartCallback ()
|
||||
{
|
||||
if (culture != null)
|
||||
CurrentCulture = culture;
|
||||
if (ui_culture != null)
|
||||
CurrentUICulture = ui_culture;
|
||||
if (m_start is ThreadStart del) {
|
||||
m_start = null;
|
||||
del ();
|
||||
} else {
|
||||
var pdel = (ParameterizedThreadStart) m_start;
|
||||
var arg = m_start_arg;
|
||||
m_start = null;
|
||||
m_start_arg = null;
|
||||
pdel (arg);
|
||||
}
|
||||
}
|
||||
|
||||
partial void ThreadNameChanged (string value)
|
||||
{
|
||||
// TODO: Should only raise the events
|
||||
SetName (this, value);
|
||||
}
|
||||
|
||||
public static bool Yield ()
|
||||
{
|
||||
return YieldInternal ();
|
||||
}
|
||||
|
||||
public bool TrySetApartmentStateUnchecked (ApartmentState state) => state == ApartmentState.Unknown;
|
||||
|
||||
ThreadState ValidateThreadState ()
|
||||
{
|
||||
var state = GetState (this);
|
||||
if ((state & ThreadState.Stopped) != 0)
|
||||
throw new ThreadStateException ("Thread is dead; state can not be accessed.");
|
||||
return state;
|
||||
}
|
||||
|
||||
[MethodImplAttribute (MethodImplOptions.InternalCall)]
|
||||
extern static void InitInternal (Thread thread);
|
||||
|
||||
[MethodImplAttribute(MethodImplOptions.InternalCall)]
|
||||
extern static Thread InitializeCurrentThread ();
|
||||
|
||||
[MethodImplAttribute(MethodImplOptions.InternalCall)]
|
||||
extern void FreeInternal ();
|
||||
|
||||
[MethodImplAttribute (MethodImplOptions.InternalCall)]
|
||||
extern static ThreadState GetState (Thread thread);
|
||||
|
||||
[MethodImplAttribute (MethodImplOptions.InternalCall)]
|
||||
extern static void SetState (Thread thread, ThreadState set);
|
||||
|
||||
[MethodImplAttribute (MethodImplOptions.InternalCall)]
|
||||
extern static void ClrState (Thread thread, ThreadState clr);
|
||||
|
||||
[MethodImplAttribute(MethodImplOptions.InternalCall)]
|
||||
extern static string GetName (Thread thread);
|
||||
|
||||
[MethodImplAttribute(MethodImplOptions.InternalCall)]
|
||||
extern static void SetName (Thread thread, String name);
|
||||
|
||||
[MethodImplAttribute(MethodImplOptions.InternalCall)]
|
||||
extern static bool YieldInternal ();
|
||||
|
||||
[MethodImplAttribute(MethodImplOptions.InternalCall)]
|
||||
extern static void SleepInternal (int millisecondsTimeout);
|
||||
|
||||
[MethodImplAttribute (MethodImplOptions.InternalCall)]
|
||||
extern static void SpinWait_nop ();
|
||||
|
||||
[MethodImplAttribute (MethodImplOptions.InternalCall)]
|
||||
extern static Thread CreateInternal ();
|
||||
|
||||
[MethodImplAttribute (MethodImplOptions.InternalCall)]
|
||||
extern static void StartInternal (Thread runtime_thread);
|
||||
|
||||
[MethodImplAttribute(MethodImplOptions.InternalCall)]
|
||||
extern static bool JoinInternal (Thread thread, int millisecondsTimeout);
|
||||
|
||||
[MethodImplAttribute(MethodImplOptions.InternalCall)]
|
||||
extern static void InterruptInternal (Thread thread);
|
||||
|
||||
[MethodImplAttribute(MethodImplOptions.InternalCall)]
|
||||
extern static void SetPriority (Thread thread, int priority);
|
||||
}
|
||||
}
|
||||
131
mcs/class/System.Private.CoreLib/System.Threading/ThreadPool.cs
Normal file
131
mcs/class/System.Private.CoreLib/System.Threading/ThreadPool.cs
Normal file
@@ -0,0 +1,131 @@
|
||||
using System.Runtime.CompilerServices;
|
||||
|
||||
namespace System.Threading
|
||||
{
|
||||
partial class ThreadPool
|
||||
{
|
||||
[MethodImplAttribute (MethodImplOptions.InternalCall)]
|
||||
static extern void InitializeVMTp (ref bool enableWorkerTracking);
|
||||
|
||||
static void EnsureInitialized ()
|
||||
{
|
||||
if (!ThreadPoolGlobals.threadPoolInitialized) {
|
||||
ThreadPool.InitializeVMTp (ref ThreadPoolGlobals.enableWorkerTracking);
|
||||
ThreadPoolGlobals.threadPoolInitialized = true;
|
||||
}
|
||||
}
|
||||
|
||||
[MethodImplAttribute (MethodImplOptions.InternalCall)]
|
||||
internal static extern bool RequestWorkerThread ();
|
||||
|
||||
internal static bool KeepDispatching (int startTickCount) => true;
|
||||
|
||||
internal static void NotifyWorkItemProgress ()
|
||||
{
|
||||
EnsureInitialized ();
|
||||
NotifyWorkItemProgressNative ();
|
||||
}
|
||||
|
||||
[MethodImplAttribute (MethodImplOptions.InternalCall)]
|
||||
internal static extern void NotifyWorkItemProgressNative ();
|
||||
|
||||
static RegisteredWaitHandle RegisterWaitForSingleObject (WaitHandle waitObject, WaitOrTimerCallback callBack, object state,
|
||||
uint millisecondsTimeOutInterval, bool executeOnlyOnce, bool compressStack)
|
||||
{
|
||||
if (waitObject == null)
|
||||
throw new ArgumentNullException ("waitObject");
|
||||
if (callBack == null)
|
||||
throw new ArgumentNullException ("callBack");
|
||||
if (millisecondsTimeOutInterval != Timeout.UnsignedInfinite && millisecondsTimeOutInterval > Int32.MaxValue)
|
||||
throw new NotSupportedException ("Timeout is too big. Maximum is Int32.MaxValue");
|
||||
|
||||
RegisteredWaitHandle waiter = new RegisteredWaitHandle (waitObject, callBack, state, new TimeSpan (0, 0, 0, 0, (int) millisecondsTimeOutInterval), executeOnlyOnce);
|
||||
if (compressStack)
|
||||
QueueUserWorkItem (new WaitCallback (waiter.Wait), null);
|
||||
else
|
||||
UnsafeQueueUserWorkItem (new WaitCallback (waiter.Wait), null);
|
||||
|
||||
return waiter;
|
||||
}
|
||||
|
||||
[MethodImplAttribute (MethodImplOptions.InternalCall)]
|
||||
internal static extern void ReportThreadStatus (bool isWorking);
|
||||
|
||||
[MethodImplAttribute (MethodImplOptions.InternalCall)]
|
||||
internal static extern bool NotifyWorkItemComplete ();
|
||||
|
||||
[MethodImplAttribute (MethodImplOptions.InternalCall)]
|
||||
static extern bool SetMinThreadsNative (int workerThreads, int completionPortThreads);
|
||||
|
||||
[MethodImplAttribute (MethodImplOptions.InternalCall)]
|
||||
static extern bool SetMaxThreadsNative (int workerThreads, int completionPortThreads);
|
||||
|
||||
[MethodImplAttribute (MethodImplOptions.InternalCall)]
|
||||
static extern void GetMinThreadsNative (out int workerThreads, out int completionPortThreads);
|
||||
|
||||
[MethodImplAttribute (MethodImplOptions.InternalCall)]
|
||||
static extern void GetMaxThreadsNative (out int workerThreads, out int completionPortThreads);
|
||||
|
||||
[MethodImplAttribute (MethodImplOptions.InternalCall)]
|
||||
static extern void GetAvailableThreadsNative (out int workerThreads, out int completionPortThreads);
|
||||
|
||||
public static bool SetMaxThreads (int workerThreads, int completionPortThreads)
|
||||
{
|
||||
return SetMaxThreadsNative (workerThreads, completionPortThreads);
|
||||
}
|
||||
|
||||
public static void GetMaxThreads (out int workerThreads, out int completionPortThreads)
|
||||
{
|
||||
GetMaxThreadsNative (out workerThreads, out completionPortThreads);
|
||||
}
|
||||
|
||||
public static bool SetMinThreads (int workerThreads, int completionPortThreads)
|
||||
{
|
||||
return SetMinThreadsNative (workerThreads, completionPortThreads);
|
||||
}
|
||||
|
||||
public static void GetMinThreads (out int workerThreads, out int completionPortThreads)
|
||||
{
|
||||
GetMinThreadsNative (out workerThreads, out completionPortThreads);
|
||||
}
|
||||
|
||||
public static void GetAvailableThreads(out int workerThreads, out int completionPortThreads)
|
||||
{
|
||||
GetAvailableThreadsNative (out workerThreads, out completionPortThreads);
|
||||
}
|
||||
|
||||
public static bool BindHandle (IntPtr osHandle) => throw new NotImplementedException ();
|
||||
public static bool BindHandle (System.Runtime.InteropServices.SafeHandle osHandle) => throw new NotImplementedException ();
|
||||
|
||||
[CLSCompliant (false)]
|
||||
public static unsafe bool UnsafeQueueNativeOverlapped (NativeOverlapped* overlapped) => throw new NotImplementedException ();
|
||||
|
||||
static long PendingUnmanagedWorkItemCount => 0;
|
||||
|
||||
public static long CompletedWorkItemCount => throw new PlatformNotSupportedException ();
|
||||
|
||||
public static int ThreadCount => throw new NotImplementedException ();
|
||||
}
|
||||
|
||||
internal static class _ThreadPoolWaitCallback
|
||||
{
|
||||
// This feature is used by Xamarin.iOS to use an NSAutoreleasePool
|
||||
// for every task done by the threadpool.
|
||||
static Func<Func<bool>, bool> dispatcher;
|
||||
|
||||
internal static void SetDispatcher (Func<Func<bool>, bool> value)
|
||||
{
|
||||
dispatcher = value;
|
||||
}
|
||||
|
||||
static internal bool PerformWaitCallback ()
|
||||
{
|
||||
// store locally first to ensure another thread doesn't clear the field between checking for null and using it.
|
||||
var dispatcher = _ThreadPoolWaitCallback.dispatcher;
|
||||
if (dispatcher != null)
|
||||
return dispatcher (ThreadPoolWorkQueue.Dispatch);
|
||||
|
||||
return ThreadPoolWorkQueue.Dispatch ();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
namespace System.Threading
|
||||
{
|
||||
public sealed partial class ThreadPoolBoundHandle : System.IDisposable
|
||||
{
|
||||
internal ThreadPoolBoundHandle() { }
|
||||
public System.Runtime.InteropServices.SafeHandle Handle { get { throw null; } }
|
||||
[System.CLSCompliantAttribute(false)]
|
||||
public unsafe System.Threading.NativeOverlapped* AllocateNativeOverlapped(System.Threading.IOCompletionCallback callback, object state, object pinData) { throw null; }
|
||||
[System.CLSCompliantAttribute(false)]
|
||||
public unsafe System.Threading.NativeOverlapped* AllocateNativeOverlapped(System.Threading.PreAllocatedOverlapped preAllocated) { throw null; }
|
||||
public static System.Threading.ThreadPoolBoundHandle BindHandle(System.Runtime.InteropServices.SafeHandle handle) { throw null; }
|
||||
public void Dispose() { }
|
||||
[System.CLSCompliantAttribute(false)]
|
||||
public unsafe void FreeNativeOverlapped(System.Threading.NativeOverlapped* overlapped) { }
|
||||
[System.CLSCompliantAttribute(false)]
|
||||
public static unsafe object GetNativeOverlappedState(System.Threading.NativeOverlapped* overlapped) { throw null; }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace System.Threading
|
||||
{
|
||||
partial class WaitHandle
|
||||
{
|
||||
[MethodImplAttribute(MethodImplOptions.InternalCall)]
|
||||
unsafe static extern int Wait_internal(IntPtr* handles, int numHandles, bool waitAll, int ms);
|
||||
|
||||
static int WaitOneCore (IntPtr waitHandle, int millisecondsTimeout)
|
||||
{
|
||||
unsafe {
|
||||
return Wait_internal (&waitHandle, 1, false, millisecondsTimeout);
|
||||
}
|
||||
}
|
||||
|
||||
[MethodImpl (MethodImplOptions.InternalCall)]
|
||||
static extern int SignalAndWait_Internal (IntPtr waitHandleToSignal, IntPtr waitHandleToWaitOn, int millisecondsTimeout);
|
||||
|
||||
const int ERROR_TOO_MANY_POSTS = 0x12A;
|
||||
const int ERROR_NOT_OWNED_BY_CALLER = 0x12B;
|
||||
|
||||
static int SignalAndWaitCore (IntPtr waitHandleToSignal, IntPtr waitHandleToWaitOn, int millisecondsTimeout)
|
||||
{
|
||||
int ret = SignalAndWait_Internal (waitHandleToSignal, waitHandleToWaitOn, millisecondsTimeout);
|
||||
if (ret == ERROR_TOO_MANY_POSTS)
|
||||
throw new InvalidOperationException (SR.Threading_WaitHandleTooManyPosts);
|
||||
if (ret == ERROR_NOT_OWNED_BY_CALLER)
|
||||
throw new ApplicationException("Attempt to release mutex not owned by caller");
|
||||
return ret;
|
||||
}
|
||||
|
||||
internal static int WaitMultipleIgnoringSyncContext (Span<IntPtr> waitHandles, bool waitAll, int millisecondsTimeout)
|
||||
{
|
||||
unsafe {
|
||||
fixed (IntPtr* handles = &MemoryMarshal.GetReference (waitHandles)) {
|
||||
return Wait_internal (handles, waitHandles.Length, waitAll, millisecondsTimeout);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user