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:
parent
cf269db0eb
commit
a27ef9beda
17 changed files with 437 additions and 30 deletions
288
BeefLibs/corlib/src/Lazy.bf
Normal file
288
BeefLibs/corlib/src/Lazy.bf
Normal 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");
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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,
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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.
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue