aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBenoit Germain <benoit.germain@ubisoft.com>2025-07-04 14:54:36 +0200
committerBenoit Germain <benoit.germain@ubisoft.com>2025-07-04 14:54:36 +0200
commit7bddb06461d8f80030b3b86175ec737dbb16ac3b (patch)
tree031238469090658f7f20535137edb2620bc77182
parent042055968ab0c48faec607889814e38c50c09efa (diff)
downloadlanes-7bddb06461d8f80030b3b86175ec737dbb16ac3b.tar.gz
lanes-7bddb06461d8f80030b3b86175ec737dbb16ac3b.tar.bz2
lanes-7bddb06461d8f80030b3b86175ec737dbb16ac3b.zip
Added Lua 5.5 support
* some unit tests fail/segfault/freeze, but that could be because Lua 5.5 is still in beta yet
-rw-r--r--CHANGES1
-rw-r--r--docs/index.html6
-rw-r--r--lanes-4.0.0-0.rockspec2
-rw-r--r--src/allocator.hpp2
-rw-r--r--src/compat.cpp38
-rw-r--r--src/compat.hpp71
-rw-r--r--src/universe.cpp2
-rw-r--r--unit_tests/embedded_tests.cpp2
-rw-r--r--unit_tests/linda_tests.cpp2
-rw-r--r--unit_tests/scripts/coro/yielding_in_non_coro_errors.lua3
10 files changed, 97 insertions, 32 deletions
diff --git a/CHANGES b/CHANGES
index b6bf3d6..17a79f7 100644
--- a/CHANGES
+++ b/CHANGES
@@ -6,6 +6,7 @@ CHANGE 2: BGe 05-Jun-25
6 - Almost all platform-specific code is gone (only a small bit for thread priority and affinity remains). 6 - Almost all platform-specific code is gone (only a small bit for thread priority and affinity remains).
7 - Decoda support inactive by default. 7 - Decoda support inactive by default.
8 - Deep userdata interface fully revamped to C++20 too. 8 - Deep userdata interface fully revamped to C++20 too.
9 - Supports Lua 5.5
9 * Lanes API changes 10 * Lanes API changes
10 - Version is now 4.0.0 11 - Version is now 4.0.0
11 - Lanes module: 12 - Lanes module:
diff --git a/docs/index.html b/docs/index.html
index f6201cc..96151fe 100644
--- a/docs/index.html
+++ b/docs/index.html
@@ -67,7 +67,7 @@
67 <br /> 67 <br />
68 <i>Copyright &copy; 2007-25 Asko Kauppi, Benoit Germain. All rights reserved.</i> 68 <i>Copyright &copy; 2007-25 Asko Kauppi, Benoit Germain. All rights reserved.</i>
69 <br /> 69 <br />
70 Lua Lanes is published under the same <a href="http://en.wikipedia.org/wiki/MIT_License">MIT license</a> as Lua 5.1, 5.2, 5.3 and 5.4. 70 Lua Lanes is published under the same <a href="http://en.wikipedia.org/wiki/MIT_License">MIT license</a> as Lua 5.1, 5.2, 5.3, 5.4 and 5.5.
71 </p> 71 </p>
72 72
73 <p> 73 <p>
@@ -89,7 +89,7 @@
89 Lanes is included into your software by the regular <tt>require "lanes"</tt> method. No C side programming is needed; all APIs are Lua side, and most existing extension modules should work seamlessly together with the multiple lanes. 89 Lanes is included into your software by the regular <tt>require "lanes"</tt> method. No C side programming is needed; all APIs are Lua side, and most existing extension modules should work seamlessly together with the multiple lanes.
90</p> 90</p>
91<p> 91<p>
92 Lanes should build and run identically with either Lua 5.1 to Lua 5.4, as well as LuaJIT. 92 Lanes should build and run identically with either Lua 5.1 to Lua 5.5, as well as LuaJIT.
93</p> 93</p>
94<p> 94<p>
95 See <A HREF="comparison.html">comparison</A> of Lua Lanes with other Lua multithreading solutions. 95 See <A HREF="comparison.html">comparison</A> of Lua Lanes with other Lua multithreading solutions.
@@ -893,7 +893,7 @@
893 The name is stored inside the Lua state registry so that it is available for error reporting. Changing <tt>decoda_name</tt> doesn't affect this hidden name or the OS thread name reported by MSVC.<br /> 893 The name is stored inside the Lua state registry so that it is available for error reporting. Changing <tt>decoda_name</tt> doesn't affect this hidden name or the OS thread name reported by MSVC.<br />
894 When Lanes is initialized by the first <a href="#initialization"><tt>lanes.configure()</tt></a> call, <tt>"main"</tt> is stored in the registry in the same fashion (but <tt>decoda_name</tt> and the OS thread name are left unchanged).<br /> 894 When Lanes is initialized by the first <a href="#initialization"><tt>lanes.configure()</tt></a> call, <tt>"main"</tt> is stored in the registry in the same fashion (but <tt>decoda_name</tt> and the OS thread name are left unchanged).<br />
895 The lane also has a method <tt>lane:get_threadname()</tt> that gives access to that name from the caller side (returns <tt>"&lt;unnamed&gt;"</tt> if unset).<br /> 895 The lane also has a method <tt>lane:get_threadname()</tt> that gives access to that name from the caller side (returns <tt>"&lt;unnamed&gt;"</tt> if unset).<br />
896 With Lua 5.4, Lanes have a <tt>__close</tt> metamethod, meaning they can be declared to-be-closed. <tt>__close</tt> calls <tt>lane:join(nil)</tt>. 896 With Lua 5.4+, Lanes have a <tt>__close</tt> metamethod, meaning they can be declared to-be-closed. <tt>__close</tt> calls <tt>lane:join(nil)</tt>.
897</p> 897</p>
898 898
899<p> 899<p>
diff --git a/lanes-4.0.0-0.rockspec b/lanes-4.0.0-0.rockspec
index e3c8709..f4de050 100644
--- a/lanes-4.0.0-0.rockspec
+++ b/lanes-4.0.0-0.rockspec
@@ -36,7 +36,7 @@ supported_platforms= { "win32",
36} 36}
37 37
38dependencies= { 38dependencies= {
39 "lua >= 5.1", -- builds with either 5.1/LuaJIT, 5.2, 5.3 and 5.4 39 "lua >= 5.1", -- builds with either 5.1/LuaJIT, 5.2, 5.3, 5.4 and 5.5
40} 40}
41 41
42build = { 42build = {
diff --git a/src/allocator.hpp b/src/allocator.hpp
index ce65a4b..b578f12 100644
--- a/src/allocator.hpp
+++ b/src/allocator.hpp
@@ -66,7 +66,7 @@ namespace lanes {
66 [[nodiscard]] 66 [[nodiscard]]
67 lua_State* newState() const 67 lua_State* newState() const
68 { 68 {
69 return lua_newstate(allocF, allocUD); 69 return luaW_newstate(allocF, allocUD, luaL_makeseed(nullptr));
70 } 70 }
71 71
72 [[nodiscard]] 72 [[nodiscard]]
diff --git a/src/compat.cpp b/src/compat.cpp
index 08f22ca..c833480 100644
--- a/src/compat.cpp
+++ b/src/compat.cpp
@@ -149,3 +149,41 @@ int lua_setiuservalue(lua_State* const L_, StackIndex const idx_, UserValueIndex
149} 149}
150 150
151#endif // LUA_VERSION_NUM 151#endif // LUA_VERSION_NUM
152
153// #################################################################################################
154
155#if LUA_VERSION_NUM < 505
156
157#include <time.h>
158
159/* Size for the buffer, in bytes */
160#define BUFSEEDB (sizeof(void*) + sizeof(time_t))
161
162/* Size for the buffer in int's, rounded up */
163#define BUFSEED ((BUFSEEDB + sizeof(int) - 1) / sizeof(int))
164
165/*
166** Copy the contents of variable 'v' into the buffer pointed by 'b'.
167** (The '&b[0]' disguises 'b' to fix an absurd warning from clang.)
168*/
169#define addbuff(b, v) (memcpy(&b[0], &(v), sizeof(v)), b += sizeof(v))
170
171// Copied from Lua 5.5 lauxlib.c
172unsigned int luaL_makeseed(lua_State*)
173{
174 unsigned int buff[BUFSEED];
175 unsigned int res;
176 unsigned int i;
177 time_t t = time(nullptr);
178 char* b = (char*) buff;
179 addbuff(b, b); /* local variable's address */
180 addbuff(b, t); /* time */
181 /* fill (rare but possible) remain of the buffer with zeros */
182 memset(b, 0, sizeof(buff) - BUFSEEDB);
183 res = buff[0];
184 for (i = 1; i < BUFSEED; i++)
185 res ^= (res >> 3) + (res << 7) + buff[i];
186 return res;
187}
188
189#endif // LUA_VERSION_NUM < 505
diff --git a/src/compat.hpp b/src/compat.hpp
index 99c468c..49029df 100644
--- a/src/compat.hpp
+++ b/src/compat.hpp
@@ -21,7 +21,7 @@
21#endif // LUA_OK 21#endif // LUA_OK
22 22
23#ifndef LUA_ERRGCMM 23#ifndef LUA_ERRGCMM
24#define LUA_ERRGCMM 666 // doesn't exist in Lua 5.1 and Lua 5.4, we don't care about the actual value 24#define LUA_ERRGCMM 666 // doesn't exist in Lua 5.1 and Lua 5.4/5.5, we don't care about the actual value
25#endif // LUA_ERRGCMM 25#endif // LUA_ERRGCMM
26 26
27 27
@@ -29,7 +29,7 @@
29#define LUA_LOADED_TABLE "_LOADED" // doesn't exist before Lua 5.3 29#define LUA_LOADED_TABLE "_LOADED" // doesn't exist before Lua 5.3
30#endif // LUA_LOADED_TABLE 30#endif // LUA_LOADED_TABLE
31 31
32// code is now preferring Lua 5.4 API 32// code is now preferring Lua 5.5 API
33 33
34// ################################################################################################# 34// #################################################################################################
35 35
@@ -76,18 +76,6 @@ int luaL_getsubtable(lua_State* L_, StackIndex idx_, char const* fname_);
76 76
77// ################################################################################################# 77// #################################################################################################
78 78
79// wrap Lua 5.3 calls under Lua 5.1 API when it is simpler that way
80#if LUA_VERSION_NUM == 503
81
82inline int luaL_optint(lua_State* L_, int n_, lua_Integer d_)
83{
84 return static_cast<int>(luaL_optinteger(L_, n_, d_));
85}
86
87#endif // LUA_VERSION_NUM == 503
88
89// #################################################################################################
90
91#if LUA_VERSION_NUM < 504 79#if LUA_VERSION_NUM < 504
92 80
93void* lua_newuserdatauv(lua_State* L_, size_t sz_, UserValueCount nuvalue_); 81void* lua_newuserdatauv(lua_State* L_, size_t sz_, UserValueCount nuvalue_);
@@ -100,15 +88,11 @@ int lua_setiuservalue(lua_State* L_, StackIndex idx_, UserValueIndex n_);
100 88
101// ################################################################################################# 89// #################################################################################################
102 90
103// wrap Lua 5.4 calls under Lua 5.1 API when it is simpler that way 91#if LUA_VERSION_NUM < 505
104#if LUA_VERSION_NUM == 504
105 92
106inline int luaL_optint(lua_State* L_, StackIndex n_, lua_Integer d_) 93unsigned int luaL_makeseed(lua_State*);
107{
108 return static_cast<int>(luaL_optinteger(L_, n_, d_));
109}
110 94
111#endif // LUA_VERSION_NUM == 504 95#endif // LUA_VERSION_NUM < 505
112 96
113// ################################################################################################# 97// #################################################################################################
114 98
@@ -284,6 +268,47 @@ LuaType luaW_getmodule(lua_State* L_, std::string_view const& name_);
284 268
285// ################################################################################################# 269// #################################################################################################
286 270
271template <typename LUA_NEWSTATE>
272concept RequiresOldLuaNewState = requires(LUA_NEWSTATE f_)
273{
274 {
275 f_(nullptr, 0)
276 } -> std::same_as<lua_State*>;
277};
278
279template <RequiresOldLuaNewState LUA_NEWSTATE>
280static inline lua_State* WrapLuaNewState(LUA_NEWSTATE const lua_newstate_, lua_Alloc const allocf_, void* const ud_, [[maybe_unused]] unsigned int const seed_)
281{
282 // until Lua 5.5, lua_newstate has only 2 parameters
283 return lua_newstate_(allocf_, ud_);
284}
285
286// -------------------------------------------------------------------------------------------------
287
288template <typename LUA_NEWSTATE>
289concept RequiresNewLuaNewState = requires(LUA_NEWSTATE f_)
290{
291 {
292 f_(nullptr, nullptr, 0)
293 } -> std::same_as<lua_State*>;
294};
295
296template <RequiresNewLuaNewState LUA_NEWSTATE>
297static inline lua_State* WrapLuaNewState(LUA_NEWSTATE const lua_newstate_, lua_Alloc const allocf_, void* const ud_, unsigned int const seed_)
298{
299 // starting with Lua 5.5, lua_newstate has 3 parameters
300 return lua_newstate_(allocf_, ud_, seed_);
301}
302
303// -------------------------------------------------------------------------------------------------
304
305static inline lua_State* luaW_newstate(lua_Alloc const allocf_, void* const ud_, unsigned int const seed_)
306{
307 return WrapLuaNewState(lua_newstate, allocf_, ud_, seed_);
308}
309
310// #################################################################################################
311
287template<typename ENUM> 312template<typename ENUM>
288requires std::is_enum_v<ENUM> 313requires std::is_enum_v<ENUM>
289[[nodiscard]] 314[[nodiscard]]
@@ -364,7 +389,7 @@ template <typename LUA_RAWGET>
364concept RequiresOldLuaRawget = requires(LUA_RAWGET f_) { { f_(nullptr, 0) } -> std::same_as<void>; }; 389concept RequiresOldLuaRawget = requires(LUA_RAWGET f_) { { f_(nullptr, 0) } -> std::same_as<void>; };
365 390
366template <RequiresOldLuaRawget LUA_RAWGET> 391template <RequiresOldLuaRawget LUA_RAWGET>
367static inline LuaType WrapLuaRawget(LUA_RAWGET lua_rawget_, lua_State* const L_, StackIndex const idx_) 392static inline LuaType WrapLuaRawget(LUA_RAWGET const lua_rawget_, lua_State* const L_, StackIndex const idx_)
368{ 393{
369 // until Lua 5.3, lua_rawget -> void 394 // until Lua 5.3, lua_rawget -> void
370 lua_rawget_(L_, idx_); 395 lua_rawget_(L_, idx_);
@@ -377,7 +402,7 @@ template <typename LUA_RAWGET>
377concept RequiresNewLuaRawget = requires(LUA_RAWGET f_) { { f_(nullptr, 0) } -> std::same_as<int>; }; 402concept RequiresNewLuaRawget = requires(LUA_RAWGET f_) { { f_(nullptr, 0) } -> std::same_as<int>; };
378 403
379template <RequiresNewLuaRawget LUA_RAWGET> 404template <RequiresNewLuaRawget LUA_RAWGET>
380static inline LuaType WrapLuaRawget(LUA_RAWGET lua_rawget_, lua_State* const L_, StackIndex const idx_) 405static inline LuaType WrapLuaRawget(LUA_RAWGET const lua_rawget_, lua_State* const L_, StackIndex const idx_)
381{ 406{
382 // starting with Lua 5.3, lua_rawget -> int (the type of the extracted value) 407 // starting with Lua 5.3, lua_rawget -> int (the type of the extracted value)
383 return static_cast<LuaType>(lua_rawget_(L_, idx_)); 408 return static_cast<LuaType>(lua_rawget_(L_, idx_));
diff --git a/src/universe.cpp b/src/universe.cpp
index 044c841..4db036b 100644
--- a/src/universe.cpp
+++ b/src/universe.cpp
@@ -447,7 +447,7 @@ int Universe::UniverseGC(lua_State* const L_)
447 if (!lua_isnil(L_, -1)) { 447 if (!lua_isnil(L_, -1)) {
448 lua_pushboolean(L_, _allLanesTerminated); // L_: U finalizer bool 448 lua_pushboolean(L_, _allLanesTerminated); // L_: U finalizer bool
449 // no protection. Lua rules for errors in finalizers apply normally: 449 // no protection. Lua rules for errors in finalizers apply normally:
450 // Lua 5.4: error is propagated in the warn system 450 // Lua 5.4+: error is propagated in the warn system
451 // older: error is swallowed 451 // older: error is swallowed
452 lua_call(L_, 1, 1); // L_: U msg? 452 lua_call(L_, 1, 1); // L_: U msg?
453 // phew, no error in finalizer, since we reached that point 453 // phew, no error in finalizer, since we reached that point
diff --git a/unit_tests/embedded_tests.cpp b/unit_tests/embedded_tests.cpp
index 58d6a8a..388548d 100644
--- a/unit_tests/embedded_tests.cpp
+++ b/unit_tests/embedded_tests.cpp
@@ -220,7 +220,7 @@ TEST_CASE("lanes.embedding.with_custom_allocator")
220 220
221 static constexpr auto launch_lane = +[](lua_CFunction on_state_create_, int id_, int n_) { 221 static constexpr auto launch_lane = +[](lua_CFunction on_state_create_, int id_, int n_) {
222 char script[500]; 222 char script[500];
223 lua_State* L = lua_newstate(local::allocf, nullptr); 223 lua_State* L = luaW_newstate(local::allocf, nullptr, luaL_makeseed(nullptr));
224 // _G.ID = id_ 224 // _G.ID = id_
225 luaL_openlibs(L); 225 luaL_openlibs(L);
226 luaL_dostring(L, "lanes = require 'lanes'"); 226 luaL_dostring(L, "lanes = require 'lanes'");
diff --git a/unit_tests/linda_tests.cpp b/unit_tests/linda_tests.cpp
index d956ae2..a36723a 100644
--- a/unit_tests/linda_tests.cpp
+++ b/unit_tests/linda_tests.cpp
@@ -35,7 +35,7 @@ TEST_CASE("linda.single_keeper.creation/close_handler")
35 LuaState S{ LuaState::WithBaseLibs{ true }, LuaState::WithFixture{ true } }; 35 LuaState S{ LuaState::WithBaseLibs{ true }, LuaState::WithFixture{ true } };
36 S.requireSuccess("lanes = require 'lanes'"); 36 S.requireSuccess("lanes = require 'lanes'");
37 37
38 if constexpr (LUA_VERSION_NUM == 504) { 38 if constexpr (LUA_VERSION_NUM >= 504) {
39 // a function is acceptable as a __close handler 39 // a function is acceptable as a __close handler
40 S.requireSuccess("local l <close> = lanes.linda{close_handler = function() end}"); 40 S.requireSuccess("local l <close> = lanes.linda{close_handler = function() end}");
41 // a callable table too (a callable full userdata as well, but I have none here) 41 // a callable table too (a callable full userdata as well, but I have none here)
diff --git a/unit_tests/scripts/coro/yielding_in_non_coro_errors.lua b/unit_tests/scripts/coro/yielding_in_non_coro_errors.lua
index 88d5fe0..fc0c072 100644
--- a/unit_tests/scripts/coro/yielding_in_non_coro_errors.lua
+++ b/unit_tests/scripts/coro/yielding_in_non_coro_errors.lua
@@ -20,7 +20,8 @@ local msgs = {
20 ["Lua 5.1"] = jit and "attempt to yield across C-call boundary" or "attempt to yield across metamethod/C-call boundary", 20 ["Lua 5.1"] = jit and "attempt to yield across C-call boundary" or "attempt to yield across metamethod/C-call boundary",
21 ["Lua 5.2"] = "attempt to yield from outside a coroutine", 21 ["Lua 5.2"] = "attempt to yield from outside a coroutine",
22 ["Lua 5.3"] = "attempt to yield from outside a coroutine", 22 ["Lua 5.3"] = "attempt to yield from outside a coroutine",
23 ["Lua 5.4"] = "attempt to yield from outside a coroutine" 23 ["Lua 5.4"] = "attempt to yield from outside a coroutine",
24 ["Lua 5.5"] = "attempt to yield from outside a coroutine"
24} 25}
25local expected_msg = msgs[_VERSION] 26local expected_msg = msgs[_VERSION]
26PRINT("expected_msg = " .. expected_msg) 27PRINT("expected_msg = " .. expected_msg)