1
0
Fork 0
mirror of https://github.com/beefytech/Beef.git synced 2025-06-23 10:08:00 +02:00

Lazy<T>, LazyTLS<T>, thread dtors

This commit is contained in:
Brian Fiete 2022-07-04 10:20:38 -07:00
parent cf269db0eb
commit a27ef9beda
17 changed files with 437 additions and 30 deletions

288
BeefLibs/corlib/src/Lazy.bf Normal file
View file

@ -0,0 +1,288 @@
using System.Threading;
namespace System
{
enum LazyThreadMode
{
None,
Lock,
Lockless
}
class Lazy<T>
{
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<T>
{
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");
}
}
}

View file

@ -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,

View file

@ -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;

View file

@ -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<delegate void()> sOnExit ~ _.Dispose();
Event<delegate void()> 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<void> 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<void> 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.