2019-08-23 11:56:54 -07:00
|
|
|
namespace System.Threading
|
|
|
|
{
|
|
|
|
using System;
|
|
|
|
using System.Diagnostics;
|
|
|
|
|
2020-03-09 06:34:16 -07:00
|
|
|
public delegate Object InternalCrossContextDelegate(Object[] args);
|
2019-08-23 11:56:54 -07:00
|
|
|
|
|
|
|
public delegate void ThreadStart();
|
|
|
|
public delegate void ParameterizedThreadStart(Object obj);
|
|
|
|
|
2021-06-24 09:24:41 -07:00
|
|
|
[StaticInitPriority(100)]
|
2019-08-23 11:56:54 -07:00
|
|
|
public sealed class Thread
|
|
|
|
{
|
|
|
|
private int mInternalThread;
|
2021-06-19 12:35:29 -07:00
|
|
|
private ThreadPriority mPriority = .Normal;
|
2019-08-23 11:56:54 -07:00
|
|
|
public int32 mMaxStackSize;
|
|
|
|
private String mName ~ delete _;
|
|
|
|
private Delegate mDelegate;
|
|
|
|
|
|
|
|
private Object mThreadStartArg;
|
|
|
|
|
|
|
|
bool mAutoDelete;
|
|
|
|
public static Thread sMainThread = new Thread() ~ delete _;
|
|
|
|
|
2021-06-24 09:24:41 -07:00
|
|
|
[StaticInitPriority(102)]
|
2019-08-23 11:56:54 -07:00
|
|
|
struct RuntimeThreadInit
|
|
|
|
{
|
|
|
|
static Object Thread_Alloc()
|
|
|
|
{
|
2020-08-16 08:34:31 -07:00
|
|
|
return Thread.CreateEmptyThread();
|
2019-08-23 11:56:54 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
static Object Thread_GetMainThread()
|
|
|
|
{
|
|
|
|
return Thread.[Friend]sMainThread;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void* Thread_GetInternalThread(Object thread)
|
|
|
|
{
|
|
|
|
return (void*)((Thread)thread).[Friend]mInternalThread;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void Thread_SetInternalThread(Object thread, void* internalThread)
|
|
|
|
{
|
2020-08-31 11:29:11 -07:00
|
|
|
if (internalThread != null)
|
|
|
|
GC.[Friend]AddPendingThread(internalThread);
|
2019-08-23 11:56:54 -07:00
|
|
|
((Thread)thread).[Friend]mInternalThread = (int)internalThread;
|
|
|
|
}
|
|
|
|
|
|
|
|
static bool Thread_IsAutoDelete(Object thread)
|
|
|
|
{
|
|
|
|
return ((Thread)thread).[Friend]mAutoDelete;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void Thread_AutoDelete(Object thread)
|
|
|
|
{
|
|
|
|
delete thread;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int32 Thread_GetMaxStackSize(Object thread)
|
|
|
|
{
|
|
|
|
return ((Thread)thread).mMaxStackSize;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void Thread_StartProc(Object threadObj)
|
|
|
|
{
|
|
|
|
Thread thread = (Thread)threadObj;
|
|
|
|
|
|
|
|
if (thread.mName != null)
|
|
|
|
thread.InformThreadNameChange(thread.mName);
|
2021-06-19 12:35:29 -07:00
|
|
|
if (thread.mPriority != .Normal)
|
|
|
|
thread.SetPriorityNative((.)thread.mPriority);
|
2019-08-23 11:56:54 -07:00
|
|
|
|
|
|
|
int32 stackStart = 0;
|
|
|
|
thread.SetStackStart((void*)&stackStart);
|
|
|
|
if (thread.mDelegate is ThreadStart)
|
|
|
|
{
|
|
|
|
((ThreadStart)thread.mDelegate)();
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
((ParameterizedThreadStart)thread.mDelegate)(thread.mThreadStartArg);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
public static this()
|
|
|
|
{
|
2021-01-22 08:50:21 -08:00
|
|
|
var cb = ref Runtime.BfRtCallbacks.[Friend]sCallbacks;
|
2019-08-23 11:56:54 -07:00
|
|
|
|
|
|
|
cb.[Friend]mThread_Alloc = => Thread_Alloc;
|
|
|
|
cb.[Friend]mThread_GetMainThread = => Thread_GetMainThread;
|
|
|
|
cb.[Friend]mThread_ThreadProc = => Thread_StartProc;
|
|
|
|
cb.[Friend]mThread_GetInternalThread = => Thread_GetInternalThread;
|
|
|
|
cb.[Friend]mThread_SetInternalThread = => Thread_SetInternalThread;
|
|
|
|
cb.[Friend]mThread_IsAutoDelete = => Thread_IsAutoDelete;
|
|
|
|
cb.[Friend]mThread_AutoDelete = => Thread_AutoDelete;
|
|
|
|
cb.[Friend]mThread_GetMaxStackSize = => Thread_GetMaxStackSize;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-01-25 07:03:14 -08:00
|
|
|
private this()
|
|
|
|
{
|
|
|
|
|
|
|
|
}
|
|
|
|
|
2019-08-23 11:56:54 -07:00
|
|
|
public this(ThreadStart start)
|
|
|
|
{
|
|
|
|
if (start == null)
|
|
|
|
{
|
|
|
|
Runtime.FatalError();
|
|
|
|
}
|
|
|
|
SetStart((Delegate)start, 0); //0 will setup Thread with default stackSize
|
|
|
|
}
|
|
|
|
|
|
|
|
public this(ThreadStart start, int32 maxStackSize)
|
|
|
|
{
|
|
|
|
if (start == null)
|
|
|
|
{
|
|
|
|
Runtime.FatalError();
|
|
|
|
}
|
|
|
|
if (0 > maxStackSize)
|
|
|
|
Runtime.FatalError();
|
|
|
|
SetStart((Delegate)start, maxStackSize);
|
|
|
|
}
|
|
|
|
|
|
|
|
public this(ParameterizedThreadStart start)
|
|
|
|
{
|
|
|
|
if (start == null)
|
|
|
|
{
|
|
|
|
Runtime.FatalError();
|
|
|
|
}
|
|
|
|
SetStart((Delegate)start, 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
public this(ParameterizedThreadStart start, int32 maxStackSize)
|
|
|
|
{
|
|
|
|
if (start == null)
|
|
|
|
{
|
|
|
|
Runtime.FatalError();
|
|
|
|
}
|
|
|
|
if (0 > maxStackSize)
|
|
|
|
Runtime.FatalError();
|
|
|
|
SetStart((Delegate)start, maxStackSize);
|
|
|
|
}
|
|
|
|
|
2021-01-05 16:16:28 -08:00
|
|
|
static void Init()
|
2019-08-23 11:56:54 -07:00
|
|
|
{
|
|
|
|
#unwarn
|
|
|
|
RuntimeThreadInit runtimeThreadInitRef = ?;
|
|
|
|
sMainThread.ManualThreadInit();
|
|
|
|
}
|
|
|
|
|
|
|
|
static Thread CreateEmptyThread()
|
|
|
|
{
|
|
|
|
return new Thread();
|
|
|
|
}
|
|
|
|
|
|
|
|
public bool AutoDelete
|
|
|
|
{
|
|
|
|
set
|
|
|
|
{
|
|
|
|
// Changing AutoDelete from another thread while we are running is a race condition
|
|
|
|
Runtime.Assert((CurrentThread == this) || (!IsAlive));
|
|
|
|
mAutoDelete = value;
|
|
|
|
}
|
|
|
|
|
|
|
|
get
|
|
|
|
{
|
|
|
|
return mAutoDelete;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
extern void ManualThreadInit();
|
|
|
|
extern void StartInternal();
|
|
|
|
extern void SetStackStart(void* ptr);
|
|
|
|
|
|
|
|
public void Start(bool autoDelete = true)
|
|
|
|
{
|
|
|
|
mAutoDelete = autoDelete;
|
|
|
|
StartInternal();
|
|
|
|
}
|
|
|
|
|
|
|
|
public void Start(Object parameter, bool autoDelete = true)
|
|
|
|
{
|
|
|
|
mAutoDelete = autoDelete;
|
|
|
|
if (mDelegate is ThreadStart)
|
|
|
|
{
|
|
|
|
Runtime.FatalError();
|
|
|
|
}
|
|
|
|
mThreadStartArg = parameter;
|
|
|
|
StartInternal();
|
|
|
|
}
|
|
|
|
|
2019-09-02 17:39:47 -07:00
|
|
|
#if BF_PLATFORM_WINDOWS
|
2019-08-23 11:56:54 -07:00
|
|
|
[CLink]
|
|
|
|
static extern int32 _tls_index;
|
|
|
|
#endif
|
|
|
|
|
|
|
|
public static int ModuleTLSIndex
|
|
|
|
{
|
|
|
|
get
|
|
|
|
{
|
2019-09-02 17:39:47 -07:00
|
|
|
#if BF_PLATFORM_WINDOWS
|
2019-08-23 11:56:54 -07:00
|
|
|
return _tls_index;
|
|
|
|
#else
|
|
|
|
return 0;
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
public void Suspend() { SuspendInternal(); }
|
2020-05-04 07:15:38 -07:00
|
|
|
[CallingConvention(.Cdecl)]
|
2019-08-23 11:56:54 -07:00
|
|
|
private extern void SuspendInternal();
|
|
|
|
|
|
|
|
public void Resume() { ResumeInternal(); }
|
2020-05-04 07:15:38 -07:00
|
|
|
[CallingConvention(.Cdecl)]
|
2019-08-23 11:56:54 -07:00
|
|
|
private extern void ResumeInternal();
|
|
|
|
|
|
|
|
public void Interrupt() { InterruptInternal(); }
|
2020-05-04 07:15:38 -07:00
|
|
|
[CallingConvention(.Cdecl)]
|
2019-08-23 11:56:54 -07:00
|
|
|
private extern void InterruptInternal();
|
|
|
|
|
|
|
|
public ThreadPriority Priority
|
|
|
|
{
|
2021-06-19 12:35:29 -07:00
|
|
|
get
|
|
|
|
{
|
|
|
|
if (mInternalThread != 0)
|
|
|
|
return (ThreadPriority)GetPriorityNative();
|
|
|
|
return mPriority;
|
|
|
|
}
|
|
|
|
set
|
|
|
|
{
|
|
|
|
mPriority = value;
|
|
|
|
if (mInternalThread != 0)
|
|
|
|
SetPriorityNative((int32)value);
|
|
|
|
}
|
2019-08-23 11:56:54 -07:00
|
|
|
}
|
2020-05-04 07:15:38 -07:00
|
|
|
[CallingConvention(.Cdecl)]
|
2019-08-23 11:56:54 -07:00
|
|
|
private extern int32 GetPriorityNative();
|
2020-05-04 07:15:38 -07:00
|
|
|
[CallingConvention(.Cdecl)]
|
2019-08-23 11:56:54 -07:00
|
|
|
private extern void SetPriorityNative(int32 priority);
|
|
|
|
|
|
|
|
extern bool GetIsAlive();
|
|
|
|
public bool IsAlive
|
|
|
|
{
|
|
|
|
get
|
|
|
|
{
|
|
|
|
return GetIsAlive();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-05-04 07:15:38 -07:00
|
|
|
[CallingConvention(.Cdecl)]
|
2019-08-23 11:56:54 -07:00
|
|
|
extern bool GetIsThreadPoolThread();
|
|
|
|
public bool IsThreadPoolThread
|
|
|
|
{
|
|
|
|
get
|
|
|
|
{
|
|
|
|
return GetIsThreadPoolThread();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
private extern bool JoinInternal(int32 millisecondsTimeout);
|
|
|
|
|
|
|
|
public void Join()
|
|
|
|
{
|
|
|
|
JoinInternal(Timeout.Infinite);
|
|
|
|
}
|
|
|
|
|
|
|
|
public bool Join(int32 millisecondsTimeout)
|
|
|
|
{
|
|
|
|
return JoinInternal(millisecondsTimeout);
|
|
|
|
}
|
|
|
|
|
|
|
|
public bool Join(TimeSpan timeout)
|
|
|
|
{
|
|
|
|
int64 tm = (int64)timeout.TotalMilliseconds;
|
|
|
|
if (tm < -1 || tm > (int64)Int32.MaxValue)
|
|
|
|
Runtime.FatalError();
|
|
|
|
|
|
|
|
return Join((int32)tm);
|
|
|
|
}
|
|
|
|
|
|
|
|
private static extern void SleepInternal(int32 millisecondsTimeout);
|
|
|
|
public static void Sleep(int32 millisecondsTimeout)
|
|
|
|
{
|
|
|
|
SleepInternal(millisecondsTimeout);
|
|
|
|
}
|
|
|
|
|
|
|
|
public static void Sleep(TimeSpan timeout)
|
|
|
|
{
|
|
|
|
int64 tm = (int64)timeout.TotalMilliseconds;
|
|
|
|
if (tm < -1 || tm > (int64)Int32.MaxValue)
|
|
|
|
Runtime.FatalError();
|
|
|
|
Sleep((int32)tm);
|
|
|
|
}
|
|
|
|
|
|
|
|
private static extern void SpinWaitInternal(int32 iterations);
|
|
|
|
|
|
|
|
public static void SpinWait(int iterations)
|
|
|
|
{
|
|
|
|
SpinWaitInternal((int32)iterations);
|
|
|
|
}
|
|
|
|
|
|
|
|
private static extern bool YieldInternal();
|
|
|
|
|
|
|
|
public static bool Yield()
|
|
|
|
{
|
|
|
|
return YieldInternal();
|
|
|
|
}
|
|
|
|
|
|
|
|
public static Thread CurrentThread
|
|
|
|
{
|
|
|
|
get
|
|
|
|
{
|
|
|
|
return GetCurrentThreadNative();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
extern int32 GetThreadId();
|
|
|
|
|
|
|
|
public int32 Id
|
|
|
|
{
|
|
|
|
get
|
|
|
|
{
|
|
|
|
return GetThreadId();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-05-04 07:15:38 -07:00
|
|
|
[CallingConvention(.Cdecl)]
|
2019-08-23 11:56:54 -07:00
|
|
|
private static extern Thread GetCurrentThreadNative();
|
|
|
|
|
2020-05-07 05:47:18 -07:00
|
|
|
void SetStart(Delegate ownStartDelegate, int32 maxStackSize)
|
2019-08-23 11:56:54 -07:00
|
|
|
{
|
2020-05-07 05:47:18 -07:00
|
|
|
mDelegate = ownStartDelegate;
|
2019-08-23 11:56:54 -07:00
|
|
|
mMaxStackSize = maxStackSize;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
public ~this()
|
|
|
|
{
|
|
|
|
// Make sure we're not deleting manually it mAutoDelete is set
|
|
|
|
Debug.Assert((!mAutoDelete) || (CurrentThread == this));
|
|
|
|
// Delegate to the unmanaged portion.
|
|
|
|
InternalFinalize();
|
|
|
|
// Thread owns delegate
|
|
|
|
delete mDelegate;
|
|
|
|
}
|
2020-05-04 07:15:38 -07:00
|
|
|
|
|
|
|
[CallingConvention(.Cdecl)]
|
2019-08-23 11:56:54 -07:00
|
|
|
private extern void InternalFinalize();
|
|
|
|
|
|
|
|
public bool IsBackground
|
|
|
|
{
|
|
|
|
get { return IsBackgroundNative(); }
|
|
|
|
set { SetBackgroundNative(value); }
|
|
|
|
}
|
2020-05-04 07:15:38 -07:00
|
|
|
[CallingConvention(.Cdecl)]
|
2019-08-23 11:56:54 -07:00
|
|
|
private extern bool IsBackgroundNative();
|
2020-05-04 07:15:38 -07:00
|
|
|
[CallingConvention(.Cdecl)]
|
2019-08-23 11:56:54 -07:00
|
|
|
private extern void SetBackgroundNative(bool isBackground);
|
2020-05-04 07:15:38 -07:00
|
|
|
[CallingConvention(.Cdecl)]
|
2019-08-23 11:56:54 -07:00
|
|
|
public extern void SetJoinOnDelete(bool joinOnDelete);
|
|
|
|
|
|
|
|
public ThreadState ThreadState
|
|
|
|
{
|
|
|
|
get { return (ThreadState)GetThreadStateNative(); }
|
|
|
|
}
|
2020-05-04 07:15:38 -07:00
|
|
|
[CallingConvention(.Cdecl)]
|
2019-08-23 11:56:54 -07:00
|
|
|
private extern int32 GetThreadStateNative();
|
|
|
|
|
|
|
|
public void SetName(String name)
|
|
|
|
{
|
|
|
|
if (name == null)
|
|
|
|
{
|
|
|
|
delete mName;
|
|
|
|
mName = null;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
String.NewOrSet!(mName, name);
|
|
|
|
}
|
|
|
|
if (mInternalThread != 0)
|
|
|
|
InformThreadNameChange(name);
|
|
|
|
}
|
|
|
|
|
|
|
|
public void GetName(String outName)
|
|
|
|
{
|
|
|
|
if (mName != null)
|
|
|
|
outName.Append(mName);
|
|
|
|
}
|
2020-05-04 07:15:38 -07:00
|
|
|
[CallingConvention(.Cdecl)]
|
2019-08-23 11:56:54 -07:00
|
|
|
private extern void InformThreadNameChange(String name);
|
|
|
|
}
|
|
|
|
}
|