aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--docs/index.html20
-rw-r--r--src/intercopycontext.cpp17
-rw-r--r--src/lane.cpp20
-rw-r--r--src/lane.h11
-rw-r--r--src/lanes.cpp3
-rw-r--r--src/lanesconf.h1
-rw-r--r--src/uniquekey.h6
-rw-r--r--src/universe.cpp6
8 files changed, 49 insertions, 35 deletions
diff --git a/docs/index.html b/docs/index.html
index 92cc38a..f5a074f 100644
--- a/docs/index.html
+++ b/docs/index.html
@@ -183,7 +183,7 @@
183 </tr> 183 </tr>
184</table> 184</table>
185<p> 185<p>
186 <tt>luaopen_lanes_embedded</tt> leaves the module table on the stack. <tt>lanes.configure()</tt> must still be called in order to use Lanes. 186 <tt>luaopen_lanes_embedded</tt> leaves the module table on the stack. <a href="#initialization"><tt>lanes.configure()</tt></a> must still be called in order to use Lanes.
187 <br/> 187 <br/>
188 If <tt>_luaopen_lanes</tt> is <tt>nullptr</tt>, a default loader will simply attempt the equivalent of <tt>luaL_dofile(L, "lanes.lua")</tt>. 188 If <tt>_luaopen_lanes</tt> is <tt>nullptr</tt>, a default loader will simply attempt the equivalent of <tt>luaL_dofile(L, "lanes.lua")</tt>.
189</p> 189</p>
@@ -249,17 +249,17 @@
249 Requiring the module follows Lua 5.2+ rules: the module is not available under the global name "lanes", but has to be accessed through <tt>require</tt>'s return value. 249 Requiring the module follows Lua 5.2+ rules: the module is not available under the global name "lanes", but has to be accessed through <tt>require</tt>'s return value.
250</p> 250</p>
251<p> 251<p>
252 After lanes is required, it is necessary to call <tt>lanes.configure()</tt>, which is the only function exposed by the module at this point. Calling <tt>configure()</tt> will perform one-time initializations and make the rest of the API available. 252 After lanes is required, it is necessary to call <tt>lanes.configure()</tt>, which is the only function exposed by the module at this point. Calling <tt>lanes.configure()</tt> will perform one-time initializations and make the rest of the API available.
253</p> 253</p>
254<p> 254<p>
255 At the same time, <tt>configure()</tt> itself will be replaced by another function that raises an error if called again with differing arguments, if any. 255 At the same time, <tt>lanes.configure()</tt> itself will be replaced by another function that raises an error if called again with differing arguments, if any.
256</p> 256</p>
257<p> 257<p>
258 Also, once Lanes is initialized, <tt>require()</tt> is replaced by another one that wraps it inside a mutex, both in the main state and in all created lanes. This prevents multiple thread-unsafe module initializations from several lanes to occur simultaneously. 258 Also, once Lanes is initialized, <tt>require()</tt> is replaced by another one that wraps it inside a mutex, both in the main state and in all created lanes. This prevents multiple thread-unsafe module initializations from several lanes to occur simultaneously.
259 It remains to be seen whether this is actually useful or not: If a module is already threadsafe, protecting its initialization isn't useful. And if it is not, any parallel operation may crash without Lanes being able to do anything about it. 259 It remains to be seen whether this is actually useful or not: If a module is already threadsafe, protecting its initialization isn't useful. And if it is not, any parallel operation may crash without Lanes being able to do anything about it.
260</p> 260</p>
261<p> 261<p>
262 <b>IMPORTANT NOTE:</b> Only the first occurence of <tt>require "lanes"</tt> must be followed by a call to <tt>.configure()</tt>. From this point, a simple <tt>require "lanes"</tt> will do wherever you need to require lanes again. 262 <b>IMPORTANT NOTE:</b> Only the first occurence of <tt>require "lanes"</tt> must be followed by a call to <tt>lanes.configure()</tt>. From this point, a simple <tt>require "lanes"</tt> will be enough wherever you need to require lanes again.
263</p> 263</p>
264 264
265<p> 265<p>
@@ -758,8 +758,10 @@
758 </table> 758 </table>
759 759
760<p> 760<p>
761 Each lane also gets a global function <tt>set_debug_threadname()</tt> that it can use anytime to do as the name says. Supported debuggers are Microsoft Visual Studio (for the C side) and Decoda (for the Lua side). 761 Each lane gets a global function <tt>set_debug_threadname()</tt> that it can use anytime to do as the name says. Supported debuggers are Microsoft Visual Studio (for the C side) and <a href="https://github.com/unknownworlds/decoda">Decoda</a> (for the Lua side).<br/>
762 <br/> 762 Decoda support is limited to setting a special global variable <tt>decoda_name</tt>. This is disabled by default. Change <tt>HAVE_DECODA_NAME()</tt> in <tt>lanesconf.h</tt> if necessary.<br/>
763 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/>
764 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/>
763 The lane also has a method <tt>lane:get_debug_threadname()</tt> that gives access to that name from the caller side (returns <tt>"&lt;unnamed&gt;"</tt> if unset, <tt>"&lt;closed&gt;"</tt> if the internal Lua state is closed). 765 The lane also has a method <tt>lane:get_debug_threadname()</tt> that gives access to that name from the caller side (returns <tt>"&lt;unnamed&gt;"</tt> if unset, <tt>"&lt;closed&gt;"</tt> if the internal Lua state is closed).
764</p> 766</p>
765 767
@@ -1334,7 +1336,7 @@
1334 1336
1335 <li> 1337 <li>
1336 Performance. Changing any slot in a Linda causes all pending threads for that Linda to be momentarily awakened (at least in the C level). 1338 Performance. Changing any slot in a Linda causes all pending threads for that Linda to be momentarily awakened (at least in the C level).
1337 This can degrade performance due to unnecessary OS level context switches. The more keeper states you declared with <tt>lanes.configure()</tt> the less this should be a problem. 1339 This can degrade performance due to unnecessary OS level context switches. The more keeper states you declared with <a href="#initialization"><tt>lanes.configure()</tt></a> the less this should be a problem.
1338 </li> 1340 </li>
1339 </ul> 1341 </ul>
1340 1342
@@ -1356,7 +1358,7 @@ events to a common Linda, but... :).</font>
1356</pre></td></tr></table> 1358</pre></td></tr></table>
1357 1359
1358<p> 1360<p>
1359 Timers are implemented as a lane. They can be enabled by setting "<tt><a href="#with_timers">with_timers</a></tt>" to <tt>true</tt> in <tt>lanes.configure()</tt> settings. 1361 Timers are implemented as a lane. They can be enabled by setting "<tt><a href="#with_timers">with_timers</a></tt>" to <tt>true</tt> in <a href="#initialization"><tt>lanes.configure()</tt></a> settings.
1360</p> 1362</p>
1361 1363
1362<p> 1364<p>
@@ -1373,7 +1375,7 @@ events to a common Linda, but... :).</font>
1373 1375
1374<table border="1" bgcolor="#FFFFE0" cellpadding="10" style="width:50%"><tr><td><pre> 1376<table border="1" bgcolor="#FFFFE0" cellpadding="10" style="width:50%"><tr><td><pre>
1375 local lanes = require "lanes" 1377 local lanes = require "lanes"
1376 lanes.configure() 1378 lanes.configure{with_timers = true}
1377 1379
1378 local linda = lanes.linda() 1380 local linda = lanes.linda()
1379 1381
diff --git a/src/intercopycontext.cpp b/src/intercopycontext.cpp
index 6c72b1c..893305e 100644
--- a/src/intercopycontext.cpp
+++ b/src/intercopycontext.cpp
@@ -29,6 +29,7 @@ THE SOFTWARE.
29#include "debugspew.h" 29#include "debugspew.h"
30#include "deep.h" 30#include "deep.h"
31#include "keeper.h" 31#include "keeper.h"
32#include "lane.h"
32#include "linda.h" 33#include "linda.h"
33#include "universe.h" 34#include "universe.h"
34 35
@@ -106,11 +107,11 @@ THE SOFTWARE.
106 if (_fqn.empty() && !lua_istable(L1, L1_i)) { // raise an error if we try to send an unknown function (but not for tables) 107 if (_fqn.empty() && !lua_istable(L1, L1_i)) { // raise an error if we try to send an unknown function (but not for tables)
107 _fqn = std::string_view{}; // just in case 108 _fqn = std::string_view{}; // just in case
108 // try to discover the name of the function we want to send 109 // try to discover the name of the function we want to send
109 lua_getglobal(L1, "decoda_name"); // L1: ... v ... decoda_name 110 kLaneNameRegKey.pushValue(L1); // L1: ... v ... lane_name
110 char const* _from{ lua_tostring(L1, -1) }; 111 char const* _from{ lua_tostring(L1, -1) };
111 lua_pushcfunction(L1, luaG_nameof); // L1: ... v ... decoda_name luaG_nameof 112 lua_pushcfunction(L1, luaG_nameof); // L1: ... v ... lane_name luaG_nameof
112 lua_pushvalue(L1, L1_i); // L1: ... v ... decoda_name luaG_nameof t 113 lua_pushvalue(L1, L1_i); // L1: ... v ... lane_name luaG_nameof t
113 lua_call(L1, 1, 2); // L1: ... v ... decoda_name "type" "name"|nil 114 lua_call(L1, 1, 2); // L1: ... v ... lane_name "type" "name"|nil
114 char const* _typewhat{ (lua_type(L1, -2) == LUA_TSTRING) ? lua_tostring(L1, -2) : luaL_typename(L1, -2) }; 115 char const* _typewhat{ (lua_type(L1, -2) == LUA_TSTRING) ? lua_tostring(L1, -2) : luaL_typename(L1, -2) };
115 // second return value can be nil if the table was not found 116 // second return value can be nil if the table was not found
116 // probable reason: the function was removed from the source Lua state before Lanes was required. 117 // probable reason: the function was removed from the source Lua state before Lanes was required.
@@ -325,10 +326,10 @@ void InterCopyContext::lookup_native_func() const
325 // nil means we don't know how to transfer stuff: user should do something 326 // nil means we don't know how to transfer stuff: user should do something
326 // anything other than function or table should not happen! 327 // anything other than function or table should not happen!
327 if (!lua_isfunction(L2, -1) && !lua_istable(L2, -1)) { 328 if (!lua_isfunction(L2, -1) && !lua_istable(L2, -1)) {
328 lua_getglobal(L1, "decoda_name"); // L1: ... f ... decoda_name 329 kLaneNameRegKey.pushValue(L1); // L1: ... f ... lane_name
329 char const* const _from{ lua_tostring(L1, -1) }; 330 char const* const _from{ lua_tostring(L1, -1) };
330 lua_pop(L1, 1); // L1: ... f ... 331 lua_pop(L1, 1); // L1: ... f ...
331 lua_getglobal(L2, "decoda_name"); // L1: ... f ... L2: {} f decoda_name 332 kLaneNameRegKey.pushValue(L2); // L1: ... f ... L2: {} f lane_name
332 char const* const _to{ lua_tostring(L2, -1) }; 333 char const* const _to{ lua_tostring(L2, -1) };
333 lua_pop(L2, 1); // L2: {} f 334 lua_pop(L2, 1); // L2: {} f
334 // when mode_ == LookupMode::FromKeeper, L is a keeper state and L2 is not, therefore L2 is the state where we want to raise the error 335 // when mode_ == LookupMode::FromKeeper, L is a keeper state and L2 is not, therefore L2 is the state where we want to raise the error
@@ -449,10 +450,10 @@ void InterCopyContext::copy_cached_func() const
449 STACK_CHECK(L2, 0); 450 STACK_CHECK(L2, 0);
450 return false; 451 return false;
451 } else if (!lua_istable(L2, -1)) { // this can happen if someone decides to replace same already registered item (for a example a standard lib function) with a table 452 } else if (!lua_istable(L2, -1)) { // this can happen if someone decides to replace same already registered item (for a example a standard lib function) with a table
452 lua_getglobal(L1, "decoda_name"); // L1: ... t ... decoda_name 453 kLaneNameRegKey.pushValue(L1); // L1: ... t ... lane_name
453 char const* _from{ lua_tostring(L1, -1) }; 454 char const* _from{ lua_tostring(L1, -1) };
454 lua_pop(L1, 1); // L1: ... t ... 455 lua_pop(L1, 1); // L1: ... t ...
455 lua_getglobal(L2, "decoda_name"); // L1: ... t ... L2: {} t decoda_name 456 kLaneNameRegKey.pushValue(L2); // L1: ... t ... L2: {} t lane_name
456 char const* _to{ lua_tostring(L2, -1) }; 457 char const* _to{ lua_tostring(L2, -1) };
457 lua_pop(L2, 1); // L1: ... t ... L2: {} t 458 lua_pop(L2, 1); // L1: ... t ... L2: {} t
458 raise_luaL_error( 459 raise_luaL_error(
diff --git a/src/lane.cpp b/src/lane.cpp
index f220bce..ada1846 100644
--- a/src/lane.cpp
+++ b/src/lane.cpp
@@ -802,20 +802,20 @@ Lane::~Lane()
802 802
803// ################################################################################################# 803// #################################################################################################
804 804
805void Lane::changeDebugName(int nameIdx_) 805void Lane::changeDebugName(int const nameIdx_)
806{ 806{
807 // xxh64 of string "debugName" generated at https://www.pelock.com/products/hash-calculator 807 int const _nameIdx{ lua_absindex(L, nameIdx_) };
808 static constexpr RegistryUniqueKey kRegKey{ 0xA194E2645C57F6DDull }; 808 luaL_checktype(L, _nameIdx, LUA_TSTRING); // L: ... "name" ...
809 nameIdx_ = lua_absindex(L, nameIdx_);
810 luaL_checktype(L, nameIdx_, LUA_TSTRING); // L: ... "name" ...
811 STACK_CHECK_START_REL(L, 0); 809 STACK_CHECK_START_REL(L, 0);
812 // store a hidden reference in the registry to make sure the string is kept around even if a lane decides to manually change the "decoda_name" global... 810 // store a hidden reference in the registry to make sure the string is kept around even if a lane decides to manually change the "decoda_name" global...
813 kRegKey.setValue(L, [nameIdx = nameIdx_](lua_State* L_) { lua_pushvalue(L_, nameIdx); }); // L: ... "name" ... 811 kLaneNameRegKey.setValue(L, [idx = _nameIdx](lua_State* L_) { lua_pushvalue(L_, idx); }); // L: ... "name" ...
814 // keep a direct pointer on the string 812 // keep a direct pointer on the string
815 debugName = lua_tostringview(L, nameIdx_); 813 debugName = lua_tostringview(L, _nameIdx);
816 // to see VM name in Decoda debugger Virtual Machine window 814 if constexpr (HAVE_DECODA_NAME()) {
817 lua_pushvalue(L, nameIdx_); // L: ... "name" ... "name" 815 // to see VM name in Decoda debugger Virtual Machine window
818 lua_setglobal(L, "decoda_name"); // L: ... "name" ... 816 lua_pushvalue(L, _nameIdx); // L: ... "name" ... "name"
817 lua_setglobal(L, "decoda_name"); // L: ... "name" ...
818 }
819 // and finally set the OS thread name 819 // and finally set the OS thread name
820 THREAD_SETNAME(debugName.data()); 820 THREAD_SETNAME(debugName.data());
821 STACK_CHECK(L, 0); 821 STACK_CHECK(L, 0);
diff --git a/src/lane.h b/src/lane.h
index 1fdd955..4dcb99e 100644
--- a/src/lane.h
+++ b/src/lane.h
@@ -13,6 +13,9 @@
13 13
14// ################################################################################################# 14// #################################################################################################
15 15
16// xxh64 of string "kExtendedStackTraceRegKey" generated at https://www.pelock.com/products/hash-calculator
17static constexpr RegistryUniqueKey kExtendedStackTraceRegKey{ 0x38147AD48FB426E2ull }; // used as registry key
18
16/* 19/*
17 * registry[FINALIZER_REG_KEY] is either nil (no finalizers) or a table 20 * registry[FINALIZER_REG_KEY] is either nil (no finalizers) or a table
18 * of functions that Lanes will call after the executing 'pcall' has ended. 21 * of functions that Lanes will call after the executing 'pcall' has ended.
@@ -24,15 +27,15 @@
24// xxh64 of string "kFinalizerRegKey" generated at https://www.pelock.com/products/hash-calculator 27// xxh64 of string "kFinalizerRegKey" generated at https://www.pelock.com/products/hash-calculator
25static constexpr RegistryUniqueKey kFinalizerRegKey{ 0xFE936BFAA718FEEAull }; 28static constexpr RegistryUniqueKey kFinalizerRegKey{ 0xFE936BFAA718FEEAull };
26 29
27// xxh64 of string "kExtendedStackTraceRegKey" generated at https://www.pelock.com/products/hash-calculator
28static constexpr RegistryUniqueKey kExtendedStackTraceRegKey{ 0x38147AD48FB426E2ull }; // used as registry key
29
30// xxh64 of string "kLaneGC" generated at https://www.pelock.com/products/hash-calculator 30// xxh64 of string "kLaneGC" generated at https://www.pelock.com/products/hash-calculator
31static constexpr UniqueKey kLaneGC{ 0x5D6122141727F960ull }; 31static constexpr UniqueKey kLaneGC{ 0x5D6122141727F960ull };
32 32
33// xxh64 of string "kLanePointerRegKey" generated at https://www.pelock.com/products/hash-calculator 33// xxh64 of string "kLanePointerRegKey" generated at https://www.pelock.com/products/hash-calculator
34static constexpr RegistryUniqueKey kLanePointerRegKey{ 0x2D8CF03FE9F0A51Aull }; // used as registry key 34static constexpr RegistryUniqueKey kLanePointerRegKey{ 0x2D8CF03FE9F0A51Aull }; // used as registry key
35 35
36 // xxh64 of string "debugName" generated at https://www.pelock.com/products/hash-calculator
37static constexpr RegistryUniqueKey kLaneNameRegKey{ 0xA194E2645C57F6DDull };
38
36// ################################################################################################# 39// #################################################################################################
37 40
38// The chain is ended by '(Lane*)(-1)', not nullptr: 'selfdestructFirst -> ... -> ... -> (-1)' 41// The chain is ended by '(Lane*)(-1)', not nullptr: 'selfdestructFirst -> ... -> ... -> (-1)'
@@ -124,7 +127,7 @@ class Lane
124 Lane(Universe* U_, lua_State* L_, ErrorTraceLevel errorTraceLevel_); 127 Lane(Universe* U_, lua_State* L_, ErrorTraceLevel errorTraceLevel_);
125 ~Lane(); 128 ~Lane();
126 129
127 void changeDebugName(int nameIdx_); 130 void changeDebugName(int const nameIdx_);
128 void close() { lua_State* _L{ L }; L = nullptr; lua_close(_L); } 131 void close() { lua_State* _L{ L }; L = nullptr; lua_close(_L); }
129 [[nodiscard]] std::string_view errorTraceLevelString() const; 132 [[nodiscard]] std::string_view errorTraceLevelString() const;
130 [[nodiscard]] int pushErrorHandler() const; 133 [[nodiscard]] int pushErrorHandler() const;
diff --git a/src/lanes.cpp b/src/lanes.cpp
index 20636b2..0ea0900 100644
--- a/src/lanes.cpp
+++ b/src/lanes.cpp
@@ -676,6 +676,9 @@ LUAG_FUNC(configure)
676 // increment refcount so that this linda remains alive as long as the universe exists. 676 // increment refcount so that this linda remains alive as long as the universe exists.
677 _U->timerLinda->refcount.fetch_add(1, std::memory_order_relaxed); 677 _U->timerLinda->refcount.fetch_add(1, std::memory_order_relaxed);
678 lua_pop(L_, 1); // L_: settings 678 lua_pop(L_, 1); // L_: settings
679 // store a hidden reference in the registry to make sure the string is kept around even if a lane decides to manually change the "decoda_name" global...
680 kLaneNameRegKey.setValue(L_, [](lua_State* L_) { std::ignore = lua_pushstringview(L_, "main"); });
681
679 } 682 }
680 STACK_CHECK(L_, 1); 683 STACK_CHECK(L_, 1);
681 684
diff --git a/src/lanesconf.h b/src/lanesconf.h
index 3836848..2df7a71 100644
--- a/src/lanesconf.h
+++ b/src/lanesconf.h
@@ -42,3 +42,4 @@
42#endif // (defined PLATFORM_WIN32) || (defined PLATFORM_POCKETPC) 42#endif // (defined PLATFORM_WIN32) || (defined PLATFORM_POCKETPC)
43 43
44#define USE_DEBUG_SPEW() 0 44#define USE_DEBUG_SPEW() 0
45#define HAVE_DECODA_NAME() 0
diff --git a/src/uniquekey.h b/src/uniquekey.h
index 9981bb8..cfc8ab0 100644
--- a/src/uniquekey.h
+++ b/src/uniquekey.h
@@ -62,9 +62,9 @@ class RegistryUniqueKey
62 void setValue(lua_State* L_, OP operation_) const 62 void setValue(lua_State* L_, OP operation_) const
63 { 63 {
64 // Note we can't check stack consistency because operation is not always a push (could be insert, replace, whatever) 64 // Note we can't check stack consistency because operation is not always a push (could be insert, replace, whatever)
65 pushKey(L_); // ... key 65 pushKey(L_); // ... key
66 operation_(L_); // ... key value 66 operation_(L_); // ... key value
67 lua_rawset(L_, LUA_REGISTRYINDEX); // ... 67 lua_rawset(L_, LUA_REGISTRYINDEX); // ...
68 } 68 }
69 // --------------------------------------------------------------------------------------------- 69 // ---------------------------------------------------------------------------------------------
70 template <typename T> 70 template <typename T>
diff --git a/src/universe.cpp b/src/universe.cpp
index 9e1ac5f..5fe53d5 100644
--- a/src/universe.cpp
+++ b/src/universe.cpp
@@ -286,7 +286,11 @@ void Universe::initializeKeepers(lua_State* L_)
286 286
287 // to see VM name in Decoda debugger 287 // to see VM name in Decoda debugger
288 lua_pushfstring(_K, "Keeper #%d", _i + 1); // L_: settings K: "Keeper #n" 288 lua_pushfstring(_K, "Keeper #%d", _i + 1); // L_: settings K: "Keeper #n"
289 lua_setglobal(_K, "decoda_name"); // L_: settings K: 289 if constexpr (HAVE_DECODA_NAME()) {
290 lua_pushvalue(_K, -1); // K: "Keeper #n" Keeper #n"
291 lua_setglobal(_K, "decoda_name"); // L_: settings K: "Keeper #n"
292 }
293 kLaneNameRegKey.setValue(_K, [](lua_State* L_) { lua_insert(L_, -2); }); // K:
290 // create the fifos table in the keeper state 294 // create the fifos table in the keeper state
291 Keepers::CreateFifosTable(_K); 295 Keepers::CreateFifosTable(_K);
292 STACK_CHECK(_K, 0); 296 STACK_CHECK(_K, 0);