Skip to content

Commit 03765f4

Browse files
ffrostfallaatxe
andauthored
Implement Runtime::runOnce() and use it in the internal scheduler loop (#286)
This PR implements a C-sided API `Runtime::runOnce()` to run a singular iteration of the scheduler loop. This returns an `std::variant` between `StepErr` and `StepSuccess`, returning the `lua_State* L` which errored if the variant is a `StepErr`. This is then utilized in `Runtime::runToCompletion`, which simplifies some logic regarding exiting the runtime loop. Fixes #272 --------- Co-authored-by: ariel <[email protected]>
1 parent 738fa18 commit 03765f4

File tree

2 files changed

+89
-45
lines changed

2 files changed

+89
-45
lines changed

runtime/include/lute/runtime.h

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
#pragma once
22

3+
#include "Luau/Variant.h"
4+
#include "lua.h"
35
#include "lute/ref.h"
46

57
#include <atomic>
@@ -19,19 +21,37 @@ struct ThreadToContinue
1921
std::function<void()> cont;
2022
};
2123

24+
struct StepErr
25+
{
26+
lua_State* L;
27+
};
28+
29+
struct StepSuccess
30+
{
31+
lua_State* L;
32+
};
33+
34+
struct StepEmpty
35+
{
36+
};
37+
38+
using RuntimeStep = Luau::Variant<StepSuccess, StepErr, StepEmpty>;
39+
2240
struct Runtime
2341
{
2442
Runtime();
2543
~Runtime();
2644

2745
bool runToCompletion();
46+
RuntimeStep runOnce();
2847

2948
// For child runtimes, run a thread waiting for work
3049
void runContinuously();
3150

3251
// Reports an error for a specified lua state.
3352
void reportError(lua_State* L);
3453

54+
bool hasWork();
3555
bool hasContinuations();
3656
bool hasThreads();
3757

runtime/src/runtime.cpp

Lines changed: 69 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -35,69 +35,93 @@ Runtime::~Runtime()
3535
runLoopThread.join();
3636
}
3737

38-
bool Runtime::runToCompletion()
38+
bool Runtime::hasWork()
3939
{
40-
// While there is some C++ or Luau code left to run (waiting for something to happen?)
41-
while (!runningThreads.empty() || hasContinuations() || activeTokens.load() != 0)
40+
return hasContinuations() || hasThreads() || activeTokens.load() != 0;
41+
}
42+
43+
RuntimeStep Runtime::runOnce()
44+
{
45+
uv_run(uv_default_loop(), UV_RUN_DEFAULT);
46+
47+
// Complete all C++ continuations
48+
std::vector<std::function<void()>> copy;
49+
4250
{
43-
uv_run(uv_default_loop(), UV_RUN_DEFAULT);
51+
std::unique_lock lock(continuationMutex);
52+
copy = std::move(continuations);
53+
continuations.clear();
54+
}
4455

45-
// Complete all C++ continuations
46-
std::vector<std::function<void()>> copy;
56+
for (auto&& continuation : copy)
57+
continuation();
4758

48-
{
49-
std::unique_lock lock(continuationMutex);
50-
copy = std::move(continuations);
51-
continuations.clear();
52-
}
59+
if (runningThreads.empty())
60+
return StepEmpty{};
5361

54-
for (auto&& continuation : copy)
55-
continuation();
62+
auto next = std::move(runningThreads.front());
63+
runningThreads.erase(runningThreads.begin());
5664

57-
if (runningThreads.empty())
58-
continue;
65+
next.ref->push(GL);
66+
lua_State* L = lua_tothread(GL, -1);
5967

60-
auto next = std::move(runningThreads.front());
61-
runningThreads.erase(runningThreads.begin());
68+
if (L == nullptr)
69+
{
70+
fprintf(stderr, "Cannot resume a non-thread reference");
71+
return StepErr{L};
72+
}
6273

63-
next.ref->push(GL);
64-
lua_State* L = lua_tothread(GL, -1);
74+
// We still have 'next' on stack to hold on to thread we are about to run
75+
lua_pop(GL, 1);
6576

66-
if (L == nullptr)
67-
{
68-
fprintf(stderr, "Cannot resume a non-thread reference");
69-
return false;
70-
}
77+
int status = LUA_OK;
7178

72-
// We still have 'next' on stack to hold on to thread we are about to run
73-
lua_pop(GL, 1);
79+
if (!next.success)
80+
status = lua_resumeerror(L, nullptr);
81+
else
82+
status = lua_resume(L, nullptr, next.argumentCount);
7483

75-
int status = LUA_OK;
84+
if (status == LUA_YIELD)
85+
{
86+
return StepSuccess{L};
87+
}
7688

77-
if (!next.success)
78-
status = lua_resumeerror(L, nullptr);
79-
else
80-
status = lua_resume(L, nullptr, next.argumentCount);
89+
if (status != LUA_OK)
90+
{
91+
return StepErr{L};
92+
};
8193

82-
if (status == LUA_YIELD)
83-
{
84-
continue;
85-
}
94+
if (next.cont)
95+
next.cont();
96+
97+
return StepSuccess{L};
98+
}
8699

87-
if (status != LUA_OK)
100+
bool Runtime::runToCompletion()
101+
{
102+
while (hasWork())
103+
{
104+
auto step = runOnce();
105+
106+
if (auto err = Luau::get_if<StepErr>(&step))
88107
{
89-
reportError(L);
108+
if (err->L == nullptr)
109+
{
110+
fprintf(stderr, "lua_State* L is nullptr");
111+
return false;
112+
}
113+
114+
reportError(err->L);
90115

91-
// If we have no work to do, then exit the process.
92-
if (!hasThreads() && !hasContinuations())
116+
// ensure we exit the process with error code properly
117+
if (!hasWork())
93118
return false;
94-
else
95-
continue;
96119
}
97-
98-
if (next.cont)
99-
next.cont();
100-
}
120+
else
121+
{
122+
continue;
123+
}
124+
};
101125

102126
return true;
103127
}

0 commit comments

Comments
 (0)