Skip to content

Commit 3de5b0e

Browse files
committed
Reuse LuaState instances, copy hook and return allocator from global state
1 parent 2e3f932 commit 3de5b0e

File tree

7 files changed

+188
-136
lines changed

7 files changed

+188
-136
lines changed

src/Laylua/Library/Lua.cs

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,14 @@ namespace Laylua;
1212
/// <remarks>
1313
/// This type is not thread-safe; operations on it are not thread-safe.
1414
/// </remarks>
15-
public unsafe partial class Lua : LuaThread, ISpanFormattable
15+
public sealed unsafe partial class Lua : LuaThread, ISpanFormattable
1616
{
17+
/// <inheritdoc/>
18+
public override LuaState State { get; }
19+
20+
/// <inheritdoc/>
21+
public override LuaStack Stack { get; }
22+
1723
/// <inheritdoc/>
1824
public override LuaThread MainThread { get; }
1925

@@ -48,8 +54,11 @@ public Lua(LuaAllocator allocator)
4854
public Lua(LuaAllocator allocator, LuaMarshaler marshaler)
4955
{
5056
Stack = new LuaStack(this);
51-
State = new LuaState(allocator);
52-
State.State = this;
57+
State = new LuaMainState(allocator)
58+
{
59+
State = this
60+
};
61+
5362
Reference = LuaRegistry.Indices.MainThread;
5463
MainThread = new LuaMainThread(this);
5564
Globals = LuaTable.CreateGlobalsTable(this);

src/Laylua/Library/LuaChildThread.cs

Lines changed: 23 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,12 @@ namespace Laylua;
77

88
internal sealed unsafe class LuaChildThread : LuaThread
99
{
10+
/// <inheritdoc />
11+
public override LuaState State => _state;
12+
13+
/// <inheritdoc />
14+
public override LuaStack Stack { get; }
15+
1016
/// <inheritdoc/>
1117
public override LuaThread MainThread => Lua.FromExtraSpace(State.L).MainThread;
1218

@@ -23,10 +29,25 @@ protected override Lua? LuaCore
2329
set => throw new InvalidOperationException();
2430
}
2531

26-
internal void Initialize(lua_State* L, int reference)
32+
private readonly LuaChildState _state;
33+
34+
public LuaChildThread()
2735
{
2836
Stack = new LuaStack(this);
29-
State = new LuaState(L);
37+
_state = new LuaChildState();
38+
}
39+
40+
internal void Initialize(lua_State* L, int reference)
41+
{
3042
Reference = reference;
43+
44+
_state.Initialize(Lua.FromExtraSpace(L).State, L);
45+
}
46+
47+
public override void Dispose()
48+
{
49+
base.Dispose();
50+
51+
_state.Close();
3152
}
3253
}

src/Laylua/Library/LuaMainThread.cs

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,12 @@ namespace Laylua;
77

88
internal sealed class LuaMainThread : LuaThread
99
{
10+
/// <inheritdoc />
11+
public override LuaState State => _lua.State;
12+
13+
/// <inheritdoc />
14+
public override LuaStack Stack => _lua.Stack;
15+
1016
public override LuaThread MainThread => this;
1117

1218
public override LuaTable Globals => _lua.Globals;
@@ -27,8 +33,6 @@ protected override Lua? LuaCore
2733
public LuaMainThread(Lua lua)
2834
{
2935
_lua = lua;
30-
Stack = lua.Stack;
31-
State = lua.State;
3236
Reference = LuaRegistry.Indices.MainThread;
3337
}
3438
}

src/Laylua/Library/LuaThread.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,15 +20,15 @@ public abstract unsafe partial class LuaThread : LuaReference
2020
/// <summary>
2121
/// Gets the low-level state of this thread.
2222
/// </summary>
23-
public LuaState State { get; protected set; } = null!;
23+
public abstract LuaState State { get; }
2424

2525
/// <summary>
2626
/// Gets the Lua stack of this thread.
2727
/// </summary>
2828
/// <remarks>
2929
/// <inheritdoc cref="LuaStack"/>
3030
/// </remarks>
31-
public LuaStack Stack { get; protected set; } = null!;
31+
public abstract LuaStack Stack { get; }
3232

3333
/// <summary>
3434
/// Gets the main Lua thread, i.e. the parent of this thread.

src/Laylua/Moon/LuaChildState.cs

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
namespace Laylua.Moon;
2+
3+
internal sealed unsafe class LuaChildState : LuaState
4+
{
5+
public override LuaAllocator? Allocator => _mainState.Allocator;
6+
7+
public override LuaGC GC => _mainState.GC;
8+
9+
protected override lua_State* LCore => _L;
10+
11+
private lua_State* _L;
12+
private LuaState _mainState = null!;
13+
14+
public void Initialize(LuaState mainState, lua_State* childState)
15+
{
16+
_mainState = mainState;
17+
_L = childState;
18+
19+
CopyHook(mainState);
20+
}
21+
22+
internal override void Close()
23+
{
24+
// TODO: reset/close thread? Adjust LuaChildThread if so
25+
_L = null;
26+
}
27+
}

src/Laylua/Moon/LuaMainState.cs

Lines changed: 92 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,92 @@
1+
using System;
2+
using System.Globalization;
3+
using Qommon;
4+
5+
namespace Laylua.Moon;
6+
7+
internal sealed unsafe class LuaMainState : LuaState
8+
{
9+
public override LuaAllocator? Allocator { get; }
10+
11+
public override LuaGC GC { get; }
12+
13+
protected override lua_State* LCore => _L;
14+
15+
internal object? State
16+
{
17+
get => _layluaState.State;
18+
set => _layluaState.State = value;
19+
}
20+
21+
private LuaAllocFunction? _safeAllocFunction;
22+
23+
private LayluaState _layluaState = null!;
24+
private lua_State* _L;
25+
26+
internal LuaMainState(LuaAllocator? allocator)
27+
{
28+
if (allocator == null)
29+
{
30+
_L = luaL_newstate();
31+
}
32+
else
33+
{
34+
_L = lua_newstate(WrapAllocFunction(allocator), null);
35+
Allocator = allocator;
36+
}
37+
38+
ValidateNewState();
39+
InitializeLayluaState();
40+
41+
GC = new(this);
42+
}
43+
44+
private void ValidateNewState()
45+
{
46+
if (_L == null)
47+
{
48+
Throw.InvalidOperationException("Failed to create a new Lua state.");
49+
}
50+
51+
var version = lua_version(_L).ToString(CultureInfo.InvariantCulture);
52+
if (version.Length != 3 || version[0] != LuaVersionMajor[0] || version[2] != LuaVersionMinor[0])
53+
{
54+
Throw.InvalidOperationException($"Invalid Lua version loaded. Expected '{LuaVersion}'.");
55+
}
56+
}
57+
58+
private void InitializeLayluaState()
59+
{
60+
if (!LayluaState.TryFromExtraSpace(_L, out var state))
61+
{
62+
var panicPtr = LayluaNative.InitializePanic();
63+
state = LayluaState.Create(panicPtr);
64+
*(IntPtr*) lua_getextraspace(_L) = state.GCPtr;
65+
lua_atpanic(_L, (delegate* unmanaged[Cdecl]<lua_State*, int>) panicPtr);
66+
}
67+
68+
_layluaState = state;
69+
}
70+
71+
internal LuaAllocFunction WrapAllocFunction(LuaAllocator allocator)
72+
{
73+
Guard.IsNotNull(allocator);
74+
75+
_safeAllocFunction = (_, ptr, osize, nsize) =>
76+
{
77+
return allocator.Allocate(ptr, osize, nsize);
78+
};
79+
80+
return _safeAllocFunction;
81+
}
82+
83+
internal override void Close()
84+
{
85+
if (_L == null)
86+
return;
87+
88+
lua_close(_L);
89+
_layluaState.Dispose();
90+
_L = null;
91+
}
92+
}

0 commit comments

Comments
 (0)