From a27ef9bedaaeb2ae168862c5b2235fb122688739 Mon Sep 17 00:00:00 2001 From: Brian Fiete Date: Mon, 4 Jul 2022 10:20:38 -0700 Subject: [PATCH] `Lazy`, `LazyTLS`, thread dtors --- BeefLibs/corlib/src/Lazy.bf | 288 ++++++++++++++++++ BeefLibs/corlib/src/Platform.bf | 13 + BeefLibs/corlib/src/Runtime.bf | 3 +- BeefLibs/corlib/src/Threading/Thread.bf | 64 +++- BeefRT/rt/BfObjects.h | 5 +- BeefRT/rt/Internal.cpp | 17 ++ BeefRT/rt/Thread.cpp | 26 +- BeefRT/rt/Thread.h | 5 +- BeefRT/rt/ThreadLocalStorage.cpp | 2 +- BeefRT/rt/ThreadLocalStorage.h | 2 +- BeefySysLib/platform/PlatformInterface.h | 4 +- BeefySysLib/platform/posix/PosixCommon.cpp | 4 +- BeefySysLib/platform/win/Platform.cpp | 10 +- .../minlib/src/System/Diagnostics/Profiler.bf | 2 +- IDE/mintest/minlib/src/System/Result.bf | 8 +- IDE/mintest/minlib/src/System/Runtime.bf | 3 +- .../minlib/src/System/Threading/Thread.bf | 11 +- 17 files changed, 437 insertions(+), 30 deletions(-) create mode 100644 BeefLibs/corlib/src/Lazy.bf diff --git a/BeefLibs/corlib/src/Lazy.bf b/BeefLibs/corlib/src/Lazy.bf new file mode 100644 index 00000000..f33470c1 --- /dev/null +++ b/BeefLibs/corlib/src/Lazy.bf @@ -0,0 +1,288 @@ +using System.Threading; + +namespace System +{ + enum LazyThreadMode + { + None, + Lock, + Lockless + } + + class Lazy + { + protected struct Entry + { + public SelfOuter mSingleton; + public T mValue; + } + + protected Monitor mMonitor ~ delete _; + protected LazyThreadMode mThreadMode; + protected volatile int mInitId; + protected T mValue; + delegate T() mCreateDlg ~ delete _; + delegate void(T value) mReleaseDlg ~ delete _; + + public this() + { + + } + + public this(LazyThreadMode threadMode) + { + mThreadMode = threadMode; + Init(); + } + + public this(LazyThreadMode threadMode, delegate T() createDlg = null, delegate void(T value) releaseDlg = null) + { + mThreadMode = threadMode; + mCreateDlg = createDlg; + mReleaseDlg = releaseDlg; + Init(); + } + + public this(delegate void(T value) releaseDlg) : this() + { + mReleaseDlg = releaseDlg; + } + + void Init() + { + switch (mThreadMode) + { + case .None: + case .Lock: + mMonitor = new Monitor(); + case .Lockless: + } + + } + + public ~this() + { + ReleaseValue(mut mValue); + } + + protected T DefaultCreateValue() + { + return default; + } + + protected T DefaultCreateValue() where T : struct, new + { + return T(); + } + + protected T DefaultCreateValue() where T : class + { + Runtime.FatalError("No create delegate specified and no public default constructor is available"); + } + + protected T DefaultCreateValue() where T : class, new + { + return new T(); + } + + protected virtual T CreateValue() + { + return DefaultCreateValue(); + } + + protected void DefaultReleaseValue(mut T val) + { + + } + + protected void DefaultReleaseValue(mut T val) where T : struct, IDisposable + { + val.Dispose(); + } + + protected void DefaultReleaseValue(mut T val) where T : class + { + delete (Object)val; + } + + protected virtual void ReleaseValue(mut T val) + { + DefaultReleaseValue(mut val); + } + + public ref T Value + { + get + { + if (mInitId == -1) + return ref mValue; + + switch (mThreadMode) + { + case .None: + mValue = CreateValue(); + case .Lock: + using (mMonitor.Enter()) + { + if (mInitId != -1) + { + mValue = CreateValue(); + Interlocked.Fence(); + mInitId = -1; + } + } + case .Lockless: + int threadId = Thread.CurrentThreadId; + while (true) + { + int initId = Interlocked.CompareExchange(ref mInitId, 0, threadId); + if (initId == -1) + break; + + if (initId == 0) + { + Interlocked.Fence(); + mValue = CreateValue(); + Interlocked.Fence(); + mInitId = -1; + break; + } + } + } + return ref mValue; + } + } + + public bool IsValueCreated => mInitId != 0; + + public static ref T operator->(Self self) => ref self.[Inline]Value; + + public override void ToString(String strBuffer) + { + if (IsValueCreated) + strBuffer.AppendF($"Value: {Value}"); + else + strBuffer.AppendF($"No Value"); + } + } + + class LazyTLS + { + protected struct Entry + { + public SelfOuter mSingleton; + public T mValue; + } + + void* mData; + delegate T() mCreateDlg ~ delete _; + delegate void(T value) mReleaseDlg ~ delete _; + + public this() + { + InitTLS(); + } + + public this(delegate T() createDlg = null, delegate void(T value) releaseDlg = null) + { + mCreateDlg = createDlg; + mReleaseDlg = releaseDlg; + InitTLS(); + } + + void InitTLS() + { + mData = Platform.BfpTLS_Create((ptr) => + { + var entry = (Entry*)ptr; + if (entry.mSingleton.mReleaseDlg != null) + entry.mSingleton.mReleaseDlg(entry.mValue); + else + entry.mSingleton.ReleaseValue(mut entry.mValue); + delete entry; + }); + } + + public ~this() + { + Platform.BfpTLS_Release((.)mData); + } + + protected T DefaultCreateValue() + { + return default; + } + + protected T DefaultCreateValue() where T : struct, new + { + return T(); + } + + protected T DefaultCreateValue() where T : class + { + Runtime.FatalError("No create delegate specified and no public default constructor is available"); + } + + protected T DefaultCreateValue() where T : class, new + { + return new T(); + } + + protected virtual T CreateValue() + { + return DefaultCreateValue(); + } + + protected void DefaultReleaseValue(mut T val) + { + + } + + protected void DefaultReleaseValue(mut T val) where T : struct, IDisposable + { + val.Dispose(); + } + + + protected void DefaultReleaseValue(mut T val) where T : class + { + delete (Object)val; + } + + protected virtual void ReleaseValue(mut T val) + { + DefaultReleaseValue(mut val); + } + + public ref T Value + { + get + { + void* ptr = Platform.BfpTLS_GetValue((.)mData); + if (ptr != null) + return ref ((Entry*)ptr).mValue; + + Entry* entry = new Entry(); + entry.mSingleton = this; + if (mCreateDlg != null) + entry.mValue = mCreateDlg(); + else + entry.mValue = CreateValue(); + Platform.BfpTLS_SetValue((.)mData, entry); + return ref entry.mValue; + } + } + + public bool IsValueCreated => Platform.BfpTLS_GetValue((.)mData) != null; + + public static ref T operator->(Self self) => ref self.[Inline]Value; + + public override void ToString(String strBuffer) + { + if (IsValueCreated) + strBuffer.AppendF($"Value: {Value}"); + else + strBuffer.AppendF($"No Value"); + } + } +} diff --git a/BeefLibs/corlib/src/Platform.bf b/BeefLibs/corlib/src/Platform.bf index b23c378f..7fc94710 100644 --- a/BeefLibs/corlib/src/Platform.bf +++ b/BeefLibs/corlib/src/Platform.bf @@ -42,6 +42,7 @@ namespace System public struct BfpEvent {}; public struct BfpFileWatcher {} public struct BfpProcess {} + public struct BfpTLS; public enum BfpSystemResult : int32 { @@ -95,6 +96,18 @@ namespace System [CallingConvention(.Stdcall), CLink] public static extern void BfpSystem_GetComputerName(char8* outStr, int32* inOutStrSize, BfpSystemResult* outResult); + [CallingConvention(.Stdcall), CLink] + public static extern int BfpThread_GetCurrentId(); + + [CallingConvention(.Stdcall), CLink] + public static extern BfpTLS* BfpTLS_Create(function [CallingConvention(.Stdcall)] void(void*) exitProc); + [CallingConvention(.Stdcall), CLink] + public static extern void BfpTLS_Release(BfpTLS* tls); + [CallingConvention(.Stdcall), CLink] + public static extern void BfpTLS_SetValue(BfpTLS* tls, void* value); + [CallingConvention(.Stdcall), CLink] + public static extern void* BfpTLS_GetValue(BfpTLS* tls); + public enum BfpFileWatcherFlags : int32 { None = 0, diff --git a/BeefLibs/corlib/src/Runtime.bf b/BeefLibs/corlib/src/Runtime.bf index b2861236..d116ca91 100644 --- a/BeefLibs/corlib/src/Runtime.bf +++ b/BeefLibs/corlib/src/Runtime.bf @@ -9,7 +9,7 @@ namespace System [StaticInitPriority(101)] static class Runtime { - const int32 cVersion = 9; + const int32 cVersion = 10; [CRepr, AlwaysInclude] struct BfDebugMessageData @@ -118,6 +118,7 @@ namespace System function bool (Object thread) mThread_IsAutoDelete; function void (Object thread) mThread_AutoDelete; function int32 (Object thread) mThread_GetMaxStackSize; + function void () mThread_Exiting; function void () mGC_MarkAllStaticMembers; function bool () mGC_CallRootCallbacks; function void () mGC_Shutdown; diff --git a/BeefLibs/corlib/src/Threading/Thread.bf b/BeefLibs/corlib/src/Threading/Thread.bf index 4fb76c2e..ed529803 100644 --- a/BeefLibs/corlib/src/Threading/Thread.bf +++ b/BeefLibs/corlib/src/Threading/Thread.bf @@ -20,8 +20,13 @@ namespace System.Threading private Object mThreadStartArg; bool mAutoDelete; - public static Thread sMainThread = new Thread() ~ delete _; - + + static Monitor sMonitor = new .() ~ delete _; + static Event sOnExit ~ _.Dispose(); + Event mOnExit ~ _.Dispose(); + + public static Thread sMainThread = new Thread() ~ delete _; + [StaticInitPriority(102)] struct RuntimeThreadInit { @@ -62,6 +67,14 @@ namespace System.Threading return ((Thread)thread).mMaxStackSize; } + static void Thread_Exiting() + { + using (sMonitor.Enter()) + { + sOnExit(); + } + } + static void Thread_StartProc(Object threadObj) { Thread thread = (Thread)threadObj; @@ -103,6 +116,7 @@ namespace System.Threading cb.[Friend]mThread_IsAutoDelete = => Thread_IsAutoDelete; cb.[Friend]mThread_AutoDelete = => Thread_AutoDelete; cb.[Friend]mThread_GetMaxStackSize = => Thread_GetMaxStackSize; + cb.[Friend]mThread_Exiting = => Thread_Exiting; } } @@ -178,6 +192,38 @@ namespace System.Threading } } + public void AddExitNotify(delegate void() dlg) + { + using (sMonitor.Enter()) + { + mOnExit.Add(dlg); + } + } + + public Result RemovedExitNotify(delegate void() dlg, bool delegateDelegate = false) + { + using (sMonitor.Enter()) + { + return mOnExit.Remove(dlg, delegateDelegate); + } + } + + public static void AddGlobalExitNotify(delegate void() dlg) + { + using (sMonitor.Enter()) + { + sOnExit.Add(dlg); + } + } + + public static Result RemoveGlobalExitNotify(delegate void() dlg, bool delegateDelegate = false) + { + using (sMonitor.Enter()) + { + return sOnExit.Remove(dlg, delegateDelegate); + } + } + extern void ManualThreadInit(); extern void StartInternal(); extern void SetStackStart(void* ptr); @@ -217,6 +263,7 @@ namespace System.Threading } } + public static extern void RequestExitNotify(); public extern void Suspend(); public extern void Resume(); @@ -316,9 +363,10 @@ namespace System.Threading } } - extern int32 GetThreadId(); + [CallingConvention(.Cdecl)] + extern int GetThreadId(); - public int32 Id + public int Id { get { @@ -326,6 +374,8 @@ namespace System.Threading } } + public static int CurrentThreadId => Platform.BfpThread_GetCurrentId(); + [CallingConvention(.Cdecl)] private static extern Thread GetCurrentThreadNative(); @@ -337,6 +387,12 @@ namespace System.Threading public ~this() { + using (sMonitor.Enter()) + { + mOnExit(); + sOnExit(); + } + // Make sure we're not deleting manually if mAutoDelete is set Debug.Assert((!mAutoDelete) || (CurrentThread == this)); // Delegate to the unmanaged portion. diff --git a/BeefRT/rt/BfObjects.h b/BeefRT/rt/BfObjects.h index 237d69c9..d8573e58 100644 --- a/BeefRT/rt/BfObjects.h +++ b/BeefRT/rt/BfObjects.h @@ -3,7 +3,7 @@ #include "BeefySysLib/Common.h" #include "BeefySysLib/util/String.h" -#define BFRT_VERSION 9 +#define BFRT_VERSION 10 #ifdef BFRT_DYNAMIC #define BFRT_EXPORT __declspec(dllexport) @@ -99,6 +99,7 @@ namespace bf bool(*Thread_IsAutoDelete)(bf::System::Threading::Thread* thread); void(*Thread_AutoDelete)(bf::System::Threading::Thread* thread); int32(*Thread_GetMaxStackSize)(bf::System::Threading::Thread* thread); + void(*Thread_Exiting)(); void(*GC_MarkAllStaticMembers)(); bool(*GC_CallRootCallbacks)(); void(*GC_Shutdown)(); @@ -107,7 +108,7 @@ namespace bf void(*DebugMessageData_SetupProfilerCmd)(const char* str); void(*DebugMessageData_Fatal)(); void(*DebugMessageData_Clear)(); - int(*CheckErrorHandler)(const char* kind, const char* arg1, const char* arg2, intptr arg3); + int(*CheckErrorHandler)(const char* kind, const char* arg1, const char* arg2, intptr arg3); }; public: diff --git a/BeefRT/rt/Internal.cpp b/BeefRT/rt/Internal.cpp index 8d36ebe4..ba90fc5c 100644 --- a/BeefRT/rt/Internal.cpp +++ b/BeefRT/rt/Internal.cpp @@ -55,6 +55,12 @@ static Beefy::StringT<0> gCmdLineString; bf::System::Runtime::BfRtCallbacks gBfRtCallbacks; BfRtFlags gBfRtFlags = (BfRtFlags)0; +#ifdef BF_PLATFORM_WINDOWS +DWORD gBfTLSKey = 0; +#else +pthread_key_t gBfTLSKey = 0; +#endif + static int gTestMethodIdx = -1; static uint32 gTestStartTick = 0; static bool gTestBreakOnFailure = false; @@ -287,6 +293,11 @@ static void GetCrashInfo() } } +static void NTAPI TlsFreeFunc(void* ptr) +{ + gBfRtCallbacks.Thread_Exiting(); +} + void bf::System::Runtime::Init(int version, int flags, BfRtCallbacks* callbacks) { BfpSystemInitFlags sysInitFlags = BfpSystemInitFlag_InstallCrashCatcher; @@ -343,6 +354,12 @@ void bf::System::Runtime::Init(int version, int flags, BfRtCallbacks* callbacks) useCmdLineStr++; } gCmdLineString = useCmdLineStr; + +#ifdef BF_PLATFORM_WINDOWS + gBfTLSKey = FlsAlloc(TlsFreeFunc); +#else + pthread_key_create(&gBfTLSKey, TlsFreeFunc); +#endif } void bf::System::Runtime::SetErrorString(char* errorStr) diff --git a/BeefRT/rt/Thread.cpp b/BeefRT/rt/Thread.cpp index 0e79e8a3..37114d63 100644 --- a/BeefRT/rt/Thread.cpp +++ b/BeefRT/rt/Thread.cpp @@ -19,6 +19,12 @@ BF_TLS_DECLSPEC Thread* Thread::sCurrentThread; static volatile int gLiveThreadCount; static Beefy::SyncEvent gThreadsDoneEvent; +#ifdef BF_PLATFORM_WINDOWS +extern DWORD gBfTLSKey; +#else +extern pthread_key_t gBfTLSKey; +#endif + bf::System::Threading::Thread* BfGetCurrentThread() { #ifdef BF_THREAD_TLS @@ -133,7 +139,8 @@ static void BF_CALLTYPE CStartProc(void* threadParam) bool wantsDelete = false; // { - internalThread->ThreadStopped(); + internalThread->ThreadStopped(); + Beefy::AutoCrit autoCrit(internalThread->mCritSect); if (isAutoDelete) gBfRtCallbacks.Thread_AutoDelete(thread); @@ -207,15 +214,28 @@ void Thread::StartInternal() #endif } +void Thread::RequestExitNotify() +{ + // Do we already have implicit exiting notification? + if (BfGetCurrentThread() != NULL) + return; + +#ifdef BF_PLATFORM_WINDOWS + FlsSetValue(gBfTLSKey, (void*)&gBfRtCallbacks); +#else + pthread_setspecific(gBfTLSKey, (void*)&gBfRtCallbacks); +#endif +} + void Thread::ThreadStarted() { auto internalThread = GetInternalThread(); internalThread->mCritSect.Unlock(); } -int Thread::GetThreadId() +intptr Thread::GetThreadId() { - return (int)GetInternalThread()->mThreadId; + return GetInternalThread()->mThreadId; } void Thread::SetStackStart(void* ptr) diff --git a/BeefRT/rt/Thread.h b/BeefRT/rt/Thread.h index 17bfec7e..22ea4d93 100644 --- a/BeefRT/rt/Thread.h +++ b/BeefRT/rt/Thread.h @@ -39,7 +39,7 @@ namespace bf private: BfInternalThread* SetupInternalThread(); - BFRT_EXPORT void ManualThreadInit(); + BFRT_EXPORT void ManualThreadInit(); BFRT_EXPORT int GetPriorityNative(); BFRT_EXPORT void SetPriorityNative(int priority); BFRT_EXPORT void SetJoinOnDelete(bool joinOnDelete); @@ -59,7 +59,7 @@ namespace bf BFRT_EXPORT void SetBackgroundNative(bool isBackground); BFRT_EXPORT int GetThreadStateNative(); BFRT_EXPORT void InformThreadNameChange(String* name); - BFRT_EXPORT int GetThreadId(); + BFRT_EXPORT intptr GetThreadId(); BFRT_EXPORT void Dbg_CreateInternal(); @@ -68,6 +68,7 @@ namespace bf BFRT_EXPORT void Resume(); BFRT_EXPORT void Abort(); + BFRT_EXPORT static void RequestExitNotify(); BFRT_EXPORT static void MemoryBarrier(); static Thread* Alloc() diff --git a/BeefRT/rt/ThreadLocalStorage.cpp b/BeefRT/rt/ThreadLocalStorage.cpp index 439f81b8..6861f501 100644 --- a/BeefRT/rt/ThreadLocalStorage.cpp +++ b/BeefRT/rt/ThreadLocalStorage.cpp @@ -35,7 +35,7 @@ uint32 BfTLSManager::Alloc() } } - mAllocatedKeys[idx] = BfpTLS_Create(); + mAllocatedKeys[idx] = BfpTLS_Create(NULL); mAssociatedTLSDatums[idx] = NULL; return idx; } diff --git a/BeefRT/rt/ThreadLocalStorage.h b/BeefRT/rt/ThreadLocalStorage.h index 93c171d1..ff1ea718 100644 --- a/BeefRT/rt/ThreadLocalStorage.h +++ b/BeefRT/rt/ThreadLocalStorage.h @@ -43,7 +43,7 @@ public: BfTLSManager() { - sInternalThreadKey = BfpTLS_Create(); + sInternalThreadKey = BfpTLS_Create(NULL); mAssociatedTLSDatums = NULL; mAllocSize = 0; mAllocIdx = 1; diff --git a/BeefySysLib/platform/PlatformInterface.h b/BeefySysLib/platform/PlatformInterface.h index 79b08843..0a260f87 100644 --- a/BeefySysLib/platform/PlatformInterface.h +++ b/BeefySysLib/platform/PlatformInterface.h @@ -223,6 +223,7 @@ enum BfpThreadCreateFlags }; typedef void (BFP_CALLTYPE *BfpThreadStartProc)(void* threadParam); +typedef void (BFP_CALLTYPE* BfpTLSProc)(void* threadParam); enum BfpThreadPriority { @@ -273,8 +274,9 @@ BFP_EXPORT void BFP_CALLTYPE BfpCritSect_Enter(BfpCritSect* critSect); BFP_EXPORT bool BFP_CALLTYPE BfpCritSect_TryEnter(BfpCritSect* critSect, int waitMS); BFP_EXPORT void BFP_CALLTYPE BfpCritSect_Leave(BfpCritSect* critSect); + struct BfpTLS; -BFP_EXPORT BfpTLS* BFP_CALLTYPE BfpTLS_Create(); +BFP_EXPORT BfpTLS* BFP_CALLTYPE BfpTLS_Create(BfpTLSProc exitProc); BFP_EXPORT void BFP_CALLTYPE BfpTLS_Release(BfpTLS* tls); BFP_EXPORT void BFP_CALLTYPE BfpTLS_SetValue(BfpTLS* tls, void* value); BFP_EXPORT void* BFP_CALLTYPE BfpTLS_GetValue(BfpTLS* tls); diff --git a/BeefySysLib/platform/posix/PosixCommon.cpp b/BeefySysLib/platform/posix/PosixCommon.cpp index ebbc35b8..15b9c611 100644 --- a/BeefySysLib/platform/posix/PosixCommon.cpp +++ b/BeefySysLib/platform/posix/PosixCommon.cpp @@ -1528,10 +1528,10 @@ BFP_EXPORT void BFP_CALLTYPE BfpCritSect_Leave(BfpCritSect* critSect) pthread_mutex_unlock(&critSect->mPMutex); } -BFP_EXPORT BfpTLS* BFP_CALLTYPE BfpTLS_Create() +BFP_EXPORT BfpTLS* BFP_CALLTYPE BfpTLS_Create(BfpTLSProc exitProc) { pthread_key_t key = 0; - pthread_key_create(&key, NULL); + pthread_key_create(&key, exitProc); return (BfpTLS*)(intptr)key; } diff --git a/BeefySysLib/platform/win/Platform.cpp b/BeefySysLib/platform/win/Platform.cpp index 4893040e..abb61588 100644 --- a/BeefySysLib/platform/win/Platform.cpp +++ b/BeefySysLib/platform/win/Platform.cpp @@ -2530,24 +2530,24 @@ BFP_EXPORT void BFP_CALLTYPE BfpCritSect_Leave(BfpCritSect* critSect) #define BFPTLS_TO_DWORD(val) ((DWORD)(intptr)(val)) struct BfpTLS; -BFP_EXPORT BfpTLS* BFP_CALLTYPE BfpTLS_Create() +BFP_EXPORT BfpTLS* BFP_CALLTYPE BfpTLS_Create(BfpTLSProc exitProc) { - return DWORD_TO_BFPTLS(::TlsAlloc()); + return DWORD_TO_BFPTLS(::FlsAlloc(exitProc)); } BFP_EXPORT void BFP_CALLTYPE BfpTLS_Release(BfpTLS* tls) { - ::TlsFree(BFPTLS_TO_DWORD(tls)); + ::FlsFree(BFPTLS_TO_DWORD(tls)); } BFP_EXPORT void BFP_CALLTYPE BfpTLS_SetValue(BfpTLS* tls, void* value) { - ::TlsSetValue(BFPTLS_TO_DWORD(tls), value); + ::FlsSetValue(BFPTLS_TO_DWORD(tls), value); } BFP_EXPORT void* BFP_CALLTYPE BfpTLS_GetValue(BfpTLS* tls) { - return ::TlsGetValue(BFPTLS_TO_DWORD(tls)); + return ::FlsGetValue(BFPTLS_TO_DWORD(tls)); } BFP_EXPORT BfpEvent* BFP_CALLTYPE BfpEvent_Create(BfpEventFlags flags) diff --git a/IDE/mintest/minlib/src/System/Diagnostics/Profiler.bf b/IDE/mintest/minlib/src/System/Diagnostics/Profiler.bf index 5df17c60..6c52f3ed 100644 --- a/IDE/mintest/minlib/src/System/Diagnostics/Profiler.bf +++ b/IDE/mintest/minlib/src/System/Diagnostics/Profiler.bf @@ -38,7 +38,7 @@ namespace System.Diagnostics } } - static Result StartSampling(int32 threadId, StringView profileDesc) + static Result StartSampling(int threadId, StringView profileDesc) { //int32 curId = Interlocked.Increment(ref gProfileId); int32 curId = gProfileId++; diff --git a/IDE/mintest/minlib/src/System/Result.bf b/IDE/mintest/minlib/src/System/Result.bf index 7b5da210..30958aeb 100644 --- a/IDE/mintest/minlib/src/System/Result.bf +++ b/IDE/mintest/minlib/src/System/Result.bf @@ -95,7 +95,7 @@ namespace System extension Result where T : IDisposable { - public void Dispose() + public new void Dispose() { if (this case .Ok(var val)) val.Dispose(); @@ -199,7 +199,7 @@ namespace System extension Result where T : IDisposable { - public void Dispose() + public new void Dispose() { if (this case .Ok(var val)) val.Dispose(); @@ -208,7 +208,7 @@ namespace System extension Result where TErr : IDisposable { - public void Dispose() + public new void Dispose() { if (this case .Err(var err)) err.Dispose(); @@ -217,7 +217,7 @@ namespace System extension Result where T : IDisposable where TErr : IDisposable { - public void Dispose() + public new void Dispose() { if (this case .Ok(var val)) val.Dispose(); diff --git a/IDE/mintest/minlib/src/System/Runtime.bf b/IDE/mintest/minlib/src/System/Runtime.bf index 7e0b9687..c4235009 100644 --- a/IDE/mintest/minlib/src/System/Runtime.bf +++ b/IDE/mintest/minlib/src/System/Runtime.bf @@ -7,7 +7,7 @@ namespace System [StaticInitPriority(100)] class Runtime { - const int32 cVersion = 9; + const int32 cVersion = 10; [CRepr, AlwaysInclude] struct BfDebugMessageData @@ -116,6 +116,7 @@ namespace System function bool (Object thread) mThread_IsAutoDelete; function void (Object thread) mThread_AutoDelete; function int32 (Object thread) mThread_GetMaxStackSize; + function void () mThread_Exiting; function void () mGC_MarkAllStaticMembers; function bool () mGC_CallRootCallbacks; function void () mGC_Shutdown; diff --git a/IDE/mintest/minlib/src/System/Threading/Thread.bf b/IDE/mintest/minlib/src/System/Threading/Thread.bf index 08ed8546..b4c49b6f 100644 --- a/IDE/mintest/minlib/src/System/Threading/Thread.bf +++ b/IDE/mintest/minlib/src/System/Threading/Thread.bf @@ -78,6 +78,11 @@ namespace System.Threading } } + static void Thread_Exiting() + { + + } + public static this() { var cb = ref Runtime.BfRtCallbacks.[Friend]sCallbacks; @@ -90,6 +95,7 @@ namespace System.Threading cb.[Friend]mThread_IsAutoDelete = => Thread_IsAutoDelete; cb.[Friend]mThread_AutoDelete = => Thread_AutoDelete; cb.[Friend]mThread_GetMaxStackSize = => Thread_GetMaxStackSize; + cb.[Friend]mThread_Exiting = => Thread_Exiting; } } @@ -280,9 +286,10 @@ namespace System.Threading } } - extern int32 GetThreadId(); + [CallingConvention(.Cdecl)] + extern int GetThreadId(); - public int32 Id + public int Id { get {