aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.gitignore1
-rw-r--r--.runsettings8
-rw-r--r--.vscode/launch.json44
-rw-r--r--CHANGES12
-rw-r--r--CMakeLists.txt5
-rw-r--r--Lanes.sln42
-rw-r--r--Lanes.vcxproj366
-rw-r--r--Makefile12
-rw-r--r--Shared.makefile4
-rw-r--r--deep_userdata_example/deep_userdata_example.cpp32
-rw-r--r--deep_userdata_example/deep_userdata_example.vcxproj221
-rw-r--r--deep_userdata_example/deeptest.lua2
-rw-r--r--docs/index.html205
-rw-r--r--lanes-4.0.0-0.rockspec4
-rw-r--r--src/_pch.hpp4
-rw-r--r--src/allocator.cpp2
-rw-r--r--src/allocator.hpp4
-rw-r--r--src/cancel.cpp140
-rw-r--r--src/compat.cpp50
-rw-r--r--src/compat.hpp138
-rw-r--r--src/deep.cpp28
-rw-r--r--src/intercopycontext.cpp195
-rw-r--r--src/keeper.cpp149
-rw-r--r--src/keeper.hpp16
-rw-r--r--src/lane.cpp424
-rw-r--r--src/lane.hpp10
-rw-r--r--src/lanes.cpp126
-rw-r--r--src/lanes.lua61
-rw-r--r--src/lanesconf.h8
-rw-r--r--src/linda.cpp640
-rw-r--r--src/linda.hpp39
-rw-r--r--src/lindafactory.cpp29
-rw-r--r--src/macros_and_utils.hpp1
-rw-r--r--src/nameof.cpp34
-rw-r--r--src/state.cpp18
-rw-r--r--src/threading.cpp154
-rw-r--r--src/threading.hpp14
-rw-r--r--src/tools.cpp101
-rw-r--r--src/tools.hpp3
-rw-r--r--src/tracker.cpp2
-rw-r--r--src/uniquekey.hpp6
-rw-r--r--src/universe.cpp107
-rw-r--r--src/universe.hpp20
-rw-r--r--tests/appendud.lua2
-rw-r--r--tests/basic.lua62
-rw-r--r--tests/cancel.lua2
-rw-r--r--tests/deadlock.lua2
-rw-r--r--tests/errhangtest.lua9
-rw-r--r--tests/error.lua11
-rw-r--r--tests/fifo.lua4
-rw-r--r--tests/finalizer.lua4
-rw-r--r--tests/func_is_string.lua13
-rw-r--r--tests/irayo_closure.lua2
-rw-r--r--tests/keeper.lua36
-rw-r--r--tests/launchtest.lua4
-rw-r--r--tests/linda_perf.lua21
-rw-r--r--tests/perftest.lua4
-rw-r--r--tests/pingpong.lua8
-rw-r--r--tests/protect_allocator.lua2
-rw-r--r--tests/rupval.lua6
-rw-r--r--tests/tobeclosed.lua17
-rw-r--r--tests/track_lanes.lua6
-rw-r--r--unit_tests/UnitTests.vcxproj279
-rw-r--r--unit_tests/UnitTests.vcxproj.filters44
-rw-r--r--unit_tests/_pch.hpp2
-rw-r--r--unit_tests/deep_tests.cpp11
-rw-r--r--unit_tests/embedded_tests.cpp22
-rw-r--r--unit_tests/init_and_shutdown.cpp680
-rw-r--r--unit_tests/lane_tests.cpp256
-rw-r--r--unit_tests/legacy_tests.cpp4
-rw-r--r--unit_tests/linda_tests.cpp333
-rw-r--r--unit_tests/scripts/_utils.lua20
-rw-r--r--unit_tests/scripts/_utils54.lua30
-rw-r--r--unit_tests/scripts/coro/basics.lua97
-rw-r--r--unit_tests/scripts/coro/cancelling_suspended.lua31
-rw-r--r--unit_tests/scripts/coro/collect_yielded_lane.lua64
-rw-r--r--unit_tests/scripts/coro/error_handling.lua6
-rw-r--r--unit_tests/scripts/coro/index_suspended.lua28
-rw-r--r--unit_tests/scripts/coro/join_suspended.lua24
-rw-r--r--unit_tests/scripts/coro/linda_in_close_handler.lua43
-rw-r--r--unit_tests/scripts/coro/regular_function.lua38
-rw-r--r--unit_tests/scripts/coro/resume_basics.lua40
-rw-r--r--unit_tests/scripts/coro/yielding_in_non_coro_errors.lua28
-rw-r--r--unit_tests/scripts/lane/body_is_a_c_function.lua28
-rw-r--r--unit_tests/scripts/lane/cooperative_shutdown.lua16
-rw-r--r--unit_tests/scripts/lane/tasking_cancelling.lua112
-rw-r--r--unit_tests/scripts/lane/tasking_cancelling_with_hook.lua68
-rw-r--r--unit_tests/scripts/lane/tasking_comms_criss_cross.lua2
-rw-r--r--unit_tests/scripts/lane/tasking_communications.lua4
-rw-r--r--unit_tests/scripts/lane/tasking_join_test.lua16
-rw-r--r--unit_tests/scripts/lane/tasking_send_receive_code.lua20
-rw-r--r--unit_tests/scripts/lane/uncooperative_shutdown.lua2
-rw-r--r--unit_tests/scripts/linda/multiple_keepers.lua6
-rw-r--r--unit_tests/scripts/linda/send_receive_func_and_string.lua13
-rw-r--r--unit_tests/scripts/linda/send_registered_userdata.lua2
-rw-r--r--unit_tests/scripts/linda/wake_period.lua42
-rw-r--r--unit_tests/scripts/misc/deeptest.lua161
-rw-r--r--unit_tests/shared.cpp57
-rw-r--r--unit_tests/shared.h2
99 files changed, 4228 insertions, 2099 deletions
diff --git a/.gitignore b/.gitignore
index 71642e3..a46a070 100644
--- a/.gitignore
+++ b/.gitignore
@@ -2,6 +2,7 @@ _Output
2_Tmp 2_Tmp
3_LuaVersions 3_LuaVersions
4.vs 4.vs
5.vscode
5*.dll 6*.dll
6*.exe 7*.exe
7*.gch 8*.gch
diff --git a/.runsettings b/.runsettings
index 8114d6a..e349e01 100644
--- a/.runsettings
+++ b/.runsettings
@@ -8,10 +8,10 @@
8 <!-- The whole setup relies on Lua Binaries and headers to be located in a folder $(SolutionDir)/_LuaVersions/$(PlatformName)/$(ConfigurationName) 8 <!-- The whole setup relies on Lua Binaries and headers to be located in a folder $(SolutionDir)/_LuaVersions/$(PlatformName)/$(ConfigurationName)
9 this is also true for linker input folders, the folder where lanes.lua is copied by the custom build operation, etc. 9 this is also true for linker input folders, the folder where lanes.lua is copied by the custom build operation, etc.
10 --> 10 -->
11 <Environment> 11 <!-- Environment>
12 <LUA_PATH value="$(SolutionDir)/_LuaVersions/$(PlatformName)/$(ConfigurationName)" /> 12 <LUA_PATH>$(SolutionDir)/_LuaVersions/$(PlatformName)/$(ConfigurationName)</LUA_PATH>
13 <LUA_CPATH value="$(SolutionDir)/_LuaVersions/$(PlatformName)/$(ConfigurationName)" /> 13 <LUA_CPATH>$(SolutionDir)/_LuaVersions/$(PlatformName)/$(ConfigurationName)</LUA_CPATH>
14 </Environment> 14 </Environment -->
15 15
16 <!-- Executable Filename 16 <!-- Executable Filename
17 Discover filenames with ... (must not include the .exe extension) 17 Discover filenames with ... (must not include the .exe extension)
diff --git a/.vscode/launch.json b/.vscode/launch.json
new file mode 100644
index 0000000..a2781fd
--- /dev/null
+++ b/.vscode/launch.json
@@ -0,0 +1,44 @@
1{
2 "version": "0.2.0",
3 "configurations": [
4
5 {
6 "name": "Debug MinGW-w64",
7 "type": "cppdbg",
8 "request": "launch",
9 "program": "${workspaceFolder}/unit_tests/UnitTests.exe",
10 "args": [
11 //"--list-tests",
12 "--rng-seed 0",
13 "-s scripted_tests.lane.tasking_cancelling"
14 ],
15 "stopAtEntry": true,
16 "cwd": "${workspaceFolder}",
17 "environment": [
18 {
19 "name" : "LUA_CPATH",
20 "value" : "./src/?.dll;./deep_userdata_example/?.dll"
21 },
22 {
23 "name" : "LUA_PATH",
24 "value" : "./src/?.lua;./tests/?.lua"
25 }
26 ],
27 "externalConsole": false, // or true, depending on your preference
28 "MIMode": "gdb",
29 "miDebuggerPath": "C:/msys64/ucrt64/bin/gdb.exe", // Replace with your GDB path
30 "setupCommands": [
31 {
32 "description": "Enable pretty-printing for gdb",
33 "text": "-enable-pretty-printing",
34 "ignoreFailures": true
35 },
36 {
37 "description": "Show GDB commands",
38 "text": "-interpreter-exec console \"monitor set debug 1\"",
39 "ignoreFailures": true
40 }
41 ]
42 }
43 ]
44}
diff --git a/CHANGES b/CHANGES
index 7cf28b2..17a79f7 100644
--- a/CHANGES
+++ b/CHANGES
@@ -1,11 +1,12 @@
1CHANGES: 1CHANGES:
2 2
3CHANGE 2: BGe 27-Nov-24 3CHANGE 2: BGe 05-Jun-25
4 * Internal changes 4 * Internal changes
5 - Lanes is implemented in C++20: thread, condition_variable, mutex, string_view, variant, lambdas, templates, and more! 5 - Lanes is implemented in C++20: thread, condition_variable, mutex, string_view, variant, lambdas, templates, and more!
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:
@@ -16,6 +17,7 @@ CHANGE 2: BGe 27-Nov-24
16 - new function lanes.finally(). Installs a function that gets called at Lanes shutdown after attempting to terminate all lanes. 17 - new function lanes.finally(). Installs a function that gets called at Lanes shutdown after attempting to terminate all lanes.
17 If some lanes still run after the finalizer, Universe::__gc with raise an error or freeze, depending on its return value. 18 If some lanes still run after the finalizer, Universe::__gc with raise an error or freeze, depending on its return value.
18 - new function lanes.collectgarbage(), to force a full GC cycle in the keeper states. 19 - new function lanes.collectgarbage(), to force a full GC cycle in the keeper states.
20 - new function lanes.thread_priority_range(), to query the valid range of priorities.
19 - Configuration settings: 21 - Configuration settings:
20 - Boolean parameters only accept boolean values. 22 - Boolean parameters only accept boolean values.
21 - allocator provider function is called with a string hint to distinguish internal allocations, lane and keeper states. 23 - allocator provider function is called with a string hint to distinguish internal allocations, lane and keeper states.
@@ -26,6 +28,8 @@ CHANGE 2: BGe 27-Nov-24
26 - verbose_errors removed. Use lane error_trace_level instead. 28 - verbose_errors removed. Use lane error_trace_level instead.
27 - with_timers is false by default. 29 - with_timers is false by default.
28 - Non-deep full userdata are processed during module registration just like ordinary module C functions, making them valid transferable (up)values (for example: io.stdin). 30 - Non-deep full userdata are processed during module registration just like ordinary module C functions, making them valid transferable (up)values (for example: io.stdin).
31 - thread API errors cause a Lua error instead of aborting the program.
32 - thread priorities can now be set using the native range of values, if desired.
29 - Lanes: 33 - Lanes:
30 - Can no longer be "killed" by hard-stopping their thread without any resource cleanup (see lane:cancel()). 34 - Can no longer be "killed" by hard-stopping their thread without any resource cleanup (see lane:cancel()).
31 - lanes.gen() settings: 35 - lanes.gen() settings:
@@ -34,10 +38,9 @@ CHANGE 2: BGe 27-Nov-24
34 - name added. Can be used to set the name early (before the lane body calls lane_threadname()). 38 - name added. Can be used to set the name early (before the lane body calls lane_threadname()).
35 - New generator lanes.coro() to start a lane as a coroutine. 39 - New generator lanes.coro() to start a lane as a coroutine.
36 - New __close metamethod that calls join(). 40 - New __close metamethod that calls join().
37 - lane:join() 41 - lane:join() returns nil, error in case of problem, else returns true followed by the lane body return values.
38 - Returns nil, error in case of problem.
39 - Forces lane function body must return a non-nil first value on success because of the above.
40 - lane:get_debug_threadname() renamed get_threadname(). 42 - lane:get_debug_threadname() renamed get_threadname().
43 - cancel_test() returns "soft"/"hard" instead of true when a cancellation request is active.
41 - Lindas: 44 - Lindas:
42 - lanes.linda() 45 - lanes.linda()
43 - Arguments can be provided in any order. 46 - Arguments can be provided in any order.
@@ -45,6 +48,7 @@ CHANGE 2: BGe 27-Nov-24
45 - Providing "auto" as name when constructing a Linda cause Lanes to provide a name built from the source location of the construction. 48 - Providing "auto" as name when constructing a Linda cause Lanes to provide a name built from the source location of the construction.
46 - Specifying a group to lanes.linda() is mandatory when Lanes is configured with user Keepers. 49 - Specifying a group to lanes.linda() is mandatory when Lanes is configured with user Keepers.
47 - linda:deep() result no longer contains the raw C pointer of the Linda object. 50 - linda:deep() result no longer contains the raw C pointer of the Linda object.
51 - new function linda:receive_batched() to replace linda:receive(linda.batched). linda.batched special value is removed.
48 - linda :receive(), :send(), :get(), :set(), :limit() return nil, error in case of problem. Returned values in case of success change too. 52 - linda :receive(), :send(), :get(), :set(), :limit() return nil, error in case of problem. Returned values in case of success change too.
49 - linda:limit() can be used to read the value if no new limit is provided. 53 - linda:limit() can be used to read the value if no new limit is provided.
50 - linda:restrict() can restrain the use of send/receive or set/get on any key. 54 - linda:restrict() can restrain the use of send/receive or set/get on any key.
diff --git a/CMakeLists.txt b/CMakeLists.txt
index be6a2f2..2c5c66f 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -3,9 +3,10 @@
3# Redistribution and use of this file is allowed according to the terms of the MIT license. 3# Redistribution and use of this file is allowed according to the terms of the MIT license.
4# For details see the COPYRIGHT file distributed with LuaDist. 4# For details see the COPYRIGHT file distributed with LuaDist.
5# Please note that the package source code is licensed under its own license. 5# Please note that the package source code is licensed under its own license.
6CMAKE_MINIMUM_REQUIRED(VERSION 3.18)
7PROJECT(lanes CXX)
8set (CMAKE_CXX_STANDARD 20)
6 9
7PROJECT(lanes C)
8CMAKE_MINIMUM_REQUIRED(VERSION 2.6)
9 10
10 11
11FIND_PACKAGE(Lua51 REQUIRED) 12FIND_PACKAGE(Lua51 REQUIRED)
diff --git a/Lanes.sln b/Lanes.sln
index b5c1d89..bc88a79 100644
--- a/Lanes.sln
+++ b/Lanes.sln
@@ -30,6 +30,9 @@ Global
30 Debug 5.4|Prospero = Debug 5.4|Prospero 30 Debug 5.4|Prospero = Debug 5.4|Prospero
31 Debug 5.4|x64 = Debug 5.4|x64 31 Debug 5.4|x64 = Debug 5.4|x64
32 Debug 5.4|x86 = Debug 5.4|x86 32 Debug 5.4|x86 = Debug 5.4|x86
33 Debug 5.5|Prospero = Debug 5.5|Prospero
34 Debug 5.5|x64 = Debug 5.5|x64
35 Debug 5.5|x86 = Debug 5.5|x86
33 Release 5.1|Prospero = Release 5.1|Prospero 36 Release 5.1|Prospero = Release 5.1|Prospero
34 Release 5.1|x64 = Release 5.1|x64 37 Release 5.1|x64 = Release 5.1|x64
35 Release 5.1|x86 = Release 5.1|x86 38 Release 5.1|x86 = Release 5.1|x86
@@ -42,6 +45,9 @@ Global
42 Release 5.4|Prospero = Release 5.4|Prospero 45 Release 5.4|Prospero = Release 5.4|Prospero
43 Release 5.4|x64 = Release 5.4|x64 46 Release 5.4|x64 = Release 5.4|x64
44 Release 5.4|x86 = Release 5.4|x86 47 Release 5.4|x86 = Release 5.4|x86
48 Release 5.5|Prospero = Release 5.5|Prospero
49 Release 5.5|x64 = Release 5.5|x64
50 Release 5.5|x86 = Release 5.5|x86
45 Release LuaJIT|Prospero = Release LuaJIT|Prospero 51 Release LuaJIT|Prospero = Release LuaJIT|Prospero
46 Release LuaJIT|x64 = Release LuaJIT|x64 52 Release LuaJIT|x64 = Release LuaJIT|x64
47 Release LuaJIT|x86 = Release LuaJIT|x86 53 Release LuaJIT|x86 = Release LuaJIT|x86
@@ -74,6 +80,12 @@ Global
74 {1DB7D861-EEFD-49DC-A8E2-3FC2BD6AD49D}.Debug 5.4|x64.Build.0 = Debug 5.4|x64 80 {1DB7D861-EEFD-49DC-A8E2-3FC2BD6AD49D}.Debug 5.4|x64.Build.0 = Debug 5.4|x64
75 {1DB7D861-EEFD-49DC-A8E2-3FC2BD6AD49D}.Debug 5.4|x86.ActiveCfg = Debug 5.4|Win32 81 {1DB7D861-EEFD-49DC-A8E2-3FC2BD6AD49D}.Debug 5.4|x86.ActiveCfg = Debug 5.4|Win32
76 {1DB7D861-EEFD-49DC-A8E2-3FC2BD6AD49D}.Debug 5.4|x86.Build.0 = Debug 5.4|Win32 82 {1DB7D861-EEFD-49DC-A8E2-3FC2BD6AD49D}.Debug 5.4|x86.Build.0 = Debug 5.4|Win32
83 {1DB7D861-EEFD-49DC-A8E2-3FC2BD6AD49D}.Debug 5.5|Prospero.ActiveCfg = Debug 5.5|Prospero
84 {1DB7D861-EEFD-49DC-A8E2-3FC2BD6AD49D}.Debug 5.5|Prospero.Build.0 = Debug 5.5|Prospero
85 {1DB7D861-EEFD-49DC-A8E2-3FC2BD6AD49D}.Debug 5.5|x64.ActiveCfg = Debug 5.5|x64
86 {1DB7D861-EEFD-49DC-A8E2-3FC2BD6AD49D}.Debug 5.5|x64.Build.0 = Debug 5.5|x64
87 {1DB7D861-EEFD-49DC-A8E2-3FC2BD6AD49D}.Debug 5.5|x86.ActiveCfg = Debug 5.5|Win32
88 {1DB7D861-EEFD-49DC-A8E2-3FC2BD6AD49D}.Debug 5.5|x86.Build.0 = Debug 5.5|Win32
77 {1DB7D861-EEFD-49DC-A8E2-3FC2BD6AD49D}.Release 5.1|Prospero.ActiveCfg = Release 5.1|Prospero 89 {1DB7D861-EEFD-49DC-A8E2-3FC2BD6AD49D}.Release 5.1|Prospero.ActiveCfg = Release 5.1|Prospero
78 {1DB7D861-EEFD-49DC-A8E2-3FC2BD6AD49D}.Release 5.1|Prospero.Build.0 = Release 5.1|Prospero 90 {1DB7D861-EEFD-49DC-A8E2-3FC2BD6AD49D}.Release 5.1|Prospero.Build.0 = Release 5.1|Prospero
79 {1DB7D861-EEFD-49DC-A8E2-3FC2BD6AD49D}.Release 5.1|x64.ActiveCfg = Release 5.1|x64 91 {1DB7D861-EEFD-49DC-A8E2-3FC2BD6AD49D}.Release 5.1|x64.ActiveCfg = Release 5.1|x64
@@ -98,6 +110,12 @@ Global
98 {1DB7D861-EEFD-49DC-A8E2-3FC2BD6AD49D}.Release 5.4|x64.Build.0 = Release 5.4|x64 110 {1DB7D861-EEFD-49DC-A8E2-3FC2BD6AD49D}.Release 5.4|x64.Build.0 = Release 5.4|x64
99 {1DB7D861-EEFD-49DC-A8E2-3FC2BD6AD49D}.Release 5.4|x86.ActiveCfg = Release 5.4|Win32 111 {1DB7D861-EEFD-49DC-A8E2-3FC2BD6AD49D}.Release 5.4|x86.ActiveCfg = Release 5.4|Win32
100 {1DB7D861-EEFD-49DC-A8E2-3FC2BD6AD49D}.Release 5.4|x86.Build.0 = Release 5.4|Win32 112 {1DB7D861-EEFD-49DC-A8E2-3FC2BD6AD49D}.Release 5.4|x86.Build.0 = Release 5.4|Win32
113 {1DB7D861-EEFD-49DC-A8E2-3FC2BD6AD49D}.Release 5.5|Prospero.ActiveCfg = Release 5.5|Prospero
114 {1DB7D861-EEFD-49DC-A8E2-3FC2BD6AD49D}.Release 5.5|Prospero.Build.0 = Release 5.5|Prospero
115 {1DB7D861-EEFD-49DC-A8E2-3FC2BD6AD49D}.Release 5.5|x64.ActiveCfg = Release 5.5|x64
116 {1DB7D861-EEFD-49DC-A8E2-3FC2BD6AD49D}.Release 5.5|x64.Build.0 = Release 5.5|x64
117 {1DB7D861-EEFD-49DC-A8E2-3FC2BD6AD49D}.Release 5.5|x86.ActiveCfg = Release 5.5|Win32
118 {1DB7D861-EEFD-49DC-A8E2-3FC2BD6AD49D}.Release 5.5|x86.Build.0 = Release 5.5|Win32
101 {1DB7D861-EEFD-49DC-A8E2-3FC2BD6AD49D}.Release LuaJIT|Prospero.ActiveCfg = Release LuaJIT|Prospero 119 {1DB7D861-EEFD-49DC-A8E2-3FC2BD6AD49D}.Release LuaJIT|Prospero.ActiveCfg = Release LuaJIT|Prospero
102 {1DB7D861-EEFD-49DC-A8E2-3FC2BD6AD49D}.Release LuaJIT|Prospero.Build.0 = Release LuaJIT|Prospero 120 {1DB7D861-EEFD-49DC-A8E2-3FC2BD6AD49D}.Release LuaJIT|Prospero.Build.0 = Release LuaJIT|Prospero
103 {1DB7D861-EEFD-49DC-A8E2-3FC2BD6AD49D}.Release LuaJIT|x64.ActiveCfg = Release LuaJIT|x64 121 {1DB7D861-EEFD-49DC-A8E2-3FC2BD6AD49D}.Release LuaJIT|x64.ActiveCfg = Release LuaJIT|x64
@@ -134,6 +152,12 @@ Global
134 {AED7F42F-139A-46BA-80FE-16E062EA1345}.Debug 5.4|x64.Build.0 = Debug 5.4|x64 152 {AED7F42F-139A-46BA-80FE-16E062EA1345}.Debug 5.4|x64.Build.0 = Debug 5.4|x64
135 {AED7F42F-139A-46BA-80FE-16E062EA1345}.Debug 5.4|x86.ActiveCfg = Debug 5.4|Win32 153 {AED7F42F-139A-46BA-80FE-16E062EA1345}.Debug 5.4|x86.ActiveCfg = Debug 5.4|Win32
136 {AED7F42F-139A-46BA-80FE-16E062EA1345}.Debug 5.4|x86.Build.0 = Debug 5.4|Win32 154 {AED7F42F-139A-46BA-80FE-16E062EA1345}.Debug 5.4|x86.Build.0 = Debug 5.4|Win32
155 {AED7F42F-139A-46BA-80FE-16E062EA1345}.Debug 5.5|Prospero.ActiveCfg = Debug 5.5|Prospero
156 {AED7F42F-139A-46BA-80FE-16E062EA1345}.Debug 5.5|Prospero.Build.0 = Debug 5.5|Prospero
157 {AED7F42F-139A-46BA-80FE-16E062EA1345}.Debug 5.5|x64.ActiveCfg = Debug 5.5|x64
158 {AED7F42F-139A-46BA-80FE-16E062EA1345}.Debug 5.5|x64.Build.0 = Debug 5.5|x64
159 {AED7F42F-139A-46BA-80FE-16E062EA1345}.Debug 5.5|x86.ActiveCfg = Debug 5.5|Win32
160 {AED7F42F-139A-46BA-80FE-16E062EA1345}.Debug 5.5|x86.Build.0 = Debug 5.5|Win32
137 {AED7F42F-139A-46BA-80FE-16E062EA1345}.Release 5.1|Prospero.ActiveCfg = Release 5.1|Prospero 161 {AED7F42F-139A-46BA-80FE-16E062EA1345}.Release 5.1|Prospero.ActiveCfg = Release 5.1|Prospero
138 {AED7F42F-139A-46BA-80FE-16E062EA1345}.Release 5.1|Prospero.Build.0 = Release 5.1|Prospero 162 {AED7F42F-139A-46BA-80FE-16E062EA1345}.Release 5.1|Prospero.Build.0 = Release 5.1|Prospero
139 {AED7F42F-139A-46BA-80FE-16E062EA1345}.Release 5.1|x64.ActiveCfg = Release 5.1|x64 163 {AED7F42F-139A-46BA-80FE-16E062EA1345}.Release 5.1|x64.ActiveCfg = Release 5.1|x64
@@ -158,6 +182,12 @@ Global
158 {AED7F42F-139A-46BA-80FE-16E062EA1345}.Release 5.4|x64.Build.0 = Release 5.4|x64 182 {AED7F42F-139A-46BA-80FE-16E062EA1345}.Release 5.4|x64.Build.0 = Release 5.4|x64
159 {AED7F42F-139A-46BA-80FE-16E062EA1345}.Release 5.4|x86.ActiveCfg = Release 5.4|Win32 183 {AED7F42F-139A-46BA-80FE-16E062EA1345}.Release 5.4|x86.ActiveCfg = Release 5.4|Win32
160 {AED7F42F-139A-46BA-80FE-16E062EA1345}.Release 5.4|x86.Build.0 = Release 5.4|Win32 184 {AED7F42F-139A-46BA-80FE-16E062EA1345}.Release 5.4|x86.Build.0 = Release 5.4|Win32
185 {AED7F42F-139A-46BA-80FE-16E062EA1345}.Release 5.5|Prospero.ActiveCfg = Release 5.5|Prospero
186 {AED7F42F-139A-46BA-80FE-16E062EA1345}.Release 5.5|Prospero.Build.0 = Release 5.5|Prospero
187 {AED7F42F-139A-46BA-80FE-16E062EA1345}.Release 5.5|x64.ActiveCfg = Release 5.5|x64
188 {AED7F42F-139A-46BA-80FE-16E062EA1345}.Release 5.5|x64.Build.0 = Release 5.5|x64
189 {AED7F42F-139A-46BA-80FE-16E062EA1345}.Release 5.5|x86.ActiveCfg = Release 5.5|Win32
190 {AED7F42F-139A-46BA-80FE-16E062EA1345}.Release 5.5|x86.Build.0 = Release 5.5|Win32
161 {AED7F42F-139A-46BA-80FE-16E062EA1345}.Release LuaJIT|Prospero.ActiveCfg = Release LuaJIT|Prospero 191 {AED7F42F-139A-46BA-80FE-16E062EA1345}.Release LuaJIT|Prospero.ActiveCfg = Release LuaJIT|Prospero
162 {AED7F42F-139A-46BA-80FE-16E062EA1345}.Release LuaJIT|Prospero.Build.0 = Release LuaJIT|Prospero 192 {AED7F42F-139A-46BA-80FE-16E062EA1345}.Release LuaJIT|Prospero.Build.0 = Release LuaJIT|Prospero
163 {AED7F42F-139A-46BA-80FE-16E062EA1345}.Release LuaJIT|x64.ActiveCfg = Release LuaJIT|x64 193 {AED7F42F-139A-46BA-80FE-16E062EA1345}.Release LuaJIT|x64.ActiveCfg = Release LuaJIT|x64
@@ -194,6 +224,12 @@ Global
194 {4C40BD18-3BAB-46D7-8F14-602A6FBE5910}.Debug 5.4|x64.Build.0 = Debug 5.4|x64 224 {4C40BD18-3BAB-46D7-8F14-602A6FBE5910}.Debug 5.4|x64.Build.0 = Debug 5.4|x64
195 {4C40BD18-3BAB-46D7-8F14-602A6FBE5910}.Debug 5.4|x86.ActiveCfg = Debug 5.4|Win32 225 {4C40BD18-3BAB-46D7-8F14-602A6FBE5910}.Debug 5.4|x86.ActiveCfg = Debug 5.4|Win32
196 {4C40BD18-3BAB-46D7-8F14-602A6FBE5910}.Debug 5.4|x86.Build.0 = Debug 5.4|Win32 226 {4C40BD18-3BAB-46D7-8F14-602A6FBE5910}.Debug 5.4|x86.Build.0 = Debug 5.4|Win32
227 {4C40BD18-3BAB-46D7-8F14-602A6FBE5910}.Debug 5.5|Prospero.ActiveCfg = Debug 5.5|Prospero
228 {4C40BD18-3BAB-46D7-8F14-602A6FBE5910}.Debug 5.5|Prospero.Build.0 = Debug 5.5|Prospero
229 {4C40BD18-3BAB-46D7-8F14-602A6FBE5910}.Debug 5.5|x64.ActiveCfg = Debug 5.5|x64
230 {4C40BD18-3BAB-46D7-8F14-602A6FBE5910}.Debug 5.5|x64.Build.0 = Debug 5.5|x64
231 {4C40BD18-3BAB-46D7-8F14-602A6FBE5910}.Debug 5.5|x86.ActiveCfg = Debug 5.5|Win32
232 {4C40BD18-3BAB-46D7-8F14-602A6FBE5910}.Debug 5.5|x86.Build.0 = Debug 5.5|Win32
197 {4C40BD18-3BAB-46D7-8F14-602A6FBE5910}.Release 5.1|Prospero.ActiveCfg = Release 5.1|Prospero 233 {4C40BD18-3BAB-46D7-8F14-602A6FBE5910}.Release 5.1|Prospero.ActiveCfg = Release 5.1|Prospero
198 {4C40BD18-3BAB-46D7-8F14-602A6FBE5910}.Release 5.1|Prospero.Build.0 = Release 5.1|Prospero 234 {4C40BD18-3BAB-46D7-8F14-602A6FBE5910}.Release 5.1|Prospero.Build.0 = Release 5.1|Prospero
199 {4C40BD18-3BAB-46D7-8F14-602A6FBE5910}.Release 5.1|x64.ActiveCfg = Release 5.1|x64 235 {4C40BD18-3BAB-46D7-8F14-602A6FBE5910}.Release 5.1|x64.ActiveCfg = Release 5.1|x64
@@ -218,6 +254,12 @@ Global
218 {4C40BD18-3BAB-46D7-8F14-602A6FBE5910}.Release 5.4|x64.Build.0 = Release 5.4|x64 254 {4C40BD18-3BAB-46D7-8F14-602A6FBE5910}.Release 5.4|x64.Build.0 = Release 5.4|x64
219 {4C40BD18-3BAB-46D7-8F14-602A6FBE5910}.Release 5.4|x86.ActiveCfg = Release 5.4|Win32 255 {4C40BD18-3BAB-46D7-8F14-602A6FBE5910}.Release 5.4|x86.ActiveCfg = Release 5.4|Win32
220 {4C40BD18-3BAB-46D7-8F14-602A6FBE5910}.Release 5.4|x86.Build.0 = Release 5.4|Win32 256 {4C40BD18-3BAB-46D7-8F14-602A6FBE5910}.Release 5.4|x86.Build.0 = Release 5.4|Win32
257 {4C40BD18-3BAB-46D7-8F14-602A6FBE5910}.Release 5.5|Prospero.ActiveCfg = Release 5.5|Prospero
258 {4C40BD18-3BAB-46D7-8F14-602A6FBE5910}.Release 5.5|Prospero.Build.0 = Release 5.5|Prospero
259 {4C40BD18-3BAB-46D7-8F14-602A6FBE5910}.Release 5.5|x64.ActiveCfg = Release 5.5|x64
260 {4C40BD18-3BAB-46D7-8F14-602A6FBE5910}.Release 5.5|x64.Build.0 = Release 5.5|x64
261 {4C40BD18-3BAB-46D7-8F14-602A6FBE5910}.Release 5.5|x86.ActiveCfg = Release 5.5|Win32
262 {4C40BD18-3BAB-46D7-8F14-602A6FBE5910}.Release 5.5|x86.Build.0 = Release 5.5|Win32
221 {4C40BD18-3BAB-46D7-8F14-602A6FBE5910}.Release LuaJIT|Prospero.ActiveCfg = Release LuaJIT|Prospero 263 {4C40BD18-3BAB-46D7-8F14-602A6FBE5910}.Release LuaJIT|Prospero.ActiveCfg = Release LuaJIT|Prospero
222 {4C40BD18-3BAB-46D7-8F14-602A6FBE5910}.Release LuaJIT|Prospero.Build.0 = Release LuaJIT|Prospero 264 {4C40BD18-3BAB-46D7-8F14-602A6FBE5910}.Release LuaJIT|Prospero.Build.0 = Release LuaJIT|Prospero
223 {4C40BD18-3BAB-46D7-8F14-602A6FBE5910}.Release LuaJIT|x64.ActiveCfg = Release LuaJIT|x64 265 {4C40BD18-3BAB-46D7-8F14-602A6FBE5910}.Release LuaJIT|x64.ActiveCfg = Release LuaJIT|x64
diff --git a/Lanes.vcxproj b/Lanes.vcxproj
index 89a1652..3d49d9e 100644
--- a/Lanes.vcxproj
+++ b/Lanes.vcxproj
@@ -49,6 +49,30 @@
49 <Configuration>Debug 5.4</Configuration> 49 <Configuration>Debug 5.4</Configuration>
50 <Platform>x64</Platform> 50 <Platform>x64</Platform>
51 </ProjectConfiguration> 51 </ProjectConfiguration>
52 <ProjectConfiguration Include="Debug 5.5|Prospero">
53 <Configuration>Debug 5.5</Configuration>
54 <Platform>Prospero</Platform>
55 </ProjectConfiguration>
56 <ProjectConfiguration Include="Debug 5.5|Win32">
57 <Configuration>Debug 5.5</Configuration>
58 <Platform>Win32</Platform>
59 </ProjectConfiguration>
60 <ProjectConfiguration Include="Debug 5.5|x64">
61 <Configuration>Debug 5.5</Configuration>
62 <Platform>x64</Platform>
63 </ProjectConfiguration>
64 <ProjectConfiguration Include="Release 5.5|Prospero">
65 <Configuration>Release 5.5</Configuration>
66 <Platform>Prospero</Platform>
67 </ProjectConfiguration>
68 <ProjectConfiguration Include="Release 5.5|Win32">
69 <Configuration>Release 5.5</Configuration>
70 <Platform>Win32</Platform>
71 </ProjectConfiguration>
72 <ProjectConfiguration Include="Release 5.5|x64">
73 <Configuration>Release 5.5</Configuration>
74 <Platform>x64</Platform>
75 </ProjectConfiguration>
52 <ProjectConfiguration Include="Release LuaJIT|Prospero"> 76 <ProjectConfiguration Include="Release LuaJIT|Prospero">
53 <Configuration>Release LuaJIT</Configuration> 77 <Configuration>Release LuaJIT</Configuration>
54 <Platform>Prospero</Platform> 78 <Platform>Prospero</Platform>
@@ -183,6 +207,12 @@
183 <PlatformToolset>v143</PlatformToolset> 207 <PlatformToolset>v143</PlatformToolset>
184 <UseDebugLibraries>true</UseDebugLibraries> 208 <UseDebugLibraries>true</UseDebugLibraries>
185 </PropertyGroup> 209 </PropertyGroup>
210 <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug 5.5|Win32'" Label="Configuration">
211 <ConfigurationType>DynamicLibrary</ConfigurationType>
212 <CharacterSet>NotSet</CharacterSet>
213 <PlatformToolset>v143</PlatformToolset>
214 <UseDebugLibraries>true</UseDebugLibraries>
215 </PropertyGroup>
186 <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release MoonJIT|Win32'" Label="Configuration"> 216 <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release MoonJIT|Win32'" Label="Configuration">
187 <ConfigurationType>DynamicLibrary</ConfigurationType> 217 <ConfigurationType>DynamicLibrary</ConfigurationType>
188 <CharacterSet>NotSet</CharacterSet> 218 <CharacterSet>NotSet</CharacterSet>
@@ -201,6 +231,12 @@
201 <PlatformToolset>v143</PlatformToolset> 231 <PlatformToolset>v143</PlatformToolset>
202 <WholeProgramOptimization>true</WholeProgramOptimization> 232 <WholeProgramOptimization>true</WholeProgramOptimization>
203 </PropertyGroup> 233 </PropertyGroup>
234 <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release 5.5|Win32'" Label="Configuration">
235 <ConfigurationType>DynamicLibrary</ConfigurationType>
236 <CharacterSet>NotSet</CharacterSet>
237 <PlatformToolset>v143</PlatformToolset>
238 <WholeProgramOptimization>true</WholeProgramOptimization>
239 </PropertyGroup>
204 <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug 5.1|x64'" Label="Configuration"> 240 <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug 5.1|x64'" Label="Configuration">
205 <ConfigurationType>DynamicLibrary</ConfigurationType> 241 <ConfigurationType>DynamicLibrary</ConfigurationType>
206 <CharacterSet>NotSet</CharacterSet> 242 <CharacterSet>NotSet</CharacterSet>
@@ -225,6 +261,12 @@
225 <PlatformToolset>v143</PlatformToolset> 261 <PlatformToolset>v143</PlatformToolset>
226 <UseDebugLibraries>true</UseDebugLibraries> 262 <UseDebugLibraries>true</UseDebugLibraries>
227 </PropertyGroup> 263 </PropertyGroup>
264 <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug 5.5|x64'" Label="Configuration">
265 <ConfigurationType>DynamicLibrary</ConfigurationType>
266 <CharacterSet>NotSet</CharacterSet>
267 <PlatformToolset>v143</PlatformToolset>
268 <UseDebugLibraries>true</UseDebugLibraries>
269 </PropertyGroup>
228 <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release MoonJIT|x64'" Label="Configuration"> 270 <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release MoonJIT|x64'" Label="Configuration">
229 <ConfigurationType>DynamicLibrary</ConfigurationType> 271 <ConfigurationType>DynamicLibrary</ConfigurationType>
230 <CharacterSet>NotSet</CharacterSet> 272 <CharacterSet>NotSet</CharacterSet>
@@ -243,6 +285,12 @@
243 <PlatformToolset>v143</PlatformToolset> 285 <PlatformToolset>v143</PlatformToolset>
244 <WholeProgramOptimization>true</WholeProgramOptimization> 286 <WholeProgramOptimization>true</WholeProgramOptimization>
245 </PropertyGroup> 287 </PropertyGroup>
288 <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release 5.5|x64'" Label="Configuration">
289 <ConfigurationType>DynamicLibrary</ConfigurationType>
290 <CharacterSet>NotSet</CharacterSet>
291 <PlatformToolset>v143</PlatformToolset>
292 <WholeProgramOptimization>true</WholeProgramOptimization>
293 </PropertyGroup>
246 <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug 5.2|Win32'" Label="Configuration"> 294 <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug 5.2|Win32'" Label="Configuration">
247 <ConfigurationType>DynamicLibrary</ConfigurationType> 295 <ConfigurationType>DynamicLibrary</ConfigurationType>
248 <CharacterSet>NotSet</CharacterSet> 296 <CharacterSet>NotSet</CharacterSet>
@@ -275,6 +323,10 @@
275 <PlatformToolset>Clang</PlatformToolset> 323 <PlatformToolset>Clang</PlatformToolset>
276 <ConfigurationType>DynamicLibrary</ConfigurationType> 324 <ConfigurationType>DynamicLibrary</ConfigurationType>
277 </PropertyGroup> 325 </PropertyGroup>
326 <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release 5.5|Prospero'" Label="Configuration">
327 <PlatformToolset>Clang</PlatformToolset>
328 <ConfigurationType>DynamicLibrary</ConfigurationType>
329 </PropertyGroup>
278 <PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Debug 5.3|Prospero'"> 330 <PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Debug 5.3|Prospero'">
279 <PlatformToolset>Clang</PlatformToolset> 331 <PlatformToolset>Clang</PlatformToolset>
280 <ConfigurationType>DynamicLibrary</ConfigurationType> 332 <ConfigurationType>DynamicLibrary</ConfigurationType>
@@ -291,6 +343,10 @@
291 <PlatformToolset>Clang</PlatformToolset> 343 <PlatformToolset>Clang</PlatformToolset>
292 <ConfigurationType>DynamicLibrary</ConfigurationType> 344 <ConfigurationType>DynamicLibrary</ConfigurationType>
293 </PropertyGroup> 345 </PropertyGroup>
346 <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug 5.5|Prospero'" Label="Configuration">
347 <PlatformToolset>Clang</PlatformToolset>
348 <ConfigurationType>DynamicLibrary</ConfigurationType>
349 </PropertyGroup>
294 <PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Release LuaJIT|Prospero'"> 350 <PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Release LuaJIT|Prospero'">
295 <PlatformToolset>Clang</PlatformToolset> 351 <PlatformToolset>Clang</PlatformToolset>
296 <ConfigurationType>DynamicLibrary</ConfigurationType> 352 <ConfigurationType>DynamicLibrary</ConfigurationType>
@@ -322,6 +378,9 @@
322 <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug 5.4|Win32'" Label="PropertySheets"> 378 <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug 5.4|Win32'" Label="PropertySheets">
323 <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" /> 379 <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
324 </ImportGroup> 380 </ImportGroup>
381 <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug 5.5|Win32'" Label="PropertySheets">
382 <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
383 </ImportGroup>
325 <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release MoonJIT|Win32'" Label="PropertySheets"> 384 <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release MoonJIT|Win32'" Label="PropertySheets">
326 <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" /> 385 <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
327 </ImportGroup> 386 </ImportGroup>
@@ -331,6 +390,9 @@
331 <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release 5.4|Win32'" Label="PropertySheets"> 390 <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release 5.4|Win32'" Label="PropertySheets">
332 <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" /> 391 <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
333 </ImportGroup> 392 </ImportGroup>
393 <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release 5.5|Win32'" Label="PropertySheets">
394 <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
395 </ImportGroup>
334 <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug 5.1|x64'" Label="PropertySheets"> 396 <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug 5.1|x64'" Label="PropertySheets">
335 <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" /> 397 <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
336 </ImportGroup> 398 </ImportGroup>
@@ -343,6 +405,9 @@
343 <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug 5.4|x64'" Label="PropertySheets"> 405 <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug 5.4|x64'" Label="PropertySheets">
344 <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" /> 406 <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
345 </ImportGroup> 407 </ImportGroup>
408 <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug 5.5|x64'" Label="PropertySheets">
409 <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
410 </ImportGroup>
346 <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release MoonJIT|x64'" Label="PropertySheets"> 411 <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release MoonJIT|x64'" Label="PropertySheets">
347 <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" /> 412 <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
348 </ImportGroup> 413 </ImportGroup>
@@ -352,6 +417,9 @@
352 <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release 5.4|x64'" Label="PropertySheets"> 417 <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release 5.4|x64'" Label="PropertySheets">
353 <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" /> 418 <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
354 </ImportGroup> 419 </ImportGroup>
420 <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release 5.5|x64'" Label="PropertySheets">
421 <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
422 </ImportGroup>
355 <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug 5.2|Win32'" Label="PropertySheets"> 423 <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug 5.2|Win32'" Label="PropertySheets">
356 <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" /> 424 <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
357 </ImportGroup> 425 </ImportGroup>
@@ -365,37 +433,46 @@
365 <OutDir Condition="'$(Configuration)|$(Platform)'=='Release LuaJIT|Win32'">$(SolutionDir)_Output\$(ProjectName)\$(PlatformName)\$(Configuration)\</OutDir> 433 <OutDir Condition="'$(Configuration)|$(Platform)'=='Release LuaJIT|Win32'">$(SolutionDir)_Output\$(ProjectName)\$(PlatformName)\$(Configuration)\</OutDir>
366 <OutDir Condition="'$(Configuration)|$(Platform)'=='Debug 5.3|Win32'">$(SolutionDir)_Output\$(ProjectName)\$(PlatformName)\$(Configuration)\</OutDir> 434 <OutDir Condition="'$(Configuration)|$(Platform)'=='Debug 5.3|Win32'">$(SolutionDir)_Output\$(ProjectName)\$(PlatformName)\$(Configuration)\</OutDir>
367 <OutDir Condition="'$(Configuration)|$(Platform)'=='Debug 5.4|Win32'">$(SolutionDir)_Output\$(ProjectName)\$(PlatformName)\$(Configuration)\</OutDir> 435 <OutDir Condition="'$(Configuration)|$(Platform)'=='Debug 5.4|Win32'">$(SolutionDir)_Output\$(ProjectName)\$(PlatformName)\$(Configuration)\</OutDir>
436 <OutDir Condition="'$(Configuration)|$(Platform)'=='Debug 5.5|Win32'">$(SolutionDir)_Output\$(ProjectName)\$(PlatformName)\$(Configuration)\</OutDir>
368 <OutDir Condition="'$(Configuration)|$(Platform)'=='Release MoonJIT|Win32'">$(SolutionDir)_Output\$(ProjectName)\$(PlatformName)\$(Configuration)\</OutDir> 437 <OutDir Condition="'$(Configuration)|$(Platform)'=='Release MoonJIT|Win32'">$(SolutionDir)_Output\$(ProjectName)\$(PlatformName)\$(Configuration)\</OutDir>
369 <OutDir Condition="'$(Configuration)|$(Platform)'=='Release 5.3|Win32'">$(SolutionDir)_Output\$(ProjectName)\$(PlatformName)\$(Configuration)\</OutDir> 438 <OutDir Condition="'$(Configuration)|$(Platform)'=='Release 5.3|Win32'">$(SolutionDir)_Output\$(ProjectName)\$(PlatformName)\$(Configuration)\</OutDir>
370 <OutDir Condition="'$(Configuration)|$(Platform)'=='Release 5.4|Win32'">$(SolutionDir)_Output\$(ProjectName)\$(PlatformName)\$(Configuration)\</OutDir> 439 <OutDir Condition="'$(Configuration)|$(Platform)'=='Release 5.4|Win32'">$(SolutionDir)_Output\$(ProjectName)\$(PlatformName)\$(Configuration)\</OutDir>
440 <OutDir Condition="'$(Configuration)|$(Platform)'=='Release 5.5|Win32'">$(SolutionDir)_Output\$(ProjectName)\$(PlatformName)\$(Configuration)\</OutDir>
371 <OutDir Condition="'$(Configuration)|$(Platform)'=='Debug 5.2|Win32'">$(SolutionDir)_Output\$(ProjectName)\$(PlatformName)\$(Configuration)\</OutDir> 441 <OutDir Condition="'$(Configuration)|$(Platform)'=='Debug 5.2|Win32'">$(SolutionDir)_Output\$(ProjectName)\$(PlatformName)\$(Configuration)\</OutDir>
372 <IntDir Condition="'$(Configuration)|$(Platform)'=='Debug 5.1|Win32'">$(SolutionDir)_Tmp\$(ProjectName)\$(PlatformName)\$(Configuration)\</IntDir> 442 <IntDir Condition="'$(Configuration)|$(Platform)'=='Debug 5.1|Win32'">$(SolutionDir)_Tmp\$(ProjectName)\$(PlatformName)\$(Configuration)\</IntDir>
373 <IntDir Condition="'$(Configuration)|$(Platform)'=='Release LuaJIT|Win32'">$(SolutionDir)_Tmp\$(ProjectName)\$(PlatformName)\$(Configuration)\</IntDir> 443 <IntDir Condition="'$(Configuration)|$(Platform)'=='Release LuaJIT|Win32'">$(SolutionDir)_Tmp\$(ProjectName)\$(PlatformName)\$(Configuration)\</IntDir>
374 <IntDir Condition="'$(Configuration)|$(Platform)'=='Debug 5.3|Win32'">$(SolutionDir)_Tmp\$(ProjectName)\$(PlatformName)\$(Configuration)\</IntDir> 444 <IntDir Condition="'$(Configuration)|$(Platform)'=='Debug 5.3|Win32'">$(SolutionDir)_Tmp\$(ProjectName)\$(PlatformName)\$(Configuration)\</IntDir>
375 <IntDir Condition="'$(Configuration)|$(Platform)'=='Debug 5.4|Win32'">$(SolutionDir)_Tmp\$(ProjectName)\$(PlatformName)\$(Configuration)\</IntDir> 445 <IntDir Condition="'$(Configuration)|$(Platform)'=='Debug 5.4|Win32'">$(SolutionDir)_Tmp\$(ProjectName)\$(PlatformName)\$(Configuration)\</IntDir>
446 <IntDir Condition="'$(Configuration)|$(Platform)'=='Debug 5.5|Win32'">$(SolutionDir)_Tmp\$(ProjectName)\$(PlatformName)\$(Configuration)\</IntDir>
376 <IntDir Condition="'$(Configuration)|$(Platform)'=='Release MoonJIT|Win32'">$(SolutionDir)_Tmp\$(ProjectName)\$(PlatformName)\$(Configuration)\</IntDir> 447 <IntDir Condition="'$(Configuration)|$(Platform)'=='Release MoonJIT|Win32'">$(SolutionDir)_Tmp\$(ProjectName)\$(PlatformName)\$(Configuration)\</IntDir>
377 <IntDir Condition="'$(Configuration)|$(Platform)'=='Release 5.3|Win32'">$(SolutionDir)_Tmp\$(ProjectName)\$(PlatformName)\$(Configuration)\</IntDir> 448 <IntDir Condition="'$(Configuration)|$(Platform)'=='Release 5.3|Win32'">$(SolutionDir)_Tmp\$(ProjectName)\$(PlatformName)\$(Configuration)\</IntDir>
378 <IntDir Condition="'$(Configuration)|$(Platform)'=='Release 5.4|Win32'">$(SolutionDir)_Tmp\$(ProjectName)\$(PlatformName)\$(Configuration)\</IntDir> 449 <IntDir Condition="'$(Configuration)|$(Platform)'=='Release 5.4|Win32'">$(SolutionDir)_Tmp\$(ProjectName)\$(PlatformName)\$(Configuration)\</IntDir>
450 <IntDir Condition="'$(Configuration)|$(Platform)'=='Release 5.5|Win32'">$(SolutionDir)_Tmp\$(ProjectName)\$(PlatformName)\$(Configuration)\</IntDir>
379 <IntDir Condition="'$(Configuration)|$(Platform)'=='Debug 5.1|x64'">$(SolutionDir)_Tmp\$(ProjectName)\$(PlatformName)\$(Configuration)\</IntDir> 451 <IntDir Condition="'$(Configuration)|$(Platform)'=='Debug 5.1|x64'">$(SolutionDir)_Tmp\$(ProjectName)\$(PlatformName)\$(Configuration)\</IntDir>
380 <IntDir Condition="'$(Configuration)|$(Platform)'=='Release LuaJIT|x64'">$(SolutionDir)_Tmp\$(ProjectName)\$(PlatformName)\$(Configuration)\</IntDir> 452 <IntDir Condition="'$(Configuration)|$(Platform)'=='Release LuaJIT|x64'">$(SolutionDir)_Tmp\$(ProjectName)\$(PlatformName)\$(Configuration)\</IntDir>
381 <IntDir Condition="'$(Configuration)|$(Platform)'=='Debug 5.3|x64'">$(SolutionDir)_Tmp\$(ProjectName)\$(PlatformName)\$(Configuration)\</IntDir> 453 <IntDir Condition="'$(Configuration)|$(Platform)'=='Debug 5.3|x64'">$(SolutionDir)_Tmp\$(ProjectName)\$(PlatformName)\$(Configuration)\</IntDir>
382 <IntDir Condition="'$(Configuration)|$(Platform)'=='Debug 5.4|x64'">$(SolutionDir)_Tmp\$(ProjectName)\$(PlatformName)\$(Configuration)\</IntDir> 454 <IntDir Condition="'$(Configuration)|$(Platform)'=='Debug 5.4|x64'">$(SolutionDir)_Tmp\$(ProjectName)\$(PlatformName)\$(Configuration)\</IntDir>
455 <IntDir Condition="'$(Configuration)|$(Platform)'=='Debug 5.5|x64'">$(SolutionDir)_Tmp\$(ProjectName)\$(PlatformName)\$(Configuration)\</IntDir>
383 <IntDir Condition="'$(Configuration)|$(Platform)'=='Release MoonJIT|x64'">$(SolutionDir)_Tmp\$(ProjectName)\$(PlatformName)\$(Configuration)\</IntDir> 456 <IntDir Condition="'$(Configuration)|$(Platform)'=='Release MoonJIT|x64'">$(SolutionDir)_Tmp\$(ProjectName)\$(PlatformName)\$(Configuration)\</IntDir>
384 <IntDir Condition="'$(Configuration)|$(Platform)'=='Release 5.3|x64'">$(SolutionDir)_Tmp\$(ProjectName)\$(PlatformName)\$(Configuration)\</IntDir> 457 <IntDir Condition="'$(Configuration)|$(Platform)'=='Release 5.3|x64'">$(SolutionDir)_Tmp\$(ProjectName)\$(PlatformName)\$(Configuration)\</IntDir>
385 <IntDir Condition="'$(Configuration)|$(Platform)'=='Release 5.4|x64'">$(SolutionDir)_Tmp\$(ProjectName)\$(PlatformName)\$(Configuration)\</IntDir> 458 <IntDir Condition="'$(Configuration)|$(Platform)'=='Release 5.4|x64'">$(SolutionDir)_Tmp\$(ProjectName)\$(PlatformName)\$(Configuration)\</IntDir>
459 <IntDir Condition="'$(Configuration)|$(Platform)'=='Release 5.5|x64'">$(SolutionDir)_Tmp\$(ProjectName)\$(PlatformName)\$(Configuration)\</IntDir>
386 <IntDir Condition="'$(Configuration)|$(Platform)'=='Debug 5.2|Win32'">$(SolutionDir)_Tmp\$(ProjectName)\$(PlatformName)\$(Configuration)\</IntDir> 460 <IntDir Condition="'$(Configuration)|$(Platform)'=='Debug 5.2|Win32'">$(SolutionDir)_Tmp\$(ProjectName)\$(PlatformName)\$(Configuration)\</IntDir>
387 <IntDir Condition="'$(Configuration)|$(Platform)'=='Debug 5.2|x64'">$(SolutionDir)_Tmp\$(ProjectName)\$(PlatformName)\$(Configuration)\</IntDir> 461 <IntDir Condition="'$(Configuration)|$(Platform)'=='Debug 5.2|x64'">$(SolutionDir)_Tmp\$(ProjectName)\$(PlatformName)\$(Configuration)\</IntDir>
388 <LinkIncremental Condition="'$(Configuration)|$(Platform)'=='Debug 5.1|Win32'">false</LinkIncremental> 462 <LinkIncremental Condition="'$(Configuration)|$(Platform)'=='Debug 5.1|Win32'">false</LinkIncremental>
389 <LinkIncremental Condition="'$(Configuration)|$(Platform)'=='Release LuaJIT|Win32'">false</LinkIncremental> 463 <LinkIncremental Condition="'$(Configuration)|$(Platform)'=='Release LuaJIT|Win32'">false</LinkIncremental>
390 <LinkIncremental Condition="'$(Configuration)|$(Platform)'=='Release 5.3|Win32'">false</LinkIncremental> 464 <LinkIncremental Condition="'$(Configuration)|$(Platform)'=='Release 5.3|Win32'">false</LinkIncremental>
391 <LinkIncremental Condition="'$(Configuration)|$(Platform)'=='Release 5.4|Win32'">false</LinkIncremental> 465 <LinkIncremental Condition="'$(Configuration)|$(Platform)'=='Release 5.4|Win32'">false</LinkIncremental>
466 <LinkIncremental Condition="'$(Configuration)|$(Platform)'=='Release 5.5|Win32'">false</LinkIncremental>
392 <LinkIncremental Condition="'$(Configuration)|$(Platform)'=='Debug 5.1|x64'">false</LinkIncremental> 467 <LinkIncremental Condition="'$(Configuration)|$(Platform)'=='Debug 5.1|x64'">false</LinkIncremental>
393 <LinkIncremental Condition="'$(Configuration)|$(Platform)'=='Release LuaJIT|x64'">false</LinkIncremental> 468 <LinkIncremental Condition="'$(Configuration)|$(Platform)'=='Release LuaJIT|x64'">false</LinkIncremental>
394 <LinkIncremental Condition="'$(Configuration)|$(Platform)'=='Debug 5.3|x64'">false</LinkIncremental> 469 <LinkIncremental Condition="'$(Configuration)|$(Platform)'=='Debug 5.3|x64'">false</LinkIncremental>
395 <LinkIncremental Condition="'$(Configuration)|$(Platform)'=='Debug 5.4|x64'">false</LinkIncremental> 470 <LinkIncremental Condition="'$(Configuration)|$(Platform)'=='Debug 5.4|x64'">false</LinkIncremental>
471 <LinkIncremental Condition="'$(Configuration)|$(Platform)'=='Debug 5.5|x64'">false</LinkIncremental>
396 <LinkIncremental Condition="'$(Configuration)|$(Platform)'=='Release MoonJIT|x64'">false</LinkIncremental> 472 <LinkIncremental Condition="'$(Configuration)|$(Platform)'=='Release MoonJIT|x64'">false</LinkIncremental>
397 <LinkIncremental Condition="'$(Configuration)|$(Platform)'=='Release 5.3|x64'">false</LinkIncremental> 473 <LinkIncremental Condition="'$(Configuration)|$(Platform)'=='Release 5.3|x64'">false</LinkIncremental>
398 <LinkIncremental Condition="'$(Configuration)|$(Platform)'=='Release 5.4|x64'">false</LinkIncremental> 474 <LinkIncremental Condition="'$(Configuration)|$(Platform)'=='Release 5.4|x64'">false</LinkIncremental>
475 <LinkIncremental Condition="'$(Configuration)|$(Platform)'=='Release 5.5|x64'">false</LinkIncremental>
399 <LinkIncremental Condition="'$(Configuration)|$(Platform)'=='Debug 5.2|x64'">false</LinkIncremental> 476 <LinkIncremental Condition="'$(Configuration)|$(Platform)'=='Debug 5.2|x64'">false</LinkIncremental>
400 <OutDir Condition="'$(Configuration)|$(Platform)'=='Release 5.1|Win32'">$(SolutionDir)_Output\$(ProjectName)\$(PlatformName)\$(Configuration)\</OutDir> 477 <OutDir Condition="'$(Configuration)|$(Platform)'=='Release 5.1|Win32'">$(SolutionDir)_Output\$(ProjectName)\$(PlatformName)\$(Configuration)\</OutDir>
401 <OutDir Condition="'$(Configuration)|$(Platform)'=='Release 5.2|Win32'">$(SolutionDir)_Output\$(ProjectName)\$(PlatformName)\$(Configuration)\</OutDir> 478 <OutDir Condition="'$(Configuration)|$(Platform)'=='Release 5.2|Win32'">$(SolutionDir)_Output\$(ProjectName)\$(PlatformName)\$(Configuration)\</OutDir>
@@ -410,16 +487,20 @@
410 <TargetName Condition="'$(Configuration)|$(Platform)'=='Release LuaJIT|Win32'">lanes_core</TargetName> 487 <TargetName Condition="'$(Configuration)|$(Platform)'=='Release LuaJIT|Win32'">lanes_core</TargetName>
411 <TargetName Condition="'$(Configuration)|$(Platform)'=='Debug 5.3|Win32'">lanes_core</TargetName> 488 <TargetName Condition="'$(Configuration)|$(Platform)'=='Debug 5.3|Win32'">lanes_core</TargetName>
412 <TargetName Condition="'$(Configuration)|$(Platform)'=='Debug 5.4|Win32'">lanes_core</TargetName> 489 <TargetName Condition="'$(Configuration)|$(Platform)'=='Debug 5.4|Win32'">lanes_core</TargetName>
490 <TargetName Condition="'$(Configuration)|$(Platform)'=='Debug 5.5|Win32'">lanes_core</TargetName>
413 <TargetName Condition="'$(Configuration)|$(Platform)'=='Release MoonJIT|Win32'">lanes_core</TargetName> 491 <TargetName Condition="'$(Configuration)|$(Platform)'=='Release MoonJIT|Win32'">lanes_core</TargetName>
414 <TargetName Condition="'$(Configuration)|$(Platform)'=='Release 5.3|Win32'">lanes_core</TargetName> 492 <TargetName Condition="'$(Configuration)|$(Platform)'=='Release 5.3|Win32'">lanes_core</TargetName>
415 <TargetName Condition="'$(Configuration)|$(Platform)'=='Release 5.4|Win32'">lanes_core</TargetName> 493 <TargetName Condition="'$(Configuration)|$(Platform)'=='Release 5.4|Win32'">lanes_core</TargetName>
494 <TargetName Condition="'$(Configuration)|$(Platform)'=='Release 5.5|Win32'">lanes_core</TargetName>
416 <TargetName Condition="'$(Configuration)|$(Platform)'=='Debug 5.1|x64'">lanes_core</TargetName> 495 <TargetName Condition="'$(Configuration)|$(Platform)'=='Debug 5.1|x64'">lanes_core</TargetName>
417 <TargetName Condition="'$(Configuration)|$(Platform)'=='Release LuaJIT|x64'">lanes_core</TargetName> 496 <TargetName Condition="'$(Configuration)|$(Platform)'=='Release LuaJIT|x64'">lanes_core</TargetName>
418 <TargetName Condition="'$(Configuration)|$(Platform)'=='Debug 5.3|x64'">lanes_core</TargetName> 497 <TargetName Condition="'$(Configuration)|$(Platform)'=='Debug 5.3|x64'">lanes_core</TargetName>
419 <TargetName Condition="'$(Configuration)|$(Platform)'=='Debug 5.4|x64'">lanes_core</TargetName> 498 <TargetName Condition="'$(Configuration)|$(Platform)'=='Debug 5.4|x64'">lanes_core</TargetName>
499 <TargetName Condition="'$(Configuration)|$(Platform)'=='Debug 5.5|x64'">lanes_core</TargetName>
420 <TargetName Condition="'$(Configuration)|$(Platform)'=='Release MoonJIT|x64'">lanes_core</TargetName> 500 <TargetName Condition="'$(Configuration)|$(Platform)'=='Release MoonJIT|x64'">lanes_core</TargetName>
421 <TargetName Condition="'$(Configuration)|$(Platform)'=='Release 5.3|x64'">lanes_core</TargetName> 501 <TargetName Condition="'$(Configuration)|$(Platform)'=='Release 5.3|x64'">lanes_core</TargetName>
422 <TargetName Condition="'$(Configuration)|$(Platform)'=='Release 5.4|x64'">lanes_core</TargetName> 502 <TargetName Condition="'$(Configuration)|$(Platform)'=='Release 5.4|x64'">lanes_core</TargetName>
503 <TargetName Condition="'$(Configuration)|$(Platform)'=='Release 5.5|x64'">lanes_core</TargetName>
423 <TargetName Condition="'$(Configuration)|$(Platform)'=='Debug 5.2|Win32'">lanes_core</TargetName> 504 <TargetName Condition="'$(Configuration)|$(Platform)'=='Debug 5.2|Win32'">lanes_core</TargetName>
424 <TargetName Condition="'$(Configuration)|$(Platform)'=='Debug 5.2|x64'">lanes_core</TargetName> 505 <TargetName Condition="'$(Configuration)|$(Platform)'=='Debug 5.2|x64'">lanes_core</TargetName>
425 <TargetName Condition="'$(Configuration)|$(Platform)'=='Release 5.1|Win32'">lanes_core</TargetName> 506 <TargetName Condition="'$(Configuration)|$(Platform)'=='Release 5.1|Win32'">lanes_core</TargetName>
@@ -447,6 +528,10 @@
447 <OutDir>$(SolutionDir)_Output\$(ProjectName)\$(PlatformName)\$(Configuration)\</OutDir> 528 <OutDir>$(SolutionDir)_Output\$(ProjectName)\$(PlatformName)\$(Configuration)\</OutDir>
448 <EnableClangTidyCodeAnalysis>true</EnableClangTidyCodeAnalysis> 529 <EnableClangTidyCodeAnalysis>true</EnableClangTidyCodeAnalysis>
449 </PropertyGroup> 530 </PropertyGroup>
531 <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug 5.5|x64'">
532 <OutDir>$(SolutionDir)_Output\$(ProjectName)\$(PlatformName)\$(Configuration)\</OutDir>
533 <EnableClangTidyCodeAnalysis>true</EnableClangTidyCodeAnalysis>
534 </PropertyGroup>
450 <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release MoonJIT|x64'"> 535 <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release MoonJIT|x64'">
451 <OutDir>$(SolutionDir)_Output\$(ProjectName)\$(PlatformName)\$(Configuration)\</OutDir> 536 <OutDir>$(SolutionDir)_Output\$(ProjectName)\$(PlatformName)\$(Configuration)\</OutDir>
452 <EnableClangTidyCodeAnalysis>true</EnableClangTidyCodeAnalysis> 537 <EnableClangTidyCodeAnalysis>true</EnableClangTidyCodeAnalysis>
@@ -459,6 +544,10 @@
459 <OutDir>$(SolutionDir)_Output\$(ProjectName)\$(PlatformName)\$(Configuration)\</OutDir> 544 <OutDir>$(SolutionDir)_Output\$(ProjectName)\$(PlatformName)\$(Configuration)\</OutDir>
460 <EnableClangTidyCodeAnalysis>true</EnableClangTidyCodeAnalysis> 545 <EnableClangTidyCodeAnalysis>true</EnableClangTidyCodeAnalysis>
461 </PropertyGroup> 546 </PropertyGroup>
547 <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release 5.5|x64'">
548 <OutDir>$(SolutionDir)_Output\$(ProjectName)\$(PlatformName)\$(Configuration)\</OutDir>
549 <EnableClangTidyCodeAnalysis>true</EnableClangTidyCodeAnalysis>
550 </PropertyGroup>
462 <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug 5.1|x64'"> 551 <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug 5.1|x64'">
463 <OutDir>$(SolutionDir)_Output\$(ProjectName)\$(PlatformName)\$(Configuration)\</OutDir> 552 <OutDir>$(SolutionDir)_Output\$(ProjectName)\$(PlatformName)\$(Configuration)\</OutDir>
464 <EnableClangTidyCodeAnalysis>true</EnableClangTidyCodeAnalysis> 553 <EnableClangTidyCodeAnalysis>true</EnableClangTidyCodeAnalysis>
@@ -479,6 +568,10 @@
479 <LinkIncremental>false</LinkIncremental> 568 <LinkIncremental>false</LinkIncremental>
480 <EnableClangTidyCodeAnalysis>true</EnableClangTidyCodeAnalysis> 569 <EnableClangTidyCodeAnalysis>true</EnableClangTidyCodeAnalysis>
481 </PropertyGroup> 570 </PropertyGroup>
571 <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug 5.5|Win32'">
572 <LinkIncremental>false</LinkIncremental>
573 <EnableClangTidyCodeAnalysis>true</EnableClangTidyCodeAnalysis>
574 </PropertyGroup>
482 <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release MoonJIT|Win32'"> 575 <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release MoonJIT|Win32'">
483 <LinkIncremental>false</LinkIncremental> 576 <LinkIncremental>false</LinkIncremental>
484 <EnableClangTidyCodeAnalysis>true</EnableClangTidyCodeAnalysis> 577 <EnableClangTidyCodeAnalysis>true</EnableClangTidyCodeAnalysis>
@@ -502,6 +595,9 @@
502 <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release 5.4|Win32'"> 595 <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release 5.4|Win32'">
503 <EnableClangTidyCodeAnalysis>true</EnableClangTidyCodeAnalysis> 596 <EnableClangTidyCodeAnalysis>true</EnableClangTidyCodeAnalysis>
504 </PropertyGroup> 597 </PropertyGroup>
598 <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release 5.5|Win32'">
599 <EnableClangTidyCodeAnalysis>true</EnableClangTidyCodeAnalysis>
600 </PropertyGroup>
505 <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug 5.1|Prospero'"> 601 <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug 5.1|Prospero'">
506 <OutDir>$(SolutionDir)_Output\$(ProjectName)\$(PlatformName)\$(Configuration)\</OutDir> 602 <OutDir>$(SolutionDir)_Output\$(ProjectName)\$(PlatformName)\$(Configuration)\</OutDir>
507 <IntDir>$(SolutionDir)_Tmp\$(ProjectName)\$(PlatformName)\$(Configuration)\</IntDir> 603 <IntDir>$(SolutionDir)_Tmp\$(ProjectName)\$(PlatformName)\$(Configuration)\</IntDir>
@@ -522,6 +618,11 @@
522 <IntDir>$(SolutionDir)_Tmp\$(ProjectName)\$(PlatformName)\$(Configuration)\</IntDir> 618 <IntDir>$(SolutionDir)_Tmp\$(ProjectName)\$(PlatformName)\$(Configuration)\</IntDir>
523 <TargetName>lanes_core</TargetName> 619 <TargetName>lanes_core</TargetName>
524 </PropertyGroup> 620 </PropertyGroup>
621 <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug 5.5|Prospero'">
622 <OutDir>$(SolutionDir)_Output\$(ProjectName)\$(PlatformName)\$(Configuration)\</OutDir>
623 <IntDir>$(SolutionDir)_Tmp\$(ProjectName)\$(PlatformName)\$(Configuration)\</IntDir>
624 <TargetName>lanes_core</TargetName>
625 </PropertyGroup>
525 <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release LuaJIT|Prospero'"> 626 <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release LuaJIT|Prospero'">
526 <OutDir>$(SolutionDir)_Output\$(ProjectName)\$(PlatformName)\$(Configuration)\</OutDir> 627 <OutDir>$(SolutionDir)_Output\$(ProjectName)\$(PlatformName)\$(Configuration)\</OutDir>
527 <IntDir>$(SolutionDir)_Tmp\$(ProjectName)\$(PlatformName)\$(Configuration)\</IntDir> 628 <IntDir>$(SolutionDir)_Tmp\$(ProjectName)\$(PlatformName)\$(Configuration)\</IntDir>
@@ -552,6 +653,11 @@
552 <IntDir>$(SolutionDir)_Tmp\$(ProjectName)\$(PlatformName)\$(Configuration)\</IntDir> 653 <IntDir>$(SolutionDir)_Tmp\$(ProjectName)\$(PlatformName)\$(Configuration)\</IntDir>
553 <TargetName>lanes_core</TargetName> 654 <TargetName>lanes_core</TargetName>
554 </PropertyGroup> 655 </PropertyGroup>
656 <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release 5.5|Prospero'">
657 <OutDir>$(SolutionDir)_Output\$(ProjectName)\$(PlatformName)\$(Configuration)\</OutDir>
658 <IntDir>$(SolutionDir)_Tmp\$(ProjectName)\$(PlatformName)\$(Configuration)\</IntDir>
659 <TargetName>lanes_core</TargetName>
660 </PropertyGroup>
555 <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug 5.1|Win32'"> 661 <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug 5.1|Win32'">
556 <PreBuildEvent> 662 <PreBuildEvent>
557 <Command> 663 <Command>
@@ -560,7 +666,7 @@
560 <ClCompile> 666 <ClCompile>
561 <Optimization>Disabled</Optimization> 667 <Optimization>Disabled</Optimization>
562 <AdditionalIncludeDirectories>$(SolutionDir)/_LuaVersions/$(PlatformName)/$(ConfigurationName)/include</AdditionalIncludeDirectories> 668 <AdditionalIncludeDirectories>$(SolutionDir)/_LuaVersions/$(PlatformName)/$(ConfigurationName)/include</AdditionalIncludeDirectories>
563 <PreprocessorDefinitions>WIN32;_DEBUG;_WINDOWS;_USRDLL;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions> 669 <PreprocessorDefinitions>LANES_DEBUG;WIN32;_DEBUG;_WINDOWS;_USRDLL;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
564 <MinimalRebuild>false</MinimalRebuild> 670 <MinimalRebuild>false</MinimalRebuild>
565 <BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks> 671 <BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>
566 <PrecompiledHeader>Use</PrecompiledHeader> 672 <PrecompiledHeader>Use</PrecompiledHeader>
@@ -598,7 +704,7 @@ xcopy /F /I /R /Y "$(OutputPath)$(TargetName).pdb" "$(SolutionDir)_LuaVersions/$
598 <ClCompile> 704 <ClCompile>
599 <Optimization>MaxSpeed</Optimization> 705 <Optimization>MaxSpeed</Optimization>
600 <AdditionalIncludeDirectories>$(SolutionDir)/_LuaVersions/$(PlatformName)/$(ConfigurationName)/include</AdditionalIncludeDirectories> 706 <AdditionalIncludeDirectories>$(SolutionDir)/_LuaVersions/$(PlatformName)/$(ConfigurationName)/include</AdditionalIncludeDirectories>
601 <PreprocessorDefinitions>WIN32;NDEBUG;_WINDOWS;_USRDLL;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions> 707 <PreprocessorDefinitions>LANES_DEBUG;WIN32;NDEBUG;_WINDOWS;_USRDLL;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
602 <MinimalRebuild>false</MinimalRebuild> 708 <MinimalRebuild>false</MinimalRebuild>
603 <BasicRuntimeChecks> 709 <BasicRuntimeChecks>
604 </BasicRuntimeChecks> 710 </BasicRuntimeChecks>
@@ -639,7 +745,7 @@ xcopy /F /I /R /Y "$(OutputPath)$(TargetName).pdb" "$(SolutionDir)_LuaVersions/$
639 <ClCompile> 745 <ClCompile>
640 <Optimization>Disabled</Optimization> 746 <Optimization>Disabled</Optimization>
641 <AdditionalIncludeDirectories>$(SolutionDir)/_LuaVersions/$(PlatformName)/$(ConfigurationName)/include</AdditionalIncludeDirectories> 747 <AdditionalIncludeDirectories>$(SolutionDir)/_LuaVersions/$(PlatformName)/$(ConfigurationName)/include</AdditionalIncludeDirectories>
642 <PreprocessorDefinitions>WIN32;_DEBUG;_WINDOWS;_USRDLL;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions> 748 <PreprocessorDefinitions>LANES_DEBUG;WIN32;_DEBUG;_WINDOWS;_USRDLL;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
643 <MinimalRebuild>false</MinimalRebuild> 749 <MinimalRebuild>false</MinimalRebuild>
644 <BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks> 750 <BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>
645 <PrecompiledHeader>Use</PrecompiledHeader> 751 <PrecompiledHeader>Use</PrecompiledHeader>
@@ -677,7 +783,45 @@ xcopy /F /I /R /Y "$(OutputPath)$(TargetName).pdb" "$(SolutionDir)_LuaVersions/$
677 <ClCompile> 783 <ClCompile>
678 <Optimization>Disabled</Optimization> 784 <Optimization>Disabled</Optimization>
679 <AdditionalIncludeDirectories>$(SolutionDir)/_LuaVersions/$(PlatformName)/$(ConfigurationName)/include</AdditionalIncludeDirectories> 785 <AdditionalIncludeDirectories>$(SolutionDir)/_LuaVersions/$(PlatformName)/$(ConfigurationName)/include</AdditionalIncludeDirectories>
680 <PreprocessorDefinitions>WIN32;_DEBUG;_WINDOWS;_USRDLL;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions> 786 <PreprocessorDefinitions>LANES_DEBUG;WIN32;_DEBUG;_WINDOWS;_USRDLL;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
787 <MinimalRebuild>false</MinimalRebuild>
788 <BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>
789 <PrecompiledHeader>Use</PrecompiledHeader>
790 <ProgramDataBaseFileName>$(IntDir)$(TargetName).pdb</ProgramDataBaseFileName>
791 <WarningLevel>Level4</WarningLevel>
792 <DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
793 <LanguageStandard>stdcpp20</LanguageStandard>
794 <PrecompiledHeaderFile>_pch.hpp</PrecompiledHeaderFile>
795 </ClCompile>
796 <Link>
797 <AdditionalDependencies>lua54.lib;%(AdditionalDependencies)</AdditionalDependencies>
798 <OutputFile>$(OutDir)$(TargetName).dll</OutputFile>
799 <AdditionalLibraryDirectories>$(SolutionDir)_LuaVersions\$(PlatformName)\$(ConfigurationName)</AdditionalLibraryDirectories>
800 <GenerateDebugInformation>true</GenerateDebugInformation>
801 <SubSystem>Windows</SubSystem>
802 <RandomizedBaseAddress>false</RandomizedBaseAddress>
803 <DataExecutionPrevention>
804 </DataExecutionPrevention>
805 <TargetMachine>MachineX86</TargetMachine>
806 <ImportLibrary>$(IntDir)$(TargetName).lib</ImportLibrary>
807 </Link>
808 <PostBuildEvent>
809 <Command>xcopy /F /I /R /Y "$(TargetPath)" "$(SolutionDir)_LuaVersions/$(PlatformName)/$(ConfigurationName)"
810xcopy /F /I /R /Y "$(OutputPath)$(TargetName).pdb" "$(SolutionDir)_LuaVersions/$(PlatformName)/$(ConfigurationName)"
811</Command>
812 <Message>
813 </Message>
814 </PostBuildEvent>
815 </ItemDefinitionGroup>
816 <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug 5.5|Win32'">
817 <PreBuildEvent>
818 <Command>
819 </Command>
820 </PreBuildEvent>
821 <ClCompile>
822 <Optimization>Disabled</Optimization>
823 <AdditionalIncludeDirectories>$(SolutionDir)/_LuaVersions/$(PlatformName)/$(ConfigurationName)/include</AdditionalIncludeDirectories>
824 <PreprocessorDefinitions>LANES_DEBUG;WIN32;_DEBUG;_WINDOWS;_USRDLL;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
681 <MinimalRebuild>false</MinimalRebuild> 825 <MinimalRebuild>false</MinimalRebuild>
682 <BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks> 826 <BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>
683 <PrecompiledHeader>Use</PrecompiledHeader> 827 <PrecompiledHeader>Use</PrecompiledHeader>
@@ -715,7 +859,7 @@ xcopy /F /I /R /Y "$(OutputPath)$(TargetName).pdb" "$(SolutionDir)_LuaVersions/$
715 <ClCompile> 859 <ClCompile>
716 <Optimization>Disabled</Optimization> 860 <Optimization>Disabled</Optimization>
717 <AdditionalIncludeDirectories>$(SolutionDir)/_LuaVersions/$(PlatformName)/$(ConfigurationName)/include</AdditionalIncludeDirectories> 861 <AdditionalIncludeDirectories>$(SolutionDir)/_LuaVersions/$(PlatformName)/$(ConfigurationName)/include</AdditionalIncludeDirectories>
718 <PreprocessorDefinitions>WIN32;NDEBUG;_WINDOWS;_USRDLL;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions> 862 <PreprocessorDefinitions>LANES_DEBUG;WIN32;NDEBUG;_WINDOWS;_USRDLL;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
719 <MinimalRebuild>false</MinimalRebuild> 863 <MinimalRebuild>false</MinimalRebuild>
720 <BasicRuntimeChecks> 864 <BasicRuntimeChecks>
721 </BasicRuntimeChecks> 865 </BasicRuntimeChecks>
@@ -754,7 +898,7 @@ xcopy /F /I /R /Y "$(OutputPath)$(TargetName).pdb" "$(SolutionDir)_LuaVersions/$
754 </PreBuildEvent> 898 </PreBuildEvent>
755 <ClCompile> 899 <ClCompile>
756 <AdditionalIncludeDirectories>$(SolutionDir)/_LuaVersions/$(PlatformName)/$(ConfigurationName)/include</AdditionalIncludeDirectories> 900 <AdditionalIncludeDirectories>$(SolutionDir)/_LuaVersions/$(PlatformName)/$(ConfigurationName)/include</AdditionalIncludeDirectories>
757 <PreprocessorDefinitions>WIN32;_DEBUG;_WINDOWS;_USRDLL;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions> 901 <PreprocessorDefinitions>LANES_DEBUG;WIN32;NDEBUG;_WINDOWS;_USRDLL;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
758 <MinimalRebuild>false</MinimalRebuild> 902 <MinimalRebuild>false</MinimalRebuild>
759 <PrecompiledHeader>Use</PrecompiledHeader> 903 <PrecompiledHeader>Use</PrecompiledHeader>
760 <ProgramDataBaseFileName>$(IntDir)$(TargetName).pdb</ProgramDataBaseFileName> 904 <ProgramDataBaseFileName>$(IntDir)$(TargetName).pdb</ProgramDataBaseFileName>
@@ -797,7 +941,7 @@ xcopy /F /I /R /Y "$(OutputPath)$(TargetName).pdb" "$(SolutionDir)_LuaVersions/$
797 </PreBuildEvent> 941 </PreBuildEvent>
798 <ClCompile> 942 <ClCompile>
799 <AdditionalIncludeDirectories>$(SolutionDir)/_LuaVersions/$(PlatformName)/$(ConfigurationName)/include</AdditionalIncludeDirectories> 943 <AdditionalIncludeDirectories>$(SolutionDir)/_LuaVersions/$(PlatformName)/$(ConfigurationName)/include</AdditionalIncludeDirectories>
800 <PreprocessorDefinitions>WIN32;_DEBUG;_WINDOWS;_USRDLL;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions> 944 <PreprocessorDefinitions>LANES_DEBUG;WIN32;NDEBUG;_WINDOWS;_USRDLL;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
801 <PrecompiledHeader>Use</PrecompiledHeader> 945 <PrecompiledHeader>Use</PrecompiledHeader>
802 <ProgramDataBaseFileName>$(IntDir)$(TargetName).pdb</ProgramDataBaseFileName> 946 <ProgramDataBaseFileName>$(IntDir)$(TargetName).pdb</ProgramDataBaseFileName>
803 <WarningLevel>Level4</WarningLevel> 947 <WarningLevel>Level4</WarningLevel>
@@ -832,6 +976,49 @@ xcopy /F /I /R /Y "$(OutputPath)$(TargetName).pdb" "$(SolutionDir)_LuaVersions/$
832 </Message> 976 </Message>
833 </PostBuildEvent> 977 </PostBuildEvent>
834 </ItemDefinitionGroup> 978 </ItemDefinitionGroup>
979 <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release 5.5|Win32'">
980 <PreBuildEvent>
981 <Command>
982 </Command>
983 </PreBuildEvent>
984 <ClCompile>
985 <AdditionalIncludeDirectories>$(SolutionDir)/_LuaVersions/$(PlatformName)/$(ConfigurationName)/include</AdditionalIncludeDirectories>
986 <PreprocessorDefinitions>LANES_DEBUG;WIN32;NDEBUG;_WINDOWS;_USRDLL;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
987 <PrecompiledHeader>Use</PrecompiledHeader>
988 <ProgramDataBaseFileName>$(IntDir)$(TargetName).pdb</ProgramDataBaseFileName>
989 <WarningLevel>Level4</WarningLevel>
990 <DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
991 <LanguageStandard>stdcpp20</LanguageStandard>
992 <WholeProgramOptimization>true</WholeProgramOptimization>
993 <PrecompiledHeaderFile>_pch.hpp</PrecompiledHeaderFile>
994 <OmitFramePointers>true</OmitFramePointers>
995 <BasicRuntimeChecks>
996 </BasicRuntimeChecks>
997 <RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary>
998 </ClCompile>
999 <Link>
1000 <AdditionalDependencies>lua54.lib;%(AdditionalDependencies)</AdditionalDependencies>
1001 <OutputFile>$(OutDir)$(TargetName).dll</OutputFile>
1002 <AdditionalLibraryDirectories>$(SolutionDir)_LuaVersions\$(PlatformName)\$(ConfigurationName)</AdditionalLibraryDirectories>
1003 <GenerateDebugInformation>true</GenerateDebugInformation>
1004 <SubSystem>Windows</SubSystem>
1005 <RandomizedBaseAddress>false</RandomizedBaseAddress>
1006 <DataExecutionPrevention>
1007 </DataExecutionPrevention>
1008 <TargetMachine>MachineX86</TargetMachine>
1009 <ImportLibrary>$(IntDir)$(TargetName).lib</ImportLibrary>
1010 <LinkTimeCodeGeneration>UseLinkTimeCodeGeneration</LinkTimeCodeGeneration>
1011 <OptimizeReferences>true</OptimizeReferences>
1012 <EnableCOMDATFolding>true</EnableCOMDATFolding>
1013 </Link>
1014 <PostBuildEvent>
1015 <Command>xcopy /F /I /R /Y "$(TargetPath)" "$(SolutionDir)_LuaVersions/$(PlatformName)/$(ConfigurationName)"
1016xcopy /F /I /R /Y "$(OutputPath)$(TargetName).pdb" "$(SolutionDir)_LuaVersions/$(PlatformName)/$(ConfigurationName)"
1017</Command>
1018 <Message>
1019 </Message>
1020 </PostBuildEvent>
1021 </ItemDefinitionGroup>
835 <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug 5.1|x64'"> 1022 <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug 5.1|x64'">
836 <PreBuildEvent> 1023 <PreBuildEvent>
837 <Command> 1024 <Command>
@@ -840,7 +1027,7 @@ xcopy /F /I /R /Y "$(OutputPath)$(TargetName).pdb" "$(SolutionDir)_LuaVersions/$
840 <ClCompile> 1027 <ClCompile>
841 <Optimization>Disabled</Optimization> 1028 <Optimization>Disabled</Optimization>
842 <AdditionalIncludeDirectories>$(SolutionDir)/_LuaVersions/$(PlatformName)/$(ConfigurationName)/include</AdditionalIncludeDirectories> 1029 <AdditionalIncludeDirectories>$(SolutionDir)/_LuaVersions/$(PlatformName)/$(ConfigurationName)/include</AdditionalIncludeDirectories>
843 <PreprocessorDefinitions>WIN32;_DEBUG;_WINDOWS;_USRDLL;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions> 1030 <PreprocessorDefinitions>LANES_DEBUG;WIN32;_DEBUG;_WINDOWS;_USRDLL;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
844 <BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks> 1031 <BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>
845 <PrecompiledHeader>Use</PrecompiledHeader> 1032 <PrecompiledHeader>Use</PrecompiledHeader>
846 <ProgramDataBaseFileName>$(IntDir)$(TargetName).pdb</ProgramDataBaseFileName> 1033 <ProgramDataBaseFileName>$(IntDir)$(TargetName).pdb</ProgramDataBaseFileName>
@@ -876,7 +1063,7 @@ xcopy /F /I /R /Y "$(OutputPath)$(TargetName).pdb" "$(SolutionDir)_LuaVersions/$
876 <ClCompile> 1063 <ClCompile>
877 <Optimization>MaxSpeed</Optimization> 1064 <Optimization>MaxSpeed</Optimization>
878 <AdditionalIncludeDirectories>$(SolutionDir)/_LuaVersions/$(PlatformName)/$(ConfigurationName)/include</AdditionalIncludeDirectories> 1065 <AdditionalIncludeDirectories>$(SolutionDir)/_LuaVersions/$(PlatformName)/$(ConfigurationName)/include</AdditionalIncludeDirectories>
879 <PreprocessorDefinitions>WIN32;NDEBUG;_WINDOWS;_USRDLL;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions> 1066 <PreprocessorDefinitions>LANES_DEBUG;WIN32;NDEBUG;_WINDOWS;_USRDLL;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
880 <BasicRuntimeChecks> 1067 <BasicRuntimeChecks>
881 </BasicRuntimeChecks> 1068 </BasicRuntimeChecks>
882 <PrecompiledHeader>Use</PrecompiledHeader> 1069 <PrecompiledHeader>Use</PrecompiledHeader>
@@ -914,7 +1101,7 @@ xcopy /F /I /R /Y "$(OutputPath)$(TargetName).pdb" "$(SolutionDir)_LuaVersions/$
914 <ClCompile> 1101 <ClCompile>
915 <Optimization>Disabled</Optimization> 1102 <Optimization>Disabled</Optimization>
916 <AdditionalIncludeDirectories>$(SolutionDir)/_LuaVersions/$(PlatformName)/$(ConfigurationName)/include</AdditionalIncludeDirectories> 1103 <AdditionalIncludeDirectories>$(SolutionDir)/_LuaVersions/$(PlatformName)/$(ConfigurationName)/include</AdditionalIncludeDirectories>
917 <PreprocessorDefinitions>WIN32;_DEBUG;_WINDOWS;_USRDLL;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions> 1104 <PreprocessorDefinitions>LANES_DEBUG;WIN32;_DEBUG;_WINDOWS;_USRDLL;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
918 <BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks> 1105 <BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>
919 <PrecompiledHeader>Use</PrecompiledHeader> 1106 <PrecompiledHeader>Use</PrecompiledHeader>
920 <ProgramDataBaseFileName>$(IntDir)$(TargetName).pdb</ProgramDataBaseFileName> 1107 <ProgramDataBaseFileName>$(IntDir)$(TargetName).pdb</ProgramDataBaseFileName>
@@ -950,7 +1137,7 @@ xcopy /F /I /R /Y "$(OutputPath)$(TargetName).pdb" "$(SolutionDir)_LuaVersions/$
950 <ClCompile> 1137 <ClCompile>
951 <Optimization>Disabled</Optimization> 1138 <Optimization>Disabled</Optimization>
952 <AdditionalIncludeDirectories>$(SolutionDir)/_LuaVersions/$(PlatformName)/$(ConfigurationName)/include</AdditionalIncludeDirectories> 1139 <AdditionalIncludeDirectories>$(SolutionDir)/_LuaVersions/$(PlatformName)/$(ConfigurationName)/include</AdditionalIncludeDirectories>
953 <PreprocessorDefinitions>WIN32;_DEBUG;_WINDOWS;_USRDLL;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions> 1140 <PreprocessorDefinitions>LANES_DEBUG;WIN32;_DEBUG;_WINDOWS;_USRDLL;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
954 <BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks> 1141 <BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>
955 <PrecompiledHeader>Use</PrecompiledHeader> 1142 <PrecompiledHeader>Use</PrecompiledHeader>
956 <ProgramDataBaseFileName>$(IntDir)$(TargetName).pdb</ProgramDataBaseFileName> 1143 <ProgramDataBaseFileName>$(IntDir)$(TargetName).pdb</ProgramDataBaseFileName>
@@ -978,6 +1165,42 @@ xcopy /F /I /R /Y "$(OutputPath)$(TargetName).pdb" "$(SolutionDir)_LuaVersions/$
978 </Message> 1165 </Message>
979 </PostBuildEvent> 1166 </PostBuildEvent>
980 </ItemDefinitionGroup> 1167 </ItemDefinitionGroup>
1168 <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug 5.5|x64'">
1169 <PreBuildEvent>
1170 <Command>
1171 </Command>
1172 </PreBuildEvent>
1173 <ClCompile>
1174 <Optimization>Disabled</Optimization>
1175 <AdditionalIncludeDirectories>$(SolutionDir)/_LuaVersions/$(PlatformName)/$(ConfigurationName)/include</AdditionalIncludeDirectories>
1176 <PreprocessorDefinitions>LANES_DEBUG;WIN32;_DEBUG;_WINDOWS;_USRDLL;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
1177 <BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>
1178 <PrecompiledHeader>Use</PrecompiledHeader>
1179 <ProgramDataBaseFileName>$(IntDir)$(TargetName).pdb</ProgramDataBaseFileName>
1180 <WarningLevel>Level4</WarningLevel>
1181 <DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
1182 <LanguageStandard>stdcpp20</LanguageStandard>
1183 <PrecompiledHeaderFile>_pch.hpp</PrecompiledHeaderFile>
1184 <OmitFramePointers>false</OmitFramePointers>
1185 </ClCompile>
1186 <Link>
1187 <AdditionalDependencies>lua55.lib;%(AdditionalDependencies)</AdditionalDependencies>
1188 <OutputFile>$(OutDir)$(TargetName).dll</OutputFile>
1189 <AdditionalLibraryDirectories>$(SolutionDir)_LuaVersions\$(PlatformName)\$(ConfigurationName)</AdditionalLibraryDirectories>
1190 <GenerateDebugInformation>true</GenerateDebugInformation>
1191 <SubSystem>Windows</SubSystem>
1192 <RandomizedBaseAddress>false</RandomizedBaseAddress>
1193 <DataExecutionPrevention>
1194 </DataExecutionPrevention>
1195 </Link>
1196 <PostBuildEvent>
1197 <Command>xcopy /F /I /R /Y "$(TargetPath)" "$(SolutionDir)_LuaVersions/$(PlatformName)/$(ConfigurationName)"
1198xcopy /F /I /R /Y "$(OutputPath)$(TargetName).pdb" "$(SolutionDir)_LuaVersions/$(PlatformName)/$(ConfigurationName)"
1199</Command>
1200 <Message>
1201 </Message>
1202 </PostBuildEvent>
1203 </ItemDefinitionGroup>
981 <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release MoonJIT|x64'"> 1204 <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release MoonJIT|x64'">
982 <PreBuildEvent> 1205 <PreBuildEvent>
983 <Command> 1206 <Command>
@@ -986,7 +1209,7 @@ xcopy /F /I /R /Y "$(OutputPath)$(TargetName).pdb" "$(SolutionDir)_LuaVersions/$
986 <ClCompile> 1209 <ClCompile>
987 <Optimization>Disabled</Optimization> 1210 <Optimization>Disabled</Optimization>
988 <AdditionalIncludeDirectories>$(SolutionDir)/_LuaVersions/$(PlatformName)/$(ConfigurationName)/include</AdditionalIncludeDirectories> 1211 <AdditionalIncludeDirectories>$(SolutionDir)/_LuaVersions/$(PlatformName)/$(ConfigurationName)/include</AdditionalIncludeDirectories>
989 <PreprocessorDefinitions>WIN32;NDEBUG;_WINDOWS;_USRDLL;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions> 1212 <PreprocessorDefinitions>LANES_DEBUG;WIN32;NDEBUG;_WINDOWS;_USRDLL;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
990 <BasicRuntimeChecks> 1213 <BasicRuntimeChecks>
991 </BasicRuntimeChecks> 1214 </BasicRuntimeChecks>
992 <PrecompiledHeader>Use</PrecompiledHeader> 1215 <PrecompiledHeader>Use</PrecompiledHeader>
@@ -1024,7 +1247,7 @@ xcopy /F /I /R /Y "$(OutputPath)$(TargetName).pdb" "$(SolutionDir)_LuaVersions/$
1024 <ClCompile> 1247 <ClCompile>
1025 <Optimization>MaxSpeed</Optimization> 1248 <Optimization>MaxSpeed</Optimization>
1026 <AdditionalIncludeDirectories>$(SolutionDir)/_LuaVersions/$(PlatformName)/$(ConfigurationName)/include</AdditionalIncludeDirectories> 1249 <AdditionalIncludeDirectories>$(SolutionDir)/_LuaVersions/$(PlatformName)/$(ConfigurationName)/include</AdditionalIncludeDirectories>
1027 <PreprocessorDefinitions>WIN32;NDEBUG;_WINDOWS;_USRDLL;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions> 1250 <PreprocessorDefinitions>LANES_DEBUG;WIN32;NDEBUG;_WINDOWS;_USRDLL;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
1028 <PrecompiledHeader>Use</PrecompiledHeader> 1251 <PrecompiledHeader>Use</PrecompiledHeader>
1029 <ProgramDataBaseFileName>$(IntDir)$(TargetName).pdb</ProgramDataBaseFileName> 1252 <ProgramDataBaseFileName>$(IntDir)$(TargetName).pdb</ProgramDataBaseFileName>
1030 <WarningLevel>Level4</WarningLevel> 1253 <WarningLevel>Level4</WarningLevel>
@@ -1064,7 +1287,7 @@ xcopy /F /I /R /Y "$(OutputPath)$(TargetName).pdb" "$(SolutionDir)_LuaVersions/$
1064 </PreBuildEvent> 1287 </PreBuildEvent>
1065 <ClCompile> 1288 <ClCompile>
1066 <AdditionalIncludeDirectories>$(SolutionDir)/_LuaVersions/$(PlatformName)/$(ConfigurationName)/include</AdditionalIncludeDirectories> 1289 <AdditionalIncludeDirectories>$(SolutionDir)/_LuaVersions/$(PlatformName)/$(ConfigurationName)/include</AdditionalIncludeDirectories>
1067 <PreprocessorDefinitions>WIN32;NDEBUG;_WINDOWS;_USRDLL;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions> 1290 <PreprocessorDefinitions>LANES_DEBUG;WIN32;NDEBUG;_WINDOWS;_USRDLL;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
1068 <PrecompiledHeader>Use</PrecompiledHeader> 1291 <PrecompiledHeader>Use</PrecompiledHeader>
1069 <ProgramDataBaseFileName>$(IntDir)$(TargetName).pdb</ProgramDataBaseFileName> 1292 <ProgramDataBaseFileName>$(IntDir)$(TargetName).pdb</ProgramDataBaseFileName>
1070 <WarningLevel>Level4</WarningLevel> 1293 <WarningLevel>Level4</WarningLevel>
@@ -1097,6 +1320,47 @@ xcopy /F /I /R /Y "$(OutputPath)$(TargetName).pdb" "$(SolutionDir)_LuaVersions/$
1097 </Message> 1320 </Message>
1098 </PostBuildEvent> 1321 </PostBuildEvent>
1099 </ItemDefinitionGroup> 1322 </ItemDefinitionGroup>
1323 <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release 5.5|x64'">
1324 <PreBuildEvent>
1325 <Command>
1326 </Command>
1327 </PreBuildEvent>
1328 <ClCompile>
1329 <AdditionalIncludeDirectories>$(SolutionDir)/_LuaVersions/$(PlatformName)/$(ConfigurationName)/include</AdditionalIncludeDirectories>
1330 <PreprocessorDefinitions>LANES_DEBUG;WIN32;NDEBUG;_WINDOWS;_USRDLL;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
1331 <PrecompiledHeader>Use</PrecompiledHeader>
1332 <ProgramDataBaseFileName>$(IntDir)$(TargetName).pdb</ProgramDataBaseFileName>
1333 <WarningLevel>Level4</WarningLevel>
1334 <DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
1335 <LanguageStandard>stdcpp20</LanguageStandard>
1336 <WholeProgramOptimization>true</WholeProgramOptimization>
1337 <PrecompiledHeaderFile>_pch.hpp</PrecompiledHeaderFile>
1338 <OmitFramePointers>true</OmitFramePointers>
1339 <BasicRuntimeChecks>
1340 </BasicRuntimeChecks>
1341 <RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary>
1342 </ClCompile>
1343 <Link>
1344 <AdditionalDependencies>lua55.lib;%(AdditionalDependencies)</AdditionalDependencies>
1345 <OutputFile>$(OutDir)$(TargetName).dll</OutputFile>
1346 <AdditionalLibraryDirectories>$(SolutionDir)_LuaVersions\$(PlatformName)\$(ConfigurationName)</AdditionalLibraryDirectories>
1347 <GenerateDebugInformation>true</GenerateDebugInformation>
1348 <SubSystem>Windows</SubSystem>
1349 <RandomizedBaseAddress>false</RandomizedBaseAddress>
1350 <DataExecutionPrevention>
1351 </DataExecutionPrevention>
1352 <LinkTimeCodeGeneration>UseLinkTimeCodeGeneration</LinkTimeCodeGeneration>
1353 <OptimizeReferences>true</OptimizeReferences>
1354 <EnableCOMDATFolding>true</EnableCOMDATFolding>
1355 </Link>
1356 <PostBuildEvent>
1357 <Command>xcopy /F /I /R /Y "$(TargetPath)" "$(SolutionDir)_LuaVersions/$(PlatformName)/$(ConfigurationName)"
1358xcopy /F /I /R /Y "$(OutputPath)$(TargetName).pdb" "$(SolutionDir)_LuaVersions/$(PlatformName)/$(ConfigurationName)"
1359</Command>
1360 <Message>
1361 </Message>
1362 </PostBuildEvent>
1363 </ItemDefinitionGroup>
1100 <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug 5.2|Win32'"> 1364 <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug 5.2|Win32'">
1101 <PreBuildEvent> 1365 <PreBuildEvent>
1102 <Command> 1366 <Command>
@@ -1105,7 +1369,7 @@ xcopy /F /I /R /Y "$(OutputPath)$(TargetName).pdb" "$(SolutionDir)_LuaVersions/$
1105 <ClCompile> 1369 <ClCompile>
1106 <Optimization>Disabled</Optimization> 1370 <Optimization>Disabled</Optimization>
1107 <AdditionalIncludeDirectories>$(SolutionDir)/_LuaVersions/$(PlatformName)/$(ConfigurationName)/include</AdditionalIncludeDirectories> 1371 <AdditionalIncludeDirectories>$(SolutionDir)/_LuaVersions/$(PlatformName)/$(ConfigurationName)/include</AdditionalIncludeDirectories>
1108 <PreprocessorDefinitions>WIN32;_DEBUG;_WINDOWS;_USRDLL;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions> 1372 <PreprocessorDefinitions>LANES_DEBUG;WIN32;_DEBUG;_WINDOWS;_USRDLL;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
1109 <MinimalRebuild>false</MinimalRebuild> 1373 <MinimalRebuild>false</MinimalRebuild>
1110 <BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks> 1374 <BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>
1111 <PrecompiledHeader>Use</PrecompiledHeader> 1375 <PrecompiledHeader>Use</PrecompiledHeader>
@@ -1143,7 +1407,7 @@ xcopy /F /I /R /Y "$(OutputPath)$(TargetName).pdb" "$(SolutionDir)_LuaVersions/$
1143 <ClCompile> 1407 <ClCompile>
1144 <Optimization>Disabled</Optimization> 1408 <Optimization>Disabled</Optimization>
1145 <AdditionalIncludeDirectories>$(SolutionDir)/_LuaVersions/$(PlatformName)/$(ConfigurationName)/include</AdditionalIncludeDirectories> 1409 <AdditionalIncludeDirectories>$(SolutionDir)/_LuaVersions/$(PlatformName)/$(ConfigurationName)/include</AdditionalIncludeDirectories>
1146 <PreprocessorDefinitions>WIN32;_DEBUG;_WINDOWS;_USRDLL;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions> 1410 <PreprocessorDefinitions>LANES_DEBUG;WIN32;_DEBUG;_WINDOWS;_USRDLL;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
1147 <BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks> 1411 <BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>
1148 <PrecompiledHeader>Use</PrecompiledHeader> 1412 <PrecompiledHeader>Use</PrecompiledHeader>
1149 <ProgramDataBaseFileName>$(IntDir)$(TargetName).pdb</ProgramDataBaseFileName> 1413 <ProgramDataBaseFileName>$(IntDir)$(TargetName).pdb</ProgramDataBaseFileName>
@@ -1178,7 +1442,7 @@ xcopy /F /I /R /Y "$(OutputPath)$(TargetName).pdb" "$(SolutionDir)_LuaVersions/$
1178 </PreBuildEvent> 1442 </PreBuildEvent>
1179 <ClCompile> 1443 <ClCompile>
1180 <AdditionalIncludeDirectories>$(SolutionDir)/_LuaVersions/$(PlatformName)/$(ConfigurationName)/include</AdditionalIncludeDirectories> 1444 <AdditionalIncludeDirectories>$(SolutionDir)/_LuaVersions/$(PlatformName)/$(ConfigurationName)/include</AdditionalIncludeDirectories>
1181 <PreprocessorDefinitions>WIN32;NDEBUG;_WINDOWS;_USRDLL;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions> 1445 <PreprocessorDefinitions>LANES_DEBUG;WIN32;NDEBUG;_WINDOWS;_USRDLL;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
1182 <PrecompiledHeader>Use</PrecompiledHeader> 1446 <PrecompiledHeader>Use</PrecompiledHeader>
1183 <ProgramDataBaseFileName>$(IntDir)$(TargetName).pdb</ProgramDataBaseFileName> 1447 <ProgramDataBaseFileName>$(IntDir)$(TargetName).pdb</ProgramDataBaseFileName>
1184 <WarningLevel>Level4</WarningLevel> 1448 <WarningLevel>Level4</WarningLevel>
@@ -1220,7 +1484,7 @@ xcopy /F /I /R /Y "$(OutputPath)$(TargetName).pdb" "$(SolutionDir)_LuaVersions/$
1220 </PreBuildEvent> 1484 </PreBuildEvent>
1221 <ClCompile> 1485 <ClCompile>
1222 <AdditionalIncludeDirectories>$(SolutionDir)/_LuaVersions/$(PlatformName)/$(ConfigurationName)/include</AdditionalIncludeDirectories> 1486 <AdditionalIncludeDirectories>$(SolutionDir)/_LuaVersions/$(PlatformName)/$(ConfigurationName)/include</AdditionalIncludeDirectories>
1223 <PreprocessorDefinitions>WIN32;NDEBUG;_WINDOWS;_USRDLL;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions> 1487 <PreprocessorDefinitions>LANES_DEBUG;WIN32;NDEBUG;_WINDOWS;_USRDLL;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
1224 <PrecompiledHeader>Use</PrecompiledHeader> 1488 <PrecompiledHeader>Use</PrecompiledHeader>
1225 <ProgramDataBaseFileName>$(IntDir)$(TargetName).pdb</ProgramDataBaseFileName> 1489 <ProgramDataBaseFileName>$(IntDir)$(TargetName).pdb</ProgramDataBaseFileName>
1226 <WarningLevel>Level4</WarningLevel> 1490 <WarningLevel>Level4</WarningLevel>
@@ -1260,7 +1524,7 @@ xcopy /F /I /R /Y "$(OutputPath)$(TargetName).pdb" "$(SolutionDir)_LuaVersions/$
1260 </PreBuildEvent> 1524 </PreBuildEvent>
1261 <ClCompile> 1525 <ClCompile>
1262 <AdditionalIncludeDirectories>$(SolutionDir)/_LuaVersions/$(PlatformName)/$(ConfigurationName)/include</AdditionalIncludeDirectories> 1526 <AdditionalIncludeDirectories>$(SolutionDir)/_LuaVersions/$(PlatformName)/$(ConfigurationName)/include</AdditionalIncludeDirectories>
1263 <PreprocessorDefinitions>WIN32;NDEBUG;_WINDOWS;_USRDLL;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions> 1527 <PreprocessorDefinitions>LANES_DEBUG;WIN32;NDEBUG;_WINDOWS;_USRDLL;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
1264 <PrecompiledHeader>Use</PrecompiledHeader> 1528 <PrecompiledHeader>Use</PrecompiledHeader>
1265 <ProgramDataBaseFileName>$(IntDir)$(TargetName).pdb</ProgramDataBaseFileName> 1529 <ProgramDataBaseFileName>$(IntDir)$(TargetName).pdb</ProgramDataBaseFileName>
1266 <WarningLevel>Level4</WarningLevel> 1530 <WarningLevel>Level4</WarningLevel>
@@ -1302,7 +1566,7 @@ xcopy /F /I /R /Y "$(OutputPath)$(TargetName).pdb" "$(SolutionDir)_LuaVersions/$
1302 </PreBuildEvent> 1566 </PreBuildEvent>
1303 <ClCompile> 1567 <ClCompile>
1304 <AdditionalIncludeDirectories>$(SolutionDir)/_LuaVersions/$(PlatformName)/$(ConfigurationName)/include</AdditionalIncludeDirectories> 1568 <AdditionalIncludeDirectories>$(SolutionDir)/_LuaVersions/$(PlatformName)/$(ConfigurationName)/include</AdditionalIncludeDirectories>
1305 <PreprocessorDefinitions>WIN32;NDEBUG;_WINDOWS;_USRDLL;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions> 1569 <PreprocessorDefinitions>LANES_DEBUG;WIN32;NDEBUG;_WINDOWS;_USRDLL;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
1306 <PrecompiledHeader>Use</PrecompiledHeader> 1570 <PrecompiledHeader>Use</PrecompiledHeader>
1307 <ProgramDataBaseFileName>$(IntDir)$(TargetName).pdb</ProgramDataBaseFileName> 1571 <ProgramDataBaseFileName>$(IntDir)$(TargetName).pdb</ProgramDataBaseFileName>
1308 <WarningLevel>Level4</WarningLevel> 1572 <WarningLevel>Level4</WarningLevel>
@@ -1367,6 +1631,14 @@ xcopy /F /I /R /Y "$(OutputPath)$(TargetName).pdb" "$(SolutionDir)_LuaVersions/$
1367 <ExtraWarnings>true</ExtraWarnings> 1631 <ExtraWarnings>true</ExtraWarnings>
1368 </ClCompile> 1632 </ClCompile>
1369 </ItemDefinitionGroup> 1633 </ItemDefinitionGroup>
1634 <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug 5.5|Prospero'">
1635 <ClCompile>
1636 <CppLanguageStd>Cpp20</CppLanguageStd>
1637 <AdditionalIncludeDirectories>$(SolutionDir)..\..\..\Lua54\include</AdditionalIncludeDirectories>
1638 <PrecompiledHeader>Use</PrecompiledHeader>
1639 <ExtraWarnings>true</ExtraWarnings>
1640 </ClCompile>
1641 </ItemDefinitionGroup>
1370 <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release LuaJIT|Prospero'"> 1642 <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release LuaJIT|Prospero'">
1371 <ClCompile> 1643 <ClCompile>
1372 <CppLanguageStd>Cpp20</CppLanguageStd> 1644 <CppLanguageStd>Cpp20</CppLanguageStd>
@@ -1413,38 +1685,52 @@ xcopy /F /I /R /Y "$(OutputPath)$(TargetName).pdb" "$(SolutionDir)_LuaVersions/$
1413 <ExtraWarnings>true</ExtraWarnings> 1685 <ExtraWarnings>true</ExtraWarnings>
1414 </ClCompile> 1686 </ClCompile>
1415 </ItemDefinitionGroup> 1687 </ItemDefinitionGroup>
1688 <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release 5.5|Prospero'">
1689 <ClCompile>
1690 <CppLanguageStd>Cpp20</CppLanguageStd>
1691 <AdditionalIncludeDirectories>$(SolutionDir)..\..\..\Lua54\include</AdditionalIncludeDirectories>
1692 <PrecompiledHeader>Use</PrecompiledHeader>
1693 <ExtraWarnings>true</ExtraWarnings>
1694 </ClCompile>
1695 </ItemDefinitionGroup>
1416 <ItemGroup> 1696 <ItemGroup>
1417 <ClCompile Include="src\allocator.cpp" /> 1697 <ClCompile Include="src\allocator.cpp" />
1418 <ClCompile Include="src\_pch.cpp"> 1698 <ClCompile Include="src\_pch.cpp">
1419 <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug 5.3|Win32'">Create</PrecompiledHeader> 1699 <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug 5.3|Win32'">Create</PrecompiledHeader>
1420 <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release MoonJIT|Win32'">Create</PrecompiledHeader> 1700 <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release MoonJIT|Win32'">Create</PrecompiledHeader>
1421 <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug 5.4|Win32'">Create</PrecompiledHeader> 1701 <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug 5.4|Win32'">Create</PrecompiledHeader>
1702 <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug 5.5|Win32'">Create</PrecompiledHeader>
1422 <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release LuaJIT|Win32'">Create</PrecompiledHeader> 1703 <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release LuaJIT|Win32'">Create</PrecompiledHeader>
1423 <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release 5.1|Win32'">Create</PrecompiledHeader> 1704 <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release 5.1|Win32'">Create</PrecompiledHeader>
1424 <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release 5.2|Win32'">Create</PrecompiledHeader> 1705 <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release 5.2|Win32'">Create</PrecompiledHeader>
1425 <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release 5.3|Win32'">Create</PrecompiledHeader> 1706 <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release 5.3|Win32'">Create</PrecompiledHeader>
1426 <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug 5.1|Win32'">Create</PrecompiledHeader> 1707 <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug 5.1|Win32'">Create</PrecompiledHeader>
1427 <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release 5.4|Win32'">Create</PrecompiledHeader> 1708 <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release 5.4|Win32'">Create</PrecompiledHeader>
1709 <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release 5.5|Win32'">Create</PrecompiledHeader>
1428 <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug 5.2|Win32'">Create</PrecompiledHeader> 1710 <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug 5.2|Win32'">Create</PrecompiledHeader>
1429 <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug 5.3|x64'">Create</PrecompiledHeader> 1711 <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug 5.3|x64'">Create</PrecompiledHeader>
1430 <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release MoonJIT|x64'">Create</PrecompiledHeader> 1712 <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release MoonJIT|x64'">Create</PrecompiledHeader>
1431 <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug 5.4|x64'">Create</PrecompiledHeader> 1713 <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug 5.4|x64'">Create</PrecompiledHeader>
1714 <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug 5.5|x64'">Create</PrecompiledHeader>
1432 <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release LuaJIT|x64'">Create</PrecompiledHeader> 1715 <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release LuaJIT|x64'">Create</PrecompiledHeader>
1433 <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release 5.1|x64'">Create</PrecompiledHeader> 1716 <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release 5.1|x64'">Create</PrecompiledHeader>
1434 <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release 5.2|x64'">Create</PrecompiledHeader> 1717 <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release 5.2|x64'">Create</PrecompiledHeader>
1435 <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release 5.3|x64'">Create</PrecompiledHeader> 1718 <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release 5.3|x64'">Create</PrecompiledHeader>
1436 <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug 5.1|x64'">Create</PrecompiledHeader> 1719 <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug 5.1|x64'">Create</PrecompiledHeader>
1437 <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release 5.4|x64'">Create</PrecompiledHeader> 1720 <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release 5.4|x64'">Create</PrecompiledHeader>
1721 <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release 5.5|x64'">Create</PrecompiledHeader>
1438 <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug 5.2|x64'">Create</PrecompiledHeader> 1722 <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug 5.2|x64'">Create</PrecompiledHeader>
1439 <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug 5.3|Prospero'">Create</PrecompiledHeader> 1723 <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug 5.3|Prospero'">Create</PrecompiledHeader>
1440 <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release MoonJIT|Prospero'">Create</PrecompiledHeader> 1724 <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release MoonJIT|Prospero'">Create</PrecompiledHeader>
1441 <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug 5.4|Prospero'">Create</PrecompiledHeader> 1725 <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug 5.4|Prospero'">Create</PrecompiledHeader>
1726 <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug 5.5|Prospero'">Create</PrecompiledHeader>
1442 <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release LuaJIT|Prospero'">Create</PrecompiledHeader> 1727 <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release LuaJIT|Prospero'">Create</PrecompiledHeader>
1443 <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release 5.1|Prospero'">Create</PrecompiledHeader> 1728 <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release 5.1|Prospero'">Create</PrecompiledHeader>
1444 <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release 5.2|Prospero'">Create</PrecompiledHeader> 1729 <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release 5.2|Prospero'">Create</PrecompiledHeader>
1445 <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release 5.3|Prospero'">Create</PrecompiledHeader> 1730 <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release 5.3|Prospero'">Create</PrecompiledHeader>
1446 <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug 5.1|Prospero'">Create</PrecompiledHeader> 1731 <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug 5.1|Prospero'">Create</PrecompiledHeader>
1447 <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release 5.4|Prospero'">Create</PrecompiledHeader> 1732 <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release 5.4|Prospero'">Create</PrecompiledHeader>
1733 <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release 5.5|Prospero'">Create</PrecompiledHeader>
1448 <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug 5.2|Prospero'">Create</PrecompiledHeader> 1734 <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug 5.2|Prospero'">Create</PrecompiledHeader>
1449 </ClCompile> 1735 </ClCompile>
1450 <ClCompile Include="src\cancel.cpp" /> 1736 <ClCompile Include="src\cancel.cpp" />
@@ -1504,12 +1790,16 @@ xcopy /F /I /R /Y "$(OutputPath)$(TargetName).pdb" "$(SolutionDir)_LuaVersions/$
1504 </Message> 1790 </Message>
1505 <Message Condition="'$(Configuration)|$(Platform)'=='Debug 5.4|Win32'"> 1791 <Message Condition="'$(Configuration)|$(Platform)'=='Debug 5.4|Win32'">
1506 </Message> 1792 </Message>
1793 <Message Condition="'$(Configuration)|$(Platform)'=='Debug 5.5|Win32'">
1794 </Message>
1507 <Message Condition="'$(Configuration)|$(Platform)'=='Release MoonJIT|Win32'"> 1795 <Message Condition="'$(Configuration)|$(Platform)'=='Release MoonJIT|Win32'">
1508 </Message> 1796 </Message>
1509 <Message Condition="'$(Configuration)|$(Platform)'=='Release 5.3|Win32'"> 1797 <Message Condition="'$(Configuration)|$(Platform)'=='Release 5.3|Win32'">
1510 </Message> 1798 </Message>
1511 <Message Condition="'$(Configuration)|$(Platform)'=='Release 5.4|Win32'"> 1799 <Message Condition="'$(Configuration)|$(Platform)'=='Release 5.4|Win32'">
1512 </Message> 1800 </Message>
1801 <Message Condition="'$(Configuration)|$(Platform)'=='Release 5.5|Win32'">
1802 </Message>
1513 <Message Condition="'$(Configuration)|$(Platform)'=='Debug 5.1|x64'"> 1803 <Message Condition="'$(Configuration)|$(Platform)'=='Debug 5.1|x64'">
1514 </Message> 1804 </Message>
1515 <Message Condition="'$(Configuration)|$(Platform)'=='Release LuaJIT|x64'"> 1805 <Message Condition="'$(Configuration)|$(Platform)'=='Release LuaJIT|x64'">
@@ -1518,12 +1808,16 @@ xcopy /F /I /R /Y "$(OutputPath)$(TargetName).pdb" "$(SolutionDir)_LuaVersions/$
1518 </Message> 1808 </Message>
1519 <Message Condition="'$(Configuration)|$(Platform)'=='Debug 5.4|x64'"> 1809 <Message Condition="'$(Configuration)|$(Platform)'=='Debug 5.4|x64'">
1520 </Message> 1810 </Message>
1811 <Message Condition="'$(Configuration)|$(Platform)'=='Debug 5.5|x64'">
1812 </Message>
1521 <Message Condition="'$(Configuration)|$(Platform)'=='Release MoonJIT|x64'"> 1813 <Message Condition="'$(Configuration)|$(Platform)'=='Release MoonJIT|x64'">
1522 </Message> 1814 </Message>
1523 <Message Condition="'$(Configuration)|$(Platform)'=='Release 5.3|x64'"> 1815 <Message Condition="'$(Configuration)|$(Platform)'=='Release 5.3|x64'">
1524 </Message> 1816 </Message>
1525 <Message Condition="'$(Configuration)|$(Platform)'=='Release 5.4|x64'"> 1817 <Message Condition="'$(Configuration)|$(Platform)'=='Release 5.4|x64'">
1526 </Message> 1818 </Message>
1819 <Message Condition="'$(Configuration)|$(Platform)'=='Release 5.5|x64'">
1820 </Message>
1527 <Message Condition="'$(Configuration)|$(Platform)'=='Debug 5.2|Win32'"> 1821 <Message Condition="'$(Configuration)|$(Platform)'=='Debug 5.2|Win32'">
1528 </Message> 1822 </Message>
1529 <Message Condition="'$(Configuration)|$(Platform)'=='Debug 5.2|x64'"> 1823 <Message Condition="'$(Configuration)|$(Platform)'=='Debug 5.2|x64'">
@@ -1532,32 +1826,40 @@ xcopy /F /I /R /Y "$(OutputPath)$(TargetName).pdb" "$(SolutionDir)_LuaVersions/$
1532 <Command Condition="'$(Configuration)|$(Platform)'=='Release LuaJIT|Win32'">xcopy /F /I /R /Y %(FullPath) "$(SolutionDir)_LuaVersions/$(PlatformName)/$(ConfigurationName)/lua"</Command> 1826 <Command Condition="'$(Configuration)|$(Platform)'=='Release LuaJIT|Win32'">xcopy /F /I /R /Y %(FullPath) "$(SolutionDir)_LuaVersions/$(PlatformName)/$(ConfigurationName)/lua"</Command>
1533 <Command Condition="'$(Configuration)|$(Platform)'=='Debug 5.3|Win32'">xcopy /F /I /R /Y %(FullPath) "$(SolutionDir)_LuaVersions/$(PlatformName)/$(ConfigurationName)"</Command> 1827 <Command Condition="'$(Configuration)|$(Platform)'=='Debug 5.3|Win32'">xcopy /F /I /R /Y %(FullPath) "$(SolutionDir)_LuaVersions/$(PlatformName)/$(ConfigurationName)"</Command>
1534 <Command Condition="'$(Configuration)|$(Platform)'=='Debug 5.4|Win32'">xcopy /F /I /R /Y %(FullPath) "$(SolutionDir)_LuaVersions/$(PlatformName)/$(ConfigurationName)"</Command> 1828 <Command Condition="'$(Configuration)|$(Platform)'=='Debug 5.4|Win32'">xcopy /F /I /R /Y %(FullPath) "$(SolutionDir)_LuaVersions/$(PlatformName)/$(ConfigurationName)"</Command>
1829 <Command Condition="'$(Configuration)|$(Platform)'=='Debug 5.5|Win32'">xcopy /F /I /R /Y %(FullPath) "$(SolutionDir)_LuaVersions/$(PlatformName)/$(ConfigurationName)"</Command>
1535 <Command Condition="'$(Configuration)|$(Platform)'=='Release MoonJIT|Win32'">xcopy /F /I /R /Y %(FullPath) "$(SolutionDir)_LuaVersions/$(PlatformName)/$(ConfigurationName)/lua"</Command> 1830 <Command Condition="'$(Configuration)|$(Platform)'=='Release MoonJIT|Win32'">xcopy /F /I /R /Y %(FullPath) "$(SolutionDir)_LuaVersions/$(PlatformName)/$(ConfigurationName)/lua"</Command>
1536 <Command Condition="'$(Configuration)|$(Platform)'=='Release 5.3|Win32'">xcopy /F /I /R /Y %(FullPath) "$(SolutionDir)_LuaVersions/$(PlatformName)/$(ConfigurationName)"</Command> 1831 <Command Condition="'$(Configuration)|$(Platform)'=='Release 5.3|Win32'">xcopy /F /I /R /Y %(FullPath) "$(SolutionDir)_LuaVersions/$(PlatformName)/$(ConfigurationName)"</Command>
1537 <Command Condition="'$(Configuration)|$(Platform)'=='Release 5.4|Win32'">xcopy /F /I /R /Y %(FullPath) "$(SolutionDir)_LuaVersions/$(PlatformName)/$(ConfigurationName)"</Command> 1832 <Command Condition="'$(Configuration)|$(Platform)'=='Release 5.4|Win32'">xcopy /F /I /R /Y %(FullPath) "$(SolutionDir)_LuaVersions/$(PlatformName)/$(ConfigurationName)"</Command>
1833 <Command Condition="'$(Configuration)|$(Platform)'=='Release 5.5|Win32'">xcopy /F /I /R /Y %(FullPath) "$(SolutionDir)_LuaVersions/$(PlatformName)/$(ConfigurationName)"</Command>
1538 <Command Condition="'$(Configuration)|$(Platform)'=='Debug 5.1|x64'">xcopy /F /I /R /Y %(FullPath) "$(SolutionDir)_LuaVersions/$(PlatformName)/$(ConfigurationName)"</Command> 1834 <Command Condition="'$(Configuration)|$(Platform)'=='Debug 5.1|x64'">xcopy /F /I /R /Y %(FullPath) "$(SolutionDir)_LuaVersions/$(PlatformName)/$(ConfigurationName)"</Command>
1539 <Command Condition="'$(Configuration)|$(Platform)'=='Release LuaJIT|x64'">xcopy /F /I /R /Y %(FullPath) "$(SolutionDir)_LuaVersions/$(PlatformName)/$(ConfigurationName)/lua"</Command> 1835 <Command Condition="'$(Configuration)|$(Platform)'=='Release LuaJIT|x64'">xcopy /F /I /R /Y %(FullPath) "$(SolutionDir)_LuaVersions/$(PlatformName)/$(ConfigurationName)/lua"</Command>
1540 <Command Condition="'$(Configuration)|$(Platform)'=='Debug 5.3|x64'">xcopy /F /I /R /Y %(FullPath) "$(SolutionDir)_LuaVersions/$(PlatformName)/$(ConfigurationName)"</Command> 1836 <Command Condition="'$(Configuration)|$(Platform)'=='Debug 5.3|x64'">xcopy /F /I /R /Y %(FullPath) "$(SolutionDir)_LuaVersions/$(PlatformName)/$(ConfigurationName)"</Command>
1541 <Command Condition="'$(Configuration)|$(Platform)'=='Debug 5.4|x64'">xcopy /F /I /R /Y %(FullPath) "$(SolutionDir)_LuaVersions/$(PlatformName)/$(ConfigurationName)"</Command> 1837 <Command Condition="'$(Configuration)|$(Platform)'=='Debug 5.4|x64'">xcopy /F /I /R /Y %(FullPath) "$(SolutionDir)_LuaVersions/$(PlatformName)/$(ConfigurationName)"</Command>
1838 <Command Condition="'$(Configuration)|$(Platform)'=='Debug 5.5|x64'">xcopy /F /I /R /Y %(FullPath) "$(SolutionDir)_LuaVersions/$(PlatformName)/$(ConfigurationName)"</Command>
1542 <Command Condition="'$(Configuration)|$(Platform)'=='Release MoonJIT|x64'">xcopy /F /I /R /Y %(FullPath) "$(SolutionDir)_LuaVersions/$(PlatformName)/$(ConfigurationName)/lua"</Command> 1839 <Command Condition="'$(Configuration)|$(Platform)'=='Release MoonJIT|x64'">xcopy /F /I /R /Y %(FullPath) "$(SolutionDir)_LuaVersions/$(PlatformName)/$(ConfigurationName)/lua"</Command>
1543 <Command Condition="'$(Configuration)|$(Platform)'=='Release 5.3|x64'">xcopy /F /I /R /Y %(FullPath) "$(SolutionDir)_LuaVersions/$(PlatformName)/$(ConfigurationName)"</Command> 1840 <Command Condition="'$(Configuration)|$(Platform)'=='Release 5.3|x64'">xcopy /F /I /R /Y %(FullPath) "$(SolutionDir)_LuaVersions/$(PlatformName)/$(ConfigurationName)"</Command>
1544 <Command Condition="'$(Configuration)|$(Platform)'=='Release 5.4|x64'">xcopy /F /I /R /Y %(FullPath) "$(SolutionDir)_LuaVersions/$(PlatformName)/$(ConfigurationName)"</Command> 1841 <Command Condition="'$(Configuration)|$(Platform)'=='Release 5.4|x64'">xcopy /F /I /R /Y %(FullPath) "$(SolutionDir)_LuaVersions/$(PlatformName)/$(ConfigurationName)"</Command>
1842 <Command Condition="'$(Configuration)|$(Platform)'=='Release 5.5|x64'">xcopy /F /I /R /Y %(FullPath) "$(SolutionDir)_LuaVersions/$(PlatformName)/$(ConfigurationName)"</Command>
1545 <Command Condition="'$(Configuration)|$(Platform)'=='Debug 5.2|Win32'">xcopy /F /I /R /Y %(FullPath) "$(SolutionDir)_LuaVersions/$(PlatformName)/$(ConfigurationName)"</Command> 1843 <Command Condition="'$(Configuration)|$(Platform)'=='Debug 5.2|Win32'">xcopy /F /I /R /Y %(FullPath) "$(SolutionDir)_LuaVersions/$(PlatformName)/$(ConfigurationName)"</Command>
1546 <Command Condition="'$(Configuration)|$(Platform)'=='Debug 5.2|x64'">xcopy /F /I /R /Y %(FullPath) "$(SolutionDir)_LuaVersions/$(PlatformName)/$(ConfigurationName)"</Command> 1844 <Command Condition="'$(Configuration)|$(Platform)'=='Debug 5.2|x64'">xcopy /F /I /R /Y %(FullPath) "$(SolutionDir)_LuaVersions/$(PlatformName)/$(ConfigurationName)"</Command>
1547 <Outputs Condition="'$(Configuration)|$(Platform)'=='Debug 5.1|Win32'">$(SolutionDir)_LuaVersions/$(PlatformName)/$(ConfigurationName)/%(Filename)%(Extension)</Outputs> 1845 <Outputs Condition="'$(Configuration)|$(Platform)'=='Debug 5.1|Win32'">$(SolutionDir)_LuaVersions/$(PlatformName)/$(ConfigurationName)/%(Filename)%(Extension)</Outputs>
1548 <Outputs Condition="'$(Configuration)|$(Platform)'=='Release LuaJIT|Win32'">$(SolutionDir)_LuaVersions/$(PlatformName)/$(ConfigurationName)/lua/%(Filename)%(Extension)</Outputs> 1846 <Outputs Condition="'$(Configuration)|$(Platform)'=='Release LuaJIT|Win32'">$(SolutionDir)_LuaVersions/$(PlatformName)/$(ConfigurationName)/lua/%(Filename)%(Extension)</Outputs>
1549 <Outputs Condition="'$(Configuration)|$(Platform)'=='Debug 5.3|Win32'">$(SolutionDir)_LuaVersions/$(PlatformName)/$(ConfigurationName)/%(Filename)%(Extension)</Outputs> 1847 <Outputs Condition="'$(Configuration)|$(Platform)'=='Debug 5.3|Win32'">$(SolutionDir)_LuaVersions/$(PlatformName)/$(ConfigurationName)/%(Filename)%(Extension)</Outputs>
1550 <Outputs Condition="'$(Configuration)|$(Platform)'=='Debug 5.4|Win32'">$(SolutionDir)_LuaVersions/$(PlatformName)/$(ConfigurationName)/%(Filename)%(Extension)</Outputs> 1848 <Outputs Condition="'$(Configuration)|$(Platform)'=='Debug 5.4|Win32'">$(SolutionDir)_LuaVersions/$(PlatformName)/$(ConfigurationName)/%(Filename)%(Extension)</Outputs>
1849 <Outputs Condition="'$(Configuration)|$(Platform)'=='Debug 5.5|Win32'">$(SolutionDir)_LuaVersions/$(PlatformName)/$(ConfigurationName)/%(Filename)%(Extension)</Outputs>
1551 <Outputs Condition="'$(Configuration)|$(Platform)'=='Release MoonJIT|Win32'">$(SolutionDir)_LuaVersions/$(PlatformName)/$(ConfigurationName)/lua/%(Filename)%(Extension)</Outputs> 1850 <Outputs Condition="'$(Configuration)|$(Platform)'=='Release MoonJIT|Win32'">$(SolutionDir)_LuaVersions/$(PlatformName)/$(ConfigurationName)/lua/%(Filename)%(Extension)</Outputs>
1552 <Outputs Condition="'$(Configuration)|$(Platform)'=='Release 5.3|Win32'">$(SolutionDir)_LuaVersions/$(PlatformName)/$(ConfigurationName)/%(Filename)%(Extension)</Outputs> 1851 <Outputs Condition="'$(Configuration)|$(Platform)'=='Release 5.3|Win32'">$(SolutionDir)_LuaVersions/$(PlatformName)/$(ConfigurationName)/%(Filename)%(Extension)</Outputs>
1553 <Outputs Condition="'$(Configuration)|$(Platform)'=='Release 5.4|Win32'">$(SolutionDir)_LuaVersions/$(PlatformName)/$(ConfigurationName)/%(Filename)%(Extension)</Outputs> 1852 <Outputs Condition="'$(Configuration)|$(Platform)'=='Release 5.4|Win32'">$(SolutionDir)_LuaVersions/$(PlatformName)/$(ConfigurationName)/%(Filename)%(Extension)</Outputs>
1853 <Outputs Condition="'$(Configuration)|$(Platform)'=='Release 5.5|Win32'">$(SolutionDir)_LuaVersions/$(PlatformName)/$(ConfigurationName)/%(Filename)%(Extension)</Outputs>
1554 <Outputs Condition="'$(Configuration)|$(Platform)'=='Debug 5.1|x64'">$(SolutionDir)_LuaVersions/$(PlatformName)/$(ConfigurationName)/%(Filename)%(Extension)</Outputs> 1854 <Outputs Condition="'$(Configuration)|$(Platform)'=='Debug 5.1|x64'">$(SolutionDir)_LuaVersions/$(PlatformName)/$(ConfigurationName)/%(Filename)%(Extension)</Outputs>
1555 <Outputs Condition="'$(Configuration)|$(Platform)'=='Release LuaJIT|x64'">$(SolutionDir)_LuaVersions/$(PlatformName)/$(ConfigurationName)/lua/%(Filename)%(Extension)</Outputs> 1855 <Outputs Condition="'$(Configuration)|$(Platform)'=='Release LuaJIT|x64'">$(SolutionDir)_LuaVersions/$(PlatformName)/$(ConfigurationName)/lua/%(Filename)%(Extension)</Outputs>
1556 <Outputs Condition="'$(Configuration)|$(Platform)'=='Debug 5.3|x64'">$(SolutionDir)_LuaVersions/$(PlatformName)/$(ConfigurationName)/%(Filename)%(Extension)</Outputs> 1856 <Outputs Condition="'$(Configuration)|$(Platform)'=='Debug 5.3|x64'">$(SolutionDir)_LuaVersions/$(PlatformName)/$(ConfigurationName)/%(Filename)%(Extension)</Outputs>
1557 <Outputs Condition="'$(Configuration)|$(Platform)'=='Debug 5.4|x64'">$(SolutionDir)_LuaVersions/$(PlatformName)/$(ConfigurationName)/%(Filename)%(Extension)</Outputs> 1857 <Outputs Condition="'$(Configuration)|$(Platform)'=='Debug 5.4|x64'">$(SolutionDir)_LuaVersions/$(PlatformName)/$(ConfigurationName)/%(Filename)%(Extension)</Outputs>
1858 <Outputs Condition="'$(Configuration)|$(Platform)'=='Debug 5.5|x64'">$(SolutionDir)_LuaVersions/$(PlatformName)/$(ConfigurationName)/%(Filename)%(Extension)</Outputs>
1558 <Outputs Condition="'$(Configuration)|$(Platform)'=='Release MoonJIT|x64'">$(SolutionDir)_LuaVersions/$(PlatformName)/$(ConfigurationName)/lua/%(Filename)%(Extension)</Outputs> 1859 <Outputs Condition="'$(Configuration)|$(Platform)'=='Release MoonJIT|x64'">$(SolutionDir)_LuaVersions/$(PlatformName)/$(ConfigurationName)/lua/%(Filename)%(Extension)</Outputs>
1559 <Outputs Condition="'$(Configuration)|$(Platform)'=='Release 5.3|x64'">$(SolutionDir)_LuaVersions/$(PlatformName)/$(ConfigurationName)/%(Filename)%(Extension)</Outputs> 1860 <Outputs Condition="'$(Configuration)|$(Platform)'=='Release 5.3|x64'">$(SolutionDir)_LuaVersions/$(PlatformName)/$(ConfigurationName)/%(Filename)%(Extension)</Outputs>
1560 <Outputs Condition="'$(Configuration)|$(Platform)'=='Release 5.4|x64'">$(SolutionDir)_LuaVersions/$(PlatformName)/$(ConfigurationName)/%(Filename)%(Extension)</Outputs> 1861 <Outputs Condition="'$(Configuration)|$(Platform)'=='Release 5.4|x64'">$(SolutionDir)_LuaVersions/$(PlatformName)/$(ConfigurationName)/%(Filename)%(Extension)</Outputs>
1862 <Outputs Condition="'$(Configuration)|$(Platform)'=='Release 5.5|x64'">$(SolutionDir)_LuaVersions/$(PlatformName)/$(ConfigurationName)/%(Filename)%(Extension)</Outputs>
1561 <Outputs Condition="'$(Configuration)|$(Platform)'=='Debug 5.2|Win32'">$(SolutionDir)_LuaVersions/$(PlatformName)/$(ConfigurationName)/%(Filename)%(Extension)</Outputs> 1863 <Outputs Condition="'$(Configuration)|$(Platform)'=='Debug 5.2|Win32'">$(SolutionDir)_LuaVersions/$(PlatformName)/$(ConfigurationName)/%(Filename)%(Extension)</Outputs>
1562 <Outputs Condition="'$(Configuration)|$(Platform)'=='Debug 5.2|x64'">$(SolutionDir)_LuaVersions/$(PlatformName)/$(ConfigurationName)/%(Filename)%(Extension)</Outputs> 1864 <Outputs Condition="'$(Configuration)|$(Platform)'=='Debug 5.2|x64'">$(SolutionDir)_LuaVersions/$(PlatformName)/$(ConfigurationName)/%(Filename)%(Extension)</Outputs>
1563 <Message Condition="'$(Configuration)|$(Platform)'=='Release 5.1|Win32'"> 1865 <Message Condition="'$(Configuration)|$(Platform)'=='Release 5.1|Win32'">
@@ -1578,14 +1880,20 @@ xcopy /F /I /R /Y "$(OutputPath)$(TargetName).pdb" "$(SolutionDir)_LuaVersions/$
1578 <Outputs Condition="'$(Configuration)|$(Platform)'=='Release 5.2|x64'">$(SolutionDir)_LuaVersions/$(PlatformName)/$(ConfigurationName)/%(Filename)%(Extension)</Outputs> 1880 <Outputs Condition="'$(Configuration)|$(Platform)'=='Release 5.2|x64'">$(SolutionDir)_LuaVersions/$(PlatformName)/$(ConfigurationName)/%(Filename)%(Extension)</Outputs>
1579 <BuildInParallel Condition="'$(Configuration)|$(Platform)'=='Debug 5.4|Win32'"> 1881 <BuildInParallel Condition="'$(Configuration)|$(Platform)'=='Debug 5.4|Win32'">
1580 </BuildInParallel> 1882 </BuildInParallel>
1883 <BuildInParallel Condition="'$(Configuration)|$(Platform)'=='Debug 5.5|Win32'">
1884 </BuildInParallel>
1581 <BuildInParallel Condition="'$(Configuration)|$(Platform)'=='Release MoonJIT|Win32'"> 1885 <BuildInParallel Condition="'$(Configuration)|$(Platform)'=='Release MoonJIT|Win32'">
1582 </BuildInParallel> 1886 </BuildInParallel>
1583 <MaxProcesses Condition="'$(Configuration)|$(Platform)'=='Debug 5.4|Win32'"> 1887 <MaxProcesses Condition="'$(Configuration)|$(Platform)'=='Debug 5.4|Win32'">
1584 </MaxProcesses> 1888 </MaxProcesses>
1889 <MaxProcesses Condition="'$(Configuration)|$(Platform)'=='Debug 5.5|Win32'">
1890 </MaxProcesses>
1585 <MaxProcesses Condition="'$(Configuration)|$(Platform)'=='Release MoonJIT|Win32'"> 1891 <MaxProcesses Condition="'$(Configuration)|$(Platform)'=='Release MoonJIT|Win32'">
1586 </MaxProcesses> 1892 </MaxProcesses>
1587 <MaxItemsInBatch Condition="'$(Configuration)|$(Platform)'=='Debug 5.4|Win32'"> 1893 <MaxItemsInBatch Condition="'$(Configuration)|$(Platform)'=='Debug 5.4|Win32'">
1588 </MaxItemsInBatch> 1894 </MaxItemsInBatch>
1895 <MaxItemsInBatch Condition="'$(Configuration)|$(Platform)'=='Debug 5.5|Win32'">
1896 </MaxItemsInBatch>
1589 <MaxItemsInBatch Condition="'$(Configuration)|$(Platform)'=='Release MoonJIT|Win32'"> 1897 <MaxItemsInBatch Condition="'$(Configuration)|$(Platform)'=='Release MoonJIT|Win32'">
1590 </MaxItemsInBatch> 1898 </MaxItemsInBatch>
1591 <BuildInParallel Condition="'$(Configuration)|$(Platform)'=='Release LuaJIT|Win32'"> 1899 <BuildInParallel Condition="'$(Configuration)|$(Platform)'=='Release LuaJIT|Win32'">
@@ -1620,14 +1928,20 @@ xcopy /F /I /R /Y "$(OutputPath)$(TargetName).pdb" "$(SolutionDir)_LuaVersions/$
1620 </MaxItemsInBatch> 1928 </MaxItemsInBatch>
1621 <BuildInParallel Condition="'$(Configuration)|$(Platform)'=='Debug 5.4|x64'"> 1929 <BuildInParallel Condition="'$(Configuration)|$(Platform)'=='Debug 5.4|x64'">
1622 </BuildInParallel> 1930 </BuildInParallel>
1931 <BuildInParallel Condition="'$(Configuration)|$(Platform)'=='Debug 5.5|x64'">
1932 </BuildInParallel>
1623 <BuildInParallel Condition="'$(Configuration)|$(Platform)'=='Release MoonJIT|x64'"> 1933 <BuildInParallel Condition="'$(Configuration)|$(Platform)'=='Release MoonJIT|x64'">
1624 </BuildInParallel> 1934 </BuildInParallel>
1625 <MaxProcesses Condition="'$(Configuration)|$(Platform)'=='Debug 5.4|x64'"> 1935 <MaxProcesses Condition="'$(Configuration)|$(Platform)'=='Debug 5.4|x64'">
1626 </MaxProcesses> 1936 </MaxProcesses>
1937 <MaxProcesses Condition="'$(Configuration)|$(Platform)'=='Debug 5.5|x64'">
1938 </MaxProcesses>
1627 <MaxProcesses Condition="'$(Configuration)|$(Platform)'=='Release MoonJIT|x64'"> 1939 <MaxProcesses Condition="'$(Configuration)|$(Platform)'=='Release MoonJIT|x64'">
1628 </MaxProcesses> 1940 </MaxProcesses>
1629 <MaxItemsInBatch Condition="'$(Configuration)|$(Platform)'=='Debug 5.4|x64'"> 1941 <MaxItemsInBatch Condition="'$(Configuration)|$(Platform)'=='Debug 5.4|x64'">
1630 </MaxItemsInBatch> 1942 </MaxItemsInBatch>
1943 <MaxItemsInBatch Condition="'$(Configuration)|$(Platform)'=='Debug 5.5|x64'">
1944 </MaxItemsInBatch>
1631 <MaxItemsInBatch Condition="'$(Configuration)|$(Platform)'=='Release MoonJIT|x64'"> 1945 <MaxItemsInBatch Condition="'$(Configuration)|$(Platform)'=='Release MoonJIT|x64'">
1632 </MaxItemsInBatch> 1946 </MaxItemsInBatch>
1633 <BuildInParallel Condition="'$(Configuration)|$(Platform)'=='Release LuaJIT|x64'"> 1947 <BuildInParallel Condition="'$(Configuration)|$(Platform)'=='Release LuaJIT|x64'">
@@ -1674,10 +1988,16 @@ xcopy /F /I /R /Y "$(OutputPath)$(TargetName).pdb" "$(SolutionDir)_LuaVersions/$
1674 </MaxItemsInBatch> 1988 </MaxItemsInBatch>
1675 <BuildInParallel Condition="'$(Configuration)|$(Platform)'=='Release 5.4|Win32'"> 1989 <BuildInParallel Condition="'$(Configuration)|$(Platform)'=='Release 5.4|Win32'">
1676 </BuildInParallel> 1990 </BuildInParallel>
1991 <BuildInParallel Condition="'$(Configuration)|$(Platform)'=='Release 5.5|Win32'">
1992 </BuildInParallel>
1677 <MaxProcesses Condition="'$(Configuration)|$(Platform)'=='Release 5.4|Win32'"> 1993 <MaxProcesses Condition="'$(Configuration)|$(Platform)'=='Release 5.4|Win32'">
1678 </MaxProcesses> 1994 </MaxProcesses>
1995 <MaxProcesses Condition="'$(Configuration)|$(Platform)'=='Release 5.5|Win32'">
1996 </MaxProcesses>
1679 <MaxItemsInBatch Condition="'$(Configuration)|$(Platform)'=='Release 5.4|Win32'"> 1997 <MaxItemsInBatch Condition="'$(Configuration)|$(Platform)'=='Release 5.4|Win32'">
1680 </MaxItemsInBatch> 1998 </MaxItemsInBatch>
1999 <MaxItemsInBatch Condition="'$(Configuration)|$(Platform)'=='Release 5.5|Win32'">
2000 </MaxItemsInBatch>
1681 <BuildInParallel Condition="'$(Configuration)|$(Platform)'=='Debug 5.3|x64'"> 2001 <BuildInParallel Condition="'$(Configuration)|$(Platform)'=='Debug 5.3|x64'">
1682 </BuildInParallel> 2002 </BuildInParallel>
1683 <MaxProcesses Condition="'$(Configuration)|$(Platform)'=='Debug 5.3|x64'"> 2003 <MaxProcesses Condition="'$(Configuration)|$(Platform)'=='Debug 5.3|x64'">
@@ -1692,10 +2012,16 @@ xcopy /F /I /R /Y "$(OutputPath)$(TargetName).pdb" "$(SolutionDir)_LuaVersions/$
1692 </MaxItemsInBatch> 2012 </MaxItemsInBatch>
1693 <BuildInParallel Condition="'$(Configuration)|$(Platform)'=='Release 5.4|x64'"> 2013 <BuildInParallel Condition="'$(Configuration)|$(Platform)'=='Release 5.4|x64'">
1694 </BuildInParallel> 2014 </BuildInParallel>
2015 <BuildInParallel Condition="'$(Configuration)|$(Platform)'=='Release 5.5|x64'">
2016 </BuildInParallel>
1695 <MaxProcesses Condition="'$(Configuration)|$(Platform)'=='Release 5.4|x64'"> 2017 <MaxProcesses Condition="'$(Configuration)|$(Platform)'=='Release 5.4|x64'">
1696 </MaxProcesses> 2018 </MaxProcesses>
2019 <MaxProcesses Condition="'$(Configuration)|$(Platform)'=='Release 5.5|x64'">
2020 </MaxProcesses>
1697 <MaxItemsInBatch Condition="'$(Configuration)|$(Platform)'=='Release 5.4|x64'"> 2021 <MaxItemsInBatch Condition="'$(Configuration)|$(Platform)'=='Release 5.4|x64'">
1698 </MaxItemsInBatch> 2022 </MaxItemsInBatch>
2023 <MaxItemsInBatch Condition="'$(Configuration)|$(Platform)'=='Release 5.5|x64'">
2024 </MaxItemsInBatch>
1699 </CustomBuild> 2025 </CustomBuild>
1700 <None Include="CMakeLists.txt" /> 2026 <None Include="CMakeLists.txt" />
1701 <None Include="docs\comparison.html" /> 2027 <None Include="docs\comparison.html" />
diff --git a/Makefile b/Makefile
index c0f08b4..ea4f1d3 100644
--- a/Makefile
+++ b/Makefile
@@ -79,7 +79,13 @@ build_DUE:
79# also run a test that shows whether lanes is successfully loaded or not 79# also run a test that shows whether lanes is successfully loaded or not
80run_unit_tests: build_lanes build_unit_tests build_DUE 80run_unit_tests: build_lanes build_unit_tests build_DUE
81 @echo ========================================================================================= 81 @echo =========================================================================================
82 $(_PREFIX) $(_UNITTEST_TARGET) "lanes.require 'lanes'" 82 $(_PREFIX) $(_UNITTEST_TARGET) --list-tests
83 $(_PREFIX) $(_UNITTEST_TARGET) --rng-seed 0
84
85debug_unit_tests: build_lanes build_unit_tests build_DUE
86 @echo =========================================================================================
87 $(_PREFIX) $(_UNITTEST_TARGET) --list-tests
88 $(_PREFIX) gdb --args $(_UNITTEST_TARGET) --rng-seed 0 -s scripted_tests.lane.tasking_cancelling
83 89
84clean: 90clean:
85 cd src && $(MAKE) -f Lanes.makefile clean 91 cd src && $(MAKE) -f Lanes.makefile clean
@@ -267,13 +273,11 @@ DESTDIR:=/usr/local
267LUA_LIBDIR:=$(DESTDIR)/lib/lua/$(LUA_VERSION) 273LUA_LIBDIR:=$(DESTDIR)/lib/lua/$(LUA_VERSION)
268LUA_SHAREDIR:=$(DESTDIR)/share/lua/$(LUA_VERSION) 274LUA_SHAREDIR:=$(DESTDIR)/share/lua/$(LUA_VERSION)
269 275
270#
271# AKa 17-Oct: changed to use 'install -m 644' and 'cp -p'
272#
273install: $(_LANES_TARGET) src/lanes.lua 276install: $(_LANES_TARGET) src/lanes.lua
274 mkdir -p $(LUA_LIBDIR) $(LUA_SHAREDIR) 277 mkdir -p $(LUA_LIBDIR) $(LUA_SHAREDIR)
275 install -m 644 $(_LANES_TARGET) $(LUA_LIBDIR) 278 install -m 644 $(_LANES_TARGET) $(LUA_LIBDIR)
276 cp -p src/lanes.lua $(LUA_SHAREDIR) 279 cp -p src/lanes.lua $(LUA_SHAREDIR)
280 install -m 644 $(_DUE_TARGET) $(LUA_LIBDIR)
277 281
278uninstall: 282uninstall:
279 rm $(LUA_LIBDIR)/lanes_core.$(_SO) 283 rm $(LUA_LIBDIR)/lanes_core.$(_SO)
diff --git a/Shared.makefile b/Shared.makefile
index 492c05d..3809538 100644
--- a/Shared.makefile
+++ b/Shared.makefile
@@ -5,7 +5,7 @@ CC := g++ -std=c++20
5LIBFLAG := -shared 5LIBFLAG := -shared
6 6
7OPT_FLAGS := -O2 7OPT_FLAGS := -O2
8# -O0 -g 8#OPT_FLAGS := -O0 -g3
9 9
10ifeq "$(findstring MINGW,$(shell uname -s))" "MINGW" 10ifeq "$(findstring MINGW,$(shell uname -s))" "MINGW"
11 # MinGW MSYS on Windows 11 # MinGW MSYS on Windows
@@ -30,7 +30,7 @@ ifeq "$(LUAROCKS)" ""
30 $(warning LUA_DEV not defined - try i.e. 'make LUA_DEV=/c/Program\ Files/Lua/5.1') 30 $(warning LUA_DEV not defined - try i.e. 'make LUA_DEV=/c/Program\ Files/Lua/5.1')
31 # this assumes Lua was built and installed from source and everything is located in default folders (/usr/local/include and /usr/local/bin) 31 # this assumes Lua was built and installed from source and everything is located in default folders (/usr/local/include and /usr/local/bin)
32 LUA_FLAGS := -I "/usr/local/include" 32 LUA_FLAGS := -I "/usr/local/include"
33 LUA_LIBS := $(word 1,$(shell which lua54.$(_SO) 2>/dev/null) $(shell which lua53.$(_SO) 2>/dev/null) $(shell which lua52.$(_SO) 2>/dev/null) $(shell which lua51$(_SO) 2>/dev/null)) 33 LUA_LIBS := $(word 1,$(shell which lua55.$(_SO) 2>/dev/null) $(shell which lua54.$(_SO) 2>/dev/null) $(shell which lua53.$(_SO) 2>/dev/null) $(shell which lua52.$(_SO) 2>/dev/null) $(shell which lua51$(_SO) 2>/dev/null))
34 $(info detected LUA_LIBS as $(LUA_LIBS)) 34 $(info detected LUA_LIBS as $(LUA_LIBS))
35 else 35 else
36 LUA_FLAGS := -I "$(LUA_DEV)/include" 36 LUA_FLAGS := -I "$(LUA_DEV)/include"
diff --git a/deep_userdata_example/deep_userdata_example.cpp b/deep_userdata_example/deep_userdata_example.cpp
index a45cc7f..6845ff1 100644
--- a/deep_userdata_example/deep_userdata_example.cpp
+++ b/deep_userdata_example/deep_userdata_example.cpp
@@ -25,7 +25,7 @@ class MyDeepFactory final : public DeepFactory
25 25
26// ################################################################################################# 26// #################################################################################################
27 27
28// a lanes-deep userdata. needs DeepPrelude and luaG_newdeepuserdata from Lanes code. 28// a lanes-deep userdata. needs DeepPrelude and luaW_newdeepuserdata from Lanes code.
29struct MyDeepUserdata : public DeepPrelude // Deep userdata MUST start with a DeepPrelude 29struct MyDeepUserdata : public DeepPrelude // Deep userdata MUST start with a DeepPrelude
30{ 30{
31 std::atomic<int> inUse{}; 31 std::atomic<int> inUse{};
@@ -82,7 +82,7 @@ static int deep_tostring(lua_State* const L_)
82{ 82{
83 MyDeepUserdata* const _self{ static_cast<MyDeepUserdata*>(MyDeepFactory::Instance.toDeep(L_, StackIndex{ 1 })) }; 83 MyDeepUserdata* const _self{ static_cast<MyDeepUserdata*>(MyDeepFactory::Instance.toDeep(L_, StackIndex{ 1 })) };
84 _self->inUse.fetch_add(1, std::memory_order_seq_cst); 84 _self->inUse.fetch_add(1, std::memory_order_seq_cst);
85 luaG_pushstring(L_, "%p:deep(%d)", _self, _self->val); 85 luaW_pushstring(L_, "%p:deep(%d)", _self, _self->val);
86 _self->inUse.fetch_sub(1, std::memory_order_seq_cst); 86 _self->inUse.fetch_sub(1, std::memory_order_seq_cst);
87 return 1; 87 return 1;
88} 88}
@@ -241,7 +241,7 @@ static int clonable_getuv(lua_State* const L_)
241static int clonable_tostring(lua_State* const L_) 241static int clonable_tostring(lua_State* const L_)
242{ 242{
243 MyClonableUserdata* _self = static_cast<MyClonableUserdata*>(lua_touserdata(L_, 1)); 243 MyClonableUserdata* _self = static_cast<MyClonableUserdata*>(lua_touserdata(L_, 1));
244 luaG_pushstring(L_, "%p:clonable(%d)", lua_topointer(L_, 1), _self->val); 244 luaW_pushstring(L_, "%p:clonable(%d)", lua_topointer(L_, 1), _self->val);
245 return 1; 245 return 1;
246} 246}
247 247
@@ -261,21 +261,21 @@ static int clonable_gc(lua_State* const L_)
261 261
262// this is all we need to make a userdata lanes-clonable. no dependency on Lanes code. 262// this is all we need to make a userdata lanes-clonable. no dependency on Lanes code.
263[[nodiscard]] 263[[nodiscard]]
264static int clonable_lanesclone(lua_State* L) 264static int clonable_lanesclone(lua_State* const L_)
265{ 265{
266 switch (lua_gettop(L)) { 266 switch (lua_gettop(L_)) {
267 case 3: 267 case 3:
268 { 268 {
269 MyClonableUserdata* self = static_cast<MyClonableUserdata*>(lua_touserdata(L, 1)); 269 MyClonableUserdata* const _self = static_cast<MyClonableUserdata*>(lua_touserdata(L_, 1));
270 MyClonableUserdata* from = static_cast<MyClonableUserdata*>(lua_touserdata(L, 2)); 270 MyClonableUserdata* const _from = static_cast<MyClonableUserdata*>(lua_touserdata(L_, 2));
271 size_t len = lua_tointeger(L, 3); 271 auto const _len{ static_cast<size_t>(lua_tointeger(L_, 3)) }; // make 32-bits builds happy
272 assert(len == sizeof(MyClonableUserdata)); 272 assert(_len == sizeof(MyClonableUserdata));
273 *self = *from; 273 *_self = *_from;
274 } 274 }
275 return 0; 275 return 0;
276 276
277 default: 277 default:
278 raise_luaL_error(L, "Lanes called clonable_lanesclone with unexpected arguments"); 278 raise_luaL_error(L_, "Lanes called clonable_lanesclone with unexpected arguments");
279 } 279 }
280 return 0; 280 return 0;
281} 281}
@@ -299,7 +299,7 @@ int luaD_new_clonable(lua_State* L)
299{ 299{
300 UserValueCount const _nuv{ static_cast<int>(luaL_optinteger(L, 1, 1)) }; 300 UserValueCount const _nuv{ static_cast<int>(luaL_optinteger(L, 1, 1)) };
301 lua_newuserdatauv(L, sizeof(MyClonableUserdata), _nuv); 301 lua_newuserdatauv(L, sizeof(MyClonableUserdata), _nuv);
302 luaG_setmetatable(L, "clonable"); 302 luaW_setmetatable(L, "clonable");
303 return 1; 303 return 1;
304} 304}
305 305
@@ -307,7 +307,7 @@ int luaD_new_clonable(lua_State* L)
307// ################################################################################################# 307// #################################################################################################
308 308
309static luaL_Reg const deep_module[] = { 309static luaL_Reg const deep_module[] = {
310 { "get_deep_count", luaD_get_deep_count }, 310 { "get_deep_count", luaD_get_deep_count },
311 { "new_deep", luaD_new_deep }, 311 { "new_deep", luaD_new_deep },
312 { "new_clonable", luaD_new_clonable }, 312 { "new_clonable", luaD_new_clonable },
313 { nullptr, nullptr } 313 { nullptr, nullptr }
@@ -317,12 +317,12 @@ static luaL_Reg const deep_module[] = {
317 317
318LANES_API int luaopen_deep_userdata_example(lua_State* L) 318LANES_API int luaopen_deep_userdata_example(lua_State* L)
319{ 319{
320 luaG_newlib<std::size(deep_module)>(L, deep_module); // M 320 luaW_newlib<std::size(deep_module)>(L, deep_module); // M
321 321
322 // preregister the metatables for the types we can instantiate so that Lanes can know about them 322 // preregister the metatables for the types we can instantiate so that Lanes can know about them
323 if (luaL_newmetatable(L, "clonable")) // M mt 323 if (luaL_newmetatable(L, "clonable")) // M mt
324 { 324 {
325 luaG_registerlibfuncs(L, clonable_mt); 325 luaW_registerlibfuncs(L, clonable_mt);
326 lua_pushvalue(L, -1); // M mt mt 326 lua_pushvalue(L, -1); // M mt mt
327 lua_setfield(L, -2, "__index"); // M mt 327 lua_setfield(L, -2, "__index"); // M mt
328 } 328 }
@@ -330,7 +330,7 @@ LANES_API int luaopen_deep_userdata_example(lua_State* L)
330 330
331 if (luaL_newmetatable(L, "deep")) // mt 331 if (luaL_newmetatable(L, "deep")) // mt
332 { 332 {
333 luaG_registerlibfuncs(L, deep_mt); 333 luaW_registerlibfuncs(L, deep_mt);
334 lua_pushvalue(L, -1); // mt mt 334 lua_pushvalue(L, -1); // mt mt
335 lua_setfield(L, -2, "__index"); // mt 335 lua_setfield(L, -2, "__index"); // mt
336 } 336 }
diff --git a/deep_userdata_example/deep_userdata_example.vcxproj b/deep_userdata_example/deep_userdata_example.vcxproj
index 54db35a..bea5edd 100644
--- a/deep_userdata_example/deep_userdata_example.vcxproj
+++ b/deep_userdata_example/deep_userdata_example.vcxproj
@@ -45,6 +45,30 @@
45 <Configuration>Debug 5.4</Configuration> 45 <Configuration>Debug 5.4</Configuration>
46 <Platform>x64</Platform> 46 <Platform>x64</Platform>
47 </ProjectConfiguration> 47 </ProjectConfiguration>
48 <ProjectConfiguration Include="Debug 5.5|Prospero">
49 <Configuration>Debug 5.5</Configuration>
50 <Platform>Prospero</Platform>
51 </ProjectConfiguration>
52 <ProjectConfiguration Include="Debug 5.5|Win32">
53 <Configuration>Debug 5.5</Configuration>
54 <Platform>Win32</Platform>
55 </ProjectConfiguration>
56 <ProjectConfiguration Include="Debug 5.5|x64">
57 <Configuration>Debug 5.5</Configuration>
58 <Platform>x64</Platform>
59 </ProjectConfiguration>
60 <ProjectConfiguration Include="Release 5.5|Prospero">
61 <Configuration>Release 5.5</Configuration>
62 <Platform>Prospero</Platform>
63 </ProjectConfiguration>
64 <ProjectConfiguration Include="Release 5.5|Win32">
65 <Configuration>Release 5.5</Configuration>
66 <Platform>Win32</Platform>
67 </ProjectConfiguration>
68 <ProjectConfiguration Include="Release 5.5|x64">
69 <Configuration>Release 5.5</Configuration>
70 <Platform>x64</Platform>
71 </ProjectConfiguration>
48 <ProjectConfiguration Include="Release LuaJIT|Prospero"> 72 <ProjectConfiguration Include="Release LuaJIT|Prospero">
49 <Configuration>Release LuaJIT</Configuration> 73 <Configuration>Release LuaJIT</Configuration>
50 <Platform>Prospero</Platform> 74 <Platform>Prospero</Platform>
@@ -173,6 +197,12 @@
173 <PlatformToolset>v143</PlatformToolset> 197 <PlatformToolset>v143</PlatformToolset>
174 <CharacterSet>MultiByte</CharacterSet> 198 <CharacterSet>MultiByte</CharacterSet>
175 </PropertyGroup> 199 </PropertyGroup>
200 <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug 5.5|Win32'" Label="Configuration">
201 <ConfigurationType>DynamicLibrary</ConfigurationType>
202 <UseDebugLibraries>true</UseDebugLibraries>
203 <PlatformToolset>v143</PlatformToolset>
204 <CharacterSet>MultiByte</CharacterSet>
205 </PropertyGroup>
176 <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release MoonJIT|Win32'" Label="Configuration"> 206 <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release MoonJIT|Win32'" Label="Configuration">
177 <ConfigurationType>DynamicLibrary</ConfigurationType> 207 <ConfigurationType>DynamicLibrary</ConfigurationType>
178 <UseDebugLibraries>true</UseDebugLibraries> 208 <UseDebugLibraries>true</UseDebugLibraries>
@@ -193,6 +223,13 @@
193 <WholeProgramOptimization>true</WholeProgramOptimization> 223 <WholeProgramOptimization>true</WholeProgramOptimization>
194 <CharacterSet>MultiByte</CharacterSet> 224 <CharacterSet>MultiByte</CharacterSet>
195 </PropertyGroup> 225 </PropertyGroup>
226 <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release 5.5|Win32'" Label="Configuration">
227 <ConfigurationType>DynamicLibrary</ConfigurationType>
228 <UseDebugLibraries>false</UseDebugLibraries>
229 <PlatformToolset>v143</PlatformToolset>
230 <WholeProgramOptimization>true</WholeProgramOptimization>
231 <CharacterSet>MultiByte</CharacterSet>
232 </PropertyGroup>
196 <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug 5.3|x64'" Label="Configuration"> 233 <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug 5.3|x64'" Label="Configuration">
197 <ConfigurationType>DynamicLibrary</ConfigurationType> 234 <ConfigurationType>DynamicLibrary</ConfigurationType>
198 <UseDebugLibraries>true</UseDebugLibraries> 235 <UseDebugLibraries>true</UseDebugLibraries>
@@ -237,6 +274,12 @@
237 <PlatformToolset>v143</PlatformToolset> 274 <PlatformToolset>v143</PlatformToolset>
238 <CharacterSet>MultiByte</CharacterSet> 275 <CharacterSet>MultiByte</CharacterSet>
239 </PropertyGroup> 276 </PropertyGroup>
277 <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug 5.5|x64'" Label="Configuration">
278 <ConfigurationType>DynamicLibrary</ConfigurationType>
279 <UseDebugLibraries>true</UseDebugLibraries>
280 <PlatformToolset>v143</PlatformToolset>
281 <CharacterSet>MultiByte</CharacterSet>
282 </PropertyGroup>
240 <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release MoonJIT|x64'" Label="Configuration"> 283 <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release MoonJIT|x64'" Label="Configuration">
241 <ConfigurationType>DynamicLibrary</ConfigurationType> 284 <ConfigurationType>DynamicLibrary</ConfigurationType>
242 <UseDebugLibraries>true</UseDebugLibraries> 285 <UseDebugLibraries>true</UseDebugLibraries>
@@ -257,6 +300,13 @@
257 <WholeProgramOptimization>true</WholeProgramOptimization> 300 <WholeProgramOptimization>true</WholeProgramOptimization>
258 <CharacterSet>MultiByte</CharacterSet> 301 <CharacterSet>MultiByte</CharacterSet>
259 </PropertyGroup> 302 </PropertyGroup>
303 <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release 5.5|x64'" Label="Configuration">
304 <ConfigurationType>DynamicLibrary</ConfigurationType>
305 <UseDebugLibraries>false</UseDebugLibraries>
306 <PlatformToolset>v143</PlatformToolset>
307 <WholeProgramOptimization>true</WholeProgramOptimization>
308 <CharacterSet>MultiByte</CharacterSet>
309 </PropertyGroup>
260 <PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Release MoonJIT|Prospero'"> 310 <PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Release MoonJIT|Prospero'">
261 <PlatformToolset>Clang</PlatformToolset> 311 <PlatformToolset>Clang</PlatformToolset>
262 </PropertyGroup> 312 </PropertyGroup>
@@ -266,6 +316,9 @@
266 <PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Release 5.4|Prospero'"> 316 <PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Release 5.4|Prospero'">
267 <PlatformToolset>Clang</PlatformToolset> 317 <PlatformToolset>Clang</PlatformToolset>
268 </PropertyGroup> 318 </PropertyGroup>
319 <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release 5.5|Prospero'" Label="Configuration">
320 <PlatformToolset>Clang</PlatformToolset>
321 </PropertyGroup>
269 <PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Debug 5.3|Prospero'"> 322 <PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Debug 5.3|Prospero'">
270 <PlatformToolset>Clang</PlatformToolset> 323 <PlatformToolset>Clang</PlatformToolset>
271 </PropertyGroup> 324 </PropertyGroup>
@@ -284,6 +337,9 @@
284 <PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Debug 5.4|Prospero'"> 337 <PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Debug 5.4|Prospero'">
285 <PlatformToolset>Clang</PlatformToolset> 338 <PlatformToolset>Clang</PlatformToolset>
286 </PropertyGroup> 339 </PropertyGroup>
340 <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug 5.5|Prospero'" Label="Configuration">
341 <PlatformToolset>Clang</PlatformToolset>
342 </PropertyGroup>
287 <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release LuaJIT|Prospero'" Label="Configuration"> 343 <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release LuaJIT|Prospero'" Label="Configuration">
288 <PlatformToolset>Clang</PlatformToolset> 344 <PlatformToolset>Clang</PlatformToolset>
289 </PropertyGroup> 345 </PropertyGroup>
@@ -313,6 +369,9 @@
313 <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug 5.4|Win32'" Label="PropertySheets"> 369 <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug 5.4|Win32'" Label="PropertySheets">
314 <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" /> 370 <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
315 </ImportGroup> 371 </ImportGroup>
372 <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug 5.5|Win32'" Label="PropertySheets">
373 <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
374 </ImportGroup>
316 <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release MoonJIT|Win32'" Label="PropertySheets"> 375 <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release MoonJIT|Win32'" Label="PropertySheets">
317 <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" /> 376 <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
318 </ImportGroup> 377 </ImportGroup>
@@ -322,6 +381,9 @@
322 <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release 5.4|Win32'" Label="PropertySheets"> 381 <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release 5.4|Win32'" Label="PropertySheets">
323 <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" /> 382 <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
324 </ImportGroup> 383 </ImportGroup>
384 <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release 5.5|Win32'" Label="PropertySheets">
385 <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
386 </ImportGroup>
325 <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug 5.3|x64'"> 387 <ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug 5.3|x64'">
326 <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" /> 388 <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
327 </ImportGroup> 389 </ImportGroup>
@@ -343,6 +405,9 @@
343 <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug 5.4|x64'" Label="PropertySheets"> 405 <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug 5.4|x64'" Label="PropertySheets">
344 <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" /> 406 <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
345 </ImportGroup> 407 </ImportGroup>
408 <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Debug 5.5|x64'" Label="PropertySheets">
409 <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
410 </ImportGroup>
346 <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release MoonJIT|x64'" Label="PropertySheets"> 411 <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release MoonJIT|x64'" Label="PropertySheets">
347 <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" /> 412 <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
348 </ImportGroup> 413 </ImportGroup>
@@ -352,6 +417,9 @@
352 <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release 5.4|x64'" Label="PropertySheets"> 417 <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release 5.4|x64'" Label="PropertySheets">
353 <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" /> 418 <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
354 </ImportGroup> 419 </ImportGroup>
420 <ImportGroup Condition="'$(Configuration)|$(Platform)'=='Release 5.5|x64'" Label="PropertySheets">
421 <Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
422 </ImportGroup>
355 <PropertyGroup Label="UserMacros" /> 423 <PropertyGroup Label="UserMacros" />
356 <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug 5.3|x64'"> 424 <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug 5.3|x64'">
357 <TargetExt>.dll</TargetExt> 425 <TargetExt>.dll</TargetExt>
@@ -395,6 +463,12 @@
395 <IntDir>$(SolutionDir)_Tmp\$(ProjectName)\$(PlatformName)\$(Configuration)\</IntDir> 463 <IntDir>$(SolutionDir)_Tmp\$(ProjectName)\$(PlatformName)\$(Configuration)\</IntDir>
396 <LinkIncremental>false</LinkIncremental> 464 <LinkIncremental>false</LinkIncremental>
397 </PropertyGroup> 465 </PropertyGroup>
466 <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug 5.5|x64'">
467 <TargetExt>.dll</TargetExt>
468 <OutDir>$(SolutionDir)_Output\$(ProjectName)\$(PlatformName)\$(Configuration)\</OutDir>
469 <IntDir>$(SolutionDir)_Tmp\$(ProjectName)\$(PlatformName)\$(Configuration)\</IntDir>
470 <LinkIncremental>false</LinkIncremental>
471 </PropertyGroup>
398 <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release MoonJIT|x64'"> 472 <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release MoonJIT|x64'">
399 <TargetExt>.dll</TargetExt> 473 <TargetExt>.dll</TargetExt>
400 <OutDir>$(SolutionDir)_Output\$(ProjectName)\$(PlatformName)\$(Configuration)\</OutDir> 474 <OutDir>$(SolutionDir)_Output\$(ProjectName)\$(PlatformName)\$(Configuration)\</OutDir>
@@ -443,6 +517,12 @@
443 <IntDir>$(SolutionDir)_Tmp\$(ProjectName)\$(PlatformName)\$(Configuration)\</IntDir> 517 <IntDir>$(SolutionDir)_Tmp\$(ProjectName)\$(PlatformName)\$(Configuration)\</IntDir>
444 <LinkIncremental>false</LinkIncremental> 518 <LinkIncremental>false</LinkIncremental>
445 </PropertyGroup> 519 </PropertyGroup>
520 <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug 5.5|Win32'">
521 <TargetExt>.dll</TargetExt>
522 <OutDir>$(SolutionDir)_Output\$(ProjectName)\$(PlatformName)\$(Configuration)\</OutDir>
523 <IntDir>$(SolutionDir)_Tmp\$(ProjectName)\$(PlatformName)\$(Configuration)\</IntDir>
524 <LinkIncremental>false</LinkIncremental>
525 </PropertyGroup>
446 <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release MoonJIT|Win32'"> 526 <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release MoonJIT|Win32'">
447 <TargetExt>.dll</TargetExt> 527 <TargetExt>.dll</TargetExt>
448 <OutDir>$(SolutionDir)_Output\$(ProjectName)\$(PlatformName)\$(Configuration)\</OutDir> 528 <OutDir>$(SolutionDir)_Output\$(ProjectName)\$(PlatformName)\$(Configuration)\</OutDir>
@@ -459,6 +539,11 @@
459 <IntDir>$(SolutionDir)_Tmp\$(ProjectName)\$(PlatformName)\$(Configuration)\</IntDir> 539 <IntDir>$(SolutionDir)_Tmp\$(ProjectName)\$(PlatformName)\$(Configuration)\</IntDir>
460 <LinkIncremental>false</LinkIncremental> 540 <LinkIncremental>false</LinkIncremental>
461 </PropertyGroup> 541 </PropertyGroup>
542 <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release 5.5|x64'">
543 <OutDir>$(SolutionDir)_Output\$(ProjectName)\$(PlatformName)\$(Configuration)\</OutDir>
544 <IntDir>$(SolutionDir)_Tmp\$(ProjectName)\$(PlatformName)\$(Configuration)\</IntDir>
545 <LinkIncremental>false</LinkIncremental>
546 </PropertyGroup>
462 <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release 5.3|Win32'"> 547 <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release 5.3|Win32'">
463 <OutDir>$(SolutionDir)_Output\$(ProjectName)\$(PlatformName)\$(Configuration)\</OutDir> 548 <OutDir>$(SolutionDir)_Output\$(ProjectName)\$(PlatformName)\$(Configuration)\</OutDir>
464 <IntDir>$(SolutionDir)_Tmp\$(ProjectName)\$(PlatformName)\$(Configuration)\</IntDir> 549 <IntDir>$(SolutionDir)_Tmp\$(ProjectName)\$(PlatformName)\$(Configuration)\</IntDir>
@@ -469,6 +554,11 @@
469 <OutDir>$(SolutionDir)_Output\$(ProjectName)\$(PlatformName)\$(Configuration)\</OutDir> 554 <OutDir>$(SolutionDir)_Output\$(ProjectName)\$(PlatformName)\$(Configuration)\</OutDir>
470 <LinkIncremental>false</LinkIncremental> 555 <LinkIncremental>false</LinkIncremental>
471 </PropertyGroup> 556 </PropertyGroup>
557 <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release 5.5|Win32'">
558 <IntDir>$(SolutionDir)_Tmp\$(ProjectName)\$(PlatformName)\$(Configuration)\</IntDir>
559 <OutDir>$(SolutionDir)_Output\$(ProjectName)\$(PlatformName)\$(Configuration)\</OutDir>
560 <LinkIncremental>false</LinkIncremental>
561 </PropertyGroup>
472 <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release 5.3|x64'"> 562 <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release 5.3|x64'">
473 <ClCompile> 563 <ClCompile>
474 <WarningLevel>Level3</WarningLevel> 564 <WarningLevel>Level3</WarningLevel>
@@ -476,7 +566,7 @@
476 <ConformanceMode>true</ConformanceMode> 566 <ConformanceMode>true</ConformanceMode>
477 <AdditionalIncludeDirectories>$(SolutionDir)/_LuaVersions/$(PlatformName)/$(ConfigurationName)/include;$(SolutionDir)..</AdditionalIncludeDirectories> 567 <AdditionalIncludeDirectories>$(SolutionDir)/_LuaVersions/$(PlatformName)/$(ConfigurationName)/include;$(SolutionDir)..</AdditionalIncludeDirectories>
478 <ProgramDataBaseFileName>$(IntDir)$(TargetName).pdb</ProgramDataBaseFileName> 568 <ProgramDataBaseFileName>$(IntDir)$(TargetName).pdb</ProgramDataBaseFileName>
479 <PreprocessorDefinitions>_WINDLL;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions> 569 <PreprocessorDefinitions>LANES_DEBUG;_WINDLL;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
480 <LanguageStandard>stdcpp20</LanguageStandard> 570 <LanguageStandard>stdcpp20</LanguageStandard>
481 <OmitFramePointers>true</OmitFramePointers> 571 <OmitFramePointers>true</OmitFramePointers>
482 <BasicRuntimeChecks /> 572 <BasicRuntimeChecks />
@@ -501,7 +591,7 @@
501 <ConformanceMode>true</ConformanceMode> 591 <ConformanceMode>true</ConformanceMode>
502 <AdditionalIncludeDirectories>$(SolutionDir)/_LuaVersions/$(PlatformName)/$(ConfigurationName)/include;$(SolutionDir)..</AdditionalIncludeDirectories> 592 <AdditionalIncludeDirectories>$(SolutionDir)/_LuaVersions/$(PlatformName)/$(ConfigurationName)/include;$(SolutionDir)..</AdditionalIncludeDirectories>
503 <ProgramDataBaseFileName>$(IntDir)$(TargetName).pdb</ProgramDataBaseFileName> 593 <ProgramDataBaseFileName>$(IntDir)$(TargetName).pdb</ProgramDataBaseFileName>
504 <PreprocessorDefinitions>_WINDLL;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions> 594 <PreprocessorDefinitions>LANES_DEBUG;_WINDLL;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
505 <LanguageStandard>stdcpp20</LanguageStandard> 595 <LanguageStandard>stdcpp20</LanguageStandard>
506 <BasicRuntimeChecks /> 596 <BasicRuntimeChecks />
507 <RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary> 597 <RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary>
@@ -518,6 +608,31 @@
518 </Message> 608 </Message>
519 </PostBuildEvent> 609 </PostBuildEvent>
520 </ItemDefinitionGroup> 610 </ItemDefinitionGroup>
611 <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release 5.5|x64'">
612 <ClCompile>
613 <WarningLevel>Level3</WarningLevel>
614 <SDLCheck>true</SDLCheck>
615 <ConformanceMode>true</ConformanceMode>
616 <AdditionalIncludeDirectories>$(SolutionDir)/_LuaVersions/$(PlatformName)/$(ConfigurationName)/include;$(SolutionDir)..</AdditionalIncludeDirectories>
617 <ProgramDataBaseFileName>$(IntDir)$(TargetName).pdb</ProgramDataBaseFileName>
618 <PreprocessorDefinitions>LANES_DEBUG;_WINDLL;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
619 <LanguageStandard>stdcpp20</LanguageStandard>
620 <BasicRuntimeChecks>
621 </BasicRuntimeChecks>
622 <RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary>
623 </ClCompile>
624 <Link>
625 <EnableCOMDATFolding>true</EnableCOMDATFolding>
626 <OptimizeReferences>true</OptimizeReferences>
627 <AdditionalDependencies>lua55.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)</AdditionalDependencies>
628 <AdditionalLibraryDirectories>$(SolutionDir)_LuaVersions\$(PlatformName)\$(ConfigurationName)</AdditionalLibraryDirectories>
629 </Link>
630 <PostBuildEvent>
631 <Command>xcopy /F /I /R /Y "$(TargetPath)" "$(SolutionDir)_LuaVersions\$(PlatformName)\$(ConfigurationName)"</Command>
632 <Message>
633 </Message>
634 </PostBuildEvent>
635 </ItemDefinitionGroup>
521 <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug 5.3|Win32'"> 636 <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug 5.3|Win32'">
522 <ClCompile> 637 <ClCompile>
523 <WarningLevel>Level3</WarningLevel> 638 <WarningLevel>Level3</WarningLevel>
@@ -528,6 +643,7 @@
528 <ProgramDataBaseFileName>$(IntDir)$(TargetName).pdb</ProgramDataBaseFileName> 643 <ProgramDataBaseFileName>$(IntDir)$(TargetName).pdb</ProgramDataBaseFileName>
529 <LanguageStandard>stdcpp20</LanguageStandard> 644 <LanguageStandard>stdcpp20</LanguageStandard>
530 <DebugInformationFormat>ProgramDatabase</DebugInformationFormat> 645 <DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
646 <PreprocessorDefinitions>LANES_DEBUG;_WINDLL;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
531 </ClCompile> 647 </ClCompile>
532 <PostBuildEvent> 648 <PostBuildEvent>
533 <Command>xcopy /F /I /R /Y "$(TargetPath)" "$(SolutionDir)_LuaVersions\$(PlatformName)\$(ConfigurationName)"</Command> 649 <Command>xcopy /F /I /R /Y "$(TargetPath)" "$(SolutionDir)_LuaVersions\$(PlatformName)\$(ConfigurationName)"</Command>
@@ -550,6 +666,7 @@
550 <LanguageStandard>stdcpp20</LanguageStandard> 666 <LanguageStandard>stdcpp20</LanguageStandard>
551 <DebugInformationFormat>ProgramDatabase</DebugInformationFormat> 667 <DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
552 <OmitFramePointers>false</OmitFramePointers> 668 <OmitFramePointers>false</OmitFramePointers>
669 <PreprocessorDefinitions>LANES_DEBUG;_WINDLL;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
553 </ClCompile> 670 </ClCompile>
554 <PostBuildEvent> 671 <PostBuildEvent>
555 <Command>xcopy /F /I /R /Y "$(TargetPath)" "$(SolutionDir)_LuaVersions\$(PlatformName)\$(ConfigurationName)"</Command> 672 <Command>xcopy /F /I /R /Y "$(TargetPath)" "$(SolutionDir)_LuaVersions\$(PlatformName)\$(ConfigurationName)"</Command>
@@ -574,6 +691,7 @@
574 <Optimization>MaxSpeed</Optimization> 691 <Optimization>MaxSpeed</Optimization>
575 <RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary> 692 <RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary>
576 <BasicRuntimeChecks /> 693 <BasicRuntimeChecks />
694 <PreprocessorDefinitions>LANES_DEBUG;_WINDLL;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
577 </ClCompile> 695 </ClCompile>
578 <PostBuildEvent> 696 <PostBuildEvent>
579 <Command>xcopy /F /I /R /Y "$(TargetPath)" "$(SolutionDir)_LuaVersions\$(PlatformName)\$(ConfigurationName)"</Command> 697 <Command>xcopy /F /I /R /Y "$(TargetPath)" "$(SolutionDir)_LuaVersions\$(PlatformName)\$(ConfigurationName)"</Command>
@@ -597,6 +715,7 @@
597 <ProgramDataBaseFileName>$(IntDir)$(TargetName).pdb</ProgramDataBaseFileName> 715 <ProgramDataBaseFileName>$(IntDir)$(TargetName).pdb</ProgramDataBaseFileName>
598 <LanguageStandard>stdcpp20</LanguageStandard> 716 <LanguageStandard>stdcpp20</LanguageStandard>
599 <DebugInformationFormat>ProgramDatabase</DebugInformationFormat> 717 <DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
718 <PreprocessorDefinitions>LANES_DEBUG;_WINDLL;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
600 </ClCompile> 719 </ClCompile>
601 <PostBuildEvent> 720 <PostBuildEvent>
602 <Command>xcopy /F /I /R /Y "$(TargetPath)" "$(SolutionDir)_LuaVersions\$(PlatformName)\$(ConfigurationName)"</Command> 721 <Command>xcopy /F /I /R /Y "$(TargetPath)" "$(SolutionDir)_LuaVersions\$(PlatformName)\$(ConfigurationName)"</Command>
@@ -621,6 +740,7 @@
621 <OmitFramePointers>true</OmitFramePointers> 740 <OmitFramePointers>true</OmitFramePointers>
622 <RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary> 741 <RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary>
623 <BasicRuntimeChecks /> 742 <BasicRuntimeChecks />
743 <PreprocessorDefinitions>LANES_DEBUG;_WINDLL;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
624 </ClCompile> 744 </ClCompile>
625 <PostBuildEvent> 745 <PostBuildEvent>
626 <Command>xcopy /F /I /R /Y "$(TargetPath)" "$(SolutionDir)_LuaVersions\$(PlatformName)\$(ConfigurationName)"</Command> 746 <Command>xcopy /F /I /R /Y "$(TargetPath)" "$(SolutionDir)_LuaVersions\$(PlatformName)\$(ConfigurationName)"</Command>
@@ -642,7 +762,7 @@
642 <ConformanceMode>true</ConformanceMode> 762 <ConformanceMode>true</ConformanceMode>
643 <AdditionalIncludeDirectories>$(SolutionDir)/_LuaVersions/$(PlatformName)/$(ConfigurationName)/include;$(SolutionDir)..</AdditionalIncludeDirectories> 763 <AdditionalIncludeDirectories>$(SolutionDir)/_LuaVersions/$(PlatformName)/$(ConfigurationName)/include;$(SolutionDir)..</AdditionalIncludeDirectories>
644 <ProgramDataBaseFileName>$(IntDir)$(TargetName).pdb</ProgramDataBaseFileName> 764 <ProgramDataBaseFileName>$(IntDir)$(TargetName).pdb</ProgramDataBaseFileName>
645 <PreprocessorDefinitions>WIN32;NDEBUG;_CONSOLE;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions> 765 <PreprocessorDefinitions>LANES_DEBUG;_WINDLL;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
646 <LanguageStandard>stdcpp20</LanguageStandard> 766 <LanguageStandard>stdcpp20</LanguageStandard>
647 <DebugInformationFormat>ProgramDatabase</DebugInformationFormat> 767 <DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
648 <BasicRuntimeChecks /> 768 <BasicRuntimeChecks />
@@ -670,6 +790,29 @@
670 <ProgramDataBaseFileName>$(IntDir)$(TargetName).pdb</ProgramDataBaseFileName> 790 <ProgramDataBaseFileName>$(IntDir)$(TargetName).pdb</ProgramDataBaseFileName>
671 <LanguageStandard>stdcpp20</LanguageStandard> 791 <LanguageStandard>stdcpp20</LanguageStandard>
672 <DebugInformationFormat>ProgramDatabase</DebugInformationFormat> 792 <DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
793 <PreprocessorDefinitions>LANES_DEBUG;_WINDLL;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
794 </ClCompile>
795 <PostBuildEvent>
796 <Command>xcopy /F /I /R /Y "$(TargetPath)" "$(SolutionDir)_LuaVersions\$(PlatformName)\$(ConfigurationName)"</Command>
797 <Message>
798 </Message>
799 </PostBuildEvent>
800 <Link>
801 <AdditionalDependencies>lua54.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)</AdditionalDependencies>
802 <AdditionalLibraryDirectories>$(SolutionDir)_LuaVersions\$(PlatformName)\$(ConfigurationName)</AdditionalLibraryDirectories>
803 </Link>
804 </ItemDefinitionGroup>
805 <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug 5.5|Win32'">
806 <ClCompile>
807 <WarningLevel>Level3</WarningLevel>
808 <Optimization>Disabled</Optimization>
809 <SDLCheck>true</SDLCheck>
810 <ConformanceMode>true</ConformanceMode>
811 <AdditionalIncludeDirectories>$(SolutionDir)/_LuaVersions/$(PlatformName)/$(ConfigurationName)/include;$(SolutionDir)..</AdditionalIncludeDirectories>
812 <ProgramDataBaseFileName>$(IntDir)$(TargetName).pdb</ProgramDataBaseFileName>
813 <LanguageStandard>stdcpp20</LanguageStandard>
814 <DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
815 <PreprocessorDefinitions>LANES_DEBUG;_WINDLL;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
673 </ClCompile> 816 </ClCompile>
674 <PostBuildEvent> 817 <PostBuildEvent>
675 <Command>xcopy /F /I /R /Y "$(TargetPath)" "$(SolutionDir)_LuaVersions\$(PlatformName)\$(ConfigurationName)"</Command> 818 <Command>xcopy /F /I /R /Y "$(TargetPath)" "$(SolutionDir)_LuaVersions\$(PlatformName)\$(ConfigurationName)"</Command>
@@ -693,7 +836,7 @@
693 <DebugInformationFormat>ProgramDatabase</DebugInformationFormat> 836 <DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
694 <BasicRuntimeChecks /> 837 <BasicRuntimeChecks />
695 <RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary> 838 <RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary>
696 <PreprocessorDefinitions>_WINDLL;NDEBUG;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions> 839 <PreprocessorDefinitions>LANES_DEBUG;_WINDLL;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
697 </ClCompile> 840 </ClCompile>
698 <PostBuildEvent> 841 <PostBuildEvent>
699 <Command>xcopy /F /I /R /Y "$(TargetPath)" "$(SolutionDir)_LuaVersions\$(PlatformName)\$(ConfigurationName)"</Command> 842 <Command>xcopy /F /I /R /Y "$(TargetPath)" "$(SolutionDir)_LuaVersions\$(PlatformName)\$(ConfigurationName)"</Command>
@@ -714,7 +857,7 @@
714 <ConformanceMode>true</ConformanceMode> 857 <ConformanceMode>true</ConformanceMode>
715 <AdditionalIncludeDirectories>$(SolutionDir)/_LuaVersions/$(PlatformName)/$(ConfigurationName)/include;$(SolutionDir)..</AdditionalIncludeDirectories> 858 <AdditionalIncludeDirectories>$(SolutionDir)/_LuaVersions/$(PlatformName)/$(ConfigurationName)/include;$(SolutionDir)..</AdditionalIncludeDirectories>
716 <ProgramDataBaseFileName>$(IntDir)$(TargetName).pdb</ProgramDataBaseFileName> 859 <ProgramDataBaseFileName>$(IntDir)$(TargetName).pdb</ProgramDataBaseFileName>
717 <PreprocessorDefinitions>_WINDLL;_DEBUG;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions> 860 <PreprocessorDefinitions>LANES_DEBUG;_WINDLL;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
718 <LanguageStandard>stdcpp20</LanguageStandard> 861 <LanguageStandard>stdcpp20</LanguageStandard>
719 <DebugInformationFormat>ProgramDatabase</DebugInformationFormat> 862 <DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
720 <OmitFramePointers>false</OmitFramePointers> 863 <OmitFramePointers>false</OmitFramePointers>
@@ -736,7 +879,7 @@
736 <ConformanceMode>true</ConformanceMode> 879 <ConformanceMode>true</ConformanceMode>
737 <AdditionalIncludeDirectories>$(SolutionDir)/_LuaVersions/$(PlatformName)/$(ConfigurationName)/include;$(SolutionDir)..</AdditionalIncludeDirectories> 880 <AdditionalIncludeDirectories>$(SolutionDir)/_LuaVersions/$(PlatformName)/$(ConfigurationName)/include;$(SolutionDir)..</AdditionalIncludeDirectories>
738 <ProgramDataBaseFileName>$(IntDir)$(TargetName).pdb</ProgramDataBaseFileName> 881 <ProgramDataBaseFileName>$(IntDir)$(TargetName).pdb</ProgramDataBaseFileName>
739 <PreprocessorDefinitions>_WINDLL;_DEBUG;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions> 882 <PreprocessorDefinitions>LANES_DEBUG;_WINDLL;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
740 <LanguageStandard>stdcpp20</LanguageStandard> 883 <LanguageStandard>stdcpp20</LanguageStandard>
741 <DebugInformationFormat>ProgramDatabase</DebugInformationFormat> 884 <DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
742 <OmitFramePointers>false</OmitFramePointers> 885 <OmitFramePointers>false</OmitFramePointers>
@@ -758,7 +901,7 @@
758 <ConformanceMode>true</ConformanceMode> 901 <ConformanceMode>true</ConformanceMode>
759 <AdditionalIncludeDirectories>$(SolutionDir)/_LuaVersions/$(PlatformName)/$(ConfigurationName)/include;$(SolutionDir)..</AdditionalIncludeDirectories> 902 <AdditionalIncludeDirectories>$(SolutionDir)/_LuaVersions/$(PlatformName)/$(ConfigurationName)/include;$(SolutionDir)..</AdditionalIncludeDirectories>
760 <ProgramDataBaseFileName>$(IntDir)$(TargetName).pdb</ProgramDataBaseFileName> 903 <ProgramDataBaseFileName>$(IntDir)$(TargetName).pdb</ProgramDataBaseFileName>
761 <PreprocessorDefinitions>_WINDLL;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions> 904 <PreprocessorDefinitions>LANES_DEBUG;_WINDLL;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
762 <LanguageStandard>stdcpp20</LanguageStandard> 905 <LanguageStandard>stdcpp20</LanguageStandard>
763 <DebugInformationFormat>ProgramDatabase</DebugInformationFormat> 906 <DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
764 <OmitFramePointers>true</OmitFramePointers> 907 <OmitFramePointers>true</OmitFramePointers>
@@ -785,7 +928,7 @@
785 <ConformanceMode>true</ConformanceMode> 928 <ConformanceMode>true</ConformanceMode>
786 <AdditionalIncludeDirectories>$(SolutionDir)/_LuaVersions/$(PlatformName)/$(ConfigurationName)/include;$(SolutionDir)..</AdditionalIncludeDirectories> 929 <AdditionalIncludeDirectories>$(SolutionDir)/_LuaVersions/$(PlatformName)/$(ConfigurationName)/include;$(SolutionDir)..</AdditionalIncludeDirectories>
787 <ProgramDataBaseFileName>$(IntDir)$(TargetName).pdb</ProgramDataBaseFileName> 930 <ProgramDataBaseFileName>$(IntDir)$(TargetName).pdb</ProgramDataBaseFileName>
788 <PreprocessorDefinitions>_WINDLL;_DEBUG;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions> 931 <PreprocessorDefinitions>LANES_DEBUG;_WINDLL;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
789 <LanguageStandard>stdcpp20</LanguageStandard> 932 <LanguageStandard>stdcpp20</LanguageStandard>
790 <DebugInformationFormat>ProgramDatabase</DebugInformationFormat> 933 <DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
791 <OmitFramePointers>false</OmitFramePointers> 934 <OmitFramePointers>false</OmitFramePointers>
@@ -807,7 +950,7 @@
807 <ConformanceMode>true</ConformanceMode> 950 <ConformanceMode>true</ConformanceMode>
808 <AdditionalIncludeDirectories>$(SolutionDir)/_LuaVersions/$(PlatformName)/$(ConfigurationName)/include;$(SolutionDir)..</AdditionalIncludeDirectories> 951 <AdditionalIncludeDirectories>$(SolutionDir)/_LuaVersions/$(PlatformName)/$(ConfigurationName)/include;$(SolutionDir)..</AdditionalIncludeDirectories>
809 <ProgramDataBaseFileName>$(IntDir)$(TargetName).pdb</ProgramDataBaseFileName> 952 <ProgramDataBaseFileName>$(IntDir)$(TargetName).pdb</ProgramDataBaseFileName>
810 <PreprocessorDefinitions>_WINDLL;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions> 953 <PreprocessorDefinitions>LANES_DEBUG;_WINDLL;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
811 <LanguageStandard>stdcpp20</LanguageStandard> 954 <LanguageStandard>stdcpp20</LanguageStandard>
812 <DebugInformationFormat>ProgramDatabase</DebugInformationFormat> 955 <DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
813 <OmitFramePointers>true</OmitFramePointers> 956 <OmitFramePointers>true</OmitFramePointers>
@@ -834,7 +977,7 @@
834 <ConformanceMode>true</ConformanceMode> 977 <ConformanceMode>true</ConformanceMode>
835 <AdditionalIncludeDirectories>$(SolutionDir)/_LuaVersions/$(PlatformName)/$(ConfigurationName)/include;$(SolutionDir)..</AdditionalIncludeDirectories> 978 <AdditionalIncludeDirectories>$(SolutionDir)/_LuaVersions/$(PlatformName)/$(ConfigurationName)/include;$(SolutionDir)..</AdditionalIncludeDirectories>
836 <ProgramDataBaseFileName>$(IntDir)$(TargetName).pdb</ProgramDataBaseFileName> 979 <ProgramDataBaseFileName>$(IntDir)$(TargetName).pdb</ProgramDataBaseFileName>
837 <PreprocessorDefinitions>_WINDLL;NDEBUG;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions> 980 <PreprocessorDefinitions>LANES_DEBUG;_WINDLL;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
838 <LanguageStandard>stdcpp20</LanguageStandard> 981 <LanguageStandard>stdcpp20</LanguageStandard>
839 <DebugInformationFormat>ProgramDatabase</DebugInformationFormat> 982 <DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
840 <OmitFramePointers>false</OmitFramePointers> 983 <OmitFramePointers>false</OmitFramePointers>
@@ -860,7 +1003,7 @@
860 <ConformanceMode>true</ConformanceMode> 1003 <ConformanceMode>true</ConformanceMode>
861 <AdditionalIncludeDirectories>$(SolutionDir)/_LuaVersions/$(PlatformName)/$(ConfigurationName)/include;$(SolutionDir)..</AdditionalIncludeDirectories> 1004 <AdditionalIncludeDirectories>$(SolutionDir)/_LuaVersions/$(PlatformName)/$(ConfigurationName)/include;$(SolutionDir)..</AdditionalIncludeDirectories>
862 <ProgramDataBaseFileName>$(IntDir)$(TargetName).pdb</ProgramDataBaseFileName> 1005 <ProgramDataBaseFileName>$(IntDir)$(TargetName).pdb</ProgramDataBaseFileName>
863 <PreprocessorDefinitions>_WINDLL;_DEBUG;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions> 1006 <PreprocessorDefinitions>LANES_DEBUG;_WINDLL;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
864 <LanguageStandard>stdcpp20</LanguageStandard> 1007 <LanguageStandard>stdcpp20</LanguageStandard>
865 <DebugInformationFormat>ProgramDatabase</DebugInformationFormat> 1008 <DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
866 <OmitFramePointers>false</OmitFramePointers> 1009 <OmitFramePointers>false</OmitFramePointers>
@@ -875,6 +1018,28 @@
875 <AdditionalLibraryDirectories>$(SolutionDir)_LuaVersions\$(PlatformName)\$(ConfigurationName)</AdditionalLibraryDirectories> 1018 <AdditionalLibraryDirectories>$(SolutionDir)_LuaVersions\$(PlatformName)\$(ConfigurationName)</AdditionalLibraryDirectories>
876 </Link> 1019 </Link>
877 </ItemDefinitionGroup> 1020 </ItemDefinitionGroup>
1021 <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug 5.5|x64'">
1022 <ClCompile>
1023 <WarningLevel>Level3</WarningLevel>
1024 <SDLCheck>true</SDLCheck>
1025 <ConformanceMode>true</ConformanceMode>
1026 <AdditionalIncludeDirectories>$(SolutionDir)/_LuaVersions/$(PlatformName)/$(ConfigurationName)/include;$(SolutionDir)..</AdditionalIncludeDirectories>
1027 <ProgramDataBaseFileName>$(IntDir)$(TargetName).pdb</ProgramDataBaseFileName>
1028 <PreprocessorDefinitions>LANES_DEBUG;_WINDLL;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
1029 <LanguageStandard>stdcpp20</LanguageStandard>
1030 <DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
1031 <OmitFramePointers>false</OmitFramePointers>
1032 </ClCompile>
1033 <PostBuildEvent>
1034 <Command>xcopy /F /I /R /Y "$(TargetPath)" "$(SolutionDir)_LuaVersions\$(PlatformName)\$(ConfigurationName)"</Command>
1035 <Message>
1036 </Message>
1037 </PostBuildEvent>
1038 <Link>
1039 <AdditionalDependencies>lua55.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)</AdditionalDependencies>
1040 <AdditionalLibraryDirectories>$(SolutionDir)_LuaVersions\$(PlatformName)\$(ConfigurationName)</AdditionalLibraryDirectories>
1041 </Link>
1042 </ItemDefinitionGroup>
878 <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release MoonJIT|x64'"> 1043 <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release MoonJIT|x64'">
879 <ClCompile> 1044 <ClCompile>
880 <WarningLevel>Level3</WarningLevel> 1045 <WarningLevel>Level3</WarningLevel>
@@ -882,7 +1047,7 @@
882 <ConformanceMode>true</ConformanceMode> 1047 <ConformanceMode>true</ConformanceMode>
883 <AdditionalIncludeDirectories>$(SolutionDir)/_LuaVersions/$(PlatformName)/$(ConfigurationName)/include;$(SolutionDir)..</AdditionalIncludeDirectories> 1048 <AdditionalIncludeDirectories>$(SolutionDir)/_LuaVersions/$(PlatformName)/$(ConfigurationName)/include;$(SolutionDir)..</AdditionalIncludeDirectories>
884 <ProgramDataBaseFileName>$(IntDir)$(TargetName).pdb</ProgramDataBaseFileName> 1049 <ProgramDataBaseFileName>$(IntDir)$(TargetName).pdb</ProgramDataBaseFileName>
885 <PreprocessorDefinitions>_WINDLL;NDEBUG;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions> 1050 <PreprocessorDefinitions>LANES_DEBUG;_WINDLL;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
886 <LanguageStandard>stdcpp20</LanguageStandard> 1051 <LanguageStandard>stdcpp20</LanguageStandard>
887 <DebugInformationFormat>ProgramDatabase</DebugInformationFormat> 1052 <DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
888 <OmitFramePointers>false</OmitFramePointers> 1053 <OmitFramePointers>false</OmitFramePointers>
@@ -912,6 +1077,7 @@
912 <OmitFramePointers>true</OmitFramePointers> 1077 <OmitFramePointers>true</OmitFramePointers>
913 <BasicRuntimeChecks /> 1078 <BasicRuntimeChecks />
914 <RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary> 1079 <RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary>
1080 <PreprocessorDefinitions>LANES_DEBUG;_WINDLL;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
915 </ClCompile> 1081 </ClCompile>
916 <Link> 1082 <Link>
917 <EnableCOMDATFolding>true</EnableCOMDATFolding> 1083 <EnableCOMDATFolding>true</EnableCOMDATFolding>
@@ -938,6 +1104,7 @@
938 <LanguageStandard>stdcpp20</LanguageStandard> 1104 <LanguageStandard>stdcpp20</LanguageStandard>
939 <BasicRuntimeChecks /> 1105 <BasicRuntimeChecks />
940 <RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary> 1106 <RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary>
1107 <PreprocessorDefinitions>LANES_DEBUG;_WINDLL;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
941 </ClCompile> 1108 </ClCompile>
942 <Link> 1109 <Link>
943 <EnableCOMDATFolding>true</EnableCOMDATFolding> 1110 <EnableCOMDATFolding>true</EnableCOMDATFolding>
@@ -954,6 +1121,36 @@
954 </Message> 1121 </Message>
955 </PostBuildEvent> 1122 </PostBuildEvent>
956 </ItemDefinitionGroup> 1123 </ItemDefinitionGroup>
1124 <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release 5.5|Win32'">
1125 <ClCompile>
1126 <WarningLevel>Level3</WarningLevel>
1127 <Optimization>MaxSpeed</Optimization>
1128 <SDLCheck>true</SDLCheck>
1129 <ConformanceMode>true</ConformanceMode>
1130 <AdditionalIncludeDirectories>$(SolutionDir)/_LuaVersions/$(PlatformName)/$(ConfigurationName)/include;$(SolutionDir)..</AdditionalIncludeDirectories>
1131 <ProgramDataBaseFileName>$(IntDir)$(TargetName).pdb</ProgramDataBaseFileName>
1132 <LanguageStandard>stdcpp20</LanguageStandard>
1133 <BasicRuntimeChecks>
1134 </BasicRuntimeChecks>
1135 <RuntimeLibrary>MultiThreadedDLL</RuntimeLibrary>
1136 <PreprocessorDefinitions>LANES_DEBUG;_WINDLL;_CRT_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
1137 </ClCompile>
1138 <Link>
1139 <EnableCOMDATFolding>true</EnableCOMDATFolding>
1140 <OptimizeReferences>true</OptimizeReferences>
1141 <AdditionalDependencies>lua54.lib;kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies)</AdditionalDependencies>
1142 <AdditionalLibraryDirectories>$(SolutionDir)_LuaVersions\$(PlatformName)\$(ConfigurationName)</AdditionalLibraryDirectories>
1143 <ImageHasSafeExceptionHandlers>
1144 </ImageHasSafeExceptionHandlers>
1145 </Link>
1146 <PostBuildEvent>
1147 <Command>xcopy /F /I /R /Y "$(TargetPath)" "$(SolutionDir)_LuaVersions\$(PlatformName)\$(ConfigurationName)"</Command>
1148 </PostBuildEvent>
1149 <PostBuildEvent>
1150 <Message>
1151 </Message>
1152 </PostBuildEvent>
1153 </ItemDefinitionGroup>
957 <ItemGroup> 1154 <ItemGroup>
958 <ClCompile Include="..\src\compat.cpp" /> 1155 <ClCompile Include="..\src\compat.cpp" />
959 <ClCompile Include="..\src\deep.cpp" /> 1156 <ClCompile Include="..\src\deep.cpp" />
diff --git a/deep_userdata_example/deeptest.lua b/deep_userdata_example/deeptest.lua
index 37136cd..7e6ffd3 100644
--- a/deep_userdata_example/deeptest.lua
+++ b/deep_userdata_example/deeptest.lua
@@ -1,5 +1,5 @@
1local lanes = require("lanes").configure{ with_timers = false} 1local lanes = require("lanes").configure{ with_timers = false}
2local l = lanes.linda "my linda" 2local l = lanes.linda{name = "my linda"}
3 3
4local table_unpack = table.unpack or unpack -- Lua 5.1 support 4local table_unpack = table.unpack or unpack -- Lua 5.1 support
5 5
diff --git a/docs/index.html b/docs/index.html
index d0f3940..2e74495 100644
--- a/docs/index.html
+++ b/docs/index.html
@@ -38,6 +38,7 @@
38 <a href="#description">Description</a> &middot; 38 <a href="#description">Description</a> &middot;
39 <a href="#systems">Supported systems</a> &middot; 39 <a href="#systems">Supported systems</a> &middot;
40 <a href="#installing">Building and Installing</a> &middot; 40 <a href="#installing">Building and Installing</a> &middot;
41 <a href="#apicheatsheet">API Cheat sheet</a>
41 <a href="#embedding">Embedding</a> 42 <a href="#embedding">Embedding</a>
42 </p> 43 </p>
43 44
@@ -64,13 +65,13 @@
64 <font size="-1"> 65 <font size="-1">
65 <p> 66 <p>
66 <br /> 67 <br />
67 <i>Copyright &copy; 2007-24 Asko Kauppi, Benoit Germain. All rights reserved.</i> 68 <i>Copyright &copy; 2007-25 Asko Kauppi, Benoit Germain. All rights reserved.</i>
68 <br /> 69 <br />
69 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.
70 </p> 71 </p>
71 72
72 <p> 73 <p>
73 This document was revised on 17-Mar-25, and applies to version <tt>4.0.0</tt>. 74 This document was revised on 03-Jul-25, and applies to version <tt>4.0.0</tt>.
74 </p> 75 </p>
75 </font> 76 </font>
76 </center> 77 </center>
@@ -88,7 +89,7 @@
88 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.
89</p> 90</p>
90<p> 91<p>
91 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.
92</p> 93</p>
93<p> 94<p>
94 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.
@@ -105,7 +106,7 @@
105 <li>Threads can be given priorities.</li> 106 <li>Threads can be given priorities.</li>
106 <li>Lanes are cancellable, with proper cleanup.</li> 107 <li>Lanes are cancellable, with proper cleanup.</li>
107 <li>No Lua-side application level locking - ever!</li> 108 <li>No Lua-side application level locking - ever!</li>
108 <li>Several totally independant Lanes universes may coexist in an application, one per "master" Lua state.</li> 109 <li>Several totally independent Lanes universes may coexist in an application, one per "master" Lua state.</li>
109 </ul> 110 </ul>
110 111
111 112
@@ -116,7 +117,7 @@
116 <li>Sharing full userdata between states needs special C side preparations (-&gt; <A HREF="#deep_userdata">deep userdata</A> and -&gt; <A HREF="#clonable_userdata">clonable userdata</A>).</li> 117 <li>Sharing full userdata between states needs special C side preparations (-&gt; <A HREF="#deep_userdata">deep userdata</A> and -&gt; <A HREF="#clonable_userdata">clonable userdata</A>).</li>
117 <li>Network level parallelism not included.</li> 118 <li>Network level parallelism not included.</li>
118 <li>Multi-CPU is done with OS threads, not processes. A lane is a Lua full userdata, therefore it will exist only as long as the Lua state that created it still exists. Therefore, a lane won't continue execution after the main program's termination.</li> 119 <li>Multi-CPU is done with OS threads, not processes. A lane is a Lua full userdata, therefore it will exist only as long as the Lua state that created it still exists. Therefore, a lane won't continue execution after the main program's termination.</li>
119 <li>Just like independant Lua states, Lanes universes cannot communicate together.</li> 120 <li>Just like independent Lua states, Lanes universes cannot communicate together.</li>
120 </ul> 121 </ul>
121</p> 122</p>
122 123
@@ -169,6 +170,84 @@
169</pre> 170</pre>
170 171
171 172
173<!-- API reference +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
174 <hr/>
175 <h2 id="apicheatsheet">API Cheat sheet</h2>
176 <ul>
177 <li>
178 <tt>require "lanes"</tt>: to require Lanes
179 </li>
180 <li>
181 The <tt>lanes</tt> module
182 <ul>
183 <li><tt>lanes.cancel_error</tt>: a special error value returned from cancelled lanes</li>
184 <li><tt>lanes.collectgarbage()</tt>: trigger a GC cycle in all Keeper states</li>
185 <li><tt>lanes.configure()</tt>: configure Lanes</li>
186 <li><tt>lanes.coro()</tt>: start a coroutine-like lane</li>
187 <li><tt>lanes.finally()</tt>: install a function called on Lanes shutdown</li>
188 <li><tt>lanes.gen()</tt>: start a lane as a regular function</li>
189 <li><tt>lanes.genactomic()</tt>: obtain an atomic counter</li>
190 <li><tt>lanes.genlock()</tt>: obtain an atomic-like data stack</li>
191 <li><tt>lanes.linda()</tt>: create a Linda</li>
192 <li><tt>lanes.nameof()</tt>: find where a value exists</li>
193 <li><tt>lanes.thread_priority_range()</tt>: obtain the valid range of thread priorities</li>
194 <li><tt>lanes.now_secs()</tt>: obtain the current clock value</li>
195 <li><tt>lanes.register()</tt>: scan modules so that functions using them can be transferred</li>
196 <li><tt>lanes.set_thread_priority()</tt>: change thread priority</li>
197 <li><tt>lanes.set_thread_affinity()</tt>: change thread affinity</li>
198 <li><tt>lanes.threads()</tt>: obtain a list of all lanes</li>
199 <li><tt>lanes.sleep()</tt>: sleep for a given duration</li>
200 <li><tt>lanes.timer()</tt>: start a timer</li>
201 <li><tt>lanes.timers()</tt>: list active timers</li>
202 </ul>
203 </li>
204 <li>
205 Given some lane handle <tt>lane_h</tt>
206 <ul>
207 <li><tt>lane_h[]</tt>: wait for, and read the values returned by the lane</li>
208 <li><tt>lane_h:cancel()</tt>: request the lane to stop running</li>
209 <li><tt>lane_h.error_trace_level</tt>: current setting of error logging level</li>
210 <li><tt>lane_h:get_threadname()</tt>: read the thread name</li>
211 <li><tt>lane_h:join()</tt>: wait for the lane to close, reading the returned values</li>
212 <li><tt>lane_h:resume()</tt>: resume a coroutine Lane</li>
213 <li><tt>lane_h.status</tt>: current status of the lane</li>
214 </ul>
215 </li>
216 <li>
217 Inside the lane
218 <ul>
219 <li><tt>cancel_test()</tt>: check for cancellation requests</li>
220 <li><tt>lane_threadname()</tt>: read or change the name of the thread</li>
221 <li><tt>set_finalizer()</tt>: install a function called when the lane exits</li>
222 </ul>
223 </li>
224 <li>
225 Given some Linda <tt>l</tt>
226 <ul>
227 <li><tt>l:cancel()</tt>: mark a Linda for cancellation</li>
228 <li><tt>l:collectgarbage()</tt>: trigger a GC cycle in the Linda's Keeper state</li>
229 <li><tt>l:deep()</tt>: obtain a light userdata uniquely representing the Linda</li>
230 <li><tt>l:dump()</tt>: have information about slot contents</li>
231 <li><tt>l:count()</tt>: obtain a count of data items in slots</li>
232 <li><tt>l:get()</tt>: read data without consuming it</li>
233 <li><tt>l:limit()</tt>: cap the amount of transiting data</li>
234 <li><tt>l:receive()</tt>: read one item of data from multiple slots</li>
235 <li><tt>l:receive_batched()</tt>: read several item of data from a single slot</li>
236 <li><tt>l:restrict()</tt>: place a restraint on the operations that can be done on a slot</li>
237 <li><tt>l:send()</tt>: append data</li>
238 <li><tt>l:set()</tt>: replace the data</li>
239 <li><tt>l:wake()</tt>: manually wake blocking calls</li>
240 </ul>
241 </li>
242 <li>
243 embedding
244 <ul>
245 <li><tt>luaopen_lanes_embedded</tt>: manually initialize Lanes</li>
246 </ul>
247 </li>
248 </ul>
249
250
172<!-- embedding +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ --> 251<!-- embedding +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
173<hr/> 252<hr/>
174<h2 id="embedding">Embedding</h2> 253<h2 id="embedding">Embedding</h2>
@@ -271,7 +350,7 @@
271</p> 350</p>
272 351
273<p> 352<p>
274 <tt>lanes.configure</tt> accepts an optional options table as sole argument. 353 <tt>lanes.configure</tt> accepts an optional table as sole argument.
275 <table border="1" cellpadding="10" style="width:100%"> 354 <table border="1" cellpadding="10" style="width:100%">
276 <tr> 355 <tr>
277 <th style="width:15%">name</th> 356 <th style="width:15%">name</th>
@@ -337,6 +416,22 @@
337 </tr> 416 </tr>
338 417
339 <tr valign=top> 418 <tr valign=top>
419 <td id="linda_wake_period">
420 <code>.linda_wake_period</code>
421 </td>
422 <td>
423 number > 0
424 </td>
425 <td>
426 Sets the default period in seconds a linda will wake by itself during blocked operations. Default is never.<br />
427 When a Linda enters a blocking call (<tt>send()</tt>, <tt>receive()</tt>, <tt>receive_batched()</tt>, <tt>sleep()</tt>), it normally sleeps either until the operation completes
428 or the specified timeout expires. With this setting, the default behavior can be changed to wake periodically. This can help for example with timing issues where a lane is signalled
429 for cancellation, but a linda inside the lane was in the middle of processing an operation but did not actually start the wait. This can result in the signal to be ignored, thus
430 causing the Linda to wait out the full operation timeout before cancellation is processed.
431 </td>
432 </tr>
433
434 <tr valign=top>
340 <td id="nb_user_keepers"> 435 <td id="nb_user_keepers">
341 <code>.nb_user_keepers</code> 436 <code>.nb_user_keepers</code>
342 </td> 437 </td>
@@ -769,12 +864,13 @@
769 </tr> 864 </tr>
770 <tr valign=top> 865 <tr valign=top>
771 <td> 866 <td>
772 <code>.priority</code> 867 <code>.priority</code><br />
868 <code>.native_priority</code>
773 </td> 869 </td>
774 <td>integer</td> 870 <td>integer</td>
775 <td> 871 <td>
776 The priority of lanes generated in the range -3..+3 (default is 0). 872 <tt>priority</tt>: The priority of lanes in the range <tt>[-3,+3]</tt> (default is 0). These values are a mapping over the actual priority range of the underlying implementation.<br />
777 These values are a mapping over the actual priority range of the underlying implementation.<br /> 873 <tt>native_priority</tt>: The priority of lanes in a platform-dependent range. Use <a href="#priority"><tt>lanes.thread_priority_range()</tt></a> to query said range.
778 Implementation and dependability of priorities varies by platform. Especially Linux kernel 2.6 is not supporting priorities in user mode.<br /> 874 Implementation and dependability of priorities varies by platform. Especially Linux kernel 2.6 is not supporting priorities in user mode.<br />
779 A lane can also change its own thread priority dynamically with <a href="#priority"><tt>lanes.set_thread_priority()</tt></a>. 875 A lane can also change its own thread priority dynamically with <a href="#priority"><tt>lanes.set_thread_priority()</tt></a>.
780 </td> 876 </td>
@@ -797,7 +893,7 @@
797 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 />
798 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 />
799 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 />
800 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>.
801</p> 897</p>
802 898
803<p> 899<p>
@@ -826,8 +922,9 @@
826 </tr> 922 </tr>
827 </table> 923 </table>
828 924
829 Coroutine lanes function mostly like regular coroutines. They can use <tt>coroutine.yield()</tt> normally, in which case the yielded values can be obtained with regular lane indexing (see <a href="#results">Results and errors</a>).<br /> 925 Coroutine lanes function mostly like regular coroutines. They can use <tt>coroutine.yield()</tt> normally.<br />
830 A yielded coroutine lane has a <tt>"suspended"</tt> status. It can be resumed with <tt>lane_h:resume(values...)</tt>. 926 A yielded coroutine lane has a <tt>"suspended"</tt> status. It can be resumed with <tt>lane_h:resume(values...), which returns the yielded values</tt>.
927 The latter can also be the returned values of <tt>lane_h:join()</tt> or accessed by regular lane indexing (see <a href="#results">Results and errors</a>).<br />
831 <table border="1" bgcolor="#FFFFE0" cellpadding="10" style="width:50%"> 928 <table border="1" bgcolor="#FFFFE0" cellpadding="10" style="width:50%">
832 <tr> 929 <tr>
833 <td> 930 <td>
@@ -836,8 +933,8 @@
836 </tr> 933 </tr>
837 </table> 934 </table>
838 935
839 The reply values are returned to the lane body at the <tt>coroutine.yield()</tt> point.<br /> 936 Just like regulare coroutines, the reply values passed to <tt>h:resume()</tt> are returned to the lane body at the <tt>coroutine.yield()</tt> point.<br />
840 If the yielded values were previously obtained by lane indexing, <tt>resume()</tt> returns <tt>nil</tt>. 937 If a coroutine lane is suspended when it is joined either by indexing or <tt>lane_h:join()</tt>, active to-be-closed variables are closed at that point, and the Lane can no longer be resumed.
841</p> 938</p>
842<h3>Free running lanes</h3> 939<h3>Free running lanes</h3>
843 940
@@ -863,14 +960,17 @@
863 <table border="1" bgcolor="#E0E0FF" cellpadding="10" style="width:50%"> 960 <table border="1" bgcolor="#E0E0FF" cellpadding="10" style="width:50%">
864 <tr> 961 <tr>
865 <td> 962 <td>
866 <pre> lanes.set_thread_priority(prio)</pre> 963 <pre> prio_min, prio_max = lanes.thread_priority_range(prio [,"native"])</pre>
964 <pre> lanes.set_thread_priority(prio [,"native"])</pre>
867 </td> 965 </td>
868 </tr> 966 </tr>
869 </table> 967 </table>
870<p> 968<p>
871 Besides setting a default priority in the generator <a href="#generator_settings">settings</a>, each thread can change its own priority at will. This is also true for the main Lua state. 969 Besides setting a default priority in the generator <a href="#generator_settings">settings</a>, each thread can change its own priority at will. This is also true for the main Lua state.
872 <br /> 970 <br />
873 The priority must be in the range <tt>[-3,+3]</tt>. 971 <tt>lanes.thread_priority_range()</tt> returns the range of acceptable mapped values. If nothing is specified, should be <tt>[-3,3]</tt> or <tt>[0,3]</tt>, depending on the threading implementation.
972 <br />
973 <tt>lanes.thread_priority_range('native')</tt> returns the range of acceptable native values. The actual values are threading implementation dependent. And some implementations can only accept some values inside that range. YMMV.
874</p> 974</p>
875 975
876 976
@@ -1057,7 +1157,7 @@
1057</p> 1157</p>
1058 1158
1059<table border="1" bgcolor="#E0E0FF" cellpadding="10" style="width:50%"><tr><td><pre> 1159<table border="1" bgcolor="#E0E0FF" cellpadding="10" style="width:50%"><tr><td><pre>
1060 [...]|[nil,err,stack_tbl]= lane_h:join([timeout]) 1160 [true, ...]|[nil,err,stack_tbl]= lane_h:join([timeout])
1061</pre></td></tr></table> 1161</pre></td></tr></table>
1062 1162
1063<p> 1163<p>
@@ -1075,9 +1175,9 @@
1075 </ul> 1175 </ul>
1076 </li> 1176 </li>
1077 <li><tt>nil, "killed"</tt> if forcefully killed.</li> 1177 <li><tt>nil, "killed"</tt> if forcefully killed.</li>
1078 <li>The return values of the lane function. If the first return value is <tt>nil</tt> (or there is no return value), an error is raised, to make sure you can tell timeout and error cases apart from successful return.</li> 1178 <li><tt>true [, returned-values]</tt>: The return values of the lane function.</li>
1079 </ul> 1179 </ul>
1080 If the lane handle obtained from <tt>lanes.gen()</tt> is to-be-closed, closing the value will cause a call to <tt>join()</tt>. Since it is implicit, the lane body isn't forced to return non-<tt>nil</tt> in that case. 1180 If the lane handle obtained from <tt>lanes.gen()</tt> is to-be-closed, closing the value will cause a call to <tt>join()</tt>.
1081</p> 1181</p>
1082 1182
1083<table border=1 bgcolor="#FFFFE0" cellpadding="10" style="width:50%"><tr><td><pre> 1183<table border=1 bgcolor="#FFFFE0" cellpadding="10" style="width:50%"><tr><td><pre>
@@ -1107,7 +1207,7 @@
1107 b = f() 1207 b = f()
1108 c = f() 1208 c = f()
1109 1209
1110 sync_linda:receive(nil, sync_linda.batched, "done", 3) -- wait for 3 lanes to write something in "done" slot of sync_linda 1210 sync_linda:receive_batched(nil, "done", 3) -- wait for 3 lanes to write something in "done" slot of sync_linda
1111</pre></td></tr></table> 1211</pre></td></tr></table>
1112 1212
1113<!-- cancelling +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ --> 1213<!-- cancelling +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
@@ -1121,38 +1221,49 @@
1121</pre></td></tr></table> 1221</pre></td></tr></table>
1122 1222
1123<p> 1223<p>
1124 <tt>timeout</tt> is an optional number &gt= 0. Defaults to 0 if left unspecified or <tt>nil</tt>.
1125 <br />
1126 <tt>cancel()</tt> sends a cancellation request to the lane. 1224 <tt>cancel()</tt> sends a cancellation request to the lane.
1127 <br /> 1225 <p>
1128 First argument is a <tt>mode</tt> can be one of: 1226 Returns <tt>true, lane_h.status</tt> if lane was already done (in <tt>"done"</tt>, <tt>"error"</tt> or <tt>"cancelled"</tt> status), or the cancellation was fruitful within <tt>timeout_secs</tt> timeout period.<br />
1227 Returns <tt>false, "timeout"</tt> otherwise.
1228 </p>
1229 First argument is a <tt>mode</tt>. It can be one of:
1129 <ul> 1230 <ul>
1130 <li> 1231 <li>
1131 <tt>"soft"</tt>: Cancellation will only cause <tt>cancel_test()</tt> to return <tt>true</tt>, so that the lane can cleanup manually. 1232 <tt>"soft"</tt>: Cancellation will only cause <tt>cancel_test()</tt> to return <tt>"soft"</tt>, so that the lane can cleanup manually.
1233 <br />
1234 Lindas will also check for cancellation inside blocking calls to early out based on their <tt>wake_period</tt>.
1132 </li> 1235 </li>
1133 <li> 1236 <li>
1134 <tt>"hard"</tt>: waits for the request to be processed, or a timeout to occur. <a href="#lindas">linda</a> operations detecting the cancellation request will raise a special cancellation error (meaning they won't return in that case).<br /> 1237 <tt>"hard"</tt>: waits for the request to be processed, or a timeout to occur. <a href="#lindas">linda</a> operations detecting the cancellation request will raise a special cancellation error (meaning they won't return in that case).
1238 <br />
1239 If the lane isn't actually waiting on a Linda when the request is issued, a lane calling <tt>cancel_test()</tt> will see it return <tt>"hard"</tt>.
1240 <br />
1135 <tt>wake_lane</tt> defaults to <tt>true</tt>, and <tt>timeout</tt> defaults to 0 if not specified. 1241 <tt>wake_lane</tt> defaults to <tt>true</tt>, and <tt>timeout</tt> defaults to 0 if not specified.
1136 </li> 1242 </li>
1137 <li> 1243 <li>
1138 <tt>"call"</tt>, <tt>"ret"</tt>, <tt>"line"</tt>, <tt>"count"</tt>: Asynchronously install the corresponding hook, then behave as <tt>"hard"</tt>. 1244 <tt>"call"</tt>, <tt>"ret"</tt>, <tt>"line"</tt>, <tt>"count"</tt>: Asynchronously install the corresponding hook, then behave as <tt>"hard"</tt>.
1245 <br />
1246 If the lane has the opportunity to call <tt>cancel_test()</tt> before the hook is invoked, calling <tt>cancel_test()</tt> will see it return <tt>"hard"</tt>.
1139 </li> 1247 </li>
1140 <li> 1248 <li>
1141 <tt>"all"</tt>: Installs all hooks in one shot, just to be sure. 1249 <tt>"all"</tt>: Installs all hooks in one shot, just to be sure.
1142 </li> 1250 </li>
1143 </ul> 1251 </ul>
1144 If <tt>mode</tt> is not specified, it defaults to <tt>"hard"</tt>. 1252 <p>
1253 If <tt>mode</tt> is not specified, it defaults to <tt>"hard"</tt>.
1254 </p>
1255</p>
1256<p>
1145 If <tt>wake_lane</tt> is <tt>true</tt>, the lane is also signalled so that execution returns from any pending <a href="#lindas">linda</a> operation. <a href="#lindas">linda</a> operations detecting the cancellation request return <tt>lanes.cancel_error</tt>. 1257 If <tt>wake_lane</tt> is <tt>true</tt>, the lane is also signalled so that execution returns from any pending <a href="#lindas">linda</a> operation. <a href="#lindas">linda</a> operations detecting the cancellation request return <tt>lanes.cancel_error</tt>.
1146</p> 1258</p>
1147<p> 1259<p>
1148 Returns <tt>true, lane_h.status</tt> if lane was already done (in <tt>"done"</tt>, <tt>"error"</tt> or <tt>"cancelled"</tt> status), or the cancellation was fruitful within <tt>timeout_secs</tt> timeout period.<br /> 1260 <tt>timeout</tt> is an optional number &gt= 0. Defaults to infinite if left unspecified or <tt>nil</tt>.
1149 Returns <tt>false, "timeout"</tt> otherwise.
1150</p> 1261</p>
1151<p> 1262<p>
1152 If the lane is still running after the timeout expired, there is a chance lanes will freeze forever at shutdown when failing to terminate all free-running lanes within the specified timeout. 1263 If the lane is still running after the timeout expired, there is a chance lanes will freeze forever at shutdown when failing to terminate all free-running lanes within the specified timeout.
1153</p> 1264</p>
1154<p> 1265<p>
1155 Cancellation is tested <u>before</u> going to sleep in <tt>receive()</tt> or <tt>send()</tt> calls and after executing <tt>cancelstep</tt> Lua statements. A pending <tt>receive()</tt>or <tt>send()</tt> call is awakened. 1266 Cancellation is tested <u>before</u> going to sleep in <tt>receive()</tt>, <tt>receive_batched()</tt> or <tt>send()</tt> calls and after executing <tt>cancelstep</tt> Lua statements. A pending <tt>receive()</tt>or <tt>send()</tt> call is awakened.
1156 <br /> 1267 <br />
1157 This means the execution of the lane will resume although the operation has not completed, to give the lane a chance to detect cancellation (even in the case the code waits on a <a href="#lindas">linda</a> with infinite timeout). 1268 This means the execution of the lane will resume although the operation has not completed, to give the lane a chance to detect cancellation (even in the case the code waits on a <a href="#lindas">linda</a> with infinite timeout).
1158 <br /> 1269 <br />
@@ -1222,7 +1333,7 @@
1222<table border="1" bgcolor="#FFFFE0" cellpadding="10" style="width:50%"><tr><td><pre> 1333<table border="1" bgcolor="#FFFFE0" cellpadding="10" style="width:50%"><tr><td><pre>
1223 local lanes = require "lanes" 1334 local lanes = require "lanes"
1224 1335
1225 local linda = lanes.linda("my linda") 1336 local linda = lanes.linda{name = "my linda"}
1226 1337
1227 local function loop(max) 1338 local function loop(max)
1228 for i = 1, max do 1339 for i = 1, max do
@@ -1260,7 +1371,7 @@
1260 <li>Two producer-side methods: <tt>:send</tt> and <tt>:set</tt> (not out).</li> 1371 <li>Two producer-side methods: <tt>:send</tt> and <tt>:set</tt> (not out).</li>
1261 <li><tt>send</tt> allows for sending multiple values -atomically- to a given slot.</li> 1372 <li><tt>send</tt> allows for sending multiple values -atomically- to a given slot.</li>
1262 <li><tt>receive</tt> can wait for multiple slots at once.</li> 1373 <li><tt>receive</tt> can wait for multiple slots at once.</li>
1263 <li><tt>receive</tt> has a batched mode to consume more than one value from a single slot, as in <tt>linda:receive(1.0, linda.batched, "slot", 3, 6).</tt></li> 1374 <li><tt>receive_batched</tt> can be used to consume more than one value from a single slot, as in <tt>linda:receive_batched(1.0, "slot", 3, 6).</tt></li>
1264 <li><tt>restrict</tt> can restrain a particular slot to function either with <tt>send/receive</tt> or <tt>set/get</tt>.</li> 1375 <li><tt>restrict</tt> can restrain a particular slot to function either with <tt>send/receive</tt> or <tt>set/get</tt>.</li>
1265 <li>Individual slots' queue length can be limited, balancing speed differences in a producer/consumer scenario (making <tt>:send</tt> wait).</li> 1376 <li>Individual slots' queue length can be limited, balancing speed differences in a producer/consumer scenario (making <tt>:send</tt> wait).</li>
1266 <li><tt>tostring(linda)</tt> returns a string of the form <tt>"Linda: &lt;opt_name&gt;"</tt></li> 1377 <li><tt>tostring(linda)</tt> returns a string of the form <tt>"Linda: &lt;opt_name&gt;"</tt></li>
@@ -1276,16 +1387,24 @@
1276</p> 1387</p>
1277 1388
1278<table border="1" bgcolor="#E0E0FF" cellpadding="10" style="width:50%"><tr><td><pre> 1389<table border="1" bgcolor="#E0E0FF" cellpadding="10" style="width:50%"><tr><td><pre>
1279 h = lanes.linda([name],[group],[close_handler]) 1390 h = lanes.linda(table|nil)
1280</pre></td></tr></table> 1391</pre></td></tr></table>
1281 1392
1282<p> 1393<p>
1283 Arguments to <tt>lanes.linda()</tt> can be provided in any order, as long as there is a single string, a single number, and a single callable value (all are optional).<br /> 1394 Argument to <tt>lanes.linda()</tt> is either <tt>nil</tt> or a single table. The table may contain the following entries:
1284 Converting the linda to a string will yield the provided name prefixed by <tt>"Linda: "</tt>.<br /> 1395 <ul>
1285 If <tt>opt_name</tt> is omitted, it will evaluate to an hexadecimal number uniquely representing that linda when the linda is converted to a string. The value is the same as returned by <tt>linda:deep()</tt>.<br /> 1396 <li><tt>close_handler</tt>: a callable object (function or table/userdata with <tt>__call</tt> metamethod). If provided, and the linda is to-be-closed (Lua 5.4+), it will be called with all the provided arguments. For older Lua versions, its presence is ignored.</li>
1286 If <tt>opt_name</tt> is <tt>"auto"</tt>, Lanes will try to construct a name from the source location that called <tt>lanes.linda()</tt>. If that fails, the linda name will be <tt>"&lt;unresolved&gt;"</tt>.<br /> 1397 <li><tt>group</tt>: an integer between 0 and the number of Keeper states. Mandatory if Lanes is configured with more than one Keeper state. Group 0 is used by the internal timer linda.</li>
1287 If Lanes is configured with more than one Keeper state, <tt>group</tt> is mandatory.<br /> 1398 <li>
1288 If the linda is to-be-closed (Lua 5.4+), and a <tt>close_handler</tt> is provided, it will be called with all the provided arguments. For older Lua versions, its presence will cause an error. 1399 <tt>name</tt>: a string. Converting the linda to a string will yield the provided name prefixed by <tt>"Linda: "</tt>.
1400 If omitted or empty, it will evaluate to the string representation of a hexadecimal number uniquely representing that linda when the linda is converted to a string. The numeric value is the same as returned by <tt>linda:deep()</tt>.<br />
1401 If <tt>"auto"</tt>, Lanes will try to construct a name from the source location that called <tt>lanes.linda()</tt>. If that fails, the linda name will be <tt>"&lt;unresolved&gt;"</tt>.
1402 </li>
1403 <li>
1404 <tt>wake_period</tt>: a number > 0 (unit: seconds). If provided, overrides <a href="#linda_wake_period"><tt>linda_wake_period</tt></a> provided to <a href="#initialization"><tt>lanes.configure()</tt></a>.
1405 </li>
1406 </ul>
1407 Unknown fields are silently ignored.
1289</p> 1408</p>
1290 1409
1291<table border="1" bgcolor="#E0E0FF" cellpadding="10" style="width:50%"><tr><td><pre> 1410<table border="1" bgcolor="#E0E0FF" cellpadding="10" style="width:50%"><tr><td><pre>
@@ -1349,12 +1468,12 @@
1349<table border="1" bgcolor="#E0E0FF" cellpadding="10" style="width:50%"><tr><td><pre> 1468<table border="1" bgcolor="#E0E0FF" cellpadding="10" style="width:50%"><tr><td><pre>
1350 slot, val = h:receive([timeout_secs,] slot [, slot...]) 1469 slot, val = h:receive([timeout_secs,] slot [, slot...])
1351 1470
1352 slot, val [, val...] = h:receive([timeout,] h.batched, slot, n_uint_min[, n_uint_max]) 1471 slot, val [, val...] = h:receive_batched([timeout,] slot, n_uint_min[, n_uint_max])
1353</pre></td></tr></table> 1472</pre></td></tr></table>
1354 1473
1355<p> 1474<p>
1356 <tt>receive()</tt> raises an error if called when a restriction forbids its use on any provided slot.<br /> 1475 <tt>receive()</tt> and <tt>receive_batched()</tt> raise an error if called when a restriction forbids their use on any provided slot.<br />
1357 In batched mode, <tt>receive()</tt> will raise an error if <tt>min_count < 1</tt> or <tt>max_count < min_count</tt>. 1476 <tt>receive_batched()</tt> will raise an error if <tt>min_count < 1</tt> or <tt>max_count < min_count</tt>.
1358</p> 1477</p>
1359 1478
1360<p> 1479<p>
diff --git a/lanes-4.0.0-0.rockspec b/lanes-4.0.0-0.rockspec
index 77e0f6a..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 = {
@@ -56,7 +56,7 @@ build = {
56 }, 56 },
57 modules = 57 modules =
58 { 58 {
59 ["lanes.core"] = 59 ["lanes_core"] =
60 { 60 {
61 sources = 61 sources =
62 { 62 {
diff --git a/src/_pch.hpp b/src/_pch.hpp
index 495a959..a77b7f5 100644
--- a/src/_pch.hpp
+++ b/src/_pch.hpp
@@ -1,5 +1,3 @@
1#pragma once
2
3#include <algorithm> 1#include <algorithm>
4#include <array> 2#include <array>
5#include <atomic> 3#include <atomic>
@@ -9,6 +7,7 @@
9#include <compare> 7#include <compare>
10#include <concepts> 8#include <concepts>
11#include <condition_variable> 9#include <condition_variable>
10#include <cstring>
12#include <functional> 11#include <functional>
13#include <iostream> 12#include <iostream>
14#ifndef __PROSPERO__ 13#ifndef __PROSPERO__
@@ -19,6 +18,7 @@
19#include <ranges> 18#include <ranges>
20#include <source_location> 19#include <source_location>
21//#include <stop_token> 20//#include <stop_token>
21#include <span>
22#include <string_view> 22#include <string_view>
23#include <thread> 23#include <thread>
24#include <tuple> 24#include <tuple>
diff --git a/src/allocator.cpp b/src/allocator.cpp
index 84acde5..243583b 100644
--- a/src/allocator.cpp
+++ b/src/allocator.cpp
@@ -35,7 +35,7 @@ namespace lanes
35{ 35{
36 AllocatorDefinition& AllocatorDefinition::Validated(lua_State* const L_, StackIndex const idx_) 36 AllocatorDefinition& AllocatorDefinition::Validated(lua_State* const L_, StackIndex const idx_)
37 { 37 {
38 lanes::AllocatorDefinition* const _def{ luaG_tofulluserdata<lanes::AllocatorDefinition>(L_, idx_) }; 38 lanes::AllocatorDefinition* const _def{ luaW_tofulluserdata<lanes::AllocatorDefinition>(L_, idx_) };
39 // raise an error and don't return if the full userdata at the specified index is not a valid AllocatorDefinition 39 // raise an error and don't return if the full userdata at the specified index is not a valid AllocatorDefinition
40 if (!_def) { 40 if (!_def) {
41 raise_luaL_error(L_, "Bad config.allocator function, provided value is not a userdata"); 41 raise_luaL_error(L_, "Bad config.allocator function, provided value is not a userdata");
diff --git a/src/allocator.hpp b/src/allocator.hpp
index c073391..b578f12 100644
--- a/src/allocator.hpp
+++ b/src/allocator.hpp
@@ -33,6 +33,8 @@ namespace lanes {
33 // can't actually delete the operator because the compiler generates stack unwinding code that could call it in case of exception 33 // can't actually delete the operator because the compiler generates stack unwinding code that could call it in case of exception
34 static void operator delete([[maybe_unused]] void* const p_, [[maybe_unused]] lua_State* const L_) {} 34 static void operator delete([[maybe_unused]] void* const p_, [[maybe_unused]] lua_State* const L_) {}
35 35
36 ~AllocatorDefinition() = default;
37
36 AllocatorDefinition(lua_Alloc const allocF_, void* const allocUD_) noexcept 38 AllocatorDefinition(lua_Alloc const allocF_, void* const allocUD_) noexcept
37 : allocF{ allocF_ } 39 : allocF{ allocF_ }
38 , allocUD{ allocUD_ } 40 , allocUD{ allocUD_ }
@@ -64,7 +66,7 @@ namespace lanes {
64 [[nodiscard]] 66 [[nodiscard]]
65 lua_State* newState() const 67 lua_State* newState() const
66 { 68 {
67 return lua_newstate(allocF, allocUD); 69 return luaW_newstate(allocF, allocUD, luaL_makeseed(nullptr));
68 } 70 }
69 71
70 [[nodiscard]] 72 [[nodiscard]]
diff --git a/src/cancel.cpp b/src/cancel.cpp
index 5bba9fc..6812b0d 100644
--- a/src/cancel.cpp
+++ b/src/cancel.cpp
@@ -38,6 +38,53 @@ THE SOFTWARE.
38#include "debugspew.hpp" 38#include "debugspew.hpp"
39#include "lane.hpp" 39#include "lane.hpp"
40 40
41namespace {
42 namespace local {
43
44 // #########################################################################################
45 // #########################################################################################
46
47 [[nodiscard]]
48 static std::optional<CancelOp> WhichCancelOp(std::string_view const& opString_)
49 {
50 if (opString_ == "soft") {
51 return std::make_optional<CancelOp>(CancelRequest::Soft, LuaHookMask::None);
52 } else if (opString_ == "hard") {
53 return std::make_optional<CancelOp>(CancelRequest::Hard, LuaHookMask::None);
54 } else if (opString_ == "call") {
55 return std::make_optional<CancelOp>(CancelRequest::Hard, LuaHookMask::Call);
56 } else if (opString_ == "ret") {
57 return std::make_optional<CancelOp>(CancelRequest::Hard, LuaHookMask::Ret);
58 } else if (opString_ == "line") {
59 return std::make_optional<CancelOp>(CancelRequest::Hard, LuaHookMask::Line);
60 } else if (opString_ == "count") {
61 return std::make_optional<CancelOp>(CancelRequest::Hard, LuaHookMask::Count);
62 } else if (opString_ == "all") {
63 return std::make_optional<CancelOp>(CancelRequest::Hard, LuaHookMask::All);
64 }
65 return std::nullopt;
66 }
67
68 // #########################################################################################
69
70 [[nodiscard]]
71 static CancelOp WhichCancelOp(lua_State* const L_, StackIndex const idx_)
72 {
73 if (luaW_type(L_, idx_) == LuaType::STRING) {
74 std::string_view const _str{ luaW_tostring(L_, idx_) };
75 auto const _op{ WhichCancelOp(_str) };
76 lua_remove(L_, idx_); // argument is processed, remove it
77 if (!_op.has_value()) {
78 raise_luaL_error(L_, "Invalid cancel operation '%s'", _str.data());
79 }
80 return _op.value();
81 }
82 return CancelOp{ CancelRequest::Hard, LuaHookMask::None };
83 }
84
85 } // namespace local
86} // namespace
87
41// ################################################################################################# 88// #################################################################################################
42// ################################################################################################# 89// #################################################################################################
43 90
@@ -60,66 +107,6 @@ CancelRequest CheckCancelRequest(lua_State* const L_)
60 107
61// ################################################################################################# 108// #################################################################################################
62// ################################################################################################# 109// #################################################################################################
63
64//---
65// = lane_cancel( lane_ud [,timeout_secs=0.0] [,wake_lindas_bool=false] )
66//
67// The originator thread asking us specifically to cancel the other thread.
68//
69// 'timeout': <0: wait forever, until the lane is finished
70// 0.0: just signal it to cancel, no time waited
71// >0: time to wait for the lane to detect cancellation
72//
73// 'wake_lindas_bool': if true, signal any linda the thread is waiting on
74// instead of waiting for its timeout (if any)
75//
76// Returns: true if the lane was already finished (Done/Error/Cancelled) or if we
77// managed to cancel it.
78// false if the cancellation timed out, or a kill was needed.
79//
80
81// #################################################################################################
82// #################################################################################################
83
84static std::optional<CancelOp> WhichCancelOp(std::string_view const& opString_)
85{
86 if (opString_ == "soft") {
87 return std::make_optional<CancelOp>(CancelRequest::Soft, LuaHookMask::None);
88 } else if (opString_ == "hard") {
89 return std::make_optional<CancelOp>(CancelRequest::Hard, LuaHookMask::None);
90 } else if (opString_== "call") {
91 return std::make_optional<CancelOp>(CancelRequest::Hard, LuaHookMask::Call);
92 } else if (opString_ == "ret") {
93 return std::make_optional<CancelOp>(CancelRequest::Hard, LuaHookMask::Ret);
94 } else if (opString_ == "line") {
95 return std::make_optional<CancelOp>(CancelRequest::Hard, LuaHookMask::Line);
96 } else if (opString_ == "count") {
97 return std::make_optional<CancelOp>(CancelRequest::Hard, LuaHookMask::Count);
98 } else if (opString_ == "all") {
99 return std::make_optional<CancelOp>(CancelRequest::Hard, LuaHookMask::All);
100 }
101 return std::nullopt;
102}
103
104// #################################################################################################
105
106[[nodiscard]]
107static CancelOp WhichCancelOp(lua_State* const L_, StackIndex const idx_)
108{
109 if (luaG_type(L_, idx_) == LuaType::STRING) {
110 std::string_view const _str{ luaG_tostring(L_, idx_) };
111 auto const _op{ WhichCancelOp(_str) };
112 lua_remove(L_, idx_); // argument is processed, remove it
113 if (!_op.has_value()) {
114 raise_luaL_error(L_, "Invalid cancel operation '%s'", _str.data());
115 }
116 return _op.value();
117 }
118 return CancelOp{ CancelRequest::Hard, LuaHookMask::None };
119}
120
121// #################################################################################################
122// #################################################################################################
123// ######################################### Lua API ############################################### 110// ######################################### Lua API ###############################################
124// ################################################################################################# 111// #################################################################################################
125// ################################################################################################# 112// #################################################################################################
@@ -133,24 +120,45 @@ static CancelOp WhichCancelOp(lua_State* const L_, StackIndex const idx_)
133LUAG_FUNC(cancel_test) 120LUAG_FUNC(cancel_test)
134{ 121{
135 CancelRequest const _test{ CheckCancelRequest(L_) }; 122 CancelRequest const _test{ CheckCancelRequest(L_) };
136 lua_pushboolean(L_, _test != CancelRequest::None); 123 if (_test == CancelRequest::None) {
124 lua_pushboolean(L_, 0);
125 } else {
126 luaW_pushstring(L_, (_test == CancelRequest::Soft) ? "soft" : "hard");
127 }
137 return 1; 128 return 1;
138} 129}
139 130
140// ################################################################################################# 131// #################################################################################################
141 132
133//---
134// = lane_cancel( lane_ud [,timeout_secs=0.0] [,wake_lindas_bool=false] )
135//
136// The originator thread asking us specifically to cancel the other thread.
137//
138// 'timeout': <0: wait forever, until the lane is finished
139// 0.0: just signal it to cancel, no time waited
140// >0: time to wait for the lane to detect cancellation
141//
142// 'wake_lindas_bool': if true, signal any linda the thread is waiting on
143// instead of waiting for its timeout (if any)
144//
145// Returns: true if the lane was already finished (Done/Error/Cancelled) or if we
146// managed to cancel it.
147// false if the cancellation timed out, or a kill was needed.
148//
149
142// bool[,reason] = lane_h:cancel( [cancel_op, hookcount] [, timeout] [, wake_lane]) 150// bool[,reason] = lane_h:cancel( [cancel_op, hookcount] [, timeout] [, wake_lane])
143LUAG_FUNC(lane_cancel) 151LUAG_FUNC(lane_cancel)
144{ 152{
145 Lane* const _lane{ ToLane(L_, StackIndex{ 1 }) }; // L_: lane [cancel_op, hookcount] [, timeout] [, wake_lane] 153 Lane* const _lane{ ToLane(L_, StackIndex{ 1 }) }; // L_: lane [cancel_op, hookcount] [, timeout] [, wake_lane]
146 CancelOp const _op{ WhichCancelOp(L_, StackIndex{ 2 }) }; // L_: lane [hookcount] [, timeout] [, wake_lane] 154 CancelOp const _op{ local::WhichCancelOp(L_, StackIndex{ 2 }) }; // L_: lane [hookcount] [, timeout] [, wake_lane]
147 155
148 int const _hook_count{ std::invoke([_op, L_]() { 156 int const _hook_count{ std::invoke([_op, L_]() {
149 if (_op.hookMask == LuaHookMask::None) { 157 if (_op.hookMask == LuaHookMask::None) {
150 // the caller shouldn't have provided a hook count in that case 158 // the caller shouldn't have provided a hook count in that case
151 return 0; 159 return 0;
152 } 160 }
153 if (luaG_type(L_, StackIndex{ 2 }) != LuaType::NUMBER) { 161 if (luaW_type(L_, StackIndex{ 2 }) != LuaType::NUMBER) {
154 raise_luaL_error(L_, "Hook count expected"); 162 raise_luaL_error(L_, "Hook count expected");
155 } 163 }
156 auto const _hook_count{ static_cast<int>(lua_tointeger(L_, 2)) }; 164 auto const _hook_count{ static_cast<int>(lua_tointeger(L_, 2)) };
@@ -162,7 +170,7 @@ LUAG_FUNC(lane_cancel)
162 }) }; 170 }) };
163 171
164 std::chrono::time_point<std::chrono::steady_clock> _until{ std::chrono::time_point<std::chrono::steady_clock>::max() }; 172 std::chrono::time_point<std::chrono::steady_clock> _until{ std::chrono::time_point<std::chrono::steady_clock>::max() };
165 if (luaG_type(L_, StackIndex{ 2 }) == LuaType::NUMBER) { // we don't want to use lua_isnumber() because of autocoercion 173 if (luaW_type(L_, StackIndex{ 2 }) == LuaType::NUMBER) { // we don't want to use lua_isnumber() because of autocoercion
166 lua_Duration const duration{ lua_tonumber(L_, 2) }; 174 lua_Duration const duration{ lua_tonumber(L_, 2) };
167 if (duration.count() >= 0.0) { 175 if (duration.count() >= 0.0) {
168 _until = std::chrono::steady_clock::now() + std::chrono::duration_cast<std::chrono::steady_clock::duration>(duration); 176 _until = std::chrono::steady_clock::now() + std::chrono::duration_cast<std::chrono::steady_clock::duration>(duration);
@@ -178,7 +186,7 @@ LUAG_FUNC(lane_cancel)
178 WakeLane _wake_lane{ (_op.mode == CancelRequest::Hard) ? WakeLane::Yes : WakeLane::No }; 186 WakeLane _wake_lane{ (_op.mode == CancelRequest::Hard) ? WakeLane::Yes : WakeLane::No };
179 if (lua_gettop(L_) >= 2) { 187 if (lua_gettop(L_) >= 2) {
180 if (!lua_isboolean(L_, 2)) { 188 if (!lua_isboolean(L_, 2)) {
181 raise_luaL_error(L_, "Boolean expected for wake_lane argument, got %s", luaG_typename(L_, StackIndex{ 2 }).data()); 189 raise_luaL_error(L_, "Boolean expected for wake_lane argument, got %s", luaW_typename(L_, StackIndex{ 2 }).data());
182 } 190 }
183 _wake_lane = lua_toboolean(L_, 2) ? WakeLane::Yes : WakeLane::No; 191 _wake_lane = lua_toboolean(L_, 2) ? WakeLane::Yes : WakeLane::No;
184 lua_remove(L_, 2); // argument is processed, remove it // L_: lane 192 lua_remove(L_, 2); // argument is processed, remove it // L_: lane
@@ -198,7 +206,7 @@ LUAG_FUNC(lane_cancel)
198 206
199 case CancelResult::Timeout: 207 case CancelResult::Timeout:
200 lua_pushboolean(L_, 0); // L_: false 208 lua_pushboolean(L_, 0); // L_: false
201 luaG_pushstring(L_, "timeout"); // L_: false "timeout" 209 luaW_pushstring(L_, "timeout"); // L_: false "timeout"
202 break; 210 break;
203 211
204 case CancelResult::Cancelled: 212 case CancelResult::Cancelled:
diff --git a/src/compat.cpp b/src/compat.cpp
index 7e90142..c833480 100644
--- a/src/compat.cpp
+++ b/src/compat.cpp
@@ -5,10 +5,10 @@
5 5
6// ################################################################################################# 6// #################################################################################################
7 7
8UserValueCount luaG_getalluservalues(lua_State* const L_, StackIndex const idx_) 8UserValueCount luaW_getalluservalues(lua_State* const L_, StackIndex const idx_)
9{ 9{
10 STACK_CHECK_START_REL(L_, 0); 10 STACK_CHECK_START_REL(L_, 0);
11 StackIndex const _idx{ luaG_absindex(L_, idx_) }; 11 StackIndex const _idx{ luaW_absindex(L_, idx_) };
12 UserValueIndex _nuv{ 0 }; 12 UserValueIndex _nuv{ 0 };
13 do { 13 do {
14 // we don't know how many uservalues we are going to extract, there might be a lot... 14 // we don't know how many uservalues we are going to extract, there might be a lot...
@@ -24,15 +24,15 @@ UserValueCount luaG_getalluservalues(lua_State* const L_, StackIndex const idx_)
24// ################################################################################################# 24// #################################################################################################
25 25
26// a small helper to obtain a module's table from the registry instead of relying on the presence of _G["<name>"] 26// a small helper to obtain a module's table from the registry instead of relying on the presence of _G["<name>"]
27LuaType luaG_getmodule(lua_State* const L_, std::string_view const& name_) 27LuaType luaW_getmodule(lua_State* const L_, std::string_view const& name_)
28{ 28{
29 STACK_CHECK_START_REL(L_, 0); 29 STACK_CHECK_START_REL(L_, 0);
30 LuaType _type{ luaG_getfield(L_, kIdxRegistry, LUA_LOADED_TABLE) }; // L_: _R._LOADED|nil 30 LuaType _type{ luaW_getfield(L_, kIdxRegistry, LUA_LOADED_TABLE) }; // L_: _R._LOADED|nil
31 if (_type != LuaType::TABLE) { // L_: _R._LOADED|nil 31 if (_type != LuaType::TABLE) { // L_: _R._LOADED|nil
32 STACK_CHECK(L_, 1); 32 STACK_CHECK(L_, 1);
33 return _type; 33 return _type;
34 } 34 }
35 _type = luaG_getfield(L_, kIdxTop, name_); // L_: _R._LOADED {module}|nil 35 _type = luaW_getfield(L_, kIdxTop, name_); // L_: _R._LOADED {module}|nil
36 lua_remove(L_, -2); // L_: {module}|nil 36 lua_remove(L_, -2); // L_: {module}|nil
37 STACK_CHECK(L_, 1); 37 STACK_CHECK(L_, 1);
38 return _type; 38 return _type;
@@ -52,7 +52,7 @@ int luaL_getsubtable(lua_State* const L_, StackIndex const idx_, char const* fna
52 return 1; /* table already there */ 52 return 1; /* table already there */
53 } else { 53 } else {
54 lua_pop(L_, 1); /* remove previous result */ 54 lua_pop(L_, 1); /* remove previous result */
55 StackIndex const _absidx{ luaG_absindex(L_, idx_) }; 55 StackIndex const _absidx{ luaW_absindex(L_, idx_) };
56 lua_newtable(L_); 56 lua_newtable(L_);
57 lua_pushvalue(L_, -1); /* copy to be left at top */ 57 lua_pushvalue(L_, -1); /* copy to be left at top */
58 lua_setfield(L_, _absidx, fname_); /* assign new table to field */ 58 lua_setfield(L_, _absidx, fname_); /* assign new table to field */
@@ -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 9a8dedf..4dc7433 100644
--- a/src/compat.hpp
+++ b/src/compat.hpp
@@ -5,7 +5,6 @@
5 5
6// try to detect if we are building against LuaJIT or MoonJIT 6// try to detect if we are building against LuaJIT or MoonJIT
7#if defined(LUA_JITLIBNAME) 7#if defined(LUA_JITLIBNAME)
8#include "luajit.h"
9#if (defined(__x86_64__) || defined(_M_X64) || defined(__LP64__)) 8#if (defined(__x86_64__) || defined(_M_X64) || defined(__LP64__))
10#define LUAJIT_FLAVOR() 64 9#define LUAJIT_FLAVOR() 64
11#else // 64 bits 10#else // 64 bits
@@ -21,7 +20,7 @@
21#endif // LUA_OK 20#endif // LUA_OK
22 21
23#ifndef LUA_ERRGCMM 22#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 23#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 24#endif // LUA_ERRGCMM
26 25
27 26
@@ -29,7 +28,7 @@
29#define LUA_LOADED_TABLE "_LOADED" // doesn't exist before Lua 5.3 28#define LUA_LOADED_TABLE "_LOADED" // doesn't exist before Lua 5.3
30#endif // LUA_LOADED_TABLE 29#endif // LUA_LOADED_TABLE
31 30
32// code is now preferring Lua 5.4 API 31// code is now preferring Lua 5.5 API
33 32
34// ################################################################################################# 33// #################################################################################################
35 34
@@ -76,18 +75,6 @@ int luaL_getsubtable(lua_State* L_, StackIndex idx_, char const* fname_);
76 75
77// ################################################################################################# 76// #################################################################################################
78 77
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 78#if LUA_VERSION_NUM < 504
92 79
93void* lua_newuserdatauv(lua_State* L_, size_t sz_, UserValueCount nuvalue_); 80void* lua_newuserdatauv(lua_State* L_, size_t sz_, UserValueCount nuvalue_);
@@ -100,15 +87,11 @@ int lua_setiuservalue(lua_State* L_, StackIndex idx_, UserValueIndex n_);
100 87
101// ################################################################################################# 88// #################################################################################################
102 89
103// wrap Lua 5.4 calls under Lua 5.1 API when it is simpler that way 90#if LUA_VERSION_NUM < 505
104#if LUA_VERSION_NUM == 504
105 91
106inline int luaL_optint(lua_State* L_, StackIndex n_, lua_Integer d_) 92unsigned int luaL_makeseed(lua_State*);
107{
108 return static_cast<int>(luaL_optinteger(L_, n_, d_));
109}
110 93
111#endif // LUA_VERSION_NUM == 504 94#endif // LUA_VERSION_NUM < 505
112 95
113// ################################################################################################# 96// #################################################################################################
114 97
@@ -136,14 +119,14 @@ inline constexpr LuaError ToLuaError(int const rc_)
136 119
137// break lexical order for that one because it's needed below 120// break lexical order for that one because it's needed below
138[[nodiscard]] 121[[nodiscard]]
139inline LuaType luaG_type(lua_State* const L_, StackIndex const idx_) 122inline LuaType luaW_type(lua_State* const L_, StackIndex const idx_)
140{ 123{
141 return static_cast<LuaType>(lua_type(L_, idx_)); 124 return static_cast<LuaType>(lua_type(L_, idx_));
142} 125}
143 126
144// ################################################################################################# 127// #################################################################################################
145// ################################################################################################# 128// #################################################################################################
146// All the compatibility wrappers we expose start with luaG_ 129// All the compatibility wrappers we expose start with luaW_
147// ################################################################################################# 130// #################################################################################################
148// ################################################################################################# 131// #################################################################################################
149 132
@@ -152,7 +135,7 @@ inline LuaType luaG_type(lua_State* const L_, StackIndex const idx_)
152 135
153// a replacement of lua_tolstring 136// a replacement of lua_tolstring
154[[nodiscard]] 137[[nodiscard]]
155inline std::string_view luaG_tostring(lua_State* const L_, StackIndex const idx_) 138inline std::string_view luaW_tostring(lua_State* const L_, StackIndex const idx_)
156{ 139{
157 size_t _len{ 0 }; 140 size_t _len{ 0 };
158 char const* _str{ lua_tolstring(L_, idx_, &_len) }; 141 char const* _str{ lua_tolstring(L_, idx_, &_len) };
@@ -160,7 +143,7 @@ inline std::string_view luaG_tostring(lua_State* const L_, StackIndex const idx_
160} 143}
161 144
162[[nodiscard]] 145[[nodiscard]]
163inline std::string_view luaG_checkstring(lua_State* const L_, StackIndex const idx_) 146inline std::string_view luaW_checkstring(lua_State* const L_, StackIndex const idx_)
164{ 147{
165 size_t _len{ 0 }; 148 size_t _len{ 0 };
166 char const* _str{ luaL_checklstring(L_, idx_, &_len) }; 149 char const* _str{ luaL_checklstring(L_, idx_, &_len) };
@@ -168,7 +151,7 @@ inline std::string_view luaG_checkstring(lua_State* const L_, StackIndex const i
168} 151}
169 152
170[[nodiscard]] 153[[nodiscard]]
171inline std::string_view luaG_optstring(lua_State* const L_, StackIndex const idx_, std::string_view const& default_) 154inline std::string_view luaW_optstring(lua_State* const L_, StackIndex const idx_, std::string_view const& default_)
172{ 155{
173 if (lua_isnoneornil(L_, idx_)) { 156 if (lua_isnoneornil(L_, idx_)) {
174 return default_; 157 return default_;
@@ -179,13 +162,13 @@ inline std::string_view luaG_optstring(lua_State* const L_, StackIndex const idx
179} 162}
180 163
181template <typename... EXTRA> 164template <typename... EXTRA>
182inline std::string_view luaG_pushstring(lua_State* const L_, std::string_view const& str_, EXTRA&&... extra_) 165inline std::string_view luaW_pushstring(lua_State* const L_, std::string_view const& str_, EXTRA&&... extra_)
183{ 166{
184 if constexpr (sizeof...(EXTRA) == 0) { 167 if constexpr (sizeof...(EXTRA) == 0) {
185 if constexpr (LUA_VERSION_NUM == 501) { 168 if constexpr (LUA_VERSION_NUM == 501) {
186 // lua_pushlstring doesn't return a value in Lua 5.1 169 // lua_pushlstring doesn't return a value in Lua 5.1
187 lua_pushlstring(L_, str_.data(), str_.size()); 170 lua_pushlstring(L_, str_.data(), str_.size());
188 return luaG_tostring(L_, kIdxTop); 171 return luaW_tostring(L_, kIdxTop);
189 } else { 172 } else {
190 return std::string_view{ lua_pushlstring(L_, str_.data(), str_.size()), str_.size() }; 173 return std::string_view{ lua_pushlstring(L_, str_.data(), str_.size()), str_.size() };
191 } 174 }
@@ -198,7 +181,7 @@ inline std::string_view luaG_pushstring(lua_State* const L_, std::string_view co
198// ################################################################################################# 181// #################################################################################################
199 182
200// use this in place of lua_absindex to save a function call 183// use this in place of lua_absindex to save a function call
201inline StackIndex luaG_absindex(lua_State* const L_, StackIndex const idx_) 184inline StackIndex luaW_absindex(lua_State* const L_, StackIndex const idx_)
202{ 185{
203 return StackIndex{ (idx_ >= 0 || idx_ <= kIdxRegistry) ? idx_ : StackIndex{ lua_gettop(L_) + idx_ + 1 } }; 186 return StackIndex{ (idx_ >= 0 || idx_ <= kIdxRegistry) ? idx_ : StackIndex{ lua_gettop(L_) + idx_ + 1 } };
204} 187}
@@ -227,14 +210,14 @@ static inline int WrapLuaDump(LUA_DUMP f_, lua_State* const L_, lua_Writer const
227 210
228// ------------------------------------------------------------------------------------------------- 211// -------------------------------------------------------------------------------------------------
229 212
230static inline int luaG_dump(lua_State* const L_, lua_Writer const writer_, void* const data_, int const strip_) 213static inline int luaW_dump(lua_State* const L_, lua_Writer const writer_, void* const data_, int const strip_)
231{ 214{
232 return WrapLuaDump(lua_dump, L_, writer_, data_, strip_); 215 return WrapLuaDump(lua_dump, L_, writer_, data_, strip_);
233} 216}
234 217
235// ################################################################################################# 218// #################################################################################################
236 219
237UserValueCount luaG_getalluservalues(lua_State* L_, StackIndex idx_); 220UserValueCount luaW_getalluservalues(lua_State* L_, StackIndex idx_);
238 221
239// ################################################################################################# 222// #################################################################################################
240 223
@@ -272,7 +255,7 @@ static inline int WrapLuaGetField(LUA_GETFIELD f_, lua_State* const L_, StackInd
272// ------------------------------------------------------------------------------------------------- 255// -------------------------------------------------------------------------------------------------
273 256
274[[nodiscard]] 257[[nodiscard]]
275static inline LuaType luaG_getfield(lua_State* const L_, StackIndex const idx_, std::string_view const& name_) 258static inline LuaType luaW_getfield(lua_State* const L_, StackIndex const idx_, std::string_view const& name_)
276{ 259{
277 return static_cast<LuaType>(WrapLuaGetField(lua_getfield, L_, idx_, name_)); 260 return static_cast<LuaType>(WrapLuaGetField(lua_getfield, L_, idx_, name_));
278} 261}
@@ -280,21 +263,62 @@ static inline LuaType luaG_getfield(lua_State* const L_, StackIndex const idx_,
280// ################################################################################################# 263// #################################################################################################
281 264
282[[nodiscard]] 265[[nodiscard]]
283LuaType luaG_getmodule(lua_State* L_, std::string_view const& name_); 266LuaType luaW_getmodule(lua_State* L_, std::string_view const& name_);
267
268// #################################################################################################
269
270template <typename LUA_NEWSTATE>
271concept RequiresOldLuaNewState = requires(LUA_NEWSTATE f_)
272{
273 {
274 f_(nullptr, 0)
275 } -> std::same_as<lua_State*>;
276};
277
278template <RequiresOldLuaNewState LUA_NEWSTATE>
279static inline lua_State* WrapLuaNewState(LUA_NEWSTATE const lua_newstate_, lua_Alloc const allocf_, void* const ud_, [[maybe_unused]] unsigned int const seed_)
280{
281 // until Lua 5.5, lua_newstate has only 2 parameters
282 return lua_newstate_(allocf_, ud_);
283}
284
285// -------------------------------------------------------------------------------------------------
286
287template <typename LUA_NEWSTATE>
288concept RequiresNewLuaNewState = requires(LUA_NEWSTATE f_)
289{
290 {
291 f_(nullptr, nullptr, 0)
292 } -> std::same_as<lua_State*>;
293};
294
295template <RequiresNewLuaNewState LUA_NEWSTATE>
296static inline lua_State* WrapLuaNewState(LUA_NEWSTATE const lua_newstate_, lua_Alloc const allocf_, void* const ud_, unsigned int const seed_)
297{
298 // starting with Lua 5.5, lua_newstate has 3 parameters
299 return lua_newstate_(allocf_, ud_, seed_);
300}
301
302// -------------------------------------------------------------------------------------------------
303
304static inline lua_State* luaW_newstate(lua_Alloc const allocf_, void* const ud_, unsigned int const seed_)
305{
306 return WrapLuaNewState(lua_newstate, allocf_, ud_, seed_);
307}
284 308
285// ################################################################################################# 309// #################################################################################################
286 310
287template<typename ENUM> 311template<typename ENUM>
288requires std::is_enum_v<ENUM> 312requires std::is_enum_v<ENUM>
289[[nodiscard]] 313[[nodiscard]]
290ENUM luaG_optenum(lua_State* const L_, StackIndex const idx_, ENUM const def_) 314ENUM luaW_optenum(lua_State* const L_, StackIndex const idx_, ENUM const def_)
291{ 315{
292 return static_cast<ENUM>(luaL_optinteger(L_, idx_, static_cast<std::underlying_type_t<ENUM>>(def_))); 316 return static_cast<ENUM>(luaL_optinteger(L_, idx_, static_cast<std::underlying_type_t<ENUM>>(def_)));
293} 317}
294 318
295// ################################################################################################# 319// #################################################################################################
296 320
297inline void luaG_registerlibfuncs(lua_State* const L_, luaL_Reg const* funcs_) 321inline void luaW_registerlibfuncs(lua_State* const L_, luaL_Reg const* funcs_)
298{ 322{
299 // fake externs to make clang happy... 323 // fake externs to make clang happy...
300 extern void luaL_register(lua_State*, char const*, luaL_Reg const*); // Lua 5.1 324 extern void luaL_register(lua_State*, char const*, luaL_Reg const*); // Lua 5.1
@@ -353,7 +377,7 @@ static inline int WrapLuaResume(LUA_RESUME const lua_resume_, lua_State* const L
353// ------------------------------------------------------------------------------------------------- 377// -------------------------------------------------------------------------------------------------
354 378
355[[nodiscard]] 379[[nodiscard]]
356static inline LuaError luaG_resume(lua_State* const L_, lua_State* const from_, int const nargs_, int* const nresults_) 380static inline LuaError luaW_resume(lua_State* const L_, lua_State* const from_, int const nargs_, int* const nresults_)
357{ 381{
358 return ToLuaError(WrapLuaResume(lua_resume, L_, from_, nargs_, nresults_)); 382 return ToLuaError(WrapLuaResume(lua_resume, L_, from_, nargs_, nresults_));
359} 383}
@@ -364,11 +388,11 @@ template <typename LUA_RAWGET>
364concept RequiresOldLuaRawget = requires(LUA_RAWGET f_) { { f_(nullptr, 0) } -> std::same_as<void>; }; 388concept RequiresOldLuaRawget = requires(LUA_RAWGET f_) { { f_(nullptr, 0) } -> std::same_as<void>; };
365 389
366template <RequiresOldLuaRawget LUA_RAWGET> 390template <RequiresOldLuaRawget LUA_RAWGET>
367static inline LuaType WrapLuaRawget(LUA_RAWGET lua_rawget_, lua_State* const L_, StackIndex const idx_) 391static inline LuaType WrapLuaRawget(LUA_RAWGET const lua_rawget_, lua_State* const L_, StackIndex const idx_)
368{ 392{
369 // until Lua 5.3, lua_rawget -> void 393 // until Lua 5.3, lua_rawget -> void
370 lua_rawget_(L_, idx_); 394 lua_rawget_(L_, idx_);
371 return luaG_type(L_, kIdxTop); 395 return luaW_type(L_, kIdxTop);
372} 396}
373 397
374// ------------------------------------------------------------------------------------------------- 398// -------------------------------------------------------------------------------------------------
@@ -377,7 +401,7 @@ template <typename LUA_RAWGET>
377concept RequiresNewLuaRawget = requires(LUA_RAWGET f_) { { f_(nullptr, 0) } -> std::same_as<int>; }; 401concept RequiresNewLuaRawget = requires(LUA_RAWGET f_) { { f_(nullptr, 0) } -> std::same_as<int>; };
378 402
379template <RequiresNewLuaRawget LUA_RAWGET> 403template <RequiresNewLuaRawget LUA_RAWGET>
380static inline LuaType WrapLuaRawget(LUA_RAWGET lua_rawget_, lua_State* const L_, StackIndex const idx_) 404static inline LuaType WrapLuaRawget(LUA_RAWGET const lua_rawget_, lua_State* const L_, StackIndex const idx_)
381{ 405{
382 // starting with Lua 5.3, lua_rawget -> int (the type of the extracted value) 406 // starting with Lua 5.3, lua_rawget -> int (the type of the extracted value)
383 return static_cast<LuaType>(lua_rawget_(L_, idx_)); 407 return static_cast<LuaType>(lua_rawget_(L_, idx_));
@@ -385,42 +409,42 @@ static inline LuaType WrapLuaRawget(LUA_RAWGET lua_rawget_, lua_State* const L_,
385 409
386// ------------------------------------------------------------------------------------------------- 410// -------------------------------------------------------------------------------------------------
387 411
388static inline LuaType luaG_rawget(lua_State* const L_, StackIndex const idx_) 412static inline LuaType luaW_rawget(lua_State* const L_, StackIndex const idx_)
389{ 413{
390 return WrapLuaRawget(lua_rawget, L_, idx_); 414 return WrapLuaRawget(lua_rawget, L_, idx_);
391} 415}
392 416
393// ################################################################################################# 417// #################################################################################################
394 418
395static inline LuaType luaG_rawgetfield(lua_State* const L_, StackIndex const idx_, std::string_view const& name_) 419static inline LuaType luaW_rawgetfield(lua_State* const L_, StackIndex const idx_, std::string_view const& name_)
396{ 420{
397 auto const _absIdx{ luaG_absindex(L_, idx_) }; 421 auto const _absIdx{ luaW_absindex(L_, idx_) };
398 luaG_pushstring(L_, name_); // L_: ... t ... name_ 422 luaW_pushstring(L_, name_); // L_: ... t ... name_
399 lua_rawget(L_, _absIdx); // L_: ... t ... <field> 423 lua_rawget(L_, _absIdx); // L_: ... t ... <field>
400 return luaG_type(L_, kIdxTop); 424 return luaW_type(L_, kIdxTop);
401} 425}
402 426
403// ################################################################################################# 427// #################################################################################################
404 428
405template <size_t N> 429template <size_t N>
406static inline void luaG_newlib(lua_State* const L_, luaL_Reg const (&funcs_)[N]) 430static inline void luaW_newlib(lua_State* const L_, luaL_Reg const (&funcs_)[N])
407{ 431{
408 lua_createtable(L_, 0, N - 1); 432 lua_createtable(L_, 0, N - 1);
409 luaG_registerlibfuncs(L_, funcs_); 433 luaW_registerlibfuncs(L_, funcs_);
410} 434}
411 435
412// ################################################################################################# 436// #################################################################################################
413 437
414template <typename T> 438template <typename T>
415[[nodiscard]] 439[[nodiscard]]
416T* luaG_newuserdatauv(lua_State* const L_, UserValueCount const nuvalue_) 440T* luaW_newuserdatauv(lua_State* const L_, UserValueCount const nuvalue_)
417{ 441{
418 return static_cast<T*>(lua_newuserdatauv(L_, sizeof(T), nuvalue_)); 442 return static_cast<T*>(lua_newuserdatauv(L_, sizeof(T), nuvalue_));
419} 443}
420 444
421// ################################################################################################# 445// #################################################################################################
422 446
423inline void luaG_pushglobaltable(lua_State* const L_) 447inline void luaW_pushglobaltable(lua_State* const L_)
424{ 448{
425#ifdef LUA_GLOBALSINDEX // All flavors of Lua 5.1 449#ifdef LUA_GLOBALSINDEX // All flavors of Lua 5.1
426 ::lua_pushvalue(L_, LUA_GLOBALSINDEX); 450 ::lua_pushvalue(L_, LUA_GLOBALSINDEX);
@@ -431,15 +455,15 @@ inline void luaG_pushglobaltable(lua_State* const L_)
431 455
432// ################################################################################################# 456// #################################################################################################
433 457
434inline void luaG_setfield(lua_State* const L_, StackIndex const idx_, char const* const k_) = delete; 458inline void luaW_setfield(lua_State* const L_, StackIndex const idx_, char const* const k_) = delete;
435inline void luaG_setfield(lua_State* const L_, StackIndex const idx_, std::string_view const& k_) 459inline void luaW_setfield(lua_State* const L_, StackIndex const idx_, std::string_view const& k_)
436{ 460{
437 lua_setfield(L_, idx_, k_.data()); 461 lua_setfield(L_, idx_, k_.data());
438} 462}
439 463
440// ################################################################################################# 464// #################################################################################################
441 465
442inline void luaG_setmetatable(lua_State* const L_, std::string_view const& tname_) 466inline void luaW_setmetatable(lua_State* const L_, std::string_view const& tname_)
443{ 467{
444 // fake externs to make clang happy... 468 // fake externs to make clang happy...
445 if constexpr (LUA_VERSION_NUM > 501) { 469 if constexpr (LUA_VERSION_NUM > 501) {
@@ -456,7 +480,7 @@ inline void luaG_setmetatable(lua_State* const L_, std::string_view const& tname
456// a small helper to extract a full userdata pointer from the stack in a safe way 480// a small helper to extract a full userdata pointer from the stack in a safe way
457template <typename T> 481template <typename T>
458[[nodiscard]] 482[[nodiscard]]
459T* luaG_tofulluserdata(lua_State* const L_, StackIndex const index_) 483T* luaW_tofulluserdata(lua_State* const L_, StackIndex const index_)
460{ 484{
461 LUA_ASSERT(L_, lua_isnil(L_, index_) || lua_type(L_, index_) == LUA_TUSERDATA); 485 LUA_ASSERT(L_, lua_isnil(L_, index_) || lua_type(L_, index_) == LUA_TUSERDATA);
462 return static_cast<T*>(lua_touserdata(L_, index_)); 486 return static_cast<T*>(lua_touserdata(L_, index_));
@@ -466,7 +490,7 @@ T* luaG_tofulluserdata(lua_State* const L_, StackIndex const index_)
466 490
467template <typename T> 491template <typename T>
468[[nodiscard]] 492[[nodiscard]]
469auto luaG_tolightuserdata(lua_State* const L_, StackIndex const index_) 493auto luaW_tolightuserdata(lua_State* const L_, StackIndex const index_)
470{ 494{
471 LUA_ASSERT(L_, lua_isnil(L_, index_) || lua_islightuserdata(L_, index_)); 495 LUA_ASSERT(L_, lua_isnil(L_, index_) || lua_islightuserdata(L_, index_));
472 if constexpr (std::is_pointer_v<T>) { 496 if constexpr (std::is_pointer_v<T>) {
@@ -479,7 +503,7 @@ auto luaG_tolightuserdata(lua_State* const L_, StackIndex const index_)
479// ------------------------------------------------------------------------------------------------- 503// -------------------------------------------------------------------------------------------------
480 504
481[[nodiscard]] 505[[nodiscard]]
482inline std::string_view luaG_typename(lua_State* const L_, LuaType const t_) 506inline std::string_view luaW_typename(lua_State* const L_, LuaType const t_)
483{ 507{
484 return lua_typename(L_, static_cast<int>(t_)); 508 return lua_typename(L_, static_cast<int>(t_));
485} 509}
@@ -487,7 +511,7 @@ inline std::string_view luaG_typename(lua_State* const L_, LuaType const t_)
487// ------------------------------------------------------------------------------------------------- 511// -------------------------------------------------------------------------------------------------
488 512
489[[nodiscard]] 513[[nodiscard]]
490inline std::string_view luaG_typename(lua_State* const L_, StackIndex const idx_) 514inline std::string_view luaW_typename(lua_State* const L_, StackIndex const idx_)
491{ 515{
492 return luaG_typename(L_, luaG_type(L_, idx_)); 516 return luaW_typename(L_, luaW_type(L_, idx_));
493} 517}
diff --git a/src/deep.cpp b/src/deep.cpp
index 82f1214..acd93a6 100644
--- a/src/deep.cpp
+++ b/src/deep.cpp
@@ -75,7 +75,7 @@ namespace {
75 lua_rawget(L_, -2); // L_: {} b 75 lua_rawget(L_, -2); // L_: {} b
76 } 76 }
77 lua_remove(L_, -2); // L_: a|b 77 lua_remove(L_, -2); // L_: a|b
78 LuaType const _type{ luaG_type(L_, kIdxTop) }; 78 LuaType const _type{ luaW_type(L_, kIdxTop) };
79 if (_type != LuaType::NIL && _type != expectedType_) { 79 if (_type != LuaType::NIL && _type != expectedType_) {
80 raise_luaL_error(L_, "INTERNAL ERROR: Unexpected value."); 80 raise_luaL_error(L_, "INTERNAL ERROR: Unexpected value.");
81 } 81 }
@@ -103,7 +103,7 @@ namespace {
103[[nodiscard]] 103[[nodiscard]]
104int DeepFactory::DeepGC(lua_State* const L_) 104int DeepFactory::DeepGC(lua_State* const L_)
105{ 105{
106 DeepPrelude* const* const _proxy{ luaG_tofulluserdata<DeepPrelude*>(L_, StackIndex{ 1 }) }; 106 DeepPrelude* const* const _proxy{ luaW_tofulluserdata<DeepPrelude*>(L_, StackIndex{ 1 }) };
107 DeepPrelude* const _p{ *_proxy }; 107 DeepPrelude* const _p{ *_proxy };
108 108
109 // can work without a universe if creating a deep userdata from some external C module when Lanes isn't loaded 109 // can work without a universe if creating a deep userdata from some external C module when Lanes isn't loaded
@@ -150,7 +150,7 @@ DeepFactory* DeepFactory::LookupFactory(lua_State* const L_, StackIndex const in
150{ 150{
151 // when looking inside a keeper, we are 100% sure the object is a deep userdata 151 // when looking inside a keeper, we are 100% sure the object is a deep userdata
152 if (mode_ == LookupMode::FromKeeper) { 152 if (mode_ == LookupMode::FromKeeper) {
153 DeepPrelude* const _proxy{ *luaG_tofulluserdata<DeepPrelude*>(L_, index_) }; 153 DeepPrelude* const _proxy{ *luaW_tofulluserdata<DeepPrelude*>(L_, index_) };
154 // we can (and must) cast and fetch the internally stored factory 154 // we can (and must) cast and fetch the internally stored factory
155 return &_proxy->factory; 155 return &_proxy->factory;
156 } else { 156 } else {
@@ -167,7 +167,7 @@ DeepFactory* DeepFactory::LookupFactory(lua_State* const L_, StackIndex const in
167 // replace metatable with the factory pointer, if it is actually a deep userdata 167 // replace metatable with the factory pointer, if it is actually a deep userdata
168 LookupDeep(L_, LuaType::LIGHTUSERDATA); // L_: deep ... factory|nil 168 LookupDeep(L_, LuaType::LIGHTUSERDATA); // L_: deep ... factory|nil
169 169
170 DeepFactory* const _ret{ luaG_tolightuserdata<DeepFactory>(L_, kIdxTop) }; // nullptr if not a userdata 170 DeepFactory* const _ret{ luaW_tolightuserdata<DeepFactory>(L_, kIdxTop) }; // nullptr if not a userdata
171 lua_pop(L_, 1); 171 lua_pop(L_, 1);
172 STACK_CHECK(L_, 0); 172 STACK_CHECK(L_, 0);
173 return _ret; 173 return _ret;
@@ -190,7 +190,7 @@ void DeepFactory::PushDeepProxy(DestState const L_, DeepPrelude* const prelude_,
190 190
191 // Check if a proxy already exists 191 // Check if a proxy already exists
192 lua_pushlightuserdata(L_, prelude_); // L_: DPC deep 192 lua_pushlightuserdata(L_, prelude_); // L_: DPC deep
193 if (luaG_rawget(L_, StackIndex{ -2 }) != LuaType::NIL) { // L_: DPC proxy 193 if (luaW_rawget(L_, StackIndex{ -2 }) != LuaType::NIL) { // L_: DPC proxy
194 lua_remove(L_, -2); // L_: proxy 194 lua_remove(L_, -2); // L_: proxy
195 STACK_CHECK(L_, 1); 195 STACK_CHECK(L_, 1);
196 return; 196 return;
@@ -202,7 +202,7 @@ void DeepFactory::PushDeepProxy(DestState const L_, DeepPrelude* const prelude_,
202 STACK_GROW(L_, 7); 202 STACK_GROW(L_, 7);
203 203
204 // a new full userdata, fitted with the specified number of uservalue slots (always 1 for Lua < 5.4) 204 // a new full userdata, fitted with the specified number of uservalue slots (always 1 for Lua < 5.4)
205 DeepPrelude** const _proxy{ luaG_newuserdatauv<DeepPrelude*>(L_, nuv_) }; // L_: DPC proxy 205 DeepPrelude** const _proxy{ luaW_newuserdatauv<DeepPrelude*>(L_, nuv_) }; // L_: DPC proxy
206 LUA_ASSERT(L_, _proxy); 206 LUA_ASSERT(L_, _proxy);
207 *_proxy = prelude_; 207 *_proxy = prelude_;
208 prelude_->refcount.fetch_add(1, std::memory_order_relaxed); // one more proxy pointing to this deep data 208 prelude_->refcount.fetch_add(1, std::memory_order_relaxed); // one more proxy pointing to this deep data
@@ -223,7 +223,7 @@ void DeepFactory::PushDeepProxy(DestState const L_, DeepPrelude* const prelude_,
223 raise_luaL_error(errL_, "Bad DeepFactory::createMetatable overload: unexpected pushed value"); 223 raise_luaL_error(errL_, "Bad DeepFactory::createMetatable overload: unexpected pushed value");
224 } 224 }
225 // if the metatable contains a __gc, we will call it from our own 225 // if the metatable contains a __gc, we will call it from our own
226 std::ignore = luaG_rawgetfield(L_, kIdxTop, "__gc"); // L_: DPC proxy metatable __gc 226 std::ignore = luaW_rawgetfield(L_, kIdxTop, "__gc"); // L_: DPC proxy metatable __gc
227 } else { 227 } else {
228 // keepers need a minimal metatable that only contains our own __gc 228 // keepers need a minimal metatable that only contains our own __gc
229 lua_createtable(L_, 0, 1); // L_: DPC proxy metatable 229 lua_createtable(L_, 0, 1); // L_: DPC proxy metatable
@@ -251,8 +251,8 @@ void DeepFactory::PushDeepProxy(DestState const L_, DeepPrelude* const prelude_,
251 raise_luaL_error(errL_, "lanes receiving deep userdata should register the 'package' library"); 251 raise_luaL_error(errL_, "lanes receiving deep userdata should register the 'package' library");
252 } 252 }
253 253
254 luaG_pushstring(L_, _modname); // L_: DPC proxy metatable require() "module" 254 luaW_pushstring(L_, _modname); // L_: DPC proxy metatable require() "module"
255 if (luaG_getfield(L_, kIdxRegistry, LUA_LOADED_TABLE) != LuaType::TABLE) { // L_: DPC proxy metatable require() "module" _R._LOADED 255 if (luaW_getfield(L_, kIdxRegistry, LUA_LOADED_TABLE) != LuaType::TABLE) { // L_: DPC proxy metatable require() "module" _R._LOADED
256 // no L.registry._LOADED; can this ever happen? 256 // no L.registry._LOADED; can this ever happen?
257 lua_pop(L_, 6); // L_: 257 lua_pop(L_, 6); // L_:
258 raise_luaL_error(errL_, "unexpected error while requiring a module identified by DeepFactory::moduleName"); 258 raise_luaL_error(errL_, "unexpected error while requiring a module identified by DeepFactory::moduleName");
@@ -270,7 +270,7 @@ void DeepFactory::PushDeepProxy(DestState const L_, DeepPrelude* const prelude_,
270 LuaError const _require_result{ lua_pcall(L_, 1, 0, 0) }; // L_: DPC proxy metatable error? 270 LuaError const _require_result{ lua_pcall(L_, 1, 0, 0) }; // L_: DPC proxy metatable error?
271 if (_require_result != LuaError::OK) { 271 if (_require_result != LuaError::OK) {
272 // failed, raise the error in the proper state 272 // failed, raise the error in the proper state
273 raise_luaL_error(errL_, luaG_tostring(L_, kIdxTop)); 273 raise_luaL_error(errL_, luaW_tostring(L_, kIdxTop));
274 } 274 }
275 } 275 }
276 } else { // already loaded, we are happy 276 } else { // already loaded, we are happy
@@ -279,7 +279,7 @@ void DeepFactory::PushDeepProxy(DestState const L_, DeepPrelude* const prelude_,
279 } 279 }
280 } 280 }
281 STACK_CHECK(L_, 3); // L_: DPC proxy metatable 281 STACK_CHECK(L_, 3); // L_: DPC proxy metatable
282 LUA_ASSERT(L_, luaG_type(L_, StackIndex{ -2 }) == LuaType::USERDATA); 282 LUA_ASSERT(L_, luaW_type(L_, StackIndex{ -2 }) == LuaType::USERDATA);
283 LUA_ASSERT(L_, lua_istable(L_, -1)); 283 LUA_ASSERT(L_, lua_istable(L_, -1));
284 lua_setmetatable(L_, -2); // L_: DPC proxy 284 lua_setmetatable(L_, -2); // L_: DPC proxy
285 285
@@ -288,7 +288,7 @@ void DeepFactory::PushDeepProxy(DestState const L_, DeepPrelude* const prelude_,
288 lua_pushvalue(L_, -2); // L_: DPC proxy deep proxy 288 lua_pushvalue(L_, -2); // L_: DPC proxy deep proxy
289 lua_rawset(L_, -4); // L_: DPC proxy 289 lua_rawset(L_, -4); // L_: DPC proxy
290 lua_remove(L_, -2); // L_: proxy 290 lua_remove(L_, -2); // L_: proxy
291 LUA_ASSERT(L_, luaG_type(L_, kIdxTop) == LuaType::USERDATA); 291 LUA_ASSERT(L_, luaW_type(L_, kIdxTop) == LuaType::USERDATA);
292 STACK_CHECK(L_, 1); 292 STACK_CHECK(L_, 1);
293} 293}
294 294
@@ -305,7 +305,7 @@ void DeepFactory::PushDeepProxy(DestState const L_, DeepPrelude* const prelude_,
305 * Reference counting and true userdata proxying are taken care of for the actual data type. 305 * Reference counting and true userdata proxying are taken care of for the actual data type.
306 * 306 *
307 * Types using the deep userdata system (and only those!) can be passed between 307 * Types using the deep userdata system (and only those!) can be passed between
308 * separate Lua states via 'luaG_inter_move()'. 308 * separate Lua states via 'luaW_inter_move()'.
309 * 309 *
310 * Returns: 'proxy' userdata for accessing the deep data via 'DeepFactory::toDeep()' 310 * Returns: 'proxy' userdata for accessing the deep data via 'DeepFactory::toDeep()'
311 */ 311 */
@@ -382,7 +382,7 @@ DeepPrelude* DeepFactory::toDeep(lua_State* const L_, StackIndex const index_) c
382 } 382 }
383 STACK_CHECK(L_, 0); 383 STACK_CHECK(L_, 0);
384 384
385 DeepPrelude** const _proxy{ luaG_tofulluserdata<DeepPrelude*>(L_, index_) }; 385 DeepPrelude** const _proxy{ luaW_tofulluserdata<DeepPrelude*>(L_, index_) };
386 return *_proxy; 386 return *_proxy;
387} 387}
388 388
diff --git a/src/intercopycontext.cpp b/src/intercopycontext.cpp
index d6716a3..6e9b66c 100644
--- a/src/intercopycontext.cpp
+++ b/src/intercopycontext.cpp
@@ -36,23 +36,6 @@ THE SOFTWARE.
36 36
37// ################################################################################################# 37// #################################################################################################
38 38
39// Lua 5.4.3 style of dumping (see lstrlib.c)
40// we have to do it that way because we can't unbalance the stack between buffer operations
41// namely, this means we can't push a function on top of the stack *after* we initialize the buffer!
42// luckily, this also works with earlier Lua versions
43[[nodiscard]]
44static int buf_writer(lua_State* L_, void const* b_, size_t size_, void* ud_)
45{
46 luaL_Buffer* const _B{ static_cast<luaL_Buffer*>(ud_) };
47 if (!_B->L) {
48 luaL_buffinit(L_, _B);
49 }
50 luaL_addlstring(_B, static_cast<char const*>(b_), size_);
51 return 0;
52}
53
54// #################################################################################################
55
56// function sentinel used to transfer native functions from/to keeper states 39// function sentinel used to transfer native functions from/to keeper states
57[[nodiscard]] 40[[nodiscard]]
58static int func_lookup_sentinel(lua_State* const L_) 41static int func_lookup_sentinel(lua_State* const L_)
@@ -93,7 +76,7 @@ static int userdata_lookup_sentinel(lua_State* const L_)
93[[nodiscard]] 76[[nodiscard]]
94std::string_view InterCopyContext::findLookupName() const 77std::string_view InterCopyContext::findLookupName() const
95{ 78{
96 LUA_ASSERT(L1, lua_isfunction(L1, L1_i) || lua_istable(L1, L1_i) || luaG_type(L1, L1_i) == LuaType::USERDATA); 79 LUA_ASSERT(L1, lua_isfunction(L1, L1_i) || lua_istable(L1, L1_i) || luaW_type(L1, L1_i) == LuaType::USERDATA);
97 STACK_CHECK_START_REL(L1, 0); // L1: ... v ... 80 STACK_CHECK_START_REL(L1, 0); // L1: ... v ...
98 STACK_GROW(L1, 3); // up to 3 slots are necessary on error 81 STACK_GROW(L1, 3); // up to 3 slots are necessary on error
99 if (mode == LookupMode::FromKeeper) { 82 if (mode == LookupMode::FromKeeper) {
@@ -114,7 +97,7 @@ std::string_view InterCopyContext::findLookupName() const
114 lua_pushvalue(L1, L1_i); // L1: ... v ... {} v 97 lua_pushvalue(L1, L1_i); // L1: ... v ... {} v
115 lua_rawget(L1, -2); // L1: ... v ... {} "f.q.n" 98 lua_rawget(L1, -2); // L1: ... v ... {} "f.q.n"
116 } 99 }
117 std::string_view _fqn{ luaG_tostring(L1, kIdxTop) }; 100 std::string_view _fqn{ luaW_tostring(L1, kIdxTop) };
118 DEBUGSPEW_CODE(DebugSpew(U) << "function [C] " << _fqn << std::endl); 101 DEBUGSPEW_CODE(DebugSpew(U) << "function [C] " << _fqn << std::endl);
119 // popping doesn't invalidate the pointer since this is an interned string gotten from the lookup database 102 // popping doesn't invalidate the pointer since this is an interned string gotten from the lookup database
120 lua_pop(L1, (mode == LookupMode::FromKeeper) ? 1 : 2); // L1: ... v ... 103 lua_pop(L1, (mode == LookupMode::FromKeeper) ? 1 : 2); // L1: ... v ...
@@ -122,12 +105,12 @@ std::string_view InterCopyContext::findLookupName() const
122 if (_fqn.empty() && !lua_istable(L1, L1_i)) { // raise an error if we try to send an unknown function/userdata (but not for tables) 105 if (_fqn.empty() && !lua_istable(L1, L1_i)) { // raise an error if we try to send an unknown function/userdata (but not for tables)
123 // try to discover the name of the function/userdata we want to send 106 // try to discover the name of the function/userdata we want to send
124 kLaneNameRegKey.pushValue(L1); // L1: ... v ... lane_name 107 kLaneNameRegKey.pushValue(L1); // L1: ... v ... lane_name
125 std::string_view const _from{ luaG_tostring(L1, kIdxTop) }; 108 std::string_view const _from{ luaW_tostring(L1, kIdxTop) };
126 lua_pushcfunction(L1, LG_nameof); // L1: ... v ... lane_name LG_nameof 109 lua_pushcfunction(L1, LG_nameof); // L1: ... v ... lane_name LG_nameof
127 lua_pushvalue(L1, L1_i); // L1: ... v ... lane_name LG_nameof t 110 lua_pushvalue(L1, L1_i); // L1: ... v ... lane_name LG_nameof t
128 lua_call(L1, 1, 2); // L1: ... v ... lane_name "type" "name"|nil 111 lua_call(L1, 1, 2); // L1: ... v ... lane_name "type" "name"|nil
129 StackIndex const _indexTypeWhat{ -2 }; 112 StackIndex const _indexTypeWhat{ -2 };
130 std::string_view const _typewhat{ (luaG_type(L1, _indexTypeWhat) == LuaType::STRING) ? luaG_tostring(L1, _indexTypeWhat) : luaG_typename(L1, _indexTypeWhat) }; 113 std::string_view const _typewhat{ (luaW_type(L1, _indexTypeWhat) == LuaType::STRING) ? luaW_tostring(L1, _indexTypeWhat) : luaW_typename(L1, _indexTypeWhat) };
131 // second return value can be nil if the table was not found 114 // second return value can be nil if the table was not found
132 // probable reason: the function was removed from the source Lua state before Lanes was required. 115 // probable reason: the function was removed from the source Lua state before Lanes was required.
133 std::string_view _what, _gotchaA, _gotchaB; 116 std::string_view _what, _gotchaA, _gotchaB;
@@ -139,7 +122,7 @@ std::string_view InterCopyContext::findLookupName() const
139 _gotchaA = ""; 122 _gotchaA = "";
140 _gotchaB = ""; 123 _gotchaB = "";
141 StackIndex const _indexWhat{ kIdxTop }; 124 StackIndex const _indexWhat{ kIdxTop };
142 _what = (luaG_type(L1, _indexWhat) == LuaType::STRING) ? luaG_tostring(L1, _indexWhat) : luaG_typename(L1, _indexWhat); 125 _what = (luaW_type(L1, _indexWhat) == LuaType::STRING) ? luaW_tostring(L1, _indexWhat) : luaW_typename(L1, _indexWhat);
143 } 126 }
144 raise_luaL_error(L1, "%s%s '%s' not found in %s origin transfer database.%s", _typewhat.data(), _gotchaA.data(), _what.data(), _from.empty() ? "main" : _from.data(), _gotchaB.data()); 127 raise_luaL_error(L1, "%s%s '%s' not found in %s origin transfer database.%s", _typewhat.data(), _gotchaA.data(), _what.data(), _from.empty() ? "main" : _from.data(), _gotchaB.data());
145 } 128 }
@@ -158,7 +141,7 @@ static constexpr RegistryUniqueKey kMtIdRegKey{ 0xA8895DCF4EC3FE3Cull };
158[[nodiscard]] 141[[nodiscard]]
159static lua_Integer get_mt_id(Universe* const U_, lua_State* const L_, StackIndex const idx_) 142static lua_Integer get_mt_id(Universe* const U_, lua_State* const L_, StackIndex const idx_)
160{ 143{
161 StackIndex const _absidx{ luaG_absindex(L_, idx_) }; 144 StackIndex const _absidx{ luaW_absindex(L_, idx_) };
162 145
163 STACK_GROW(L_, 3); 146 STACK_GROW(L_, 3);
164 147
@@ -195,11 +178,12 @@ static lua_Integer get_mt_id(Universe* const U_, lua_State* const L_, StackIndex
195// L2 has the cache key for this function at the top of the stack 178// L2 has the cache key for this function at the top of the stack
196void InterCopyContext::copyFunction() const 179void InterCopyContext::copyFunction() const
197{ 180{
198 LUA_ASSERT(L1, L2_cache_i != 0); // L2: ... {cache} ... p 181 LUA_ASSERT(L1, L2_cache_i != 0); // L1: ... f L2: ... {cache} ... p
199 STACK_GROW(L1, 2); 182 STACK_GROW(L1, 2);
200 STACK_CHECK_START_REL(L1, 0); 183 STACK_CHECK_START_REL(L1, 0);
184 STACK_CHECK_START_REL(L2, 0);
201 185
202 // 'luaG_dump()' needs the function at top of stack 186 // 'luaW_dump()' needs the function at top of stack
203 // if already on top of the stack, no need to push again 187 // if already on top of the stack, no need to push again
204 bool const _needToPush{ L1_i != lua_gettop(L1) }; 188 bool const _needToPush{ L1_i != lua_gettop(L1) };
205 if (_needToPush) { 189 if (_needToPush) {
@@ -211,19 +195,17 @@ void InterCopyContext::copyFunction() const
211 // to the writer" (and we only return 0) 195 // to the writer" (and we only return 0)
212 // not sure this could ever fail but for memory shortage reasons 196 // not sure this could ever fail but for memory shortage reasons
213 // last argument is Lua 5.4-specific (no stripping) 197 // last argument is Lua 5.4-specific (no stripping)
214 luaL_Buffer B{}; 198 tools::PushFunctionBytecode(L1, L2, U->stripFunctions); // L1: ... f L2: ... {cache} ... p "<bytecode>"
215 if (luaG_dump(L1, buf_writer, &B, U->stripFunctions) != 0) {
216 raise_luaL_error(getErrL(), "internal error: function dump failed.");
217 }
218 199
219 // pushes dumped string on 'L1' 200 // if pushed, we need to pop
220 luaL_pushresult(&B); // L1: ... f b
221
222 // if not pushed, no need to pop
223 if (_needToPush) { 201 if (_needToPush) {
224 lua_remove(L1, -2); // L1: ... b 202 lua_pop(L1, 1); // L1: ...
225 } 203 }
226 204
205 // When we are done, the stack of L1 should be the original one, with the bytecode string added on top of L2
206 STACK_CHECK(L1, 0);
207 STACK_CHECK(L2, 1);
208
227 // transfer the bytecode, then the upvalues, to create a similar closure 209 // transfer the bytecode, then the upvalues, to create a similar closure
228 { 210 {
229 char const* _fname{}; 211 char const* _fname{};
@@ -231,16 +213,16 @@ void InterCopyContext::copyFunction() const
231 if constexpr (LOG_FUNC_INFO) 213 if constexpr (LOG_FUNC_INFO)
232 { 214 {
233 lua_Debug _ar; 215 lua_Debug _ar;
234 lua_pushvalue(L1, L1_i); // L1: ... b f 216 lua_pushvalue(L1, L1_i); // L1: ... f
235 // "To get information about a function you push it onto the stack and start the what string with the character '>'." 217 // "To get information about a function you push it onto the stack and start the what string with the character '>'."
236 // fills 'fname' 'namewhat' and 'linedefined', pops function 218 // fills 'fname' 'namewhat' and 'linedefined', pops function
237 lua_getinfo(L1, ">nS", &_ar); // L1: ... b 219 lua_getinfo(L1, ">nS", &_ar); // L1: ...
238 _fname = _ar.namewhat; 220 _fname = _ar.namewhat;
239 DEBUGSPEW_CODE(DebugSpew(U) << "FNAME: " << _ar.short_src << " @ " << _ar.linedefined << std::endl); 221 DEBUGSPEW_CODE(DebugSpew(U) << "FNAME: " << _ar.short_src << " @ " << _ar.linedefined << std::endl);
240 } 222 }
241 223
242 { 224 {
243 std::string_view const _bytecode{ luaG_tostring(L1, kIdxTop) }; // L1: ... b 225 std::string_view const _bytecode{ luaW_tostring(L2, kIdxTop) }; // L2: ... {cache} ... p "<bytecode>"
244 LUA_ASSERT(L1, !_bytecode.empty()); 226 LUA_ASSERT(L1, !_bytecode.empty());
245 STACK_GROW(L2, 2); 227 STACK_GROW(L2, 2);
246 // Note: Line numbers seem to be taken precisely from the 228 // Note: Line numbers seem to be taken precisely from the
@@ -249,15 +231,15 @@ void InterCopyContext::copyFunction() const
249 // 231 //
250 // TBD: Can we get the function's original name through, as well? 232 // TBD: Can we get the function's original name through, as well?
251 // 233 //
252 if (luaL_loadbuffer(L2, _bytecode.data(), _bytecode.size(), _fname) != 0) { // L2: ... {cache} ... p function 234 if (luaL_loadbuffer(L2, _bytecode.data(), _bytecode.size(), _fname) != 0) { // L2: ... {cache} ... p "<bytecode>" function
253 // chunk is precompiled so only LUA_ERRMEM can happen 235 // chunk is precompiled so only LUA_ERRMEM can happen
254 // "Otherwise, it pushes an error message" 236 // "Otherwise, it pushes an error message"
255 // 237 //
256 STACK_GROW(L1, 1); 238 STACK_GROW(L1, 1);
257 raise_luaL_error(getErrL(), "%s: %s", _fname, lua_tostring(L2, -1)); 239 raise_luaL_error(getErrL(), "%s: %s", _fname, lua_tostring(L2, kIdxTop));
258 } 240 }
259 // remove the dumped string 241 // remove the dumped string
260 lua_pop(L1, 1); // ... 242 lua_replace(L2, -2); // L2: ... {cache} ... p function
261 // now set the cache as soon as we can. 243 // now set the cache as soon as we can.
262 // this is necessary if one of the function's upvalues references it indirectly 244 // this is necessary if one of the function's upvalues references it indirectly
263 // we need to find it in the cache even if it isn't fully transfered yet 245 // we need to find it in the cache even if it isn't fully transfered yet
@@ -267,6 +249,7 @@ void InterCopyContext::copyFunction() const
267 lua_rawset(L2, L2_cache_i); // L2: ... {cache} ... function 249 lua_rawset(L2, L2_cache_i); // L2: ... {cache} ... function
268 } 250 }
269 STACK_CHECK(L1, 0); 251 STACK_CHECK(L1, 0);
252 STACK_CHECK(L2, 0); // cache key is replaced by the function, so no stack level change
270 253
271 /* push over any upvalues; references to this function will come from 254 /* push over any upvalues; references to this function will come from
272 * cache so we don't end up in eternal loop. 255 * cache so we don't end up in eternal loop.
@@ -278,12 +261,12 @@ void InterCopyContext::copyFunction() const
278 { 261 {
279 InterCopyContext _c{ U, L2, L1, L2_cache_i, {}, VT::NORMAL, mode, {} }; 262 InterCopyContext _c{ U, L2, L1, L2_cache_i, {}, VT::NORMAL, mode, {} };
280 // if we encounter an upvalue equal to the global table in the source, bind it to the destination's global table 263 // if we encounter an upvalue equal to the global table in the source, bind it to the destination's global table
281 luaG_pushglobaltable(L1); // L1: ... _G 264 luaW_pushglobaltable(L1); // L1: ... _G
282 for (char const* _upname{}; (_upname = lua_getupvalue(L1, L1_i, 1 + _n)); ++_n) { // L1: ... _G up[n] 265 for (char const* _upname{}; (_upname = lua_getupvalue(L1, L1_i, 1 + _n)); ++_n) { // L1: ... _G up[n]
283 DEBUGSPEW_CODE(DebugSpew(U) << "UPNAME[" << _n << "]: " << _c.name << " -> "); 266 DEBUGSPEW_CODE(DebugSpew(U) << "UPNAME[" << _n << "]: " << _c.name << " -> ");
284 if (lua_rawequal(L1, -1, -2)) { // is the upvalue equal to the global table? 267 if (lua_rawequal(L1, -1, -2)) { // is the upvalue equal to the global table?
285 DEBUGSPEW_CODE(DebugSpew(nullptr) << "pushing destination global scope" << std::endl); 268 DEBUGSPEW_CODE(DebugSpew(nullptr) << "pushing destination global scope" << std::endl);
286 luaG_pushglobaltable(L2); // L2: ... {cache} ... function <upvalues> 269 luaW_pushglobaltable(L2); // L2: ... {cache} ... function <upvalues>
287 } else { 270 } else {
288 DEBUGSPEW_CODE(DebugSpew(nullptr) << "copying value" << std::endl); 271 DEBUGSPEW_CODE(DebugSpew(nullptr) << "copying value" << std::endl);
289 _c.name = _upname; 272 _c.name = _upname;
@@ -297,6 +280,7 @@ void InterCopyContext::copyFunction() const
297 lua_pop(L1, 1); // L1: ... 280 lua_pop(L1, 1); // L1: ...
298 } // L2: ... {cache} ... function + 'n' upvalues (>=0) 281 } // L2: ... {cache} ... function + 'n' upvalues (>=0)
299 STACK_CHECK(L1, 0); 282 STACK_CHECK(L1, 0);
283 STACK_CHECK(L2, _n);
300 284
301 // Set upvalues (originally set to 'nil' by 'lua_load') 285 // Set upvalues (originally set to 'nil' by 'lua_load')
302 for (StackIndex const _func_index{ lua_gettop(L2) - _n }; _n > 0; --_n) { 286 for (StackIndex const _func_index{ lua_gettop(L2) - _n }; _n > 0; --_n) {
@@ -307,6 +291,7 @@ void InterCopyContext::copyFunction() const
307 // once all upvalues have been set we are left 291 // once all upvalues have been set we are left
308 // with the function at the top of the stack // L2: ... {cache} ... function 292 // with the function at the top of the stack // L2: ... {cache} ... function
309 } 293 }
294 STACK_CHECK(L2, 0);
310 STACK_CHECK(L1, 0); 295 STACK_CHECK(L1, 0);
311} 296}
312 297
@@ -327,7 +312,7 @@ void InterCopyContext::lookupNativeFunction() const
327 312
328 case LookupMode::ToKeeper: 313 case LookupMode::ToKeeper:
329 // push a sentinel closure that holds the lookup name as upvalue 314 // push a sentinel closure that holds the lookup name as upvalue
330 luaG_pushstring(L2, _fqn); // L1: ... f ... L2: "f.q.n" 315 luaW_pushstring(L2, _fqn); // L1: ... f ... L2: "f.q.n"
331 lua_pushcclosure(L2, func_lookup_sentinel, 1); // L1: ... f ... L2: f 316 lua_pushcclosure(L2, func_lookup_sentinel, 1); // L1: ... f ... L2: f
332 break; 317 break;
333 318
@@ -336,16 +321,16 @@ void InterCopyContext::lookupNativeFunction() const
336 kLookupRegKey.pushValue(L2); // L1: ... f ... L2: {} 321 kLookupRegKey.pushValue(L2); // L1: ... f ... L2: {}
337 STACK_CHECK(L2, 1); 322 STACK_CHECK(L2, 1);
338 LUA_ASSERT(L1, lua_istable(L2, -1)); 323 LUA_ASSERT(L1, lua_istable(L2, -1));
339 luaG_pushstring(L2, _fqn); // L1: ... f ... L2: {} "f.q.n" 324 luaW_pushstring(L2, _fqn); // L1: ... f ... L2: {} "f.q.n"
340 LuaType const _objType{ luaG_rawget(L2, StackIndex{ -2 }) }; // L1: ... f ... L2: {} f 325 LuaType const _objType{ luaW_rawget(L2, StackIndex{ -2 }) }; // L1: ... f ... L2: {} f
341 // 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
342 // anything other than function or table should not happen! 327 // anything other than function or table should not happen!
343 if (_objType != LuaType::FUNCTION && _objType != LuaType::TABLE && _objType != LuaType::USERDATA) { 328 if (_objType != LuaType::FUNCTION && _objType != LuaType::TABLE && _objType != LuaType::USERDATA) {
344 kLaneNameRegKey.pushValue(L1); // L1: ... f ... lane_name 329 kLaneNameRegKey.pushValue(L1); // L1: ... f ... lane_name
345 std::string_view const _from{ luaG_tostring(L1, kIdxTop) }; 330 std::string_view const _from{ luaW_tostring(L1, kIdxTop) };
346 lua_pop(L1, 1); // L1: ... f ... 331 lua_pop(L1, 1); // L1: ... f ...
347 kLaneNameRegKey.pushValue(L2); // L1: ... f ... L2: {} f lane_name 332 kLaneNameRegKey.pushValue(L2); // L1: ... f ... L2: {} f lane_name
348 std::string_view const _to{ luaG_tostring(L2, kIdxTop) }; 333 std::string_view const _to{ luaW_tostring(L2, kIdxTop) };
349 lua_pop(L2, 1); // L2: {} f 334 lua_pop(L2, 1); // L2: {} f
350 raise_luaL_error( 335 raise_luaL_error(
351 getErrL(), 336 getErrL(),
@@ -368,7 +353,7 @@ void InterCopyContext::lookupNativeFunction() const
368// Always pushes a function to 'L2'. 353// Always pushes a function to 'L2'.
369void InterCopyContext::copyCachedFunction() const 354void InterCopyContext::copyCachedFunction() const
370{ 355{
371 FuncSubType const _funcSubType{ luaG_getfuncsubtype(L1, L1_i) }; 356 FuncSubType const _funcSubType{ luaW_getfuncsubtype(L1, L1_i) };
372 if (_funcSubType == FuncSubType::Bytecode) { 357 if (_funcSubType == FuncSubType::Bytecode) {
373 void* const _aspointer{ const_cast<void*>(lua_topointer(L1, L1_i)) }; 358 void* const _aspointer{ const_cast<void*>(lua_topointer(L1, L1_i)) };
374 // TODO: Merge this and same code for tables 359 // TODO: Merge this and same code for tables
@@ -386,10 +371,10 @@ void InterCopyContext::copyCachedFunction() const
386 // push a light userdata uniquely representing the function 371 // push a light userdata uniquely representing the function
387 lua_pushlightuserdata(L2, _aspointer); // L2: ... {cache} ... p 372 lua_pushlightuserdata(L2, _aspointer); // L2: ... {cache} ... p
388 373
389 //DEBUGSPEW_CODE(DebugSpew(U) << "<< ID: " << luaG_tostring(L2, -1) << " >>" << std::endl); 374 //DEBUGSPEW_CODE(DebugSpew(U) << "<< ID: " << luaW_tostring(L2, -1) << " >>" << std::endl);
390 375
391 lua_pushvalue(L2, -1); // L2: ... {cache} ... p p 376 lua_pushvalue(L2, -1); // L2: ... {cache} ... p p
392 if (luaG_rawget(L2, L2_cache_i) == LuaType::NIL) { // function is unknown // L2: ... {cache} ... p function|nil|true 377 if (luaW_rawget(L2, L2_cache_i) == LuaType::NIL) { // function is unknown // L2: ... {cache} ... p function|nil|true
393 lua_pop(L2, 1); // L2: ... {cache} ... p 378 lua_pop(L2, 1); // L2: ... {cache} ... p
394 379
395 // Set to 'true' for the duration of creation; need to find self-references 380 // Set to 'true' for the duration of creation; need to find self-references
@@ -405,7 +390,7 @@ void InterCopyContext::copyCachedFunction() const
405 } else { // function is native/LuaJIT: no need to cache 390 } else { // function is native/LuaJIT: no need to cache
406 lookupNativeFunction(); // L2: ... {cache} ... function 391 lookupNativeFunction(); // L2: ... {cache} ... function
407 // if the function was in fact a lookup sentinel, we can either get a function, table or full userdata here 392 // if the function was in fact a lookup sentinel, we can either get a function, table or full userdata here
408 LUA_ASSERT(L1, lua_isfunction(L2, kIdxTop) || lua_istable(L2, kIdxTop) || luaG_type(L2, kIdxTop) == LuaType::USERDATA); 393 LUA_ASSERT(L1, lua_isfunction(L2, kIdxTop) || lua_istable(L2, kIdxTop) || luaW_type(L2, kIdxTop) == LuaType::USERDATA);
409 } 394 }
410} 395}
411 396
@@ -430,7 +415,7 @@ bool InterCopyContext::lookupTable() const
430 415
431 case LookupMode::ToKeeper: 416 case LookupMode::ToKeeper:
432 // push a sentinel closure that holds the lookup name as upvalue 417 // push a sentinel closure that holds the lookup name as upvalue
433 luaG_pushstring(L2, _fqn); // L1: ... t ... L2: "f.q.n" 418 luaW_pushstring(L2, _fqn); // L1: ... t ... L2: "f.q.n"
434 lua_pushcclosure(L2, table_lookup_sentinel, 1); // L1: ... t ... L2: f 419 lua_pushcclosure(L2, table_lookup_sentinel, 1); // L1: ... t ... L2: f
435 break; 420 break;
436 421
@@ -439,26 +424,26 @@ bool InterCopyContext::lookupTable() const
439 kLookupRegKey.pushValue(L2); // L1: ... t ... L2: {} 424 kLookupRegKey.pushValue(L2); // L1: ... t ... L2: {}
440 STACK_CHECK(L2, 1); 425 STACK_CHECK(L2, 1);
441 LUA_ASSERT(L1, lua_istable(L2, -1)); 426 LUA_ASSERT(L1, lua_istable(L2, -1));
442 luaG_pushstring(L2, _fqn); // L2: {} "f.q.n" 427 luaW_pushstring(L2, _fqn); // L2: {} "f.q.n"
443 // we accept destination lookup failures in the case of transfering the Lanes body function (this will result in the source table being cloned instead) 428 // we accept destination lookup failures in the case of transfering the Lanes body function (this will result in the source table being cloned instead)
444 // but not when we extract something out of a keeper, as there is nothing to clone! 429 // but not when we extract something out of a keeper, as there is nothing to clone!
445 if (luaG_rawget(L2, StackIndex{ -2 }) == LuaType::NIL && mode == LookupMode::LaneBody) { // L2: {} t 430 if (luaW_rawget(L2, StackIndex{ -2 }) == LuaType::NIL && mode == LookupMode::LaneBody) { // L2: {} t
446 lua_pop(L2, 2); // L1: ... t ... L2: 431 lua_pop(L2, 2); // L1: ... t ... L2:
447 STACK_CHECK(L2, 0); 432 STACK_CHECK(L2, 0);
448 return false; 433 return false;
449 } 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 434 } 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
450 kLaneNameRegKey.pushValue(L1); // L1: ... t ... lane_name 435 kLaneNameRegKey.pushValue(L1); // L1: ... t ... lane_name
451 std::string_view const _from{ luaG_tostring(L1, kIdxTop) }; 436 std::string_view const _from{ luaW_tostring(L1, kIdxTop) };
452 lua_pop(L1, 1); // L1: ... t ... 437 lua_pop(L1, 1); // L1: ... t ...
453 kLaneNameRegKey.pushValue(L2); // L1: ... t ... L2: {} t lane_name 438 kLaneNameRegKey.pushValue(L2); // L1: ... t ... L2: {} t lane_name
454 std::string_view const _to{ luaG_tostring(L2, kIdxTop) }; 439 std::string_view const _to{ luaW_tostring(L2, kIdxTop) };
455 lua_pop(L2, 1); // L1: ... t ... L2: {} t 440 lua_pop(L2, 1); // L1: ... t ... L2: {} t
456 raise_luaL_error( 441 raise_luaL_error(
457 getErrL(), 442 getErrL(),
458 "%s: source table '%s' found as %s in %s destination transfer database.", 443 "%s: source table '%s' found as %s in %s destination transfer database.",
459 _from.empty() ? "main" : _from.data(), 444 _from.empty() ? "main" : _from.data(),
460 _fqn.data(), 445 _fqn.data(),
461 luaG_typename(L2, kIdxTop).data(), 446 luaW_typename(L2, kIdxTop).data(),
462 _to.empty() ? "main" : _to.data()); 447 _to.empty() ? "main" : _to.data());
463 } 448 }
464 lua_remove(L2, -2); // L1: ... t ... L2: t 449 lua_remove(L2, -2); // L1: ... t ... L2: t
@@ -487,8 +472,8 @@ void InterCopyContext::interCopyKeyValuePair() const
487 char* _valPath{ nullptr }; 472 char* _valPath{ nullptr };
488 if (U->verboseErrors) { 473 if (U->verboseErrors) {
489 // for debug purposes, let's try to build a useful name 474 // for debug purposes, let's try to build a useful name
490 if (luaG_type(L1, _key_i) == LuaType::STRING) { 475 if (luaW_type(L1, _key_i) == LuaType::STRING) {
491 std::string_view const _key{ luaG_tostring(L1, _key_i) }; 476 std::string_view const _key{ luaW_tostring(L1, _key_i) };
492 size_t const _bufLen{ name.size() + _key.size() + 2 }; // +2 for separator dot and terminating 0 477 size_t const _bufLen{ name.size() + _key.size() + 2 }; // +2 for separator dot and terminating 0
493 _valPath = static_cast<char*>(alloca(_bufLen)); 478 _valPath = static_cast<char*>(alloca(_bufLen));
494 sprintf(_valPath, "%s." STRINGVIEW_FMT, name.data(), (int) _key.size(), _key.data()); 479 sprintf(_valPath, "%s." STRINGVIEW_FMT, name.data(), (int) _key.size(), _key.data());
@@ -500,15 +485,15 @@ void InterCopyContext::interCopyKeyValuePair() const
500 sprintf(_valPath, "%s[" LUA_INTEGER_FMT "]", name.data(), key); 485 sprintf(_valPath, "%s[" LUA_INTEGER_FMT "]", name.data(), key);
501 } 486 }
502#endif // defined LUA_LNUM || LUA_VERSION_NUM >= 503 487#endif // defined LUA_LNUM || LUA_VERSION_NUM >= 503
503 else if (luaG_type(L1, _key_i) == LuaType::NUMBER) { 488 else if (luaW_type(L1, _key_i) == LuaType::NUMBER) {
504 lua_Number const key{ lua_tonumber(L1, _key_i) }; 489 lua_Number const key{ lua_tonumber(L1, _key_i) };
505 _valPath = (char*) alloca(name.size() + 32 + 3); // +3 for [] and terminating 0 490 _valPath = (char*) alloca(name.size() + 32 + 3); // +3 for [] and terminating 0
506 sprintf(_valPath, "%s[" LUA_NUMBER_FMT "]", name.data(), key); 491 sprintf(_valPath, "%s[" LUA_NUMBER_FMT "]", name.data(), key);
507 } else if (luaG_type(L1, _key_i) == LuaType::LIGHTUSERDATA) { 492 } else if (luaW_type(L1, _key_i) == LuaType::LIGHTUSERDATA) {
508 void* const _key{ lua_touserdata(L1, _key_i) }; 493 void* const _key{ lua_touserdata(L1, _key_i) };
509 _valPath = (char*) alloca(name.size() + 16 + 5); // +5 for [U:] and terminating 0 494 _valPath = (char*) alloca(name.size() + 16 + 5); // +5 for [U:] and terminating 0
510 sprintf(_valPath, "%s[U:%p]", name.data(), _key); 495 sprintf(_valPath, "%s[U:%p]", name.data(), _key);
511 } else if (luaG_type(L1, _key_i) == LuaType::BOOLEAN) { 496 } else if (luaW_type(L1, _key_i) == LuaType::BOOLEAN) {
512 int const _key{ lua_toboolean(L1, _key_i) }; 497 int const _key{ lua_toboolean(L1, _key_i) };
513 _valPath = (char*) alloca(name.size() + 8); // +8 for [], 'false' and terminating 0 498 _valPath = (char*) alloca(name.size() + 8); // +8 for [], 'false' and terminating 0
514 sprintf(_valPath, "%s[%s]", name.data(), _key ? "true" : "false"); 499 sprintf(_valPath, "%s[%s]", name.data(), _key ? "true" : "false");
@@ -532,7 +517,7 @@ LuaType InterCopyContext::processConversion() const
532{ 517{
533 static constexpr int kPODmask = (1 << LUA_TNIL) | (1 << LUA_TBOOLEAN) | (1 << LUA_TLIGHTUSERDATA) | (1 << LUA_TNUMBER) | (1 << LUA_TSTRING); 518 static constexpr int kPODmask = (1 << LUA_TNIL) | (1 << LUA_TBOOLEAN) | (1 << LUA_TLIGHTUSERDATA) | (1 << LUA_TNUMBER) | (1 << LUA_TSTRING);
534 519
535 LuaType _val_type{ luaG_type(L1, L1_i) }; 520 LuaType _val_type{ luaW_type(L1, L1_i) };
536 521
537 STACK_CHECK_START_REL(L1, 0); 522 STACK_CHECK_START_REL(L1, 0);
538 523
@@ -548,7 +533,7 @@ LuaType InterCopyContext::processConversion() const
548 } 533 }
549 // we have a metatable // L1: ... mt 534 // we have a metatable // L1: ... mt
550 static constexpr std::string_view kConvertField{ "__lanesconvert" }; 535 static constexpr std::string_view kConvertField{ "__lanesconvert" };
551 LuaType const _converterType{ luaG_getfield(L1, kIdxTop, kConvertField) }; // L1: ... mt kConvertField 536 LuaType const _converterType{ luaW_getfield(L1, kIdxTop, kConvertField) }; // L1: ... mt kConvertField
552 switch (_converterType) { 537 switch (_converterType) {
553 case LuaType::NIL: 538 case LuaType::NIL:
554 // no __lanesconvert, nothing to do 539 // no __lanesconvert, nothing to do
@@ -557,18 +542,18 @@ LuaType InterCopyContext::processConversion() const
557 542
558 case LuaType::LIGHTUSERDATA: 543 case LuaType::LIGHTUSERDATA:
559 if (kNilSentinel.equals(L1, kIdxTop)) { 544 if (kNilSentinel.equals(L1, kIdxTop)) {
560 DEBUGSPEW_CODE(DebugSpew(U) << "converted " << luaG_typename(L1, _val_type) << " to nil" << std::endl); 545 DEBUGSPEW_CODE(DebugSpew(U) << "converted " << luaW_typename(L1, _val_type) << " to nil" << std::endl);
561 lua_replace(L1, L1_i); // L1: ... mt 546 lua_replace(L1, L1_i); // L1: ... mt
562 lua_pop(L1, 1); // L1: ... 547 lua_pop(L1, 1); // L1: ...
563 _val_type = _converterType; 548 _val_type = _converterType;
564 } else { 549 } else {
565 raise_luaL_error(getErrL(), "Invalid %s type %s", kConvertField.data(), luaG_typename(L1, _converterType).data()); 550 raise_luaL_error(getErrL(), "Invalid %s type %s", kConvertField.data(), luaW_typename(L1, _converterType).data());
566 } 551 }
567 break; 552 break;
568 553
569 case LuaType::STRING: 554 case LuaType::STRING:
570 // kConvertField == "decay" -> replace source value with it's pointer 555 // kConvertField == "decay" -> replace source value with it's pointer
571 if (std::string_view const _mode{ luaG_tostring(L1, kIdxTop) }; _mode == "decay") { 556 if (std::string_view const _mode{ luaW_tostring(L1, kIdxTop) }; _mode == "decay") {
572 lua_pop(L1, 1); // L1: ... mt 557 lua_pop(L1, 1); // L1: ... mt
573 lua_pushlightuserdata(L1, const_cast<void*>(lua_topointer(L1, L1_i))); // L1: ... mt decayed 558 lua_pushlightuserdata(L1, const_cast<void*>(lua_topointer(L1, L1_i))); // L1: ... mt decayed
574 lua_replace(L1, L1_i); // L1: ... mt 559 lua_replace(L1, L1_i); // L1: ... mt
@@ -581,18 +566,18 @@ LuaType InterCopyContext::processConversion() const
581 566
582 case LuaType::FUNCTION: 567 case LuaType::FUNCTION:
583 lua_pushvalue(L1, L1_i); // L1: ... mt kConvertField val 568 lua_pushvalue(L1, L1_i); // L1: ... mt kConvertField val
584 luaG_pushstring(L1, mode == LookupMode::ToKeeper ? "keeper" : "regular"); // L1: ... mt kConvertField val string 569 luaW_pushstring(L1, mode == LookupMode::ToKeeper ? "keeper" : "regular"); // L1: ... mt kConvertField val string
585 lua_call(L1, 2, 1); // val:kConvertField(str) -> result // L1: ... mt kConvertField converted 570 lua_call(L1, 2, 1); // val:kConvertField(str) -> result // L1: ... mt kConvertField converted
586 lua_replace(L1, L1_i); // L1: ... mt 571 lua_replace(L1, L1_i); // L1: ... mt
587 lua_pop(L1, 1); // L1: ... mt 572 lua_pop(L1, 1); // L1: ... mt
588 _val_type = luaG_type(L1, L1_i); 573 _val_type = luaW_type(L1, L1_i);
589 break; 574 break;
590 575
591 default: 576 default:
592 raise_luaL_error(getErrL(), "Invalid %s type %s", kConvertField.data(), luaG_typename(L1, _converterType).data()); 577 raise_luaL_error(getErrL(), "Invalid %s type %s", kConvertField.data(), luaW_typename(L1, _converterType).data());
593 } 578 }
594 STACK_CHECK(L1, 0); 579 STACK_CHECK(L1, 0);
595 LUA_ASSERT(getErrL(), luaG_type(L1, L1_i) == _val_type); 580 LUA_ASSERT(getErrL(), luaW_type(L1, L1_i) == _val_type);
596 return _val_type; 581 return _val_type;
597} 582}
598 583
@@ -615,7 +600,7 @@ bool InterCopyContext::pushCachedMetatable() const
615 // do we already know this metatable? 600 // do we already know this metatable?
616 std::ignore = kMtIdRegKey.getSubTable(L2, NArr{ 0 }, NRec{ 0 }); // L2: _R[kMtIdRegKey] 601 std::ignore = kMtIdRegKey.getSubTable(L2, NArr{ 0 }, NRec{ 0 }); // L2: _R[kMtIdRegKey]
617 lua_pushinteger(L2, _mt_id); // L2: _R[kMtIdRegKey] id 602 lua_pushinteger(L2, _mt_id); // L2: _R[kMtIdRegKey] id
618 if (luaG_rawget(L2, StackIndex{ -2 }) == LuaType::NIL) { // L2 did not know the metatable // L2: _R[kMtIdRegKey] mt|nil 603 if (luaW_rawget(L2, StackIndex{ -2 }) == LuaType::NIL) { // L2 did not know the metatable // L2: _R[kMtIdRegKey] mt|nil
619 lua_pop(L2, 1); // L2: _R[kMtIdRegKey] 604 lua_pop(L2, 1); // L2: _R[kMtIdRegKey]
620 InterCopyContext const _c{ U, L2, L1, L2_cache_i, SourceIndex{ lua_gettop(L1) }, VT::METATABLE, mode, name }; 605 InterCopyContext const _c{ U, L2, L1, L2_cache_i, SourceIndex{ lua_gettop(L1) }, VT::METATABLE, mode, name };
621 if (_c.interCopyOne() != InterCopyResult::Success) { // L2: _R[kMtIdRegKey] mt? 606 if (_c.interCopyOne() != InterCopyResult::Success) { // L2: _R[kMtIdRegKey] mt?
@@ -662,9 +647,9 @@ bool InterCopyContext::pushCachedTable() const
662 // push a light userdata uniquely representing the table 647 // push a light userdata uniquely representing the table
663 lua_pushlightuserdata(L2, const_cast<void*>(_p)); // L1: ... t ... L2: ... p 648 lua_pushlightuserdata(L2, const_cast<void*>(_p)); // L1: ... t ... L2: ... p
664 649
665 //DEBUGSPEW_CODE(DebugSpew(U) << "<< ID: " << luaG_tostring(L2, -1) << " >>" << std::endl); 650 //DEBUGSPEW_CODE(DebugSpew(U) << "<< ID: " << luaW_tostring(L2, -1) << " >>" << std::endl);
666 651
667 bool const _not_found_in_cache{ luaG_rawget(L2, L2_cache_i) == LuaType::NIL }; // L1: ... t ... L2: ... {cached|nil} 652 bool const _not_found_in_cache{ luaW_rawget(L2, L2_cache_i) == LuaType::NIL }; // L1: ... t ... L2: ... {cached|nil}
668 if (_not_found_in_cache) { 653 if (_not_found_in_cache) {
669 // create a new entry in the cache 654 // create a new entry in the cache
670 lua_pop(L2, 1); // L1: ... t ... L2: ... 655 lua_pop(L2, 1); // L1: ... t ... L2: ...
@@ -696,7 +681,7 @@ bool InterCopyContext::lookupUserdata() const
696 681
697 case LookupMode::ToKeeper: 682 case LookupMode::ToKeeper:
698 // push a sentinel closure that holds the lookup name as upvalue 683 // push a sentinel closure that holds the lookup name as upvalue
699 luaG_pushstring(L2, _fqn); // L1: ... f ... L2: "f.q.n" 684 luaW_pushstring(L2, _fqn); // L1: ... f ... L2: "f.q.n"
700 lua_pushcclosure(L2, userdata_lookup_sentinel, 1); // L1: ... f ... L2: f 685 lua_pushcclosure(L2, userdata_lookup_sentinel, 1); // L1: ... f ... L2: f
701 break; 686 break;
702 687
@@ -705,16 +690,16 @@ bool InterCopyContext::lookupUserdata() const
705 kLookupRegKey.pushValue(L2); // L1: ... f ... L2: {} 690 kLookupRegKey.pushValue(L2); // L1: ... f ... L2: {}
706 STACK_CHECK(L2, 1); 691 STACK_CHECK(L2, 1);
707 LUA_ASSERT(L1, lua_istable(L2, -1)); 692 LUA_ASSERT(L1, lua_istable(L2, -1));
708 luaG_pushstring(L2, _fqn); // L1: ... f ... L2: {} "f.q.n" 693 luaW_pushstring(L2, _fqn); // L1: ... f ... L2: {} "f.q.n"
709 LuaType const _type{ luaG_rawget(L2, StackIndex{ -2 }) }; // L1: ... f ... L2: {} f 694 LuaType const _type{ luaW_rawget(L2, StackIndex{ -2 }) }; // L1: ... f ... L2: {} f
710 // nil means we don't know how to transfer stuff: user should do something 695 // nil means we don't know how to transfer stuff: user should do something
711 // anything other than function or table should not happen! 696 // anything other than function or table should not happen!
712 if (_type != LuaType::FUNCTION && _type != LuaType::TABLE) { 697 if (_type != LuaType::FUNCTION && _type != LuaType::TABLE) {
713 kLaneNameRegKey.pushValue(L1); // L1: ... f ... lane_name 698 kLaneNameRegKey.pushValue(L1); // L1: ... f ... lane_name
714 std::string_view const _from{ luaG_tostring(L1, kIdxTop) }; 699 std::string_view const _from{ luaW_tostring(L1, kIdxTop) };
715 lua_pop(L1, 1); // L1: ... f ... 700 lua_pop(L1, 1); // L1: ... f ...
716 kLaneNameRegKey.pushValue(L2); // L1: ... f ... L2: {} f lane_name 701 kLaneNameRegKey.pushValue(L2); // L1: ... f ... L2: {} f lane_name
717 std::string_view const _to{ luaG_tostring(L2, kIdxTop) }; 702 std::string_view const _to{ luaW_tostring(L2, kIdxTop) };
718 lua_pop(L2, 1); // L2: {} f 703 lua_pop(L2, 1); // L2: {} f
719 raise_luaL_error( 704 raise_luaL_error(
720 getErrL(), 705 getErrL(),
@@ -736,7 +721,7 @@ bool InterCopyContext::lookupUserdata() const
736[[nodiscard]] 721[[nodiscard]]
737bool InterCopyContext::tryCopyClonable() const 722bool InterCopyContext::tryCopyClonable() const
738{ 723{
739 SourceIndex const _L1_i{ luaG_absindex(L1, L1_i).value() }; 724 SourceIndex const _L1_i{ luaW_absindex(L1, L1_i).value() };
740 void* const _source{ lua_touserdata(L1, _L1_i) }; 725 void* const _source{ lua_touserdata(L1, _L1_i) };
741 726
742 STACK_CHECK_START_REL(L1, 0); 727 STACK_CHECK_START_REL(L1, 0);
@@ -744,7 +729,7 @@ bool InterCopyContext::tryCopyClonable() const
744 729
745 // Check if the source was already cloned during this copy 730 // Check if the source was already cloned during this copy
746 lua_pushlightuserdata(L2, _source); // L2: ... source 731 lua_pushlightuserdata(L2, _source); // L2: ... source
747 if (luaG_rawget(L2, L2_cache_i) != LuaType::NIL) { // L2: ... clone? 732 if (luaW_rawget(L2, L2_cache_i) != LuaType::NIL) { // L2: ... clone?
748 STACK_CHECK(L2, 1); 733 STACK_CHECK(L2, 1);
749 return true; 734 return true;
750 } else { 735 } else {
@@ -759,7 +744,7 @@ bool InterCopyContext::tryCopyClonable() const
759 } 744 }
760 745
761 // no __lanesclone? -> not clonable 746 // no __lanesclone? -> not clonable
762 if (luaG_getfield(L1, kIdxTop, "__lanesclone") == LuaType::NIL) { // L1: ... mt nil 747 if (luaW_getfield(L1, kIdxTop, "__lanesclone") == LuaType::NIL) { // L1: ... mt nil
763 lua_pop(L1, 2); // L1: ... 748 lua_pop(L1, 2); // L1: ...
764 STACK_CHECK(L1, 0); 749 STACK_CHECK(L1, 0);
765 return false; 750 return false;
@@ -769,10 +754,10 @@ bool InterCopyContext::tryCopyClonable() const
769 754
770 // we need to copy over the uservalues of the userdata as well 755 // we need to copy over the uservalues of the userdata as well
771 { 756 {
772 StackIndex const _mt{ luaG_absindex(L1, StackIndex{ -2 }) }; // L1: ... mt __lanesclone 757 StackIndex const _mt{ luaW_absindex(L1, StackIndex{ -2 }) }; // L1: ... mt __lanesclone
773 size_t const userdata_size{ lua_rawlen(L1, _L1_i) }; 758 auto const userdata_size{ static_cast<size_t>(lua_rawlen(L1, _L1_i)) }; // make 32-bits builds happy
774 // extract all the uservalues, but don't transfer them yet 759 // extract all the uservalues, but don't transfer them yet
775 UserValueCount const _nuv{ luaG_getalluservalues(L1, _L1_i) }; // L1: ... mt __lanesclone [uv]* 760 UserValueCount const _nuv{ luaW_getalluservalues(L1, _L1_i) }; // L1: ... mt __lanesclone [uv]*
776 // create the clone userdata with the required number of uservalue slots 761 // create the clone userdata with the required number of uservalue slots
777 void* const _clone{ lua_newuserdatauv(L2, userdata_size, _nuv) }; // L2: ... u 762 void* const _clone{ lua_newuserdatauv(L2, userdata_size, _nuv) }; // L2: ... u
778 // copy the metatable in the target state, and give it to the clone we put there 763 // copy the metatable in the target state, and give it to the clone we put there
@@ -804,7 +789,7 @@ bool InterCopyContext::tryCopyClonable() const
804 // assign uservalues 789 // assign uservalues
805 UserValueIndex _uvi{ _nuv.value() }; 790 UserValueIndex _uvi{ _nuv.value() };
806 while (_uvi > 0) { 791 while (_uvi > 0) {
807 _c.L1_i = SourceIndex{ luaG_absindex(L1, kIdxTop).value() }; 792 _c.L1_i = SourceIndex{ luaW_absindex(L1, kIdxTop).value() };
808 if (_c.interCopyOne() != InterCopyResult::Success) { // L2: ... u uv 793 if (_c.interCopyOne() != InterCopyResult::Success) { // L2: ... u uv
809 raise_luaL_error(getErrL(), "Cannot copy upvalue type '%s'", luaL_typename(L1, -1)); 794 raise_luaL_error(getErrL(), "Cannot copy upvalue type '%s'", luaL_typename(L1, -1));
810 } 795 }
@@ -850,10 +835,10 @@ bool InterCopyContext::tryCopyDeep() const
850 STACK_CHECK_START_REL(L2, 0); 835 STACK_CHECK_START_REL(L2, 0);
851 836
852 // extract all uservalues of the source. unfortunately, the only way to know their count is to iterate until we fail 837 // extract all uservalues of the source. unfortunately, the only way to know their count is to iterate until we fail
853 UserValueCount const _nuv{ luaG_getalluservalues(L1, L1_i) }; // L1: ... deep ... [uv]* 838 UserValueCount const _nuv{ luaW_getalluservalues(L1, L1_i) }; // L1: ... deep ... [uv]*
854 STACK_CHECK(L1, _nuv); 839 STACK_CHECK(L1, _nuv);
855 840
856 DeepPrelude* const _deep{ *luaG_tofulluserdata<DeepPrelude*>(L1, L1_i) }; 841 DeepPrelude* const _deep{ *luaW_tofulluserdata<DeepPrelude*>(L1, L1_i) };
857 DeepFactory::PushDeepProxy(L2, _deep, _nuv, mode, getErrL()); // L1: ... deep ... [uv]* L2: deep 842 DeepFactory::PushDeepProxy(L2, _deep, _nuv, mode, getErrL()); // L1: ... deep ... [uv]* L2: deep
858 843
859 // transfer all uservalues of the source in the destination 844 // transfer all uservalues of the source in the destination
@@ -863,7 +848,7 @@ bool InterCopyContext::tryCopyDeep() const
863 STACK_GROW(L2, _nuv); 848 STACK_GROW(L2, _nuv);
864 UserValueIndex _uvi{ _nuv.value() }; 849 UserValueIndex _uvi{ _nuv.value() };
865 while (_uvi) { 850 while (_uvi) {
866 _c.L1_i = SourceIndex{ luaG_absindex(L1, kIdxTop).value() }; 851 _c.L1_i = SourceIndex{ luaW_absindex(L1, kIdxTop).value() };
867 if (_c.interCopyOne() != InterCopyResult::Success) { // L1: ... deep ... [uv]* L2: deep uv 852 if (_c.interCopyOne() != InterCopyResult::Success) { // L1: ... deep ... [uv]* L2: deep uv
868 raise_luaL_error(getErrL(), "Cannot copy upvalue type '%s'", luaL_typename(L1, -1)); 853 raise_luaL_error(getErrL(), "Cannot copy upvalue type '%s'", luaL_typename(L1, -1));
869 } 854 }
@@ -911,7 +896,7 @@ bool InterCopyContext::interCopyFunction() const
911 lua_getupvalue(L1, L1_i, 2); // L1: ... u 896 lua_getupvalue(L1, L1_i, 2); // L1: ... u
912 void* _source{ lua_touserdata(L1, -1) }; 897 void* _source{ lua_touserdata(L1, -1) };
913 lua_pushlightuserdata(L2, _source); // L2: ... source 898 lua_pushlightuserdata(L2, _source); // L2: ... source
914 if (luaG_rawget(L2, L2_cache_i) != LuaType::NIL) { // L2: ... u? 899 if (luaW_rawget(L2, L2_cache_i) != LuaType::NIL) { // L2: ... u?
915 lua_pop(L1, 1); // L1: ... 900 lua_pop(L1, 1); // L1: ...
916 STACK_CHECK(L1, 0); 901 STACK_CHECK(L1, 0);
917 STACK_CHECK(L2, 1); 902 STACK_CHECK(L2, 1);
@@ -930,10 +915,10 @@ bool InterCopyContext::interCopyFunction() const
930 _source = lua_touserdata(L1, -1); 915 _source = lua_touserdata(L1, -1);
931 void* _clone{ nullptr }; 916 void* _clone{ nullptr };
932 // get the number of bytes to allocate for the clone 917 // get the number of bytes to allocate for the clone
933 size_t const _userdata_size{ lua_rawlen(L1, kIdxTop) }; 918 auto const _userdata_size{ static_cast<size_t>(lua_rawlen(L1, kIdxTop)) }; // make 32-bits builds happy
934 { 919 {
935 // extract uservalues (don't transfer them yet) 920 // extract uservalues (don't transfer them yet)
936 UserValueCount const _nuv{ luaG_getalluservalues(L1, source_i) }; // L1: ... u [uv]* 921 UserValueCount const _nuv{ luaW_getalluservalues(L1, source_i) }; // L1: ... u [uv]*
937 STACK_CHECK(L1, _nuv + 1); 922 STACK_CHECK(L1, _nuv + 1);
938 // create the clone userdata with the required number of uservalue slots 923 // create the clone userdata with the required number of uservalue slots
939 _clone = lua_newuserdatauv(L2, _userdata_size, _nuv); // L2: ... mt u 924 _clone = lua_newuserdatauv(L2, _userdata_size, _nuv); // L2: ... mt u
@@ -948,7 +933,7 @@ bool InterCopyContext::interCopyFunction() const
948 InterCopyContext _c{ *this }; 933 InterCopyContext _c{ *this };
949 UserValueIndex _uvi{ _nuv.value() }; 934 UserValueIndex _uvi{ _nuv.value() };
950 while (_uvi > 0) { 935 while (_uvi > 0) {
951 _c.L1_i = SourceIndex{ luaG_absindex(L1, kIdxTop).value() }; 936 _c.L1_i = SourceIndex{ luaW_absindex(L1, kIdxTop).value() };
952 if (_c.interCopyOne() != InterCopyResult::Success) { // L2: ... mt u uv 937 if (_c.interCopyOne() != InterCopyResult::Success) { // L2: ... mt u uv
953 raise_luaL_error(getErrL(), "Cannot copy upvalue type '%s'", luaL_typename(L1, -1)); 938 raise_luaL_error(getErrL(), "Cannot copy upvalue type '%s'", luaL_typename(L1, -1));
954 } 939 }
@@ -965,9 +950,9 @@ bool InterCopyContext::interCopyFunction() const
965 // perform the custom cloning part 950 // perform the custom cloning part
966 lua_insert(L2, -2); // L2: ... u mt 951 lua_insert(L2, -2); // L2: ... u mt
967 // __lanesclone should always exist because we wouldn't be restoring data from a userdata_clone_sentinel closure to begin with 952 // __lanesclone should always exist because we wouldn't be restoring data from a userdata_clone_sentinel closure to begin with
968 LuaType const _funcType{ luaG_getfield(L2, kIdxTop, "__lanesclone") }; // L2: ... u mt __lanesclone 953 LuaType const _funcType{ luaW_getfield(L2, kIdxTop, "__lanesclone") }; // L2: ... u mt __lanesclone
969 if (_funcType != LuaType::FUNCTION) { 954 if (_funcType != LuaType::FUNCTION) {
970 raise_luaL_error(getErrL(), "INTERNAL ERROR: __lanesclone is a %s, not a function", luaG_typename(L2, _funcType).data()); 955 raise_luaL_error(getErrL(), "INTERNAL ERROR: __lanesclone is a %s, not a function", luaW_typename(L2, _funcType).data());
971 } 956 }
972 lua_remove(L2, -2); // L2: ... u __lanesclone 957 lua_remove(L2, -2); // L2: ... u __lanesclone
973 lua_pushlightuserdata(L2, _clone); // L2: ... u __lanesclone clone 958 lua_pushlightuserdata(L2, _clone); // L2: ... u __lanesclone clone
@@ -994,7 +979,7 @@ bool InterCopyContext::interCopyLightuserdata() const
994 // recognize and print known UniqueKey names here 979 // recognize and print known UniqueKey names here
995 if constexpr (USE_DEBUG_SPEW()) { 980 if constexpr (USE_DEBUG_SPEW()) {
996 bool _found{ false }; 981 bool _found{ false };
997 static constexpr std::array<std::reference_wrapper<UniqueKey const>, 3> kKeysToCheck{ kLindaBatched, kCancelError, kNilSentinel }; 982 static constexpr std::array<std::reference_wrapper<UniqueKey const>, 2> kKeysToCheck{ kCancelError, kNilSentinel };
998 for (UniqueKey const& _key : kKeysToCheck) { 983 for (UniqueKey const& _key : kKeysToCheck) {
999 if (_key.equals(L1, L1_i)) { 984 if (_key.equals(L1, L1_i)) {
1000 DEBUGSPEW_CODE(DebugSpew(nullptr) << _key.debugName); 985 DEBUGSPEW_CODE(DebugSpew(nullptr) << _key.debugName);
@@ -1060,9 +1045,9 @@ bool InterCopyContext::interCopyNumber() const
1060[[nodiscard]] 1045[[nodiscard]]
1061bool InterCopyContext::interCopyString() const 1046bool InterCopyContext::interCopyString() const
1062{ 1047{
1063 std::string_view const _s{ luaG_tostring(L1, L1_i) }; 1048 std::string_view const _s{ luaW_tostring(L1, L1_i) };
1064 DEBUGSPEW_CODE(DebugSpew(nullptr) << "'" << _s << "'" << std::endl); 1049 DEBUGSPEW_CODE(DebugSpew(nullptr) << "'" << _s << "'" << std::endl);
1065 luaG_pushstring(L2, _s); 1050 luaW_pushstring(L2, _s);
1066 return true; 1051 return true;
1067} 1052}
1068 1053
@@ -1154,7 +1139,7 @@ bool InterCopyContext::interCopyUserdata() const
1154 1139
1155 // Last, let's try to see if this userdata is special (aka is it some userdata that we registered in our lookup databases during module registration?) 1140 // Last, let's try to see if this userdata is special (aka is it some userdata that we registered in our lookup databases during module registration?)
1156 if (lookupUserdata()) { 1141 if (lookupUserdata()) {
1157 LUA_ASSERT(L1, luaG_type(L2, kIdxTop) == LuaType::USERDATA || (lua_tocfunction(L2, kIdxTop) == userdata_lookup_sentinel)); // from lookup data. can also be userdata_lookup_sentinel if this is a userdata we know 1142 LUA_ASSERT(L1, luaW_type(L2, kIdxTop) == LuaType::USERDATA || (lua_tocfunction(L2, kIdxTop) == userdata_lookup_sentinel)); // from lookup data. can also be userdata_lookup_sentinel if this is a userdata we know
1158 return true; 1143 return true;
1159 } 1144 }
1160 1145
@@ -1291,8 +1276,8 @@ InterCopyResult InterCopyContext::interCopyPackage() const
1291 } const _onExit{ L2 }; 1276 } const _onExit{ L2 };
1292 1277
1293 STACK_CHECK_START_REL(L1, 0); 1278 STACK_CHECK_START_REL(L1, 0);
1294 if (luaG_type(L1, L1_i) != LuaType::TABLE) { 1279 if (luaW_type(L1, L1_i) != LuaType::TABLE) {
1295 std::string_view const _msg{ luaG_pushstring(L1, "expected package as table, got a %s", luaL_typename(L1, L1_i)) }; 1280 std::string_view const _msg{ luaW_pushstring(L1, "expected package as table, got a %s", luaL_typename(L1, L1_i)) };
1296 STACK_CHECK(L1, 1); 1281 STACK_CHECK(L1, 1);
1297 // raise the error when copying from lane to lane, else just leave it on the stack to be raised later 1282 // raise the error when copying from lane to lane, else just leave it on the stack to be raised later
1298 if (mode == LookupMode::LaneBody) { 1283 if (mode == LookupMode::LaneBody) {
@@ -1300,7 +1285,7 @@ InterCopyResult InterCopyContext::interCopyPackage() const
1300 } 1285 }
1301 return InterCopyResult::Error; 1286 return InterCopyResult::Error;
1302 } 1287 }
1303 if (luaG_getmodule(L2, LUA_LOADLIBNAME) == LuaType::NIL) { // package library not loaded: do nothing 1288 if (luaW_getmodule(L2, LUA_LOADLIBNAME) == LuaType::NIL) { // package library not loaded: do nothing
1304 DEBUGSPEW_CODE(DebugSpew(U) << "'package' not loaded, nothing to do" << std::endl); 1289 DEBUGSPEW_CODE(DebugSpew(U) << "'package' not loaded, nothing to do" << std::endl);
1305 STACK_CHECK(L1, 0); 1290 STACK_CHECK(L1, 0);
1306 return InterCopyResult::Success; 1291 return InterCopyResult::Success;
@@ -1317,7 +1302,7 @@ InterCopyResult InterCopyContext::interCopyPackage() const
1317 continue; 1302 continue;
1318 } 1303 }
1319 DEBUGSPEW_CODE(DebugSpew(U) << "package." << _entry << std::endl); 1304 DEBUGSPEW_CODE(DebugSpew(U) << "package." << _entry << std::endl);
1320 if (luaG_getfield(L1, L1_i, _entry) == LuaType::NIL) { 1305 if (luaW_getfield(L1, L1_i, _entry) == LuaType::NIL) {
1321 lua_pop(L1, 1); 1306 lua_pop(L1, 1);
1322 } else { 1307 } else {
1323 { 1308 {
@@ -1328,9 +1313,9 @@ InterCopyResult InterCopyContext::interCopyPackage() const
1328 STACK_CHECK(L1, 0); 1313 STACK_CHECK(L1, 0);
1329 } 1314 }
1330 if (_result == InterCopyResult::Success) { 1315 if (_result == InterCopyResult::Success) {
1331 luaG_setfield(L2, StackIndex{ -2 }, _entry); // set package[entry] 1316 luaW_setfield(L2, StackIndex{ -2 }, _entry); // set package[entry]
1332 } else { 1317 } else {
1333 std::string_view const _msg{ luaG_pushstring(L1, "failed to copy package.%s", _entry.data()) }; 1318 std::string_view const _msg{ luaW_pushstring(L1, "failed to copy package.%s", _entry.data()) };
1334 // raise the error when copying from lane to lane, else just leave it on the stack to be raised later 1319 // raise the error when copying from lane to lane, else just leave it on the stack to be raised later
1335 if (mode == LookupMode::LaneBody) { 1320 if (mode == LookupMode::LaneBody) {
1336 raise_luaL_error(getErrL(), _msg); 1321 raise_luaL_error(getErrL(), _msg);
diff --git a/src/keeper.cpp b/src/keeper.cpp
index cad9207..4af0d86 100644
--- a/src/keeper.cpp
+++ b/src/keeper.cpp
@@ -77,7 +77,7 @@ class KeyUD final
77 77
78 // a fifo full userdata has one uservalue, the table that holds the actual fifo contents 78 // a fifo full userdata has one uservalue, the table that holds the actual fifo contents
79 [[nodiscard]] 79 [[nodiscard]]
80 static void* operator new([[maybe_unused]] size_t size_, KeeperState L_) noexcept { return luaG_newuserdatauv<KeyUD>(L_, UserValueCount{ 1 }); } 80 static void* operator new([[maybe_unused]] size_t size_, KeeperState L_) noexcept { return luaW_newuserdatauv<KeyUD>(L_, UserValueCount{ 1 }); }
81 // always embedded somewhere else or "in-place constructed" as a full userdata 81 // always embedded somewhere else or "in-place constructed" as a full userdata
82 // can't actually delete the operator because the compiler generates stack unwinding code that could call it in case of exception 82 // can't actually delete the operator because the compiler generates stack unwinding code that could call it in case of exception
83 static void operator delete([[maybe_unused]] void* p_, [[maybe_unused]] KeeperState L_) { LUA_ASSERT(L_, !"should never be called"); } 83 static void operator delete([[maybe_unused]] void* p_, [[maybe_unused]] KeeperState L_) { LUA_ASSERT(L_, !"should never be called"); }
@@ -104,6 +104,7 @@ class KeyUD final
104 104
105// ################################################################################################# 105// #################################################################################################
106 106
107[[nodiscard]]
107bool KeyUD::changeLimit(LindaLimit const limit_) 108bool KeyUD::changeLimit(LindaLimit const limit_)
108{ 109{
109 bool const _newSlackAvailable{ 110 bool const _newSlackAvailable{
@@ -127,6 +128,7 @@ LindaRestrict KeyUD::changeRestrict(LindaRestrict const restrict_)
127 128
128// in: nothing 129// in: nothing
129// out: { first = 1, count = 0, limit = -1} 130// out: { first = 1, count = 0, limit = -1}
131[[nodiscard]]
130KeyUD* KeyUD::Create(KeeperState const K_) 132KeyUD* KeyUD::Create(KeeperState const K_)
131{ 133{
132 STACK_GROW(K_, 2); 134 STACK_GROW(K_, 2);
@@ -141,9 +143,10 @@ KeyUD* KeyUD::Create(KeeperState const K_)
141 143
142// ################################################################################################# 144// #################################################################################################
143 145
146[[nodiscard]]
144KeyUD* KeyUD::GetPtr(KeeperState const K_, StackIndex const idx_) 147KeyUD* KeyUD::GetPtr(KeeperState const K_, StackIndex const idx_)
145{ 148{
146 return luaG_tofulluserdata<KeyUD>(K_, idx_); 149 return luaW_tofulluserdata<KeyUD>(K_, idx_);
147} 150}
148 151
149// ################################################################################################# 152// #################################################################################################
@@ -181,6 +184,7 @@ void KeyUD::peek(KeeperState const K_, int const count_) const
181 184
182// in: fifo 185// in: fifo
183// out: remove the fifo table from the stack, push as many items as required on the stack (function assumes they exist in sufficient number) 186// out: remove the fifo table from the stack, push as many items as required on the stack (function assumes they exist in sufficient number)
187[[nodiscard]]
184int KeyUD::pop(KeeperState const K_, int const minCount_, int const maxCount_) 188int KeyUD::pop(KeeperState const K_, int const minCount_, int const maxCount_)
185{ 189{
186 if (count < minCount_) { 190 if (count < minCount_) {
@@ -191,23 +195,33 @@ int KeyUD::pop(KeeperState const K_, int const minCount_, int const maxCount_)
191 int const _popCount{ std::min(count, maxCount_) }; 195 int const _popCount{ std::min(count, maxCount_) };
192 LUA_ASSERT(K_, KeyUD::GetPtr(K_, kIdxTop) == this); // K_: ... this 196 LUA_ASSERT(K_, KeyUD::GetPtr(K_, kIdxTop) == this); // K_: ... this
193 prepareAccess(K_, kIdxTop); // K_: ... fifo 197 prepareAccess(K_, kIdxTop); // K_: ... fifo
198
199 STACK_CHECK_START_REL(K_, 0);
194 StackIndex const _fifo_idx{ lua_gettop(K_) }; 200 StackIndex const _fifo_idx{ lua_gettop(K_) };
195 // each iteration pushes a value on the stack! 201 // each iteration pushes a value on the stack!
196 STACK_GROW(K_, _popCount + 2); 202 STACK_GROW(K_, _popCount + 2);
197 // skip first item, we will push it last 203
198 for (int const _i : std::ranges::iota_view{ 1, _popCount }) { 204 // remove an element from fifo sequence and push it on the stack
205 auto _extractFifoItem = [K = K_, first = first, fifo_idx = lua_gettop(K_)](int const _i)
206 {
207 STACK_CHECK_START_REL(K, 0);
199 int const _at{ first + _i }; 208 int const _at{ first + _i };
200 // push item on the stack 209 // push item on the stack
201 lua_rawgeti(K_, _fifo_idx, _at); // K_: ... fifo val 210 lua_rawgeti(K, fifo_idx, _at); // K_: ... fifo val
202 // remove item from the fifo 211 // remove item from the fifo
203 lua_pushnil(K_); // K_: ... fifo val nil 212 lua_pushnil(K); // K_: ... fifo val nil
204 lua_rawseti(K_, _fifo_idx, _at); // K_: ... fifo val 213 lua_rawseti(K, fifo_idx, _at); // K_: ... fifo val
214 STACK_CHECK(K, 1);
215 };
216
217 // skip first item, we will push it last to avoid shifting the whole stack when removing 'fifo'
218 for (int const _i : std::ranges::iota_view{ 1, _popCount }) {
219 _extractFifoItem(_i); // K_: ... fifo val1...valN
205 } 220 }
206 // now process first item 221 // now process first item
207 lua_rawgeti(K_, _fifo_idx, first); // K_: ... fifo vals val 222 _extractFifoItem(0); // K_: ... fifo val1...valN val0
208 lua_pushnil(K_); // K_: ... fifo vals val nil 223 STACK_CHECK(K_, _popCount);
209 lua_rawseti(K_, _fifo_idx, first); // K_: ... fifo vals val 224 lua_replace(K_, _fifo_idx); // K_: ... val0...valN
210 lua_replace(K_, _fifo_idx); // K_: ... vals
211 225
212 // avoid ever-growing indexes by resetting each time we detect the fifo is empty 226 // avoid ever-growing indexes by resetting each time we detect the fifo is empty
213 int const _new_count{ count - _popCount }; 227 int const _new_count{ count - _popCount };
@@ -222,7 +236,7 @@ int KeyUD::pop(KeeperState const K_, int const minCount_, int const maxCount_)
222// replaces it by its uservalue on the stack (the table holding the fifo values) 236// replaces it by its uservalue on the stack (the table holding the fifo values)
223void KeyUD::prepareAccess(KeeperState const K_, StackIndex const idx_) const 237void KeyUD::prepareAccess(KeeperState const K_, StackIndex const idx_) const
224{ 238{
225 StackIndex const _idx{ luaG_absindex(K_, idx_) }; 239 StackIndex const _idx{ luaW_absindex(K_, idx_) };
226 LUA_ASSERT(K_, KeyUD::GetPtr(K_, idx_) == this); 240 LUA_ASSERT(K_, KeyUD::GetPtr(K_, idx_) == this);
227 // we can replace the key userdata in the stack without fear of it being GCed, there are other references around 241 // we can replace the key userdata in the stack without fear of it being GCed, there are other references around
228 lua_getiuservalue(K_, _idx, kContentsTableIndex); 242 lua_getiuservalue(K_, _idx, kContentsTableIndex);
@@ -233,9 +247,10 @@ void KeyUD::prepareAccess(KeeperState const K_, StackIndex const idx_) const
233 247
234// in: expect this val... on top of the stack 248// in: expect this val... on top of the stack
235// out: nothing, removes all pushed values from the stack 249// out: nothing, removes all pushed values from the stack
250[[nodiscard]]
236bool KeyUD::push(KeeperState const K_, int const count_, bool const enforceLimit_) 251bool KeyUD::push(KeeperState const K_, int const count_, bool const enforceLimit_)
237{ 252{
238 StackIndex const _fifoIdx{ luaG_absindex(K_, StackIndex{ -1 - count_ }) }; 253 StackIndex const _fifoIdx{ luaW_absindex(K_, StackIndex{ -1 - count_ }) };
239 LUA_ASSERT(K_, KeyUD::GetPtr(K_, _fifoIdx) == this); // K_: this val... 254 LUA_ASSERT(K_, KeyUD::GetPtr(K_, _fifoIdx) == this); // K_: this val...
240 if (enforceLimit_ && (limit >= 0) && (count + count_ > limit)) { // not enough room 255 if (enforceLimit_ && (limit >= 0) && (count + count_ > limit)) { // not enough room
241 return false; 256 return false;
@@ -259,16 +274,16 @@ bool KeyUD::push(KeeperState const K_, int const count_, bool const enforceLimit
259void KeyUD::pushFillStatus(KeeperState const K_) const 274void KeyUD::pushFillStatus(KeeperState const K_) const
260{ 275{
261 if (limit < 0) { 276 if (limit < 0) {
262 luaG_pushstring(K_, kUnder); 277 luaW_pushstring(K_, kUnder);
263 return; 278 return;
264 } 279 }
265 int const _delta{limit - count}; 280 int const _delta{ limit - count };
266 if (_delta < 0) { 281 if (_delta < 0) {
267 luaG_pushstring(K_, kOver); 282 luaW_pushstring(K_, kOver);
268 } else if (_delta > 0) { 283 } else if (_delta > 0) {
269 luaG_pushstring(K_, kUnder); 284 luaW_pushstring(K_, kUnder);
270 } else { 285 } else {
271 luaG_pushstring(K_, kExact); 286 luaW_pushstring(K_, kExact);
272 } 287 }
273} 288}
274 289
@@ -279,13 +294,16 @@ void KeyUD::PushFillStatus(KeeperState const K_, KeyUD const* const key_)
279 if (key_) { 294 if (key_) {
280 key_->pushFillStatus(K_); // _K: ... <fill status> 295 key_->pushFillStatus(K_); // _K: ... <fill status>
281 } else { 296 } else {
282 luaG_pushstring(K_, KeyUD::kUnder); // _K: ... "under" 297 luaW_pushstring(K_, KeyUD::kUnder); // _K: ... "under"
283 } 298 }
284} 299}
285 300
286// ################################################################################################# 301// #################################################################################################
287 302
288// expects 'this' on top of the stack 303// in: expects 'this' on top of the stack
304// out: nothing
305// returns true if the channel was full
306[[nodiscard]]
289bool KeyUD::reset(KeeperState const K_) 307bool KeyUD::reset(KeeperState const K_)
290{ 308{
291 LUA_ASSERT(K_, KeyUD::GetPtr(K_, kIdxTop) == this); 309 LUA_ASSERT(K_, KeyUD::GetPtr(K_, kIdxTop) == this);
@@ -312,10 +330,10 @@ static void PushKeysDB(KeeperState const K_, StackIndex const idx_)
312{ 330{
313 STACK_GROW(K_, 5); 331 STACK_GROW(K_, 5);
314 STACK_CHECK_START_REL(K_, 0); 332 STACK_CHECK_START_REL(K_, 0);
315 StackIndex const _absidx{ luaG_absindex(K_, idx_) }; 333 StackIndex const _absidx{ luaW_absindex(K_, idx_) };
316 kLindasRegKey.pushValue(K_); // K_: ... LindasDB 334 kLindasRegKey.pushValue(K_); // K_: ... LindasDB
317 lua_pushvalue(K_, _absidx); // K_: ... LindasDB linda 335 lua_pushvalue(K_, _absidx); // K_: ... LindasDB linda
318 if (luaG_rawget(K_, StackIndex{ -2 }) == LuaType::NIL) { // K_: ... LindasDB KeysDB 336 if (luaW_rawget(K_, StackIndex{ -2 }) == LuaType::NIL) { // K_: ... LindasDB KeysDB
319 lua_pop(K_, 1); // K_: ... LindasDB 337 lua_pop(K_, 1); // K_: ... LindasDB
320 // add a new KeysDB table for this linda 338 // add a new KeysDB table for this linda
321 lua_newtable(K_); // K_: ... LindasDB KeysDB 339 lua_newtable(K_); // K_: ... LindasDB KeysDB
@@ -337,6 +355,7 @@ static void PushKeysDB(KeeperState const K_, StackIndex const idx_)
337 355
338// in: linda 356// in: linda
339// out: nothing 357// out: nothing
358[[nodiscard]]
340int keepercall_collectgarbage(lua_State* const L_) 359int keepercall_collectgarbage(lua_State* const L_)
341{ 360{
342 lua_gc(L_, LUA_GCCOLLECT, 0); 361 lua_gc(L_, LUA_GCCOLLECT, 0);
@@ -346,6 +365,7 @@ int keepercall_collectgarbage(lua_State* const L_)
346// ################################################################################################# 365// #################################################################################################
347 366
348// in: linda [, key [, ...]] 367// in: linda [, key [, ...]]
368[[nodiscard]]
349int keepercall_count(lua_State* const L_) 369int keepercall_count(lua_State* const L_)
350{ 370{
351 KeeperState const _K{ L_ }; 371 KeeperState const _K{ L_ };
@@ -370,7 +390,7 @@ int keepercall_count(lua_State* const L_)
370 case 2: // _K: linda key 390 case 2: // _K: linda key
371 PushKeysDB(_K, StackIndex{ 1 }); // _K: linda key KeysDB 391 PushKeysDB(_K, StackIndex{ 1 }); // _K: linda key KeysDB
372 lua_replace(_K, 1); // _K: KeysDB key 392 lua_replace(_K, 1); // _K: KeysDB key
373 if (luaG_rawget(_K, StackIndex{ -2 }) == LuaType::NIL) { // the key is unknown // _K: KeysDB KeyUD|nil 393 if (luaW_rawget(_K, StackIndex{ -2 }) == LuaType::NIL) { // the key is unknown // _K: KeysDB KeyUD|nil
374 lua_remove(_K, -2); // _K: nil 394 lua_remove(_K, -2); // _K: nil
375 } else { // the key is known // _K: KeysDB KeyUD 395 } else { // the key is known // _K: KeysDB KeyUD
376 KeyUD* const _key{ KeyUD::GetPtr(_K, kIdxTop) }; 396 KeyUD* const _key{ KeyUD::GetPtr(_K, kIdxTop) };
@@ -409,6 +429,7 @@ int keepercall_count(lua_State* const L_)
409 429
410// in: linda 430// in: linda
411// not part of the linda public API, only used for cleanup at linda GC 431// not part of the linda public API, only used for cleanup at linda GC
432[[nodiscard]]
412int keepercall_destruct(lua_State* const L_) 433int keepercall_destruct(lua_State* const L_)
413{ 434{
414 STACK_GROW(L_, 3); 435 STACK_GROW(L_, 3);
@@ -427,6 +448,7 @@ int keepercall_destruct(lua_State* const L_)
427 448
428// in: linda_ud key [count] 449// in: linda_ud key [count]
429// out: N <N values>|kRestrictedChannel 450// out: N <N values>|kRestrictedChannel
451[[nodiscard]]
430int keepercall_get(lua_State* const L_) 452int keepercall_get(lua_State* const L_)
431{ 453{
432 KeeperState const _K{ L_ }; 454 KeeperState const _K{ L_ };
@@ -461,6 +483,7 @@ int keepercall_get(lua_State* const L_)
461 483
462// in: linda key [n|nil] 484// in: linda key [n|nil]
463// out: boolean, <fill status: string> 485// out: boolean, <fill status: string>
486[[nodiscard]]
464int keepercall_limit(lua_State* const L_) 487int keepercall_limit(lua_State* const L_)
465{ 488{
466 KeeperState const _K{ L_ }; 489 KeeperState const _K{ L_ };
@@ -480,7 +503,7 @@ int keepercall_limit(lua_State* const L_)
480 if (_key && _key->limit >= 0) { 503 if (_key && _key->limit >= 0) {
481 lua_pushinteger(_K, _key->limit); // _K: limit 504 lua_pushinteger(_K, _key->limit); // _K: limit
482 } else { // if the key doesn't exist, it is unlimited by default 505 } else { // if the key doesn't exist, it is unlimited by default
483 luaG_pushstring(_K, "unlimited"); // _K: "unlimited" 506 luaW_pushstring(_K, "unlimited"); // _K: "unlimited"
484 } 507 }
485 // return a single value: the limit of the key 508 // return a single value: the limit of the key
486 } else { 509 } else {
@@ -504,6 +527,7 @@ int keepercall_limit(lua_State* const L_)
504 527
505// in: linda, key [, key]? 528// in: linda, key [, key]?
506// out: (key, val) or nothing 529// out: (key, val) or nothing
530[[nodiscard]]
507int keepercall_receive(lua_State* const L_) 531int keepercall_receive(lua_State* const L_)
508{ 532{
509 KeeperState const _K{ L_ }; 533 KeeperState const _K{ L_ };
@@ -548,6 +572,7 @@ int keepercall_receive(lua_State* const L_)
548// ################################################################################################# 572// #################################################################################################
549 573
550// in: linda key mincount [maxcount] 574// in: linda key mincount [maxcount]
575[[nodiscard]]
551int keepercall_receive_batched(lua_State* const L_) 576int keepercall_receive_batched(lua_State* const L_)
552{ 577{
553 KeeperState const _K{ L_ }; 578 KeeperState const _K{ L_ };
@@ -581,6 +606,7 @@ int keepercall_receive_batched(lua_State* const L_)
581 606
582// in: linda key [mode] 607// in: linda key [mode]
583// out: mode 608// out: mode
609[[nodiscard]]
584int keepercall_restrict(lua_State* const L_) 610int keepercall_restrict(lua_State* const L_)
585{ 611{
586 KeeperState const _K{ L_ }; 612 KeeperState const _K{ L_ };
@@ -591,7 +617,7 @@ int keepercall_restrict(lua_State* const L_)
591 if (_reading) { 617 if (_reading) {
592 return LindaRestrict::None; 618 return LindaRestrict::None;
593 } 619 }
594 std::string_view const _val{ luaG_tostring(_K, StackIndex{ 3 }) }; 620 std::string_view const _val{ luaW_tostring(_K, StackIndex{ 3 }) };
595 if (_val == "set/get") { 621 if (_val == "set/get") {
596 return LindaRestrict::SetGet; 622 return LindaRestrict::SetGet;
597 } 623 }
@@ -623,7 +649,7 @@ int keepercall_restrict(lua_State* const L_)
623 lua_settop(_K, 0); // _K: 649 lua_settop(_K, 0); // _K:
624 auto const _prevRstrct{ _key ? _key->restrict : LindaRestrict::None }; 650 auto const _prevRstrct{ _key ? _key->restrict : LindaRestrict::None };
625 // return a single value: the restrict mode of the key 651 // return a single value: the restrict mode of the key
626 luaG_pushstring(_K, _encodeRestrict(_prevRstrct)); // _K: _previous 652 luaW_pushstring(_K, _encodeRestrict(_prevRstrct)); // _K: _previous
627 } else { 653 } else {
628 if (_key == nullptr) { // _K: KeysDB key nil 654 if (_key == nullptr) { // _K: KeysDB key nil
629 lua_pop(_K, 1); // _K: KeysDB key 655 lua_pop(_K, 1); // _K: KeysDB key
@@ -635,7 +661,7 @@ int keepercall_restrict(lua_State* const L_)
635 // return true if we decide that blocked threads waiting to write on that key should be awakened 661 // return true if we decide that blocked threads waiting to write on that key should be awakened
636 // this is the case if we detect the key was full but it is no longer the case 662 // this is the case if we detect the key was full but it is no longer the case
637 LindaRestrict const _previous{ _key->changeRestrict(_rstrct) }; 663 LindaRestrict const _previous{ _key->changeRestrict(_rstrct) };
638 luaG_pushstring(_K, _encodeRestrict(_previous)); // _K: _previous 664 luaW_pushstring(_K, _encodeRestrict(_previous)); // _K: _previous
639 } 665 }
640 STACK_CHECK(_K, 1); 666 STACK_CHECK(_K, 1);
641 return 1; 667 return 1;
@@ -645,6 +671,7 @@ int keepercall_restrict(lua_State* const L_)
645 671
646// in: linda, key, ... 672// in: linda, key, ...
647// out: true|false|kRestrictedChannel 673// out: true|false|kRestrictedChannel
674[[nodiscard]]
648int keepercall_send(lua_State* const L_) 675int keepercall_send(lua_State* const L_)
649{ 676{
650 KeeperState const _K{ L_ }; 677 KeeperState const _K{ L_ };
@@ -653,7 +680,7 @@ int keepercall_send(lua_State* const L_)
653 PushKeysDB(_K, StackIndex{ 1 }); // _K: linda key val... KeysDB 680 PushKeysDB(_K, StackIndex{ 1 }); // _K: linda key val... KeysDB
654 // get the fifo associated to this key in this linda, create it if it doesn't exist 681 // get the fifo associated to this key in this linda, create it if it doesn't exist
655 lua_pushvalue(_K, 2); // _K: linda key val... KeysDB key 682 lua_pushvalue(_K, 2); // _K: linda key val... KeysDB key
656 if (luaG_rawget(_K, StackIndex{ -2 }) == LuaType::NIL) { // _K: linda key val... KeysDB KeyUD|nil 683 if (luaW_rawget(_K, StackIndex{ -2 }) == LuaType::NIL) { // _K: linda key val... KeysDB KeyUD|nil
657 lua_pop(_K, 1); // _K: linda key val... KeysDB 684 lua_pop(_K, 1); // _K: linda key val... KeysDB
658 std::ignore = KeyUD::Create(KeeperState{ _K }); // _K: linda key val... KeysDB KeyUD 685 std::ignore = KeyUD::Create(KeeperState{ _K }); // _K: linda key val... KeysDB KeyUD
659 // KeysDB[key] = KeyUD 686 // KeysDB[key] = KeyUD
@@ -684,6 +711,7 @@ int keepercall_send(lua_State* const L_)
684 711
685// in: linda key [val...] 712// in: linda key [val...]
686// out: true if the linda was full but it's no longer the case, else false, or kRestrictedChannel if the key is restricted 713// out: true if the linda was full but it's no longer the case, else false, or kRestrictedChannel if the key is restricted
714[[nodiscard]]
687int keepercall_set(lua_State* const L_) 715int keepercall_set(lua_State* const L_)
688{ 716{
689 KeeperState const _K{ L_ }; 717 KeeperState const _K{ L_ };
@@ -753,6 +781,7 @@ int keepercall_set(lua_State* const L_)
753 * 781 *
754 * Returns: number of return values (pushed to 'L'), unset in case of error 782 * Returns: number of return values (pushed to 'L'), unset in case of error
755 */ 783 */
784[[nodiscard]]
756KeeperCallResult keeper_call(KeeperState const K_, keeper_api_t const func_, lua_State* const L_, Linda* const linda_, StackIndex const starting_index_) 785KeeperCallResult keeper_call(KeeperState const K_, keeper_api_t const func_, lua_State* const L_, Linda* const linda_, StackIndex const starting_index_)
757{ 786{
758 KeeperCallResult _result; 787 KeeperCallResult _result;
@@ -811,22 +840,6 @@ KeeperCallResult keeper_call(KeeperState const K_, keeper_api_t const func_, lua
811// ################################################################################################# 840// #################################################################################################
812// ################################################################################################# 841// #################################################################################################
813 842
814void* Keeper::operator new[](size_t size_, Universe* U_) noexcept
815{
816 // size_ is the memory for the element count followed by the elements themselves
817 return U_->internalAllocator.alloc(size_);
818}
819
820// #################################################################################################
821
822// can't actually delete the operator because the compiler generates stack unwinding code that could call it in case of exception
823void Keeper::operator delete[](void* p_, Universe* U_)
824{
825 U_->internalAllocator.free(p_, *static_cast<size_t*>(p_) * sizeof(Keeper) + sizeof(size_t));
826}
827
828// #################################################################################################
829
830// only used by linda:dump() and linda:__towatch() for debugging purposes 843// only used by linda:dump() and linda:__towatch() for debugging purposes
831// table is populated as follows: 844// table is populated as follows:
832// { 845// {
@@ -838,6 +851,7 @@ void Keeper::operator delete[](void* p_, Universe* U_)
838// } 851// }
839// ... 852// ...
840// } 853// }
854[[nodiscard]]
841int Keeper::PushLindaStorage(Linda& linda_, DestState const L_) 855int Keeper::PushLindaStorage(Linda& linda_, DestState const L_)
842{ 856{
843 Keeper* const _keeper{ linda_.whichKeeper() }; 857 Keeper* const _keeper{ linda_.whichKeeper() };
@@ -849,7 +863,7 @@ int Keeper::PushLindaStorage(Linda& linda_, DestState const L_)
849 STACK_CHECK_START_REL(_K, 0); 863 STACK_CHECK_START_REL(_K, 0);
850 kLindasRegKey.pushValue(_K); // _K: LindasDB L_: 864 kLindasRegKey.pushValue(_K); // _K: LindasDB L_:
851 lua_pushlightuserdata(_K, &linda_); // _K: LindasDB linda L_: 865 lua_pushlightuserdata(_K, &linda_); // _K: LindasDB linda L_:
852 LuaType const _type{ luaG_rawget(_K, StackIndex{ -2 }) }; // _K: LindasDB KeysDB L_: 866 LuaType const _type{ luaW_rawget(_K, StackIndex{ -2 }) }; // _K: LindasDB KeysDB L_:
853 lua_remove(_K, -2); // _K: KeysDB L_: 867 lua_remove(_K, -2); // _K: KeysDB L_:
854 if (_type != LuaType::TABLE) { // possible if we didn't send anything through that linda 868 if (_type != LuaType::TABLE) { // possible if we didn't send anything through that linda
855 lua_pop(_K, 1); // _K: L_: 869 lua_pop(_K, 1); // _K: L_:
@@ -886,20 +900,20 @@ int Keeper::PushLindaStorage(Linda& linda_, DestState const L_)
886 if (_key->limit >= 0) { 900 if (_key->limit >= 0) {
887 lua_pushinteger(L_, _key->limit); // _K: KeysDB key L_: out key keyout fifo limit 901 lua_pushinteger(L_, _key->limit); // _K: KeysDB key L_: out key keyout fifo limit
888 } else { 902 } else {
889 luaG_pushstring(L_, "unlimited"); // _K: KeysDB key L_: out key keyout fifo limit 903 luaW_pushstring(L_, "unlimited"); // _K: KeysDB key L_: out key keyout fifo limit
890 } 904 }
891 STACK_CHECK(L_, 5); 905 STACK_CHECK(L_, 5);
892 lua_setfield(L_, -3, "limit"); // _K: KeysDB key L_: out key keyout fifo 906 lua_setfield(L_, -3, "limit"); // _K: KeysDB key L_: out key keyout fifo
893 // keyout.restrict 907 // keyout.restrict
894 switch (_key->restrict) { 908 switch (_key->restrict) {
895 case LindaRestrict::None: 909 case LindaRestrict::None:
896 luaG_pushstring(L_, "none"); // _K: KeysDB key L_: out key keyout fifo restrict 910 luaW_pushstring(L_, "none"); // _K: KeysDB key L_: out key keyout fifo restrict
897 break; 911 break;
898 case LindaRestrict::SetGet: 912 case LindaRestrict::SetGet:
899 luaG_pushstring(L_, "set/get"); // _K: KeysDB key L_: out key keyout fifo restrict 913 luaW_pushstring(L_, "set/get"); // _K: KeysDB key L_: out key keyout fifo restrict
900 break; 914 break;
901 case LindaRestrict::SendReceive: 915 case LindaRestrict::SendReceive:
902 luaG_pushstring(L_, "send/receive"); // _K: KeysDB key L_: out key keyout fifo restrict 916 luaW_pushstring(L_, "send/receive"); // _K: KeysDB key L_: out key keyout fifo restrict
903 break; 917 break;
904 } 918 }
905 STACK_CHECK(L_, 5); 919 STACK_CHECK(L_, 5);
@@ -927,7 +941,7 @@ void Keepers::DeleteKV::operator()(Keeper* const k_) const
927 for (auto& _k : std::span<Keeper>(k_, count)) { 941 for (auto& _k : std::span<Keeper>(k_, count)) {
928 _k.~Keeper(); 942 _k.~Keeper();
929 } 943 }
930 U->internalAllocator.free(k_, count * sizeof(Keeper)); 944 U.internalAllocator.free(k_, count * sizeof(Keeper));
931} 945}
932 946
933// ################################################################################################# 947// #################################################################################################
@@ -959,24 +973,24 @@ void Keepers::collectGarbage()
959 // when keeper N+1 is closed, object is GCed, linda operation is called, which attempts to acquire keeper N, whose Lua state no longer exists 973 // when keeper N+1 is closed, object is GCed, linda operation is called, which attempts to acquire keeper N, whose Lua state no longer exists
960 // in that case, the linda operation should do nothing. which means that these operations must check for keeper acquisition success 974 // in that case, the linda operation should do nothing. which means that these operations must check for keeper acquisition success
961 // which is early-outed with a keepers->nbKeepers null-check 975 // which is early-outed with a keepers->nbKeepers null-check
962 for (size_t const _i : std::ranges::iota_view{ size_t{ 0 }, _kv.nbKeepers }) { 976 for (Keeper& _k : std::span<Keeper>{ _kv.keepers.get(), _kv.nbKeepers }) {
963 _gcOneKeeper(_kv.keepers[_i]); 977 _gcOneKeeper(_k);
964 } 978 }
965 } 979 }
966} 980}
967 981
968// ################################################################################################# 982// #################################################################################################
969 983
970 984[[nodiscard]]
971void Keepers::close() 985bool Keepers::close()
972{ 986{
973 if (isClosing.test_and_set(std::memory_order_release)) { 987 if (isClosing.test_and_set(std::memory_order_release)) {
974 assert(false); // should never close more than once in practice 988 return false; // should never close more than once in practice
975 return;
976 } 989 }
977 990
991 // We may have not initialized the keepers if an error was raised in Universe::Create because of bad settings
978 if (std::holds_alternative<std::monostate>(keeper_array)) { 992 if (std::holds_alternative<std::monostate>(keeper_array)) {
979 return; 993 return true;
980 } 994 }
981 995
982 auto _closeOneKeeper = [](Keeper& keeper_) { 996 auto _closeOneKeeper = [](Keeper& keeper_) {
@@ -996,9 +1010,8 @@ void Keepers::close()
996 // when keeper N+1 is closed, object is GCed, linda operation is called, which attempts to acquire keeper N, whose Lua state no longer exists 1010 // when keeper N+1 is closed, object is GCed, linda operation is called, which attempts to acquire keeper N, whose Lua state no longer exists
997 // in that case, the linda operation should do nothing. which means that these operations must check for keeper acquisition success 1011 // in that case, the linda operation should do nothing. which means that these operations must check for keeper acquisition success
998 // which is early-outed with a keepers->nbKeepers null-check 1012 // which is early-outed with a keepers->nbKeepers null-check
999 size_t const _nbKeepers{ std::exchange(_kv.nbKeepers, size_t{ 0 }) }; 1013 for (Keeper& _k : std::span<Keeper>{ _kv.keepers.get(), std::exchange(_kv.nbKeepers, size_t{ 0 }) }) {
1000 for (size_t const _i : std::ranges::iota_view{ size_t{ 0 }, _nbKeepers }) { 1014 if (!_closeOneKeeper(_k)) {
1001 if (!_closeOneKeeper(_kv.keepers[_i])) {
1002 // detected partial init: destroy only the mutexes that got initialized properly 1015 // detected partial init: destroy only the mutexes that got initialized properly
1003 break; 1016 break;
1004 } 1017 }
@@ -1006,6 +1019,7 @@ void Keepers::close()
1006 } 1019 }
1007 1020
1008 keeper_array.emplace<std::monostate>(); 1021 keeper_array.emplace<std::monostate>();
1022 return true;
1009} 1023}
1010 1024
1011// ################################################################################################# 1025// #################################################################################################
@@ -1076,7 +1090,7 @@ void Keepers::initialize(Universe& U_, lua_State* L_, size_t const nbKeepers_, i
1076 keeper_.K = _K; 1090 keeper_.K = _K;
1077 1091
1078 // Give a name to the state 1092 // Give a name to the state
1079 luaG_pushstring(_K, "Keeper #%d", i_ + 1); // L_: settings _K: "Keeper #n" 1093 luaW_pushstring(_K, "Keeper #%d", i_ + 1); // L_: settings _K: "Keeper #n"
1080 if constexpr (HAVE_DECODA_SUPPORT()) { 1094 if constexpr (HAVE_DECODA_SUPPORT()) {
1081 lua_pushvalue(_K, -1); // _K: "Keeper #n" Keeper #n" 1095 lua_pushvalue(_K, -1); // _K: "Keeper #n" Keeper #n"
1082 lua_setglobal(_K, "decoda_name"); // L_: settings _K: "Keeper #n" 1096 lua_setglobal(_K, "decoda_name"); // L_: settings _K: "Keeper #n"
@@ -1098,9 +1112,9 @@ void Keepers::initialize(Universe& U_, lua_State* L_, size_t const nbKeepers_, i
1098 STACK_CHECK(_K, 0); 1112 STACK_CHECK(_K, 0);
1099 1113
1100 // copy package.path and package.cpath from the source state 1114 // copy package.path and package.cpath from the source state
1101 if (luaG_getmodule(L, LUA_LOADLIBNAME) != LuaType::NIL) { // L_: settings package _K: 1115 if (luaW_getmodule(L, LUA_LOADLIBNAME) != LuaType::NIL) { // L_: settings package _K:
1102 // when copying with mode LookupMode::ToKeeper, error message is pushed at the top of the stack, not raised immediately 1116 // when copying with mode LookupMode::ToKeeper, error message is pushed at the top of the stack, not raised immediately
1103 InterCopyContext _c{ U, DestState{ _K.value() }, SourceState{ L }, {}, SourceIndex{ luaG_absindex(L, kIdxTop).value() }, {}, LookupMode::ToKeeper, {} }; 1117 InterCopyContext _c{ U, DestState{ _K.value() }, SourceState{ L }, {}, SourceIndex{ luaW_absindex(L, kIdxTop).value() }, {}, LookupMode::ToKeeper, {} };
1104 if (_c.interCopyPackage() != InterCopyResult::Success) { // L_: settings ... error_msg _K: 1118 if (_c.interCopyPackage() != InterCopyResult::Success) { // L_: settings ... error_msg _K:
1105 // if something went wrong, the error message is at the top of the stack 1119 // if something went wrong, the error message is at the top of the stack
1106 lua_remove(L, -2); // L_: settings error_msg 1120 lua_remove(L, -2); // L_: settings error_msg
@@ -1137,11 +1151,14 @@ void Keepers::initialize(Universe& U_, lua_State* L_, size_t const nbKeepers_, i
1137 1151
1138 default: 1152 default:
1139 KV& _kv = keeper_array.emplace<KV>( 1153 KV& _kv = keeper_array.emplace<KV>(
1140 std::unique_ptr<Keeper[], DeleteKV>{ new(&U_) Keeper[nbKeepers_], DeleteKV{ &U_, nbKeepers_ } }, 1154 std::unique_ptr<Keeper, DeleteKV>{ static_cast<Keeper*>(U_.internalAllocator.alloc(sizeof(Keeper) * nbKeepers_)), DeleteKV{ U_, nbKeepers_ } },
1141 nbKeepers_ 1155 nbKeepers_
1142 ); 1156 );
1143 for (size_t const _i : std::ranges::iota_view{ size_t{ 0 }, nbKeepers_ }) { 1157 // fak. std::ranges::views::enumerate is c++23 (would help having item and index iterated over simultaneously)
1144 _initOneKeeper(_kv.keepers[_i], static_cast<int>(_i)); 1158 int _i{};
1159 for (Keeper& _k : std::span<Keeper>{ _kv.keepers.get(), nbKeepers_ }) {
1160 new (&_k) Keeper{};
1161 _initOneKeeper(_k, _i++);
1145 } 1162 }
1146 } 1163 }
1147} 1164}
diff --git a/src/keeper.hpp b/src/keeper.hpp
index 5cebe07..955577c 100644
--- a/src/keeper.hpp
+++ b/src/keeper.hpp
@@ -26,12 +26,6 @@ struct Keeper
26 std::mutex mutex; 26 std::mutex mutex;
27 KeeperState K{ static_cast<lua_State*>(nullptr) }; 27 KeeperState K{ static_cast<lua_State*>(nullptr) };
28 28
29 [[nodiscard]]
30 static void* operator new[](size_t size_, Universe* U_) noexcept;
31 // can't actually delete the operator because the compiler generates stack unwinding code that could call it in case of exception
32 static void operator delete[](void* p_, Universe* U_);
33
34
35 ~Keeper() = default; 29 ~Keeper() = default;
36 Keeper() = default; 30 Keeper() = default;
37 // non-copyable, non-movable 31 // non-copyable, non-movable
@@ -51,14 +45,15 @@ struct Keepers
51 private: 45 private:
52 struct DeleteKV 46 struct DeleteKV
53 { 47 {
54 Universe* U{}; 48 Universe& U;
55 size_t count{}; 49 size_t count{};
56 void operator()(Keeper* k_) const; 50 void operator()(Keeper* k_) const;
57 }; 51 };
58 // can't use std::vector<Keeper> because Keeper contains a mutex, so we need a raw memory buffer 52 // can't use std::unique_ptr<Keeper[]> because of interactions with placement new and custom deleters
53 // and I'm not using std::vector<Keeper> because I don't have an allocator to plug on the Universe (yet)
59 struct KV 54 struct KV
60 { 55 {
61 std::unique_ptr<Keeper[], DeleteKV> keepers; 56 std::unique_ptr<Keeper, DeleteKV> keepers;
62 size_t nbKeepers{}; 57 size_t nbKeepers{};
63 }; 58 };
64 std::variant<std::monostate, Keeper, KV> keeper_array; 59 std::variant<std::monostate, Keeper, KV> keeper_array;
@@ -73,7 +68,8 @@ struct Keepers
73 68
74 Keepers() = default; 69 Keepers() = default;
75 void collectGarbage(); 70 void collectGarbage();
76 void close(); 71 [[nodiscard]]
72 bool close();
77 [[nodiscard]] 73 [[nodiscard]]
78 Keeper* getKeeper(KeeperIndex idx_); 74 Keeper* getKeeper(KeeperIndex idx_);
79 [[nodiscard]] 75 [[nodiscard]]
diff --git a/src/lane.cpp b/src/lane.cpp
index 5cebdfa..b23ff78 100644
--- a/src/lane.cpp
+++ b/src/lane.cpp
@@ -49,7 +49,7 @@ static LUAG_FUNC(lane_get_threadname)
49{ 49{
50 Lane* const _lane{ ToLane(L_, StackIndex{ 1 }) }; 50 Lane* const _lane{ ToLane(L_, StackIndex{ 1 }) };
51 luaL_argcheck(L_, lua_gettop(L_) == 1, 2, "too many arguments"); 51 luaL_argcheck(L_, lua_gettop(L_) == 1, 2, "too many arguments");
52 luaG_pushstring(L_, _lane->getDebugName()); 52 luaW_pushstring(L_, _lane->getDebugName());
53 return 1; 53 return 1;
54} 54}
55 55
@@ -85,17 +85,17 @@ static LUAG_FUNC(set_finalizer)
85static LUAG_FUNC(lane_threadname) 85static LUAG_FUNC(lane_threadname)
86{ 86{
87 // C s_lane structure is a light userdata upvalue 87 // C s_lane structure is a light userdata upvalue
88 Lane* const _lane{ luaG_tolightuserdata<Lane>(L_, StackIndex{ lua_upvalueindex(1) }) }; 88 Lane* const _lane{ luaW_tolightuserdata<Lane>(L_, StackIndex{ lua_upvalueindex(1) }) };
89 LUA_ASSERT(L_, L_ == _lane->L); // this function is exported in a lane's state, therefore it is callable only from inside the Lane's state 89 LUA_ASSERT(L_, L_ == _lane->L); // this function is exported in a lane's state, therefore it is callable only from inside the Lane's state
90 if (lua_gettop(L_) == 1) { 90 if (lua_gettop(L_) == 1) {
91 lua_settop(L_, 1); 91 lua_settop(L_, 1);
92 STACK_CHECK_START_REL(L_, 0); 92 STACK_CHECK_START_REL(L_, 0);
93 _lane->storeDebugName(luaG_tostring(L_, kIdxTop)); 93 _lane->storeDebugName(luaW_tostring(L_, kIdxTop));
94 _lane->applyDebugName(); 94 _lane->applyDebugName();
95 STACK_CHECK(L_, 0); 95 STACK_CHECK(L_, 0);
96 return 0; 96 return 0;
97 } else if (lua_gettop(L_) == 0) { 97 } else if (lua_gettop(L_) == 0) {
98 luaG_pushstring(L_, _lane->getDebugName()); 98 luaW_pushstring(L_, _lane->getDebugName());
99 return 1; 99 return 1;
100 } else { 100 } else {
101 raise_luaL_error(L_, "Wrong number of arguments"); 101 raise_luaL_error(L_, "Wrong number of arguments");
@@ -105,7 +105,7 @@ static LUAG_FUNC(lane_threadname)
105// ################################################################################################# 105// #################################################################################################
106 106
107//--- 107//---
108// [...] | [nil, err_any, stack_tbl]= lane:join([wait_secs]) 108// [true, ...] | [nil, err_any, stack_tbl]= lane:join([wait_secs])
109// 109//
110// timeout: returns nil 110// timeout: returns nil
111// done: returns return values (0..N) 111// done: returns return values (0..N)
@@ -117,7 +117,7 @@ static LUAG_FUNC(lane_join)
117 Lane* const _lane{ ToLane(L_, StackIndex{ 1 }) }; 117 Lane* const _lane{ ToLane(L_, StackIndex{ 1 }) };
118 118
119 std::chrono::time_point<std::chrono::steady_clock> _until{ std::chrono::time_point<std::chrono::steady_clock>::max() }; 119 std::chrono::time_point<std::chrono::steady_clock> _until{ std::chrono::time_point<std::chrono::steady_clock>::max() };
120 if (luaG_type(L_, StackIndex{ 2 }) == LuaType::NUMBER) { // we don't want to use lua_isnumber() because of autocoercion 120 if (luaW_type(L_, StackIndex{ 2 }) == LuaType::NUMBER) { // we don't want to use lua_isnumber() because of autocoercion
121 lua_Duration const duration{ lua_tonumber(L_, 2) }; 121 lua_Duration const duration{ lua_tonumber(L_, 2) };
122 if (duration.count() >= 0.0) { 122 if (duration.count() >= 0.0) {
123 _until = std::chrono::steady_clock::now() + std::chrono::duration_cast<std::chrono::steady_clock::duration>(duration); 123 _until = std::chrono::steady_clock::now() + std::chrono::duration_cast<std::chrono::steady_clock::duration>(duration);
@@ -128,71 +128,20 @@ static LUAG_FUNC(lane_join)
128 } else if (!lua_isnoneornil(L_, 2)) { 128 } else if (!lua_isnoneornil(L_, 2)) {
129 raise_luaL_argerror(L_, StackIndex{ 2 }, "incorrect duration type"); 129 raise_luaL_argerror(L_, StackIndex{ 2 }, "incorrect duration type");
130 } 130 }
131
132 lua_settop(L_, 1); // L_: lane 131 lua_settop(L_, 1); // L_: lane
133 bool const _done{ !_lane->thread.joinable() || _lane->waitForCompletion(_until) };
134 132
135 if (!_done) { 133 // wait until suspended or done
136 lua_pushnil(L_); // L_: lane nil 134 STACK_CHECK_START_REL(L_, 0); // L_: lane
137 luaG_pushstring(L_, "timeout"); // L_: lane nil "timeout" 135 if (!_lane->waitForJoin(L_, _until)) {
136 // in that case, should have pushed nil, "timeout"
137 STACK_CHECK(L_, 2);
138 return 2; 138 return 2;
139 } 139 }
140 STACK_CHECK(L_, 0); // L_: lane
141 // Thread is Done/Error/Cancelled; the Lane thread isn't working with it, therefore we can.
140 142
141 STACK_CHECK_START_REL(L_, 0); // L_: lane 143 std::ignore = _lane->storeResults(L_);
142 // Thread is Suspended or Done/Error/Cancelled; the Lane thread isn't working with it, therefore we can. 144 int const _ret{ _lane->pushStoredResults(L_) };
143
144 int _ret{ 0 };
145 int const _stored{ _lane->storeResults(L_) };
146 STACK_GROW(L_, std::max(3, _stored + 1));
147 switch (_lane->status.load(std::memory_order_acquire)) {
148 case Lane::Suspended: // got yielded values
149 case Lane::Done: // got regular return values
150 {
151 if (_stored == 0) {
152 raise_luaL_error(L_, _lane->L ? "First return value must be non-nil when using join()" : "Can't join() more than once or after indexing");
153 }
154 lua_getiuservalue(L_, StackIndex{ 1 }, UserValueIndex{ 1 }); // L_: lane {uv}
155 for (int _i = 2; _i <= _stored; ++_i) {
156 lua_rawgeti(L_, 2, _i); // L_: lane {uv} results2...N
157 }
158 lua_rawgeti(L_, 2, 1); // L_: lane {uv} results2...N result1
159 lua_replace(L_, 2); // L_: lane results
160 _ret = _stored;
161 }
162 break;
163
164 case Lane::Error:
165 {
166 LUA_ASSERT(L_, _stored == 2 || _stored == 3);
167 lua_getiuservalue(L_, StackIndex{ 1 }, UserValueIndex{ 1 }); // L_: lane {uv}
168 lua_rawgeti(L_, 2, 2); // L_: lane {uv} <error>
169 lua_rawgeti(L_, 2, 3); // L_: lane {uv} <error> <trace>|nil
170 if (lua_isnil(L_, -1)) {
171 lua_replace(L_, 2); // L_: lane nil <error>
172 } else {
173 lua_rawgeti(L_, 2, 1); // L_: lane {uv} <error> <trace> nil
174 lua_replace(L_, 2); // L_: lane nil <error> <trace>
175 }
176 _ret = lua_gettop(L_) - 1; // 2 or 3
177 }
178 break;
179
180 case Lane::Cancelled:
181 LUA_ASSERT(L_, _stored == 2);
182 lua_getiuservalue(L_, StackIndex{ 1 }, UserValueIndex{ 1 }); // L_: lane {uv}
183 lua_rawgeti(L_, 2, 2); // L_: lane {uv} cancel_error
184 lua_rawgeti(L_, 2, 1); // L_: lane {uv} cancel_error nil
185 lua_replace(L_, -3); // L_: lane nil cancel_error
186 LUA_ASSERT(L_, lua_isnil(L_, -2) && kCancelError.equals(L_, kIdxTop));
187 _ret = 2;
188 break;
189
190 default:
191 DEBUGSPEW_CODE(DebugSpew(nullptr) << "Unknown Lane status: " << static_cast<int>(_lane->status.load(std::memory_order_relaxed)) << std::endl);
192 LUA_ASSERT(L_, false);
193 _ret = 0;
194 }
195 STACK_CHECK(L_, _ret);
196 return _ret; 145 return _ret;
197} 146}
198 147
@@ -204,23 +153,13 @@ LUAG_FUNC(lane_resume)
204 Lane* const _lane{ ToLane(L_, kIdxSelf) }; 153 Lane* const _lane{ ToLane(L_, kIdxSelf) };
205 lua_State* const _L2{ _lane->L }; 154 lua_State* const _L2{ _lane->L };
206 155
207 // wait until the lane yields 156 // wait until the lane yields or returns
208 std::optional<Lane::Status> _hadToWait{}; // for debugging, if we ever raise the error just below 157 std::ignore = _lane->waitForCompletion(std::chrono::time_point<std::chrono::steady_clock>::max(), true);
209 { 158
210 std::unique_lock _guard{ _lane->doneMutex };
211 Lane::Status const _status{ _lane->status.load(std::memory_order_acquire) };
212 if (_status == Lane::Pending || _status == Lane::Running || _status == Lane::Resuming) {
213 _hadToWait = _status;
214 _lane->doneCondVar.wait(_guard, [_lane]() { return _lane->status.load(std::memory_order_acquire) == Lane::Suspended; });
215 }
216 }
217 if (_lane->status.load(std::memory_order_acquire) != Lane::Suspended) { 159 if (_lane->status.load(std::memory_order_acquire) != Lane::Suspended) {
218 if (_hadToWait) { 160 raise_luaL_error(L_, "cannot resume non-suspended coroutine Lane");
219 raise_luaL_error(L_, "INTERNAL ERROR: Lane status is %s instead of 'suspended'", _lane->threadStatusString().data());
220 } else {
221 raise_luaL_error(L_, "Can't resume a non-suspended coroutine-type Lane");
222 }
223 } 161 }
162
224 int const _nargs{ lua_gettop(L_) - 1 }; 163 int const _nargs{ lua_gettop(L_) - 1 };
225 int const _nresults{ lua_gettop(_L2) }; 164 int const _nresults{ lua_gettop(_L2) };
226 STACK_CHECK_START_ABS(L_, 1 + _nargs); // L_: self args... _L2: results... 165 STACK_CHECK_START_ABS(L_, 1 + _nargs); // L_: self args... _L2: results...
@@ -263,12 +202,17 @@ static int lane_index_number(lua_State* L_)
263 int const _key{ static_cast<int>(lua_tointeger(L_, 2)) }; 202 int const _key{ static_cast<int>(lua_tointeger(L_, 2)) };
264 lua_pop(L_, 1); // L_: lane 203 lua_pop(L_, 1); // L_: lane
265 204
205 // wait until suspended or done
206 STACK_CHECK_START_REL(L_, 0); // L_: lane
266 std::chrono::time_point<std::chrono::steady_clock> _until{ std::chrono::time_point<std::chrono::steady_clock>::max() }; 207 std::chrono::time_point<std::chrono::steady_clock> _until{ std::chrono::time_point<std::chrono::steady_clock>::max() };
267 if (!_lane->waitForCompletion(_until)) { 208 if (!_lane->waitForJoin(L_, _until)) {
268 raise_luaL_error(L_, "INTERNAL ERROR: Failed to join"); 209 // in that case, should have pushed nil, "timeout"
210 STACK_CHECK(L_, 2);
211 return 2;
269 } 212 }
213 STACK_CHECK(L_, 0); // L_: lane
214 // Thread is Done/Error/Cancelled; the Lane thread isn't working with it, therefore we can.
270 215
271 // make sure results are stored
272 int const _stored{ _lane->storeResults(L_) }; 216 int const _stored{ _lane->storeResults(L_) };
273 if (_key > _stored) { 217 if (_key > _stored) {
274 // get nil if indexing beyond the actual returned value count 218 // get nil if indexing beyond the actual returned value count
@@ -276,6 +220,7 @@ static int lane_index_number(lua_State* L_)
276 } else { 220 } else {
277 _lane->pushIndexedResult(L_, _key); // L_: lane result 221 _lane->pushIndexedResult(L_, _key); // L_: lane result
278 } 222 }
223
279 return 1; 224 return 1;
280} 225}
281 226
@@ -292,13 +237,13 @@ static int lane_index_string(lua_State* L_)
292 Lane* const _lane{ ToLane(L_, kIdxSelf) }; 237 Lane* const _lane{ ToLane(L_, kIdxSelf) };
293 LUA_ASSERT(L_, lua_gettop(L_) == 2); // L_: lane "key" 238 LUA_ASSERT(L_, lua_gettop(L_) == 2); // L_: lane "key"
294 239
295 std::string_view const _keystr{ luaG_tostring(L_, kIdxKey) }; 240 std::string_view const _keystr{ luaW_tostring(L_, kIdxKey) };
296 lua_settop(L_, 2); // keep only our original arguments on the stack 241 lua_settop(L_, 2); // keep only our original arguments on the stack
297 242
298 // look in metatable first 243 // look in metatable first
299 lua_getmetatable(L_, kIdxSelf); // L_: lane "key" mt 244 lua_getmetatable(L_, kIdxSelf); // L_: lane "key" mt
300 lua_replace(L_, -3); // L_: mt "key" 245 lua_replace(L_, -3); // L_: mt "key"
301 if (luaG_rawget(L_, StackIndex{ -2 }) != LuaType::NIL) { // found something? // L_: mt value 246 if (luaW_rawget(L_, StackIndex{ -2 }) != LuaType::NIL) { // found something? // L_: mt value
302 return 1; // done 247 return 1; // done
303 } 248 }
304 249
@@ -324,7 +269,7 @@ static LUAG_FUNC(lane_index)
324 Lane* const _lane{ ToLane(L_, kIdxSelf) }; 269 Lane* const _lane{ ToLane(L_, kIdxSelf) };
325 LUA_ASSERT(L_, lua_gettop(L_) == 2); 270 LUA_ASSERT(L_, lua_gettop(L_) == 2);
326 271
327 switch (luaG_type(L_, kKey)) { 272 switch (luaW_type(L_, kKey)) {
328 case LuaType::NUMBER: 273 case LuaType::NUMBER:
329 return lane_index_number(L_); // stack modification is undefined, returned value is at the top 274 return lane_index_number(L_); // stack modification is undefined, returned value is at the top
330 275
@@ -334,19 +279,19 @@ static LUAG_FUNC(lane_index)
334 default: // unknown key 279 default: // unknown key
335 lua_getmetatable(L_, kIdxSelf); // L_: mt 280 lua_getmetatable(L_, kIdxSelf); // L_: mt
336 kCachedError.pushKey(L_); // L_: mt kCachedError 281 kCachedError.pushKey(L_); // L_: mt kCachedError
337 if (luaG_rawget(L_, StackIndex{ -2 }) != LuaType::FUNCTION) { // L_: mt error() 282 if (luaW_rawget(L_, StackIndex{ -2 }) != LuaType::FUNCTION) { // L_: mt error()
338 raise_luaL_error(L_, "INTERNAL ERROR: cached error() is a %s, not a function", luaG_typename(L_, kIdxTop).data()); 283 raise_luaL_error(L_, "INTERNAL ERROR: cached error() is a %s, not a function", luaW_typename(L_, kIdxTop).data());
339 } 284 }
340 luaG_pushstring(L_, "Unknown key: "); // L_: mt error() "Unknown key: " 285 luaW_pushstring(L_, "Unknown key: "); // L_: mt error() "Unknown key: "
341 kCachedTostring.pushKey(L_); // L_: mt error() "Unknown key: " kCachedTostring 286 kCachedTostring.pushKey(L_); // L_: mt error() "Unknown key: " kCachedTostring
342 if (luaG_rawget(L_, StackIndex{ -4 }) != LuaType::FUNCTION) { // L_: mt error() "Unknown key: " tostring() 287 if (luaW_rawget(L_, StackIndex{ -4 }) != LuaType::FUNCTION) { // L_: mt error() "Unknown key: " tostring()
343 raise_luaL_error(L_, "INTERNAL ERROR: cached tostring() is a %s, not a function", luaG_typename(L_, kIdxTop).data()); 288 raise_luaL_error(L_, "INTERNAL ERROR: cached tostring() is a %s, not a function", luaW_typename(L_, kIdxTop).data());
344 } 289 }
345 lua_pushvalue(L_, kKey); // L_: mt error() "Unknown key: " tostring() k 290 lua_pushvalue(L_, kKey); // L_: mt error() "Unknown key: " tostring() k
346 lua_call(L_, 1, 1); // L_: mt error() "Unknown key: " "k" 291 lua_call(L_, 1, 1); // L_: mt error() "Unknown key: " "k"
347 lua_concat(L_, 2); // L_: mt error() "Unknown key: <k>" 292 lua_concat(L_, 2); // L_: mt error() "Unknown key: <k>"
348 lua_call(L_, 1, 0); // error( "Unknown key: " .. key) -> doesn't return // L_: mt 293 lua_call(L_, 1, 0); // error( "Unknown key: " .. key) -> doesn't return // L_: mt
349 raise_luaL_error(L_, "%s[%s]: should not get here!", _lane->getDebugName().data(), luaG_typename(L_, kKey).data()); 294 raise_luaL_error(L_, "%s[%s]: should not get here!", _lane->getDebugName().data(), luaW_typename(L_, kKey).data());
350 } 295 }
351} 296}
352 297
@@ -437,7 +382,7 @@ int Lane::LuaErrorHandler(lua_State* L_)
437 // table of { "sourcefile.lua:<line>", ... } 382 // table of { "sourcefile.lua:<line>", ... }
438 // 383 //
439 lua_newtable(L_); // L_: some_error {} 384 lua_newtable(L_); // L_: some_error {}
440 StackIndex const kIdxTraceTbl{ luaG_absindex(L_, kIdxTop) }; 385 StackIndex const kIdxTraceTbl{ luaW_absindex(L_, kIdxTop) };
441 386
442 // Best to start from level 1, but in some cases it might be a C function 387 // Best to start from level 1, but in some cases it might be a C function
443 // and we don't get '.currentline' for that. It's okay - just keep level 388 // and we don't get '.currentline' for that. It's okay - just keep level
@@ -448,25 +393,25 @@ int Lane::LuaErrorHandler(lua_State* L_)
448 lua_getinfo(L_, _extended ? "Sln" : "Sl", &_ar); 393 lua_getinfo(L_, _extended ? "Sln" : "Sl", &_ar);
449 if (_extended) { 394 if (_extended) {
450 lua_newtable(L_); // L_: some_error {} {} 395 lua_newtable(L_); // L_: some_error {} {}
451 StackIndex const kIdxFrameTbl{ luaG_absindex(L_, kIdxTop) }; 396 StackIndex const kIdxFrameTbl{ luaW_absindex(L_, kIdxTop) };
452 lua_pushstring(L_, _ar.source); // L_: some_error {} {} source 397 lua_pushstring(L_, _ar.source); // L_: some_error {} {} source
453 luaG_setfield(L_, kIdxFrameTbl, std::string_view{ "source" }); // L_: some_error {} {} 398 luaW_setfield(L_, kIdxFrameTbl, std::string_view{ "source" }); // L_: some_error {} {}
454 399
455 lua_pushinteger(L_, _ar.currentline); // L_: some_error {} {} currentline 400 lua_pushinteger(L_, _ar.currentline); // L_: some_error {} {} currentline
456 luaG_setfield(L_, kIdxFrameTbl, std::string_view{ "currentline" }); // L_: some_error {} {} 401 luaW_setfield(L_, kIdxFrameTbl, std::string_view{ "currentline" }); // L_: some_error {} {}
457 402
458 lua_pushstring(L_, _ar.name ? _ar.name : "<?>"); // L_: some_error {} {} name 403 lua_pushstring(L_, _ar.name ? _ar.name : "<?>"); // L_: some_error {} {} name
459 luaG_setfield(L_, kIdxFrameTbl, std::string_view{ "name" }); // L_: some_error {} {} 404 luaW_setfield(L_, kIdxFrameTbl, std::string_view{ "name" }); // L_: some_error {} {}
460 405
461 lua_pushstring(L_, _ar.namewhat); // L_: some_error {} {} namewhat 406 lua_pushstring(L_, _ar.namewhat); // L_: some_error {} {} namewhat
462 luaG_setfield(L_, kIdxFrameTbl, std::string_view{ "namewhat" }); // L_: some_error {} {} 407 luaW_setfield(L_, kIdxFrameTbl, std::string_view{ "namewhat" }); // L_: some_error {} {}
463 408
464 lua_pushstring(L_, _ar.what); // L_: some_error {} {} what 409 lua_pushstring(L_, _ar.what); // L_: some_error {} {} what
465 luaG_setfield(L_, kIdxFrameTbl, std::string_view{ "what" }); // L_: some_error {} {} 410 luaW_setfield(L_, kIdxFrameTbl, std::string_view{ "what" }); // L_: some_error {} {}
466 } else if (_ar.currentline > 0) { 411 } else if (_ar.currentline > 0) {
467 luaG_pushstring(L_, "%s:%d", _ar.short_src, _ar.currentline); // L_: some_error {} "blah:blah" 412 luaW_pushstring(L_, "%s:%d", _ar.short_src, _ar.currentline); // L_: some_error {} "blah:blah"
468 } else { 413 } else {
469 luaG_pushstring(L_, "%s:?", _ar.short_src); // L_: some_error {} "blah" 414 luaW_pushstring(L_, "%s:?", _ar.short_src); // L_: some_error {} "blah"
470 } 415 }
471 lua_rawseti(L_, kIdxTraceTbl, static_cast<lua_Integer>(_n)); // L_: some_error {} 416 lua_rawseti(L_, kIdxTraceTbl, static_cast<lua_Integer>(_n)); // L_: some_error {}
472 } 417 }
@@ -489,6 +434,7 @@ static int PushStackTrace(lua_State* const L_, Lane::ErrorTraceLevel const error
489 StackIndex const _top{ lua_gettop(L_) }; 434 StackIndex const _top{ lua_gettop(L_) };
490 switch (rc_) { 435 switch (rc_) {
491 case LuaError::OK: // no error, body return values are on the stack 436 case LuaError::OK: // no error, body return values are on the stack
437 case LuaError::YIELD:
492 break; 438 break;
493 439
494 case LuaError::ERRRUN: // cancellation or a runtime error 440 case LuaError::ERRRUN: // cancellation or a runtime error
@@ -502,7 +448,7 @@ static int PushStackTrace(lua_State* const L_, Lane::ErrorTraceLevel const error
502 448
503 // For cancellation the error message is kCancelError, and a stack trace isn't placed 449 // For cancellation the error message is kCancelError, and a stack trace isn't placed
504 // For other errors, the message can be whatever was thrown, and we should have a stack trace table 450 // For other errors, the message can be whatever was thrown, and we should have a stack trace table
505 LUA_ASSERT(L_, luaG_type(L_, StackIndex{ 1 + stk_base_ }) == (kCancelError.equals(L_, stk_base_) ? LuaType::NIL : LuaType::TABLE)); 451 LUA_ASSERT(L_, luaW_type(L_, StackIndex{ 1 + stk_base_ }) == (kCancelError.equals(L_, stk_base_) ? LuaType::NIL : LuaType::TABLE));
506 // Just leaving the stack trace table on the stack is enough to get it through to the master. 452 // Just leaving the stack trace table on the stack is enough to get it through to the master.
507 } else { 453 } else {
508 // any kind of error can be thrown with error(), or through a lane/linda cancellation 454 // any kind of error can be thrown with error(), or through a lane/linda cancellation
@@ -514,7 +460,7 @@ static int PushStackTrace(lua_State* const L_, Lane::ErrorTraceLevel const error
514 case LuaError::ERRERR: // error while running the error handler (if any, for example an out-of-memory condition) 460 case LuaError::ERRERR: // error while running the error handler (if any, for example an out-of-memory condition)
515 default: 461 default:
516 // the Lua core provides a string error message in those situations 462 // the Lua core provides a string error message in those situations
517 LUA_ASSERT(L_, (lua_gettop(L_) == stk_base_) && (luaG_type(L_, stk_base_) == LuaType::STRING)); 463 LUA_ASSERT(L_, (lua_gettop(L_) == stk_base_) && (luaW_type(L_, stk_base_) == LuaType::STRING));
518 break; 464 break;
519 } 465 }
520 return lua_gettop(L_) - _top; // either 0 or 1 466 return lua_gettop(L_) - _top; // either 0 or 1
@@ -563,7 +509,7 @@ static LuaError run_finalizers(Lane* const lane_, Lane::ErrorTraceLevel const er
563 LUA_ASSERT(_L, lua_isfunction(_L, -1)); 509 LUA_ASSERT(_L, lua_isfunction(_L, -1));
564 if (lua_rc_ != LuaError::OK) { // we have <error>, [trace] on the thread stack 510 if (lua_rc_ != LuaError::OK) { // we have <error>, [trace] on the thread stack
565 LUA_ASSERT(_L, lane_->nresults == 1 || lane_->nresults == 2); 511 LUA_ASSERT(_L, lane_->nresults == 1 || lane_->nresults == 2);
566 //std::string_view const _err_msg{ luaG_tostring(_L, 1) }; 512 //std::string_view const _err_msg{ luaW_tostring(_L, 1) };
567 if (lane_->isCoroutine()) { 513 if (lane_->isCoroutine()) {
568 // transfer them on the main state 514 // transfer them on the main state
569 lua_pushvalue(lane_->L, 1); 515 lua_pushvalue(lane_->L, 1);
@@ -615,7 +561,7 @@ static LuaError run_finalizers(Lane* const lane_, Lane::ErrorTraceLevel const er
615 561
616 if (lane_->isCoroutine()) { 562 if (lane_->isCoroutine()) {
617 // only the coroutine thread should remain on the master state when we are done 563 // only the coroutine thread should remain on the master state when we are done
618 LUA_ASSERT(_L, lua_gettop(_L) == 1 && luaG_type(_L, StackIndex{ 1 }) == LuaType::THREAD); 564 LUA_ASSERT(_L, lua_gettop(_L) == 1 && luaW_type(_L, StackIndex{ 1 }) == LuaType::THREAD);
619 } 565 }
620 566
621 return _rc; 567 return _rc;
@@ -711,7 +657,7 @@ static void lane_main(Lane* const lane_)
711 LuaError _rc{ LuaError::ERRRUN }; 657 LuaError _rc{ LuaError::ERRRUN };
712 if (lane_->status.load(std::memory_order_acquire) == Lane::Pending) { // nothing wrong happened during preparation, we can work 658 if (lane_->status.load(std::memory_order_acquire) == Lane::Pending) { // nothing wrong happened during preparation, we can work
713 // At this point, the lane function and arguments are on the stack, possibly preceded by the error handler 659 // At this point, the lane function and arguments are on the stack, possibly preceded by the error handler
714 int const _errorHandlerCount{ lane_->errorHandlerCount() }; 660 int const _errorHandlerCount{ lane_->errorHandlerCount() }; // no error handler for coroutines, ever.
715 int _nargs{ lua_gettop(_L) - 1 - _errorHandlerCount }; 661 int _nargs{ lua_gettop(_L) - 1 - _errorHandlerCount };
716 { 662 {
717 std::unique_lock _guard{ lane_->doneMutex }; 663 std::unique_lock _guard{ lane_->doneMutex };
@@ -724,27 +670,60 @@ static void lane_main(Lane* const lane_)
724 lane_->nresults = lua_gettop(_L) - _errorHandlerCount; 670 lane_->nresults = lua_gettop(_L) - _errorHandlerCount;
725 } else { 671 } else {
726 // S and L are different: we run as a coroutine in Lua thread L created in state S 672 // S and L are different: we run as a coroutine in Lua thread L created in state S
673 bool _shouldClose{ false };
727 do { 674 do {
728 // starting with Lua 5.4, lua_resume can leave more stuff on the stack below the actual yielded values. 675 // starting with Lua 5.4, lua_resume can leave more stuff on the stack below the actual yielded values.
729 // that's why we have lane_->nresults 676 // that's why we have lane_->nresults
730 _rc = luaG_resume(_L, nullptr, _nargs, &lane_->nresults); // L: eh? ... retvals|err... 677 _rc = luaW_resume(_L, nullptr, _nargs, &lane_->nresults); // L: ... retvals|err...
731 if (_rc == LuaError::YIELD) { 678 if (_rc == LuaError::YIELD) {
732 // change our status to suspended, and wait until someone wants us to resume
733 std::unique_lock _guard{ lane_->doneMutex };
734 lane_->status.store(Lane::Suspended, std::memory_order_release); // Running -> Suspended
735 lane_->doneCondVar.notify_one();
736 // wait until the user wants us to resume
737 // TODO: do I update waiting_on or not, so that the lane can be woken by cancellation requests here?
738 // lane_->waiting_on = &lane_->doneCondVar;
739 lane_->doneCondVar.wait(_guard, [lane_]() { return lane_->status.load(std::memory_order_acquire) == Lane::Resuming; });
740 // here lane_->doneMutex is locked again
741 // lane_->waiting_on = nullptr;
742 lane_->status.store(Lane::Running, std::memory_order_release); // Resuming -> Running
743 // on the stack we find the values pushed by lane:resume() 679 // on the stack we find the values pushed by lane:resume()
744 _nargs = lua_gettop(_L); 680 _nargs = lua_gettop(_L);
681 if (std::unique_lock _guard{ lane_->doneMutex }; true) {
682 // change our status to suspended, and wait until someone wants us to resume
683 lane_->status.store(Lane::Suspended, std::memory_order_release); // Running -> Suspended
684 lane_->doneCondVar.notify_one();
685 // wait until the user wants us to resume
686 // update waiting_on, so that the lane can be woken by cancellation requests here
687 lane_->waiting_on = &lane_->doneCondVar;
688 lane_->doneCondVar.wait(_guard,
689 [lane_,&_shouldClose]()
690 {
691 auto const _status{ lane_->status.load(std::memory_order_acquire) };
692 // wait interrupted because of a cancellation or join request means we have to abort the resume loop
693 _shouldClose = (_status == Lane::Closing);
694 return _shouldClose || (_status == Lane::Resuming) || (lane_->cancelRequest.load(std::memory_order_relaxed) != CancelRequest::None);
695 }
696 );
697 // here lane_->doneMutex is locked again
698 lane_->waiting_on = nullptr;
699 lane_->status.store(Lane::Running, std::memory_order_release); // Resuming -> Running
700 }
701 } else {
702 _shouldClose = true;
745 } 703 }
746 } while (_rc == LuaError::YIELD); 704 } while (!_shouldClose);
747 if (_rc != LuaError::OK) { // : err... 705 if (_rc == LuaError::YIELD) {
706#if LUA_VERSION_NUM >= 504
707 lua_State* const _S{ lane_->S };
708 STACK_CHECK_START_REL(_S, 0);
709 // lua_closethread cleans the stack, meaning we lose the yielded values! -> store
710 lua_xmove(_L, _S, lane_->nresults);
711 // lane is cancelled before completion (for example at Lanes shutdown), close everything
712 _rc = static_cast<LuaError>(lua_closethread(_L, nullptr)); // L: ... retvals|err <close_err>
713 // then restore the yielded values
714 if (_rc == LuaError::OK) {
715 lua_xmove(_S, _L, lane_->nresults);
716 } else {
717 lua_pop(_S, lane_->nresults);
718 }
719 STACK_CHECK(_S, 0);
720
721#else // LUA_VERSION_NUM
722 // Lua prior to 5.4 do not have lua_closethread.
723 _rc = LuaError::OK;
724#endif // LUA_VERSION_NUM
725 }
726 if (_rc != LuaError::OK) { // an error occurred // L: err...
748 // for some reason, in my tests with Lua 5.4, when the coroutine raises an error, I have 3 copies of it on the stack 727 // for some reason, in my tests with Lua 5.4, when the coroutine raises an error, I have 3 copies of it on the stack
749 // or false + the error message when running Lua 5.1 728 // or false + the error message when running Lua 5.1
750 // since the rest of our code wants only the error message, let us keep only the latter. 729 // since the rest of our code wants only the error message, let us keep only the latter.
@@ -769,7 +748,7 @@ static void lane_main(Lane* const lane_)
769 // in case of error and if it exists, fetch stack trace from registry and push it 748 // in case of error and if it exists, fetch stack trace from registry and push it
770 lane_->nresults += PushStackTrace(_L, lane_->errorTraceLevel, _rc, StackIndex{ 1 }); // L: retvals|error [trace] 749 lane_->nresults += PushStackTrace(_L, lane_->errorTraceLevel, _rc, StackIndex{ 1 }); // L: retvals|error [trace]
771 750
772 DEBUGSPEW_CODE(DebugSpew(lane_->U) << "Lane " << _L << " body: " << GetErrcodeName(_rc) << " (" << (kCancelError.equals(_L, StackIndex{ 1 }) ? "cancelled" : luaG_typename(_L, StackIndex{ 1 })) << ")" << std::endl); 751 DEBUGSPEW_CODE(DebugSpew(lane_->U) << "Lane " << _L << " body: " << GetErrcodeName(_rc) << " (" << (kCancelError.equals(_L, StackIndex{ 1 }) ? "cancelled" : luaW_typename(_L, StackIndex{ 1 })) << ")" << std::endl);
773 // Call finalizers, if the script has set them up. 752 // Call finalizers, if the script has set them up.
774 // If the lane is not a coroutine, there is only a regular state, so everything is the same whether we use S or L. 753 // If the lane is not a coroutine, there is only a regular state, so everything is the same whether we use S or L.
775 // If the lane is a coroutine, this has to be done from the master state (S), not the thread (L), because we can't lua_pcall in a thread state 754 // If the lane is a coroutine, this has to be done from the master state (S), not the thread (L), because we can't lua_pcall in a thread state
@@ -783,10 +762,12 @@ static void lane_main(Lane* const lane_)
783 if (lane_->selfdestructRemove()) { // check and remove (under lock!) 762 if (lane_->selfdestructRemove()) { // check and remove (under lock!)
784 // We're a free-running thread and no-one is there to clean us up. 763 // We're a free-running thread and no-one is there to clean us up.
785 lane_->closeState(); 764 lane_->closeState();
786 lane_->U->selfdestructMutex.lock(); 765
787 // done with lua_close(), terminal shutdown sequence may proceed 766 // let's try not to crash if the lane didn't terminate gracefully and the Universe met its end
788 lane_->U->selfdestructingCount.fetch_sub(1, std::memory_order_release); 767 if (!lane_->flaggedAfterUniverseGC.load(std::memory_order_relaxed)) {
789 lane_->U->selfdestructMutex.unlock(); 768 // done with lua_close(), terminal shutdown sequence may proceed
769 lane_->U->selfdestructingCount.fetch_sub(1, std::memory_order_release);
770 }
790 771
791 // we destroy ourselves, therefore our thread member too, from inside the thread body 772 // we destroy ourselves, therefore our thread member too, from inside the thread body
792 // detach so that we don't try to join, as this doesn't seem a good idea 773 // detach so that we don't try to join, as this doesn't seem a good idea
@@ -807,6 +788,8 @@ static void lane_main(Lane* const lane_)
807// ################################################################################################# 788// #################################################################################################
808 789
809#if LUA_VERSION_NUM >= 504 790#if LUA_VERSION_NUM >= 504
791
792// __close(lane_ud, <err>)
810static LUAG_FUNC(lane_close) 793static LUAG_FUNC(lane_close)
811{ 794{
812 [[maybe_unused]] Lane* const _lane{ ToLane(L_, StackIndex{ 1 }) }; // L_: lane err|nil 795 [[maybe_unused]] Lane* const _lane{ ToLane(L_, StackIndex{ 1 }) }; // L_: lane err|nil
@@ -814,12 +797,13 @@ static LUAG_FUNC(lane_close)
814 lua_settop(L_, 1); // L_: lane 797 lua_settop(L_, 1); // L_: lane
815 798
816 // no error if the lane body doesn't return a non-nil first value 799 // no error if the lane body doesn't return a non-nil first value
817 luaG_pushstring(L_, "close"); // L_: lane "close" 800 luaW_pushstring(L_, "close"); // L_: lane "close"
818 lua_pushcclosure(L_, LG_lane_join, 1); // L_: lane join() 801 lua_pushcclosure(L_, LG_lane_join, 1); // L_: lane join()
819 lua_insert(L_, 1); // L_: join() lane 802 lua_insert(L_, 1); // L_: join() lane
820 lua_call(L_, 1, LUA_MULTRET); // L_: join() results 803 lua_call(L_, 1, LUA_MULTRET); // L_: join() results
821 return lua_gettop(L_); 804 return lua_gettop(L_);
822} 805}
806
823#endif // LUA_VERSION_NUM >= 504 807#endif // LUA_VERSION_NUM >= 504
824 808
825// ################################################################################################# 809// #################################################################################################
@@ -843,9 +827,9 @@ static LUAG_FUNC(lane_gc)
843 // if there a gc callback? 827 // if there a gc callback?
844 lua_getiuservalue(L_, StackIndex{ 1 }, UserValueIndex{ 1 }); // L_: ud uservalue 828 lua_getiuservalue(L_, StackIndex{ 1 }, UserValueIndex{ 1 }); // L_: ud uservalue
845 kLaneGC.pushKey(L_); // L_: ud uservalue __gc 829 kLaneGC.pushKey(L_); // L_: ud uservalue __gc
846 if (luaG_rawget(L_, StackIndex{ -2 }) != LuaType::NIL) { // L_: ud uservalue gc_cb|nil 830 if (luaW_rawget(L_, StackIndex{ -2 }) != LuaType::NIL) { // L_: ud uservalue gc_cb|nil
847 lua_remove(L_, -2); // L_: ud gc_cb|nil 831 lua_remove(L_, -2); // L_: ud gc_cb|nil
848 luaG_pushstring(L_, _lane->getDebugName()); // L_: ud gc_cb name 832 luaW_pushstring(L_, _lane->getDebugName()); // L_: ud gc_cb name
849 _have_gc_cb = true; 833 _have_gc_cb = true;
850 } else { 834 } else {
851 lua_pop(L_, 2); // L_: ud 835 lua_pop(L_, 2); // L_: ud
@@ -856,7 +840,7 @@ static LUAG_FUNC(lane_gc)
856 // still running: will have to be cleaned up later 840 // still running: will have to be cleaned up later
857 _lane->selfdestructAdd(); 841 _lane->selfdestructAdd();
858 if (_have_gc_cb) { 842 if (_have_gc_cb) {
859 luaG_pushstring(L_, "selfdestruct"); // L_: ud gc_cb name status 843 luaW_pushstring(L_, "selfdestruct"); // L_: ud gc_cb name status
860 lua_call(L_, 2, 0); // L_: ud 844 lua_call(L_, 2, 0); // L_: ud
861 } 845 }
862 return 0; 846 return 0;
@@ -871,7 +855,7 @@ static LUAG_FUNC(lane_gc)
871 855
872 // do this after lane cleanup in case the callback triggers an error 856 // do this after lane cleanup in case the callback triggers an error
873 if (_have_gc_cb) { 857 if (_have_gc_cb) {
874 luaG_pushstring(L_, "closed"); // L_: ud gc_cb name status 858 luaW_pushstring(L_, "closed"); // L_: ud gc_cb name status
875 lua_call(L_, 2, 0); // L_: ud 859 lua_call(L_, 2, 0); // L_: ud
876 } 860 }
877 return 0; 861 return 0;
@@ -916,7 +900,7 @@ void Lane::applyDebugName() const
916{ 900{
917 if constexpr (HAVE_DECODA_SUPPORT()) { 901 if constexpr (HAVE_DECODA_SUPPORT()) {
918 // to see VM name in Decoda debugger Virtual Machine window 902 // to see VM name in Decoda debugger Virtual Machine window
919 luaG_pushstring(L, debugName); // L: ... "name" 903 luaW_pushstring(L, debugName); // L: ... "name"
920 lua_setglobal(L, "decoda_name"); // L: ... 904 lua_setglobal(L, "decoda_name"); // L: ...
921 } 905 }
922 // and finally set the OS thread name 906 // and finally set the OS thread name
@@ -941,7 +925,8 @@ CancelResult Lane::cancel(CancelOp const op_, std::chrono::time_point<std::chron
941 925
942 // remember that lanes are not transferable: only one thread can cancel a lane, so no multithreading issue here 926 // remember that lanes are not transferable: only one thread can cancel a lane, so no multithreading issue here
943 // We can read status without locks, but not wait for it (if Posix no PTHREAD_TIMEDJOIN) 927 // We can read status without locks, but not wait for it (if Posix no PTHREAD_TIMEDJOIN)
944 if (status.load(std::memory_order_acquire) >= Lane::Done) { 928 auto const _status{ status.load(std::memory_order_acquire) };
929 if (_status == Lane::Done || _status == Lane::Error || _status == Lane::Cancelled) {
945 // say "ok" by default, including when lane is already done 930 // say "ok" by default, including when lane is already done
946 return CancelResult::Cancelled; 931 return CancelResult::Cancelled;
947 } 932 }
@@ -968,14 +953,15 @@ CancelResult Lane::internalCancel(CancelRequest const rq_, std::chrono::time_poi
968 // lane_->thread.get_stop_source().request_stop(); 953 // lane_->thread.get_stop_source().request_stop();
969 } 954 }
970 if (wakeLane_ == WakeLane::Yes) { // wake the thread so that execution returns from any pending linda operation if desired 955 if (wakeLane_ == WakeLane::Yes) { // wake the thread so that execution returns from any pending linda operation if desired
971 if (status.load(std::memory_order_acquire) == Lane::Waiting) { // waiting_on is updated under control of status acquire/release semantics 956 auto const _status{ status.load(std::memory_order_acquire) };
957 if (_status == Lane::Waiting || _status == Lane::Suspended) { // waiting_on is updated under control of status acquire/release semantics
972 if (std::condition_variable* const _waiting_on{ waiting_on }) { 958 if (std::condition_variable* const _waiting_on{ waiting_on }) {
973 _waiting_on->notify_all(); 959 _waiting_on->notify_all();
974 } 960 }
975 } 961 }
976 } 962 }
977 // wait until the lane stops working with its state (either Suspended or Done+) 963 // wait until the lane stops working with its state (either Suspended or Done+)
978 CancelResult const result{ waitForCompletion(until_) ? CancelResult::Cancelled : CancelResult::Timeout }; 964 CancelResult const result{ waitForCompletion(until_, false) ? CancelResult::Cancelled : CancelResult::Timeout };
979 return result; 965 return result;
980} 966}
981 967
@@ -1027,7 +1013,7 @@ void Lane::PushMetatable(lua_State* const L_)
1027{ 1013{
1028 STACK_CHECK_START_REL(L_, 0); 1014 STACK_CHECK_START_REL(L_, 0);
1029 if (luaL_newmetatable(L_, kLaneMetatableName.data())) { // L_: mt 1015 if (luaL_newmetatable(L_, kLaneMetatableName.data())) { // L_: mt
1030 luaG_registerlibfuncs(L_, local::sLaneFunctions); 1016 luaW_registerlibfuncs(L_, local::sLaneFunctions);
1031 // cache error() and tostring() 1017 // cache error() and tostring()
1032 kCachedError.pushKey(L_); // L_: mt kCachedError 1018 kCachedError.pushKey(L_); // L_: mt kCachedError
1033 lua_getglobal(L_, "error"); // L_: mt kCachedError error() 1019 lua_getglobal(L_, "error"); // L_: mt kCachedError error()
@@ -1036,7 +1022,7 @@ void Lane::PushMetatable(lua_State* const L_)
1036 lua_getglobal(L_, "tostring"); // L_: mt kCachedTostring tostring() 1022 lua_getglobal(L_, "tostring"); // L_: mt kCachedTostring tostring()
1037 lua_rawset(L_, -3); // L_: mt 1023 lua_rawset(L_, -3); // L_: mt
1038 // hide the actual metatable from getmetatable() 1024 // hide the actual metatable from getmetatable()
1039 luaG_pushstring(L_, kLaneMetatableName); // L_: mt "Lane" 1025 luaW_pushstring(L_, kLaneMetatableName); // L_: mt "Lane"
1040 lua_setfield(L_, -2, "__metatable"); // L_: mt 1026 lua_setfield(L_, -2, "__metatable"); // L_: mt
1041 } 1027 }
1042 STACK_CHECK(L_, 1); 1028 STACK_CHECK(L_, 1);
@@ -1049,7 +1035,7 @@ void Lane::pushStatusString(lua_State* const L_) const
1049 std::string_view const _str{ threadStatusString() }; 1035 std::string_view const _str{ threadStatusString() };
1050 LUA_ASSERT(L_, !_str.empty()); 1036 LUA_ASSERT(L_, !_str.empty());
1051 1037
1052 luaG_pushstring(L_, _str); 1038 luaW_pushstring(L_, _str);
1053} 1039}
1054 1040
1055// ################################################################################################# 1041// #################################################################################################
@@ -1108,12 +1094,88 @@ void Lane::pushIndexedResult(lua_State* const L_, int const key_) const
1108// ################################################################################################# 1094// #################################################################################################
1109 1095
1110[[nodiscard]] 1096[[nodiscard]]
1097int Lane::pushStoredResults(lua_State* const L_) const
1098{
1099 STACK_CHECK_START_ABS(L_, 1); // should only have the lane UD on the stack
1100 static constexpr StackIndex kIdxSelf{ 1 };
1101 static constexpr UserValueIndex kUvResults{ 1 };
1102 LUA_ASSERT(L_, ToLane(L_, kIdxSelf) == this); // L_: lane
1103 lua_getiuservalue(L_, kIdxSelf, kUvResults); // L_: lane {uv}
1104 lua_rawgeti(L_, kIdxTop, 0); // L_: lane {uv} stored
1105 int const _stored{ static_cast<int>(lua_tointeger(L_, kIdxTop)) };
1106 lua_pop(L_, 1); // L_: lane {uv}
1107
1108 int _ret{};
1109 STACK_GROW(L_, std::max(3, _stored + 1));
1110 switch (status.load(std::memory_order_acquire)) {
1111 case Lane::Suspended:
1112 raise_luaL_error(L_, "INTERNAL ERROR: SHOULD NEVER BE SUSPENDED HERE");
1113 break;
1114
1115 case Lane::Done: // got regular return values
1116 if (_stored > 0) {
1117 for (int _i = 2; _i <= _stored; ++_i) {
1118 lua_rawgeti(L_, 2, _i); // L_: lane {uv} results2...N
1119 }
1120 lua_rawgeti(L_, 2, 1); // L_: lane {uv} results2...N result1
1121 lua_replace(L_, 2); // L_: lane results
1122 } else {
1123 lua_pop(L_, 1); // L_: lane
1124 }
1125 // we precede the lane body returned values with boolean true
1126 lua_pushboolean(L_, 1); // L_: lane results true
1127 lua_replace(L_, 1); // L_: true results
1128 _ret = _stored + 1;
1129 STACK_CHECK(L_, _ret);
1130 break;
1131
1132 case Lane::Error:
1133 {
1134 LUA_ASSERT(L_, _stored == 2 || _stored == 3); // contains nil error [trace]
1135 lua_rawgeti(L_, 2, 2); // L_: lane {uv} <error>
1136 lua_rawgeti(L_, 2, 3); // L_: lane {uv} <error> <trace>|nil
1137 if (lua_isnil(L_, -1)) {
1138 lua_replace(L_, 2); // L_: lane nil <error>
1139 } else {
1140 lua_rawgeti(L_, 2, 1); // L_: lane {uv} <error> <trace> nil
1141 lua_replace(L_, 2); // L_: lane nil <error> <trace>
1142 }
1143 _ret = _stored; // 2 or 3
1144 STACK_CHECK(L_, _ret + 1); // stack still contains the lane UD below
1145 }
1146 break;
1147
1148 case Lane::Cancelled:
1149 {
1150 LUA_ASSERT(L_, _stored == 2);
1151 lua_rawgeti(L_, 2, 2); // L_: lane {uv} cancel_error
1152 lua_rawgeti(L_, 2, 1); // L_: lane {uv} cancel_error nil
1153 lua_replace(L_, -3); // L_: lane nil cancel_error
1154 LUA_ASSERT(L_, lua_isnil(L_, -2) && kCancelError.equals(L_, kIdxTop));
1155 _ret = 2;
1156 STACK_CHECK(L_, _ret + 1); // stack still contains the lane UD below
1157 }
1158 break;
1159
1160 default:
1161 DEBUGSPEW_CODE(DebugSpew(nullptr) << "Unknown Lane status: " << static_cast<int>(_lane->status.load(std::memory_order_relaxed)) << std::endl);
1162 LUA_ASSERT(L_, false);
1163 _ret = 0;
1164 STACK_CHECK(L_, _ret);
1165 }
1166 LUA_ASSERT(L_, lua_gettop(L_) >= _ret);
1167 return _ret;
1168}
1169
1170// #################################################################################################
1171
1172[[nodiscard]]
1111std::string_view Lane::pushErrorTraceLevel(lua_State* L_) const 1173std::string_view Lane::pushErrorTraceLevel(lua_State* L_) const
1112{ 1174{
1113 std::string_view const _str{ errorTraceLevelString() }; 1175 std::string_view const _str{ errorTraceLevelString() };
1114 LUA_ASSERT(L_, !_str.empty()); 1176 LUA_ASSERT(L_, !_str.empty());
1115 1177
1116 return luaG_pushstring(L_, _str); 1178 return luaW_pushstring(L_, _str);
1117} 1179}
1118 1180
1119// ################################################################################################# 1181// #################################################################################################
@@ -1124,7 +1186,7 @@ void Lane::resetResultsStorage(lua_State* const L_, StackIndex const self_idx_)
1124{ 1186{
1125 STACK_GROW(L_, 4); 1187 STACK_GROW(L_, 4);
1126 STACK_CHECK_START_REL(L_, 0); 1188 STACK_CHECK_START_REL(L_, 0);
1127 StackIndex const _self_idx{ luaG_absindex(L_, self_idx_) }; 1189 StackIndex const _self_idx{ luaW_absindex(L_, self_idx_) };
1128 LUA_ASSERT(L_, ToLane(L_, _self_idx) == this); // L_: ... self ... 1190 LUA_ASSERT(L_, ToLane(L_, _self_idx) == this); // L_: ... self ...
1129 // create the new table 1191 // create the new table
1130 lua_newtable(L_); // L_: ... self ... {} 1192 lua_newtable(L_); // L_: ... self ... {}
@@ -1158,7 +1220,7 @@ void Lane::securizeDebugName(lua_State* const L_)
1158 lua_newtable(L_); // L_: lane ... {uv} {} 1220 lua_newtable(L_); // L_: lane ... {uv} {}
1159 { 1221 {
1160 std::lock_guard<std::mutex> _guard{ debugNameMutex }; 1222 std::lock_guard<std::mutex> _guard{ debugNameMutex };
1161 debugName = luaG_pushstring(L_, debugName); // L_: lane ... {uv} {} name 1223 debugName = luaW_pushstring(L_, debugName); // L_: lane ... {uv} {} name
1162 } 1224 }
1163 lua_rawset(L_, -3); // L_: lane ... {uv} 1225 lua_rawset(L_, -3); // L_: lane ... {uv}
1164 lua_pop(L_, 1); // L_: lane 1226 lua_pop(L_, 1); // L_: lane
@@ -1167,11 +1229,11 @@ void Lane::securizeDebugName(lua_State* const L_)
1167 1229
1168// ################################################################################################# 1230// #################################################################################################
1169 1231
1170void Lane::startThread(int const priority_) 1232void Lane::startThread(lua_State* const L_, int const priority_, NativePrioFlag native_)
1171{ 1233{
1172 thread = std::thread([this]() { lane_main(this); }); 1234 thread = std::thread([this]() { lane_main(this); });
1173 if (priority_ != kThreadPrioDefault) { 1235 if (priority_ != kThreadPrioDefault) {
1174 THREAD_SET_PRIORITY(thread, priority_, U->sudo); 1236 THREAD_SET_PRIORITY(L_, thread, priority_, native_, U->sudo);
1175 } 1237 }
1176} 1238}
1177 1239
@@ -1181,13 +1243,13 @@ void Lane::storeDebugName(std::string_view const& name_)
1181{ 1243{
1182 STACK_CHECK_START_REL(L, 0); 1244 STACK_CHECK_START_REL(L, 0);
1183 // 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... 1245 // 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...
1184 kLaneNameRegKey.setValue(L, [name = name_](lua_State* L_) { luaG_pushstring(L_, name); }); 1246 kLaneNameRegKey.setValue(L, [name = name_](lua_State* L_) { luaW_pushstring(L_, name); });
1185 STACK_CHECK(L, 0); 1247 STACK_CHECK(L, 0);
1186 kLaneNameRegKey.pushValue(L); // L: ... "name" ... 1248 kLaneNameRegKey.pushValue(L); // L: ... "name" ...
1187 // keep a direct view on the stored string 1249 // keep a direct view on the stored string
1188 { 1250 {
1189 std::lock_guard<std::mutex> _guard{ debugNameMutex }; 1251 std::lock_guard<std::mutex> _guard{ debugNameMutex };
1190 debugName = luaG_tostring(L, kIdxTop); 1252 debugName = luaW_tostring(L, kIdxTop);
1191 } 1253 }
1192 lua_pop(L, 1); 1254 lua_pop(L, 1);
1193 STACK_CHECK(L, 0); 1255 STACK_CHECK(L, 0);
@@ -1207,20 +1269,21 @@ int Lane::storeResults(lua_State* const L_)
1207 lua_getiuservalue(L_, kIdxSelf, UserValueIndex{ 1 }); // L_: lane ... {uv} 1269 lua_getiuservalue(L_, kIdxSelf, UserValueIndex{ 1 }); // L_: lane ... {uv}
1208 StackIndex const _tidx{ lua_gettop(L_) }; 1270 StackIndex const _tidx{ lua_gettop(L_) };
1209 1271
1210 int _stored{}; 1272 // if the results were already stored from a previous indexing, just say how many values we have in store
1211 if (nresults == 0) { 1273 if (!L) {
1212 lua_rawgeti(L_, -1, 0); // L_: lane ... {uv} nresults 1274 lua_rawgeti(L_, -1, 0); // L_: lane ... {uv} nresults
1213 _stored = static_cast<int>(lua_tointeger(L_, -1)); 1275 auto const _stored{ static_cast<int>(lua_tointeger(L_, -1)) };
1214 lua_pop(L_, 2); 1276 lua_pop(L_, 2);
1215 STACK_CHECK(L_, 0); 1277 STACK_CHECK(L_, 0);
1216 return _stored; 1278 return _stored;
1217 } 1279 }
1218 1280
1281 int _stored{};
1219 switch (status.load(std::memory_order_acquire)) { 1282 switch (status.load(std::memory_order_acquire)) {
1220 default: 1283 default:
1221 // this is an internal error, we probably never get here 1284 // this is an internal error, we probably never get here
1222 lua_settop(L_, 0); // L_: 1285 lua_settop(L_, 0); // L_:
1223 luaG_pushstring(L_, "Unexpected status: "); // L_: "Unexpected status: " 1286 luaW_pushstring(L_, "Unexpected status: "); // L_: "Unexpected status: "
1224 pushStatusString(L_); // L_: "Unexpected status: " "<status>" 1287 pushStatusString(L_); // L_: "Unexpected status: " "<status>"
1225 lua_concat(L_, 2); // L_: "Unexpected status: <status>" 1288 lua_concat(L_, 2); // L_: "Unexpected status: <status>"
1226 raise_lua_error(L_); 1289 raise_lua_error(L_);
@@ -1295,12 +1358,13 @@ int Lane::storeResults(lua_State* const L_)
1295//--- 1358//---
1296// str= thread_status( lane ) 1359// str= thread_status( lane )
1297// 1360//
1298// "pending" -> | ("running" <-> "waiting") <-> "suspended" <-> "resuming" | -> "done"/"error"/"cancelled" 1361// "pending" -> | ("running" <-> "waiting") <-> "suspended" <-> "resuming/closing" | -> "done"/"error"/"cancelled"
1299 1362
1300// "pending" not started yet 1363// "pending" not started yet
1301// "running" started, doing its work.. 1364// "running" started, doing its work..
1302// "suspended" returned from a lua_resume 1365// "suspended" returned from a lua_resume
1303// "resuming" told by its parent state to resume 1366// "resuming" told by its parent state to resume
1367// "closing" not observable from the outside: happens only inside a join()/indexation call to unblock a suspended coroutine Lane so that it can join properly
1304// "waiting" blocked in a send()/receive() 1368// "waiting" blocked in a send()/receive()
1305// "done" finished, results are there 1369// "done" finished, results are there
1306// "error" finished at an error, error value is there 1370// "error" finished at an error, error value is there
@@ -1311,7 +1375,7 @@ std::string_view Lane::threadStatusString() const
1311{ 1375{
1312 static constexpr std::string_view kStrs[] = { 1376 static constexpr std::string_view kStrs[] = {
1313 "pending", 1377 "pending",
1314 "running", "suspended", "resuming", 1378 "running", "suspended", "resuming", "closing",
1315 "waiting", 1379 "waiting",
1316 "done", "error", "cancelled" 1380 "done", "error", "cancelled"
1317 }; 1381 };
@@ -1319,12 +1383,13 @@ std::string_view Lane::threadStatusString() const
1319 static_assert(1 == static_cast<std::underlying_type_t<Lane::Status>>(Running)); 1383 static_assert(1 == static_cast<std::underlying_type_t<Lane::Status>>(Running));
1320 static_assert(2 == static_cast<std::underlying_type_t<Lane::Status>>(Suspended)); 1384 static_assert(2 == static_cast<std::underlying_type_t<Lane::Status>>(Suspended));
1321 static_assert(3 == static_cast<std::underlying_type_t<Lane::Status>>(Resuming)); 1385 static_assert(3 == static_cast<std::underlying_type_t<Lane::Status>>(Resuming));
1322 static_assert(4 == static_cast<std::underlying_type_t<Lane::Status>>(Waiting)); 1386 static_assert(4 == static_cast<std::underlying_type_t<Lane::Status>>(Closing));
1323 static_assert(5 == static_cast<std::underlying_type_t<Lane::Status>>(Done)); 1387 static_assert(5 == static_cast<std::underlying_type_t<Lane::Status>>(Waiting));
1324 static_assert(6 == static_cast<std::underlying_type_t<Lane::Status>>(Error)); 1388 static_assert(6 == static_cast<std::underlying_type_t<Lane::Status>>(Done));
1325 static_assert(7 == static_cast<std::underlying_type_t<Lane::Status>>(Cancelled)); 1389 static_assert(7 == static_cast<std::underlying_type_t<Lane::Status>>(Error));
1390 static_assert(8 == static_cast<std::underlying_type_t<Lane::Status>>(Cancelled));
1326 auto const _status{ static_cast<std::underlying_type_t<Lane::Status>>(status.load(std::memory_order_acquire)) }; 1391 auto const _status{ static_cast<std::underlying_type_t<Lane::Status>>(status.load(std::memory_order_acquire)) };
1327 if (_status < 0 || _status > 7) { // should never happen, but better safe than sorry 1392 if (_status < 0 || _status > 8) { // should never happen, but better safe than sorry
1328 return ""; 1393 return "";
1329 } 1394 }
1330 return kStrs[_status]; 1395 return kStrs[_status];
@@ -1332,17 +1397,52 @@ std::string_view Lane::threadStatusString() const
1332 1397
1333// ################################################################################################# 1398// #################################################################################################
1334 1399
1335bool Lane::waitForCompletion(std::chrono::time_point<std::chrono::steady_clock> until_) 1400bool Lane::waitForCompletion(std::chrono::time_point<std::chrono::steady_clock> until_, bool const _acceptSuspended)
1336{ 1401{
1337 std::unique_lock _guard{ doneMutex }; 1402 std::unique_lock _guard{ doneMutex };
1338 // std::stop_token token{ thread.get_stop_token() }; 1403 // std::stop_token token{ thread.get_stop_token() };
1339 // return doneCondVar.wait_until(lock, token, secs_, [this](){ return status >= Lane::Done; }); 1404 // return doneCondVar.wait_until(lock, token, secs_, [this](){ return status >= Lane::Done; });
1340 1405
1341 // wait until the lane stops working with its state (either Suspended or Done+) 1406 // wait until the lane exits lane_main (which is the only place where status can become one of the 3 tested values)
1342 return doneCondVar.wait_until(_guard, until_, [this]() 1407 return doneCondVar.wait_until(_guard, until_, [this, suspended = _acceptSuspended ? Lane::Suspended : Lane::Done]() {
1408 auto const _status{ status.load(std::memory_order_acquire) };
1409 return _status == Lane::Done || _status == Lane::Error || _status == Lane::Cancelled || _status == suspended;
1410 });
1411}
1412
1413// #################################################################################################
1414
1415[[nodiscard]]
1416bool Lane::waitForJoin(lua_State* const L_, std::chrono::time_point<std::chrono::steady_clock> until_)
1417{
1418 // wait until suspended or done
1419 {
1420 bool const _done{ !thread.joinable() || waitForCompletion(until_, true) };
1421
1422 if (!_done) {
1423 lua_pushnil(L_); // L_: lane nil
1424 luaW_pushstring(L_, "timeout"); // L_: lane nil "timeout"
1425 return false;
1426 }
1427 }
1428
1429 // if lane is suspended, force the yield loop to break, and the termination of the thread
1430 if (status.load(std::memory_order_acquire) == Lane::Suspended) {
1431 LUA_ASSERT(L_, waiting_on == &doneCondVar);
1432 status.store(Lane::Closing, std::memory_order_release);
1433 doneCondVar.notify_all();
1434 // wait until done
1343 { 1435 {
1344 auto const _status{ status.load(std::memory_order_acquire) }; 1436 bool const _done{ !thread.joinable() || waitForCompletion(until_, true) };
1345 return _status == Lane::Suspended || _status >= Lane::Done; 1437
1438 if (!_done) {
1439 lua_pushnil(L_); // L_: lane nil
1440 luaW_pushstring(L_, "timeout"); // L_: lane nil "timeout"
1441 return false;
1442 }
1346 } 1443 }
1347 ); 1444 LUA_ASSERT(L_, status.load(std::memory_order_acquire) != Lane::Closing);
1445 }
1446 LUA_ASSERT(L_, status.load(std::memory_order_acquire) != Lane::Suspended);
1447 return true;
1348} 1448}
diff --git a/src/lane.hpp b/src/lane.hpp
index 5fe36b6..bd328b1 100644
--- a/src/lane.hpp
+++ b/src/lane.hpp
@@ -56,6 +56,7 @@ class Lane final
56 /* 56 /*
57 Pending: The Lua VM hasn't done anything yet. 57 Pending: The Lua VM hasn't done anything yet.
58 Resuming: The user requested the lane to resume execution from Suspended state. 58 Resuming: The user requested the lane to resume execution from Suspended state.
59 Closing: The user is joining the lane, specifically interrupting a suspended Lane.
59 Suspended: returned from lua_resume, waiting for the client to request a lua_resume. 60 Suspended: returned from lua_resume, waiting for the client to request a lua_resume.
60 Running, Suspended, Waiting: Thread is inside the Lua VM. 61 Running, Suspended, Waiting: Thread is inside the Lua VM.
61 Done, Error, Cancelled: Thread execution is outside the Lua VM. It can be lua_close()d. 62 Done, Error, Cancelled: Thread execution is outside the Lua VM. It can be lua_close()d.
@@ -66,6 +67,7 @@ class Lane final
66 Running, 67 Running,
67 Suspended, 68 Suspended,
68 Resuming, 69 Resuming,
70 Closing,
69 Waiting, 71 Waiting,
70 Done, 72 Done,
71 Error, 73 Error,
@@ -199,12 +201,14 @@ class Lane final
199 static void PushMetatable(lua_State* L_); 201 static void PushMetatable(lua_State* L_);
200 void pushStatusString(lua_State* L_) const; 202 void pushStatusString(lua_State* L_) const;
201 void pushIndexedResult(lua_State* L_, int key_) const; 203 void pushIndexedResult(lua_State* L_, int key_) const;
204 [[nodiscard]]
205 int pushStoredResults(lua_State* L_) const;
202 void resetResultsStorage(lua_State* L_, StackIndex self_idx_); 206 void resetResultsStorage(lua_State* L_, StackIndex self_idx_);
203 void selfdestructAdd(); 207 void selfdestructAdd();
204 [[nodiscard]] 208 [[nodiscard]]
205 bool selfdestructRemove(); 209 bool selfdestructRemove();
206 void securizeDebugName(lua_State* L_); 210 void securizeDebugName(lua_State* L_);
207 void startThread(int priority_); 211 void startThread(lua_State* L_, int priority_, NativePrioFlag native_);
208 void storeDebugName( std::string_view const& name_); 212 void storeDebugName( std::string_view const& name_);
209 [[nodiscard]] 213 [[nodiscard]]
210 int storeResults(lua_State* L_); 214 int storeResults(lua_State* L_);
@@ -212,7 +216,9 @@ class Lane final
212 std::string_view threadStatusString() const; 216 std::string_view threadStatusString() const;
213 // wait until the lane stops working with its state (either Suspended or Done+) 217 // wait until the lane stops working with its state (either Suspended or Done+)
214 [[nodiscard]] 218 [[nodiscard]]
215 bool waitForCompletion(std::chrono::time_point<std::chrono::steady_clock> until_); 219 bool waitForCompletion(std::chrono::time_point<std::chrono::steady_clock> until_, bool const _acceptSuspended);
220 [[nodiscard]]
221 bool waitForJoin(lua_State* _L, std::chrono::time_point<std::chrono::steady_clock> until_);
216}; 222};
217 223
218// ################################################################################################# 224// #################################################################################################
diff --git a/src/lanes.cpp b/src/lanes.cpp
index d1a353b..4373aee 100644
--- a/src/lanes.cpp
+++ b/src/lanes.cpp
@@ -137,13 +137,15 @@ LUAG_FUNC(set_singlethreaded)
137LUAG_FUNC(set_thread_priority) 137LUAG_FUNC(set_thread_priority)
138{ 138{
139 lua_Integer const _prio{ luaL_checkinteger(L_, 1) }; 139 lua_Integer const _prio{ luaL_checkinteger(L_, 1) };
140 NativePrioFlag const _native{ std::string_view{ "native" } == luaL_optstring(L_, 2, "mapped") };
140 // public Lanes API accepts a generic range -3/+3 141 // public Lanes API accepts a generic range -3/+3
141 // that will be remapped into the platform-specific scheduler priority scheme 142 // that will be remapped into the platform-specific scheduler priority scheme
142 // On some platforms, -3 is equivalent to -2 and +3 to +2 143 // On some platforms, -3 is equivalent to -2 and +3 to +2
143 if (_prio < kThreadPrioMin || _prio > kThreadPrioMax) { 144 if (!_native && (_prio < kThreadPrioMin || _prio > kThreadPrioMax)) {
144 raise_luaL_error(L_, "priority out of range: %d..+%d (%d)", kThreadPrioMin, kThreadPrioMax, _prio); 145 raise_luaL_error(L_, "priority out of range: %d..+%d (%d)", kThreadPrioMin, kThreadPrioMax, _prio);
145 } 146 }
146 THREAD_SET_PRIORITY(static_cast<int>(_prio), Universe::Get(L_)->sudo); 147
148 THREAD_SET_PRIORITY(L_, static_cast<int>(_prio), _native, Universe::Get(L_)->sudo);
147 return 0; 149 return 0;
148} 150}
149 151
@@ -155,7 +157,8 @@ LUAG_FUNC(set_thread_affinity)
155 if (_affinity <= 0) { 157 if (_affinity <= 0) {
156 raise_luaL_error(L_, "invalid affinity (%d)", _affinity); 158 raise_luaL_error(L_, "invalid affinity (%d)", _affinity);
157 } 159 }
158 THREAD_SET_AFFINITY(static_cast<unsigned int>(_affinity)); 160
161 THREAD_SET_AFFINITY(L_, static_cast<unsigned int>(_affinity));
159 return 0; 162 return 0;
160} 163}
161 164
@@ -170,17 +173,21 @@ LUAG_FUNC(sleep)
170 lua_pushcfunction(L_, LG_linda_receive); // L_: duration|nil receive() 173 lua_pushcfunction(L_, LG_linda_receive); // L_: duration|nil receive()
171 STACK_CHECK_START_REL(L_, 0); // we pushed the function we intend to call, now prepare the arguments 174 STACK_CHECK_START_REL(L_, 0); // we pushed the function we intend to call, now prepare the arguments
172 _U->timerLinda->push(L_); // L_: duration|nil receive() timerLinda 175 _U->timerLinda->push(L_); // L_: duration|nil receive() timerLinda
173 if (luaG_tostring(L_, StackIndex{ 1 }) == "indefinitely") { 176 if (luaW_tostring(L_, StackIndex{ 1 }) == "indefinitely") {
174 lua_pushnil(L_); // L_: duration? receive() timerLinda nil 177 lua_pushnil(L_); // L_: duration? receive() timerLinda nil
175 } else if (lua_isnoneornil(L_, 1)) { 178 } else if (lua_isnoneornil(L_, 1)) {
176 lua_pushnumber(L_, 0); // L_: duration? receive() timerLinda 0 179 lua_pushnumber(L_, 0); // L_: duration? receive() timerLinda 0
177 } else if (!lua_isnumber(L_, 1)) { 180 } else if (!lua_isnumber(L_, 1)) {
178 raise_luaL_argerror(L_, StackIndex{ 1 }, "invalid duration"); 181 raise_luaL_argerror(L_, StackIndex{ 1 }, "duration must be a number");
179 } 182 }
180 else { 183 else {
184 auto const _n{ lua_tonumber(L_, 1) };
185 if (_n < 0) {
186 raise_luaL_argerror(L_, StackIndex{ 1 }, "duration must be >= 0");
187 }
181 lua_pushnumber(L_, lua_tonumber(L_, 1)); // L_: duration? receive() timerLinda duration 188 lua_pushnumber(L_, lua_tonumber(L_, 1)); // L_: duration? receive() timerLinda duration
182 } 189 }
183 luaG_pushstring(L_, "ac100de1-a696-4619-b2f0-a26de9d58ab8"); // L_: duration? receive() timerLinda duration key 190 luaW_pushstring(L_, "ac100de1-a696-4619-b2f0-a26de9d58ab8"); // L_: duration? receive() timerLinda duration key
184 STACK_CHECK(L_, 3); // 3 arguments ready 191 STACK_CHECK(L_, 3); // 3 arguments ready
185 lua_call(L_, 3, LUA_MULTRET); // timerLinda:receive(duration,key) // L_: duration? result... 192 lua_call(L_, 3, LUA_MULTRET); // timerLinda:receive(duration,key) // L_: duration? result...
186 return lua_gettop(L_) - 1; 193 return lua_gettop(L_) - 1;
@@ -194,7 +201,7 @@ LUAG_FUNC(sleep)
194// upvalue[1]: _G.require 201// upvalue[1]: _G.require
195LUAG_FUNC(require) 202LUAG_FUNC(require)
196{ 203{
197 std::string_view const _name{ luaG_tostring(L_, StackIndex{ 1 }) }; // L_: "name" ... 204 std::string_view const _name{ luaW_tostring(L_, StackIndex{ 1 }) }; // L_: "name" ...
198 int const _nargs{ lua_gettop(L_) }; 205 int const _nargs{ lua_gettop(L_) };
199 DEBUGSPEW_CODE(Universe * _U{ Universe::Get(L_) }); 206 DEBUGSPEW_CODE(Universe * _U{ Universe::Get(L_) });
200 STACK_CHECK_START_REL(L_, 0); 207 STACK_CHECK_START_REL(L_, 0);
@@ -220,8 +227,8 @@ int lanes_register(lua_State* const L_)
220 if (!_U) { 227 if (!_U) {
221 raise_luaL_error(L_, "Lanes is not ready"); 228 raise_luaL_error(L_, "Lanes is not ready");
222 } 229 }
223 std::string_view const _name{ luaG_checkstring(L_, StackIndex{ 1 }) }; 230 std::string_view const _name{ luaW_checkstring(L_, StackIndex{ 1 }) };
224 LuaType const _mod_type{ luaG_type(L_, StackIndex{ 2 }) }; 231 LuaType const _mod_type{ luaW_type(L_, StackIndex{ 2 }) };
225 // ignore extra arguments, just in case 232 // ignore extra arguments, just in case
226 lua_settop(L_, 2); 233 lua_settop(L_, 2);
227 luaL_argcheck(L_, (_mod_type == LuaType::TABLE) || (_mod_type == LuaType::FUNCTION), 2, "unexpected module type"); 234 luaL_argcheck(L_, (_mod_type == LuaType::TABLE) || (_mod_type == LuaType::FUNCTION), 2, "unexpected module type");
@@ -236,9 +243,26 @@ int lanes_register(lua_State* const L_)
236 243
237// ################################################################################################# 244// #################################################################################################
238 245
246LUAG_FUNC(thread_priority_range)
247{
248 NativePrioFlag const _native{ std::string_view{ "native" } == luaL_optstring(L_, 1, "mapped") };
249 if (_native) {
250 auto const [_prio_min, _prio_max] = THREAD_NATIVE_PRIOS();
251 lua_pushinteger(L_, _prio_min);
252 lua_pushinteger(L_, _prio_max);
253 } else {
254 lua_pushinteger(L_, kThreadPrioMin);
255 lua_pushinteger(L_, kThreadPrioMax);
256 }
257 return 2;
258}
259
260// #################################################################################################
261
239//--- [] means can be nil 262//--- [] means can be nil
240// lane_ud = lane_new( function 263// lane_ud = lane_new( function
241// , [libs_str] 264// , [libs_str]
265// , [prio_is_native_bool]
242// , [priority_int] 266// , [priority_int]
243// , [globals_tbl] 267// , [globals_tbl]
244// , [package_tbl] 268// , [package_tbl]
@@ -255,15 +279,16 @@ LUAG_FUNC(lane_new)
255{ 279{
256 static constexpr StackIndex kFuncIdx{ 1 }; 280 static constexpr StackIndex kFuncIdx{ 1 };
257 static constexpr StackIndex kLibsIdx{ 2 }; 281 static constexpr StackIndex kLibsIdx{ 2 };
258 static constexpr StackIndex kPrioIdx{ 3 }; 282 static constexpr StackIndex kPrinIdx{ 3 };
259 static constexpr StackIndex kGlobIdx{ 4 }; 283 static constexpr StackIndex kPrioIdx{ 4 };
260 static constexpr StackIndex kPackIdx{ 5 }; 284 static constexpr StackIndex kGlobIdx{ 5 };
261 static constexpr StackIndex kRequIdx{ 6 }; 285 static constexpr StackIndex kPackIdx{ 6 };
262 static constexpr StackIndex kGcCbIdx{ 7 }; 286 static constexpr StackIndex kRequIdx{ 7 };
263 static constexpr StackIndex kNameIdx{ 8 }; 287 static constexpr StackIndex kGcCbIdx{ 8 };
264 static constexpr StackIndex kErTlIdx{ 9 }; 288 static constexpr StackIndex kNameIdx{ 9 };
265 static constexpr StackIndex kAsCoro{ 10 }; 289 static constexpr StackIndex kErTlIdx{ 10 };
266 static constexpr StackIndex kFixedArgsIdx{ 10 }; 290 static constexpr StackIndex kAsCoro{ 11 };
291 static constexpr StackIndex kFixedArgsIdx{ 11 };
267 292
268 int const _nargs{ lua_gettop(L_) - kFixedArgsIdx }; 293 int const _nargs{ lua_gettop(L_) - kFixedArgsIdx };
269 LUA_ASSERT(L_, _nargs >= 0); 294 LUA_ASSERT(L_, _nargs >= 0);
@@ -271,7 +296,7 @@ LUAG_FUNC(lane_new)
271 Universe* const _U{ Universe::Get(L_) }; 296 Universe* const _U{ Universe::Get(L_) };
272 DEBUGSPEW_CODE(DebugSpew(_U) << "lane_new: setup" << std::endl); 297 DEBUGSPEW_CODE(DebugSpew(_U) << "lane_new: setup" << std::endl);
273 298
274 std::optional<std::string_view> _libs_str{ lua_isnil(L_, kLibsIdx) ? std::nullopt : std::make_optional(luaG_tostring(L_, kLibsIdx)) }; 299 std::optional<std::string_view> _libs_str{ lua_isnil(L_, kLibsIdx) ? std::nullopt : std::make_optional(luaW_tostring(L_, kLibsIdx)) };
275 lua_State* const _S{ state::NewLaneState(_U, SourceState{ L_ }, _libs_str) }; // L_: [fixed] ... L2: 300 lua_State* const _S{ state::NewLaneState(_U, SourceState{ L_ }, _libs_str) }; // L_: [fixed] ... L2:
276 STACK_CHECK_START_REL(_S, 0); 301 STACK_CHECK_START_REL(_S, 0);
277 302
@@ -333,7 +358,7 @@ LUAG_FUNC(lane_new)
333 DEBUGSPEW_CODE(DebugSpew(lane->U) << "lane_new: preparing lane userdata" << std::endl); 358 DEBUGSPEW_CODE(DebugSpew(lane->U) << "lane_new: preparing lane userdata" << std::endl);
334 STACK_CHECK_START_REL(L, 0); 359 STACK_CHECK_START_REL(L, 0);
335 // a Lane full userdata needs a single uservalue 360 // a Lane full userdata needs a single uservalue
336 Lane** const _ud{ luaG_newuserdatauv<Lane*>(L, UserValueCount{ 1 }) }; // L: ... lane 361 Lane** const _ud{ luaW_newuserdatauv<Lane*>(L, UserValueCount{ 1 }) }; // L: ... lane
337 *_ud = lane; // don't forget to store the pointer in the userdata! 362 *_ud = lane; // don't forget to store the pointer in the userdata!
338 363
339 // Set metatable for the userdata 364 // Set metatable for the userdata
@@ -357,25 +382,25 @@ LUAG_FUNC(lane_new)
357 lua_setiuservalue(L, StackIndex{ -2 }, UserValueIndex{ 1 }); // L: ... lane 382 lua_setiuservalue(L, StackIndex{ -2 }, UserValueIndex{ 1 }); // L: ... lane
358 383
359 StackIndex const _name_idx{ lua_isnoneornil(L, kNameIdx) ? kIdxNone : kNameIdx }; 384 StackIndex const _name_idx{ lua_isnoneornil(L, kNameIdx) ? kIdxNone : kNameIdx };
360 std::string_view _debugName{ (_name_idx > 0) ? luaG_tostring(L, _name_idx) : std::string_view{} }; 385 std::string_view _debugName{ (_name_idx > 0) ? luaW_tostring(L, _name_idx) : std::string_view{} };
361 if (!_debugName.empty()) 386 if (!_debugName.empty())
362 { 387 {
363 if (_debugName == "auto") { 388 if (_debugName == "auto") {
364 if (luaG_type(L, kFuncIdx) == LuaType::STRING) { 389 if (luaW_type(L, kFuncIdx) == LuaType::STRING) {
365 lua_Debug _ar; 390 lua_Debug _ar;
366 if (lua_getstack(L, 2, &_ar) == 0) { // 0 is here, 1 is lanes.gen, 2 is its caller 391 if (lua_getstack(L, 2, &_ar) == 0) { // 0 is here, 1 is lanes.gen, 2 is its caller
367 lua_getstack(L, 1, &_ar); // level 2 may not exist with LuaJIT, try again with level 1 392 lua_getstack(L, 1, &_ar); // level 2 may not exist with LuaJIT, try again with level 1
368 } 393 }
369 lua_getinfo(L, "Sl", &_ar); 394 lua_getinfo(L, "Sl", &_ar);
370 luaG_pushstring(L, "%s:%d", _ar.short_src, _ar.currentline); // L: ... lane "<name>" 395 luaW_pushstring(L, "%s:%d", _ar.short_src, _ar.currentline); // L: ... lane "<name>"
371 } else { 396 } else {
372 lua_Debug _ar; 397 lua_Debug _ar;
373 lua_pushvalue(L, kFuncIdx); // L: ... lane func 398 lua_pushvalue(L, kFuncIdx); // L: ... lane func
374 lua_getinfo(L, ">S", &_ar); // L: ... lane 399 lua_getinfo(L, ">S", &_ar); // L: ... lane
375 luaG_pushstring(L, "%s:%d", _ar.short_src, _ar.linedefined); // L: ... lane "<name>" 400 luaW_pushstring(L, "%s:%d", _ar.short_src, _ar.linedefined); // L: ... lane "<name>"
376 } 401 }
377 lua_replace(L, _name_idx); // L: ... lane 402 lua_replace(L, _name_idx); // L: ... lane
378 _debugName = luaG_tostring(L, _name_idx); 403 _debugName = luaW_tostring(L, _name_idx);
379 } 404 }
380 lane->storeDebugName(_debugName); 405 lane->storeDebugName(_debugName);
381 } 406 }
@@ -400,21 +425,22 @@ LUAG_FUNC(lane_new)
400 // public Lanes API accepts a generic range -3/+3 425 // public Lanes API accepts a generic range -3/+3
401 // that will be remapped into the platform-specific scheduler priority scheme 426 // that will be remapped into the platform-specific scheduler priority scheme
402 // On some platforms, -3 is equivalent to -2 and +3 to +2 427 // On some platforms, -3 is equivalent to -2 and +3 to +2
403 int const _priority{ 428 auto const [_priority, _native] {
404 std::invoke([L = L_]() { 429 std::invoke([L = L_]() {
430 NativePrioFlag const _native{ static_cast<bool>(lua_toboolean(L, kPrinIdx)) };
405 StackIndex const _prio_idx{ lua_isnoneornil(L, kPrioIdx) ? kIdxNone : kPrioIdx }; 431 StackIndex const _prio_idx{ lua_isnoneornil(L, kPrioIdx) ? kIdxNone : kPrioIdx };
406 if (_prio_idx == 0) { 432 if (_prio_idx == kIdxNone) {
407 return kThreadPrioDefault; 433 return std::make_pair(kThreadPrioDefault, _native);
408 } 434 }
409 int const _priority{ static_cast<int>(lua_tointeger(L, _prio_idx)) }; 435 int const _priority{ static_cast<int>(lua_tointeger(L, _prio_idx)) };
410 if ((_priority < kThreadPrioMin || _priority > kThreadPrioMax)) { 436 if (!_native && (_priority < kThreadPrioMin || _priority > kThreadPrioMax)) {
411 raise_luaL_error(L, "Priority out of range: %d..+%d (%d)", kThreadPrioMin, kThreadPrioMax, _priority); 437 raise_luaL_error(L, "Priority out of range: %d..+%d (%d)", kThreadPrioMin, kThreadPrioMax, _priority);
412 } 438 }
413 return _priority; 439 return std::make_pair(_priority, _native);
414 }) 440 })
415 }; 441 };
416 442
417 _lane->startThread(_priority); 443 _lane->startThread(L_, _priority, _native);
418 444
419 STACK_GROW(_L2, _nargs + 3); 445 STACK_GROW(_L2, _nargs + 3);
420 STACK_GROW(L_, 3); 446 STACK_GROW(L_, 3);
@@ -439,17 +465,17 @@ LUAG_FUNC(lane_new)
439 DEBUGSPEW_CODE(DebugSpew(_U) << "lane_new: process 'required' list" << std::endl); 465 DEBUGSPEW_CODE(DebugSpew(_U) << "lane_new: process 'required' list" << std::endl);
440 DEBUGSPEW_CODE(DebugSpewIndentScope _scope{ _U }); 466 DEBUGSPEW_CODE(DebugSpewIndentScope _scope{ _U });
441 // should not happen, was checked in lanes.lua before calling lane_new() 467 // should not happen, was checked in lanes.lua before calling lane_new()
442 if (luaG_type(L_, _required_idx) != LuaType::TABLE) { 468 if (luaW_type(L_, _required_idx) != LuaType::TABLE) {
443 raise_luaL_error(L_, "expected required module list as a table, got %s", luaL_typename(L_, _required_idx)); 469 raise_luaL_error(L_, "expected required module list as a table, got %s", luaL_typename(L_, _required_idx));
444 } 470 }
445 471
446 lua_pushnil(L_); // L_: [fixed] args... nil L2: 472 lua_pushnil(L_); // L_: [fixed] args... nil L2:
447 while (lua_next(L_, _required_idx) != 0) { // L_: [fixed] args... n "modname" L2: 473 while (lua_next(L_, _required_idx) != 0) { // L_: [fixed] args... n "modname" L2:
448 if (luaG_type(L_, kIdxTop) != LuaType::STRING || luaG_type(L_, StackIndex{ -2 }) != LuaType::NUMBER || lua_tonumber(L_, -2) != _nbRequired) { 474 if (luaW_type(L_, kIdxTop) != LuaType::STRING || luaW_type(L_, StackIndex{ -2 }) != LuaType::NUMBER || lua_tonumber(L_, -2) != _nbRequired) {
449 raise_luaL_error(L_, "required module list should be a list of strings"); 475 raise_luaL_error(L_, "required module list should be a list of strings");
450 } else { 476 } else {
451 // require the module in the target state, and populate the lookup table there too 477 // require the module in the target state, and populate the lookup table there too
452 std::string_view const _name{ luaG_tostring(L_, kIdxTop) }; 478 std::string_view const _name{ luaW_tostring(L_, kIdxTop) };
453 DEBUGSPEW_CODE(DebugSpew(_U) << "lane_new: require '" << _name << "'" << std::endl); 479 DEBUGSPEW_CODE(DebugSpew(_U) << "lane_new: require '" << _name << "'" << std::endl);
454 480
455 // require the module in the target lane 481 // require the module in the target lane
@@ -458,7 +484,7 @@ LUAG_FUNC(lane_new)
458 lua_pop(_L2, 1); // L_: [fixed] args... n "modname" L2: 484 lua_pop(_L2, 1); // L_: [fixed] args... n "modname" L2:
459 raise_luaL_error(L_, "cannot pre-require modules without loading 'package' library first"); 485 raise_luaL_error(L_, "cannot pre-require modules without loading 'package' library first");
460 } else { 486 } else {
461 luaG_pushstring(_L2, _name); // L_: [fixed] args... n "modname" L2: require() name 487 luaW_pushstring(_L2, _name); // L_: [fixed] args... n "modname" L2: require() name
462 LuaError const _rc{ lua_pcall(_L2, 1, 1, 0) }; // L_: [fixed] args... n "modname" L2: ret/errcode 488 LuaError const _rc{ lua_pcall(_L2, 1, 1, 0) }; // L_: [fixed] args... n "modname" L2: ret/errcode
463 if (_rc != LuaError::OK) { 489 if (_rc != LuaError::OK) {
464 // propagate error to main state if any 490 // propagate error to main state if any
@@ -493,7 +519,7 @@ LUAG_FUNC(lane_new)
493 lua_pushnil(L_); // L_: [fixed] args... nil L2: 519 lua_pushnil(L_); // L_: [fixed] args... nil L2:
494 // Lua 5.2 wants us to push the globals table on the stack 520 // Lua 5.2 wants us to push the globals table on the stack
495 InterCopyContext _c{ _U, DestState{ _L2 }, SourceState{ L_ }, {}, {}, {}, {}, {} }; 521 InterCopyContext _c{ _U, DestState{ _L2 }, SourceState{ L_ }, {}, {}, {}, {}, {} };
496 luaG_pushglobaltable(_L2); // L_: [fixed] args... nil L2: _G 522 luaW_pushglobaltable(_L2); // L_: [fixed] args... nil L2: _G
497 while (lua_next(L_, _globals_idx)) { // L_: [fixed] args... k v L2: _G 523 while (lua_next(L_, _globals_idx)) { // L_: [fixed] args... k v L2: _G
498 std::ignore = _c.interCopy(2); // L_: [fixed] args... k v L2: _G k v 524 std::ignore = _c.interCopy(2); // L_: [fixed] args... k v L2: _G k v
499 // assign it in L2's globals table 525 // assign it in L2's globals table
@@ -507,7 +533,7 @@ LUAG_FUNC(lane_new)
507 533
508 // Lane main function 534 // Lane main function
509 [[maybe_unused]] int const _errorHandlerCount{ _lane->pushErrorHandler() }; // L_: [fixed] args... L2: eh? 535 [[maybe_unused]] int const _errorHandlerCount{ _lane->pushErrorHandler() }; // L_: [fixed] args... L2: eh?
510 LuaType const _func_type{ luaG_type(L_, kFuncIdx) }; 536 LuaType const _func_type{ luaW_type(L_, kFuncIdx) };
511 if (_func_type == LuaType::FUNCTION) { 537 if (_func_type == LuaType::FUNCTION) {
512 DEBUGSPEW_CODE(DebugSpew(_U) << "lane_new: transfer lane body" << std::endl); 538 DEBUGSPEW_CODE(DebugSpew(_U) << "lane_new: transfer lane body" << std::endl);
513 DEBUGSPEW_CODE(DebugSpewIndentScope _scope{ _U }); 539 DEBUGSPEW_CODE(DebugSpewIndentScope _scope{ _U });
@@ -524,7 +550,7 @@ LUAG_FUNC(lane_new)
524 raise_luaL_error(L_, "error when parsing lane function code"); 550 raise_luaL_error(L_, "error when parsing lane function code");
525 } 551 }
526 } else { 552 } else {
527 raise_luaL_error(L_, "Expected function, got %s", luaG_typename(L_, _func_type).data()); 553 raise_luaL_error(L_, "Expected function, got %s", luaW_typename(L_, _func_type).data());
528 } 554 }
529 STACK_CHECK(L_, 0); 555 STACK_CHECK(L_, 0);
530 STACK_CHECK(_L2, _errorHandlerCount + 1); 556 STACK_CHECK(_L2, _errorHandlerCount + 1);
@@ -612,7 +638,7 @@ LUAG_FUNC(wakeup_conv)
612 638
613 STACK_CHECK_START_REL(L_, 0); 639 STACK_CHECK_START_REL(L_, 0);
614 auto _readInteger = [L = L_](std::string_view const& name_) { 640 auto _readInteger = [L = L_](std::string_view const& name_) {
615 std::ignore = luaG_getfield(L, StackIndex{ 1 }, name_); 641 std::ignore = luaW_getfield(L, StackIndex{ 1 }, name_);
616 lua_Integer const val{ lua_tointeger(L, -1) }; 642 lua_Integer const val{ lua_tointeger(L, -1) };
617 lua_pop(L, 1); 643 lua_pop(L, 1);
618 return static_cast<int>(val); 644 return static_cast<int>(val);
@@ -628,7 +654,7 @@ LUAG_FUNC(wakeup_conv)
628 // If Lua table has '.isdst' we trust that. If it does not, we'll let 654 // If Lua table has '.isdst' we trust that. If it does not, we'll let
629 // 'mktime' decide on whether the time is within DST or not (value -1). 655 // 'mktime' decide on whether the time is within DST or not (value -1).
630 // 656 //
631 int const _isdst{ (luaG_getfield(L_, StackIndex{ 1 }, "isdst") == LuaType::BOOLEAN) ? lua_toboolean(L_, -1) : -1 }; 657 int const _isdst{ (luaW_getfield(L_, StackIndex{ 1 }, "isdst") == LuaType::BOOLEAN) ? lua_toboolean(L_, -1) : -1 };
632 lua_pop(L_, 1); 658 lua_pop(L_, 1);
633 STACK_CHECK(L_, 0); 659 STACK_CHECK(L_, 0);
634 660
@@ -658,6 +684,7 @@ namespace {
658 { Universe::kFinally, Universe::InitializeFinalizer }, 684 { Universe::kFinally, Universe::InitializeFinalizer },
659 { "linda", LG_linda }, 685 { "linda", LG_linda },
660 { "nameof", LG_nameof }, 686 { "nameof", LG_nameof },
687 { "thread_priority_range", LG_thread_priority_range },
661 { "now_secs", LG_now_secs }, 688 { "now_secs", LG_now_secs },
662 { "register", lanes_register }, 689 { "register", lanes_register },
663 { "set_singlethreaded", LG_set_singlethreaded }, 690 { "set_singlethreaded", LG_set_singlethreaded },
@@ -692,8 +719,8 @@ LUAG_FUNC(configure)
692 719
693 Universe* _U{ Universe::Get(L_) }; 720 Universe* _U{ Universe::Get(L_) };
694 bool const _from_master_state{ _U == nullptr }; 721 bool const _from_master_state{ _U == nullptr };
695 std::string_view const _name{ luaG_checkstring(L_, StackIndex{ lua_upvalueindex(1) }) }; 722 std::string_view const _name{ luaW_checkstring(L_, StackIndex{ lua_upvalueindex(1) }) };
696 LUA_ASSERT(L_, luaG_type(L_, StackIndex{ 1 }) == LuaType::TABLE); 723 LUA_ASSERT(L_, luaW_type(L_, StackIndex{ 1 }) == LuaType::TABLE);
697 724
698 STACK_GROW(L_, 4); 725 STACK_GROW(L_, 4);
699 STACK_CHECK_START_ABS(L_, 1); // L_: settings 726 STACK_CHECK_START_ABS(L_, 1); // L_: settings
@@ -703,7 +730,7 @@ LUAG_FUNC(configure)
703 730
704 if (_U == nullptr) { 731 if (_U == nullptr) {
705 // 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... 732 // 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...
706 kLaneNameRegKey.setValue(L_, [](lua_State* L_) { luaG_pushstring(L_, "main"); }); 733 kLaneNameRegKey.setValue(L_, [](lua_State* L_) { luaW_pushstring(L_, "main"); });
707 734
708 // create the universe 735 // create the universe
709 _U = Universe::Create(L_); // L_: settings universe 736 _U = Universe::Create(L_); // L_: settings universe
@@ -719,7 +746,7 @@ LUAG_FUNC(configure)
719 lua_pushnil(L_); // L_: settings M nil 746 lua_pushnil(L_); // L_: settings M nil
720 lua_setfield(L_, -2, "configure"); // L_: settings M 747 lua_setfield(L_, -2, "configure"); // L_: settings M
721 // add functions to the module's table 748 // add functions to the module's table
722 luaG_registerlibfuncs(L_, local::sLanesFunctions); 749 luaW_registerlibfuncs(L_, local::sLanesFunctions);
723 750
724 // register core.threads() only if settings say it should be available 751 // register core.threads() only if settings say it should be available
725 if (_U->tracker.isActive()) { 752 if (_U->tracker.isActive()) {
@@ -744,7 +771,7 @@ LUAG_FUNC(configure)
744 lua_pushcclosure(L_, LG_require, 1); // L_: settings M lanes.require 771 lua_pushcclosure(L_, LG_require, 1); // L_: settings M lanes.require
745 lua_setfield(L_, -2, "require"); // L_: settings M 772 lua_setfield(L_, -2, "require"); // L_: settings M
746 773
747 luaG_pushstring( 774 luaW_pushstring(
748 L_, 775 L_,
749 "%d.%d.%d", 776 "%d.%d.%d",
750 LANES_VERSION_MAJOR, 777 LANES_VERSION_MAJOR,
@@ -753,9 +780,6 @@ LUAG_FUNC(configure)
753 ); // L_: settings M VERSION 780 ); // L_: settings M VERSION
754 lua_setfield(L_, -2, "version"); // L_: settings M 781 lua_setfield(L_, -2, "version"); // L_: settings M
755 782
756 lua_pushinteger(L_, kThreadPrioMax); // L_: settings M kThreadPrioMax
757 lua_setfield(L_, -2, "max_prio"); // L_: settings M
758
759 kCancelError.pushKey(L_); // L_: settings M kCancelError 783 kCancelError.pushKey(L_); // L_: settings M kCancelError
760 lua_setfield(L_, -2, "cancel_error"); // L_: settings M 784 lua_setfield(L_, -2, "cancel_error"); // L_: settings M
761 785
@@ -779,7 +803,7 @@ LUAG_FUNC(configure)
779 // don't do this when called during the initialization of a new lane, 803 // don't do this when called during the initialization of a new lane,
780 // because we will do it after on_state_create() is called, 804 // because we will do it after on_state_create() is called,
781 // and we don't want to skip _G because of caching in case globals are created then 805 // and we don't want to skip _G because of caching in case globals are created then
782 luaG_pushglobaltable(L_); // L_: settings M _G 806 luaW_pushglobaltable(L_); // L_: settings M _G
783 tools::PopulateFuncLookupTable(L_, kIdxTop, {}); 807 tools::PopulateFuncLookupTable(L_, kIdxTop, {});
784 lua_pop(L_, 1); // L_: settings M 808 lua_pop(L_, 1); // L_: settings M
785 } 809 }
@@ -859,10 +883,10 @@ LANES_API int luaopen_lanes_core(lua_State* const L_)
859 883
860 // Prevent PUC-Lua/LuaJIT mismatch. Hopefully this works for MoonJIT too 884 // Prevent PUC-Lua/LuaJIT mismatch. Hopefully this works for MoonJIT too
861 if constexpr (LUAJIT_FLAVOR() == 0) { 885 if constexpr (LUAJIT_FLAVOR() == 0) {
862 if (luaG_getmodule(L_, LUA_JITLIBNAME) != LuaType::NIL) 886 if (luaW_getmodule(L_, LUA_JITLIBNAME) != LuaType::NIL)
863 raise_luaL_error(L_, "Lanes is built for PUC-Lua, don't run from LuaJIT"); 887 raise_luaL_error(L_, "Lanes is built for PUC-Lua, don't run from LuaJIT");
864 } else { 888 } else {
865 if (luaG_getmodule(L_, LUA_JITLIBNAME) == LuaType::NIL) 889 if (luaW_getmodule(L_, LUA_JITLIBNAME) == LuaType::NIL)
866 raise_luaL_error(L_, "Lanes is built for LuaJIT, don't run from PUC-Lua"); 890 raise_luaL_error(L_, "Lanes is built for LuaJIT, don't run from PUC-Lua");
867 } 891 }
868 lua_pop(L_, 1); // L_: 892 lua_pop(L_, 1); // L_:
diff --git a/src/lanes.lua b/src/lanes.lua
index 98f8c20..c5b3315 100644
--- a/src/lanes.lua
+++ b/src/lanes.lua
@@ -96,6 +96,7 @@ local default_params =
96 -- it looks also like LuaJIT allocator may not appreciate direct use of its allocator for other purposes than the VM operation 96 -- it looks also like LuaJIT allocator may not appreciate direct use of its allocator for other purposes than the VM operation
97 internal_allocator = isLuaJIT and "libc" or "allocator", 97 internal_allocator = isLuaJIT and "libc" or "allocator",
98 keepers_gc_threshold = -1, 98 keepers_gc_threshold = -1,
99 linda_wake_period = 'never',
99 nb_user_keepers = 0, 100 nb_user_keepers = 0,
100 on_state_create = nil, 101 on_state_create = nil,
101 shutdown_timeout = 0.25, 102 shutdown_timeout = 0.25,
@@ -141,6 +142,19 @@ local param_checkers =
141 end 142 end
142 return true 143 return true
143 end, 144 end,
145 linda_wake_period = function(val_)
146 -- linda_wake_period should be a number > 0, or the string 'never'
147 if val_ == 'never' then
148 return true
149 end
150 if type(val_) ~= "number" then
151 return nil, "not a number"
152 end
153 if val_ <= 0 then
154 return nil, "value out of range"
155 end
156 return true
157 end,
144 nb_user_keepers = function(val_) 158 nb_user_keepers = function(val_)
145 -- nb_user_keepers should be a number in [0,100] (so that nobody tries to run OOM by specifying a huge amount) 159 -- nb_user_keepers should be a number in [0,100] (so that nobody tries to run OOM by specifying a huge amount)
146 if type(val_) ~= "number" then 160 if type(val_) ~= "number" then
@@ -266,6 +280,10 @@ local opt_validators =
266 local tv = type(v_) 280 local tv = type(v_)
267 return (tv == "string") and v_ or raise_option_error("name", tv, v_) 281 return (tv == "string") and v_ or raise_option_error("name", tv, v_)
268 end, 282 end,
283 native_priority = function(v_)
284 local tv = type(v_)
285 return (tv == "number") and v_ or raise_option_error("native_priority", tv, v_)
286 end,
269 package = function(v_) 287 package = function(v_)
270 local tv = type(v_) 288 local tv = type(v_)
271 return (tv == "table") and v_ or raise_option_error("package", tv, v_) 289 return (tv == "table") and v_ or raise_option_error("package", tv, v_)
@@ -281,7 +299,7 @@ local opt_validators =
281} 299}
282 300
283-- ############################################################################################# 301-- #############################################################################################
284-- ##################################### lanes.gen() ########################################### 302-- ################################### lanes.gen/coro() ########################################
285-- ############################################################################################# 303-- #############################################################################################
286 304
287local process_gen_opt = function(...) 305local process_gen_opt = function(...)
@@ -353,9 +371,16 @@ local process_gen_opt = function(...)
353 opt[k] = validator(v) 371 opt[k] = validator(v)
354 end 372 end
355 end 373 end
374
375 -- special case: can't have priority and native_priority at the same time
376 if opt.priority and opt.native_priority then
377 error "priority and native_priority cannot be specified together"
378 end
356 return func, libs, opt 379 return func, libs, opt
357end -- process_gen_opt 380end -- process_gen_opt
358 381
382-- #################################################################################################
383
359-- lane_h[1..n]: lane results, same as via 'lane_h:join()' 384-- lane_h[1..n]: lane results, same as via 'lane_h:join()'
360-- lane_h[0]: can be read to make sure a thread has finished (gives the number of available results) 385-- lane_h[0]: can be read to make sure a thread has finished (gives the number of available results)
361-- lane_h[negative]: error message, without propagating the error 386-- lane_h[negative]: error message, without propagating the error
@@ -394,25 +419,28 @@ end -- process_gen_opt
394-- Calling with a function argument ('lane_func') ends the string/table 419-- Calling with a function argument ('lane_func') ends the string/table
395-- modifiers, and prepares a lane generator. 420-- modifiers, and prepares a lane generator.
396 421
397-- receives a sequence of strings and tables, plus a function 422local make_generator = function(is_coro_, ...)
398local gen = function(...)
399 local func, libs, opt = process_gen_opt(...) 423 local func, libs, opt = process_gen_opt(...)
400 local core_lane_new = assert(core.lane_new) 424 local core_lane_new = assert(core.lane_new)
401 local priority, globals, package, required, gc_cb, name, error_trace_level = opt.priority, opt.globals, opt.package or package, opt.required, opt.gc_cb, opt.name, error_trace_levels[opt.error_trace_level] 425 local prio_is_native = opt.native_priority and true or false
426 local priority, globals, package, required, gc_cb, name, error_trace_level = opt.priority or opt.native_priority, opt.globals, opt.package or package, opt.required, opt.gc_cb, opt.name, error_trace_levels[opt.error_trace_level]
402 return function(...) 427 return function(...)
403 -- must pass functions args last else they will be truncated to the first one 428 -- must pass functions args last else they will be truncated to the first one
404 return core_lane_new(func, libs, priority, globals, package, required, gc_cb, name, error_trace_level, false, ...) 429 return core_lane_new(func, libs, prio_is_native, priority, globals, package, required, gc_cb, name, error_trace_level, is_coro_, ...)
405 end 430 end
431end -- make_generator
432
433-- #################################################################################################
434
435-- receives a sequence of strings and tables, plus a function
436local gen = function(...)
437 return make_generator(false, ...)
406end -- gen() 438end -- gen()
407 439
440-- #################################################################################################
441
408local coro = function(...) 442local coro = function(...)
409 local func, libs, opt = process_gen_opt(...) 443 return make_generator(true, ...)
410 local core_lane_new = assert(core.lane_new)
411 local priority, globals, package, required, gc_cb, name, error_trace_level = opt.priority, opt.globals, opt.package or package, opt.required, opt.gc_cb, opt.name, error_trace_levels[opt.error_trace_level]
412 return function(...)
413 -- must pass functions args last else they will be truncated to the first one
414 return core_lane_new(func, libs, priority, globals, package, required, gc_cb, name, error_trace_level, true, ...)
415 end
416end -- coro() 444end -- coro()
417 445
418-- ################################################################################################# 446-- #################################################################################################
@@ -603,7 +631,6 @@ local configure_timers = function()
603 return next_wakeup -- may be 'nil' 631 return next_wakeup -- may be 'nil'
604 end -- check_timers() 632 end -- check_timers()
605 633
606 local timer_gateway_batched = timerLinda.batched
607 set_finalizer(function(err, stk) 634 set_finalizer(function(err, stk)
608 if err and type(err) ~= "userdata" then 635 if err and type(err) ~= "userdata" then
609 error("LanesTimer error: "..tostring(err)) 636 error("LanesTimer error: "..tostring(err))
@@ -628,7 +655,7 @@ local configure_timers = function()
628 655
629 if _timerKey == TGW_KEY then 656 if _timerKey == TGW_KEY then
630 assert(getmetatable(_what) == "Linda") -- '_what' should be a linda on which the client sets a timer 657 assert(getmetatable(_what) == "Linda") -- '_what' should be a linda on which the client sets a timer
631 local _, key, wakeup_at, period = timerLinda:receive(0, timer_gateway_batched, TGW_KEY, 3) 658 local _, key, wakeup_at, period = timerLinda:receive_batched(0, TGW_KEY, 3)
632 assert(key) 659 assert(key)
633 set_timer(_what, key, wakeup_at, period and period > 0 and period or nil) 660 set_timer(_what, key, wakeup_at, period and period > 0 and period or nil)
634 elseif _timerKey == TGW_QUERY then 661 elseif _timerKey == TGW_QUERY then
@@ -643,7 +670,8 @@ local configure_timers = function()
643 end 670 end
644 end 671 end
645 end -- timer_body() 672 end -- timer_body()
646 timer_lane = gen("lanes_core,table", { name = "LanesTimer", package = {}, priority = core.max_prio }, timer_body)() 673 local min_prio, max_prio = core.thread_priority_range()
674 timer_lane = gen("lanes_core,table", { name = "LanesTimer", package = {}, priority = max_prio }, timer_body)()
647 end -- first_time 675 end -- first_time
648 676
649 ----- 677 -----
@@ -758,7 +786,7 @@ local genlock = function(linda_, key_, N)
758 -- 'nil' timeout allows 'key_' to be numeric 786 -- 'nil' timeout allows 'key_' to be numeric
759 return linda_:send(timeout, key_, trues(M_)) -- suspends until been able to push them 787 return linda_:send(timeout, key_, trues(M_)) -- suspends until been able to push them
760 else 788 else
761 local _k, _v = linda_:receive(nil, linda_.batched, key_, -M_) 789 local _k, _v = linda_:receive_batched(nil, key_, -M_)
762 -- propagate cancel_error if we got it, else return true or false 790 -- propagate cancel_error if we got it, else return true or false
763 return (_v == cancel_error and _v) or (_k and true or false) 791 return (_v == cancel_error and _v) or (_k and true or false)
764 end 792 end
@@ -863,6 +891,7 @@ local configure = function(settings_)
863 lanes.set_thread_affinity = core.set_thread_affinity 891 lanes.set_thread_affinity = core.set_thread_affinity
864 lanes.set_thread_priority = core.set_thread_priority 892 lanes.set_thread_priority = core.set_thread_priority
865 lanes.sleep = core.sleep 893 lanes.sleep = core.sleep
894 lanes.thread_priority_range = core.thread_priority_range
866 lanes.threads = core.threads or function() error "lane tracking is not available" end -- core.threads isn't registered if settings.track_lanes is false 895 lanes.threads = core.threads or function() error "lane tracking is not available" end -- core.threads isn't registered if settings.track_lanes is false
867 896
868 lanes.gen = gen 897 lanes.gen = gen
diff --git a/src/lanesconf.h b/src/lanesconf.h
index 0afd493..07f1d52 100644
--- a/src/lanesconf.h
+++ b/src/lanesconf.h
@@ -42,12 +42,12 @@
42#endif // __cplusplus 42#endif // __cplusplus
43#endif // (defined PLATFORM_WIN32) || (defined PLATFORM_POCKETPC) 43#endif // (defined PLATFORM_WIN32) || (defined PLATFORM_POCKETPC)
44 44
45// kind of MSVC-specific 45// LANES_DEBUG has to be provided externally (makefile, vcproj, whatever)
46#ifdef _DEBUG 46#ifdef LANES_DEBUG
47#define HAVE_LUA_ASSERT() 1 47#define HAVE_LUA_ASSERT() 1
48#else // NDEBUG 48#else // LANES_DEBUG
49#define HAVE_LUA_ASSERT() 0 49#define HAVE_LUA_ASSERT() 0
50#endif // NDEBUG 50#endif // LANES_DEBUG
51 51
52#define USE_DEBUG_SPEW() 0 52#define USE_DEBUG_SPEW() 0
53#define HAVE_DECODA_SUPPORT() 0 53#define HAVE_DECODA_SUPPORT() 0
diff --git a/src/linda.cpp b/src/linda.cpp
index a094a8f..1f4b19d 100644
--- a/src/linda.cpp
+++ b/src/linda.cpp
@@ -43,12 +43,11 @@ namespace {
43 // ############################################################################################# 43 // #############################################################################################
44 // ############################################################################################# 44 // #############################################################################################
45 45
46
47 static void CheckKeyTypes(lua_State* const L_, StackIndex const start_, StackIndex const end_) 46 static void CheckKeyTypes(lua_State* const L_, StackIndex const start_, StackIndex const end_)
48 { 47 {
49 STACK_CHECK_START_REL(L_, 0); 48 STACK_CHECK_START_REL(L_, 0);
50 for (StackIndex const _i : std::ranges::iota_view{ start_, StackIndex{ end_ + 1 } }) { 49 for (StackIndex const _i : std::ranges::iota_view{ start_, StackIndex{ end_ + 1 } }) {
51 LuaType const _t{ luaG_type(L_, _i) }; 50 LuaType const _t{ luaW_type(L_, _i) };
52 switch (_t) { 51 switch (_t) {
53 case LuaType::BOOLEAN: 52 case LuaType::BOOLEAN:
54 case LuaType::NUMBER: 53 case LuaType::NUMBER:
@@ -63,7 +62,7 @@ namespace {
63 62
64 case LuaType::LIGHTUSERDATA: 63 case LuaType::LIGHTUSERDATA:
65 { 64 {
66 static constexpr std::array<std::reference_wrapper<UniqueKey const>, 3> kKeysToCheck{ kLindaBatched, kCancelError, kNilSentinel }; 65 static constexpr std::array<std::reference_wrapper<UniqueKey const>, 2> kKeysToCheck{ kCancelError, kNilSentinel };
67 for (UniqueKey const& _key : kKeysToCheck) { 66 for (UniqueKey const& _key : kKeysToCheck) {
68 if (_key.equals(L_, _i)) { 67 if (_key.equals(L_, _i)) {
69 raise_luaL_error(L_, "argument #%d: can't use %s as a slot", _i, _key.debugName.data()); 68 raise_luaL_error(L_, "argument #%d: can't use %s as a slot", _i, _key.debugName.data());
@@ -110,13 +109,13 @@ namespace {
110 { 109 {
111 Linda* const _linda{ ToLinda<OPT>(L_, idx_) }; 110 Linda* const _linda{ ToLinda<OPT>(L_, idx_) };
112 if (_linda != nullptr) { 111 if (_linda != nullptr) {
113 luaG_pushstring(L_, "Linda: "); 112 luaW_pushstring(L_, "Linda: ");
114 std::string_view const _lindaName{ _linda->getName() }; 113 std::string_view const _lindaName{ _linda->getName() };
115 if (!_lindaName.empty()) { 114 if (!_lindaName.empty()) {
116 luaG_pushstring(L_, _lindaName); 115 luaW_pushstring(L_, _lindaName);
117 } else { 116 } else {
118 // obfuscate the pointer so that we can't read the value with our eyes out of a script 117 // obfuscate the pointer so that we can't read the value with our eyes out of a script
119 luaG_pushstring(L_, "%p", _linda->obfuscated()); 118 luaW_pushstring(L_, "%p", _linda->obfuscated());
120 } 119 }
121 lua_concat(L_, 2); 120 lua_concat(L_, 2);
122 return 1; 121 return 1;
@@ -125,6 +124,183 @@ namespace {
125 } 124 }
126 125
127 // ############################################################################################# 126 // #############################################################################################
127
128 // a helper to process the timeout argument of linda:send() and linda:receive()
129 [[nodiscard]]
130 static auto ProcessTimeoutArg(lua_State* const L_)
131 {
132 StackIndex _key_i{ 2 }; // index of first slot, if timeout not there
133
134 std::chrono::time_point<std::chrono::steady_clock> _until{ std::chrono::time_point<std::chrono::steady_clock>::max() };
135 if (luaW_type(L_, StackIndex{ 2 }) == LuaType::NUMBER) { // we don't want to use lua_isnumber() because of autocoercion
136 lua_Duration const _duration{ lua_tonumber(L_, 2) };
137 if (_duration.count() >= 0.0) {
138 _until = std::chrono::steady_clock::now() + std::chrono::duration_cast<std::chrono::steady_clock::duration>(_duration);
139 } else {
140 raise_luaL_argerror(L_, StackIndex{ 2 }, "duration cannot be < 0");
141 }
142 ++_key_i;
143 } else if (lua_isnil(L_, 2)) { // alternate explicit "infinite timeout" by passing nil before the slot
144 ++_key_i;
145 }
146 return std::make_pair(_key_i, _until);
147 }
148
149 // #############################################################################################
150 static bool WaitInternal([[maybe_unused]] lua_State* const L_, Lane* const lane_, Linda* const linda_, Keeper* const keeper_, std::condition_variable& waitingOn_, std::chrono::time_point<std::chrono::steady_clock> until_)
151 {
152 Lane::Status _prev_status{ Lane::Error }; // prevent 'might be used uninitialized' warnings
153 if (lane_ != nullptr) {
154 // change status of lane to "waiting"
155 _prev_status = lane_->status.load(std::memory_order_acquire); // Running, most likely
156 LUA_ASSERT(L_, _prev_status == Lane::Running); // but check, just in case
157 LUA_ASSERT(L_, lane_->waiting_on == nullptr);
158 lane_->waiting_on = &waitingOn_;
159 lane_->status.store(Lane::Waiting, std::memory_order_release);
160 }
161
162 // wait until the final target date by small increments, interrupting regularly so that we can check for cancel requests,
163 // in case some timing issue caused a cancel request to be issued, and the condvar signalled, before we actually wait for it
164 auto const [_forceTryAgain, _until_check_cancel] = std::invoke([until_, wakePeriod = linda_->getWakePeriod()] {
165 auto _until_check_cancel{ std::chrono::time_point<std::chrono::steady_clock>::max() };
166 if (wakePeriod.count() > 0.0f) {
167 _until_check_cancel = std::chrono::steady_clock::now() + std::chrono::duration_cast<std::chrono::steady_clock::duration>(wakePeriod);
168 }
169 bool const _forceTryAgain{ _until_check_cancel < until_ };
170 return std::make_tuple(_forceTryAgain, _forceTryAgain ? _until_check_cancel : until_);
171 });
172
173 // operation can't complete: wake when it is signalled to be possible, or when timeout is reached
174 std::unique_lock<std::mutex> _guard{ keeper_->mutex, std::adopt_lock };
175 std::cv_status const _status{ waitingOn_.wait_until(_guard, _until_check_cancel) };
176 _guard.release(); // we don't want to unlock the mutex on exit!
177 bool const _try_again{ _forceTryAgain || (_status == std::cv_status::no_timeout) }; // detect spurious wakeups
178 if (lane_ != nullptr) {
179 lane_->waiting_on = nullptr;
180 lane_->status.store(_prev_status, std::memory_order_release);
181 }
182 return _try_again;
183 }
184
185 // #############################################################################################
186
187 // the implementation for linda:receive() and linda:receive_batched()
188 static int ReceiveInternal(lua_State* const L_, bool const batched_)
189 {
190 Linda* const _linda{ ToLinda<false>(L_, StackIndex{ 1 }) };
191
192 auto const [_key_i, _until] = ProcessTimeoutArg(L_);
193
194 keeper_api_t _selected_keeper_receive{ nullptr };
195 int _expected_pushed_min{ 0 }, _expected_pushed_max{ 0 };
196 // are we in batched mode?
197 if (batched_) {
198 // make sure the keys are of a valid type
199 CheckKeyTypes(L_, _key_i, _key_i);
200 // receive multiple values from a single slot
201 _selected_keeper_receive = KEEPER_API(receive_batched);
202 // we expect a user-defined amount of return value
203 _expected_pushed_min = (int) luaL_checkinteger(L_, _key_i + 1);
204 if (_expected_pushed_min < 1) {
205 raise_luaL_argerror(L_, StackIndex{ _key_i + 1 }, "bad min count");
206 }
207 _expected_pushed_max = (int) luaL_optinteger(L_, _key_i + 2, _expected_pushed_min);
208 // don't forget to count the slot in addition to the values
209 ++_expected_pushed_min;
210 ++_expected_pushed_max;
211 if (_expected_pushed_min > _expected_pushed_max) {
212 raise_luaL_argerror(L_, StackIndex{ _key_i + 2 }, "batched min/max error");
213 }
214 } else {
215 // make sure the keys are of a valid type
216 CheckKeyTypes(L_, _key_i, StackIndex{ lua_gettop(L_) });
217 // receive a single value, checking multiple slots
218 _selected_keeper_receive = KEEPER_API(receive);
219 // we expect a single (value, slot) pair of returned values
220 _expected_pushed_min = _expected_pushed_max = 2;
221 }
222
223 Lane* const _lane{ kLanePointerRegKey.readLightUserDataValue<Lane>(L_) };
224 Keeper* const _keeper{ _linda->whichKeeper() };
225 KeeperState const _K{ _keeper ? _keeper->K : KeeperState{ static_cast<lua_State*>(nullptr) } };
226 if (_K == nullptr)
227 return 0;
228
229 CancelRequest _cancel{ CancelRequest::None };
230 KeeperCallResult _pushed{};
231
232 STACK_CHECK_START_REL(_K, 0);
233 for (bool _try_again{ true };;) {
234 if (_lane != nullptr) {
235 _cancel = _lane->cancelRequest.load(std::memory_order_relaxed);
236 }
237 _cancel = (_cancel != CancelRequest::None)
238 ? _cancel
239 : ((_linda->cancelStatus == Linda::Cancelled) ? CancelRequest::Soft : CancelRequest::None);
240
241 // if user wants to cancel, or looped because of a timeout, the call returns without sending anything
242 if (!_try_again || _cancel != CancelRequest::None) {
243 _pushed.emplace(0);
244 break;
245 }
246
247 // all arguments of receive() but the first are passed to the keeper's receive function
248 STACK_CHECK(_K, 0);
249 _pushed = keeper_call(_K, _selected_keeper_receive, L_, _linda, _key_i);
250 if (!_pushed.has_value()) {
251 break;
252 }
253 if (_pushed.value() > 0) {
254 LUA_ASSERT(L_, _pushed.value() >= _expected_pushed_min && _pushed.value() <= _expected_pushed_max);
255 if (kRestrictedChannel.equals(L_, StackIndex{ kIdxTop })) {
256 raise_luaL_error(L_, "Key is restricted");
257 }
258 _linda->readHappened.notify_all();
259 break;
260 }
261
262 if (std::chrono::steady_clock::now() >= _until) {
263 break; /* instant timeout */
264 }
265
266 // nothing received, wait until timeout or signalled that we should try again
267 _try_again = WaitInternal(L_, _lane, _linda, _keeper, _linda->writeHappened, _until);
268 }
269 STACK_CHECK(_K, 0);
270
271 if (!_pushed.has_value()) {
272 raise_luaL_error(L_, "tried to copy unsupported types");
273 }
274
275 switch (_cancel) {
276 case CancelRequest::None:
277 {
278 int const _nbPushed{ _pushed.value() };
279 if (_nbPushed == 0) {
280 // not enough data in the linda slot to fulfill the request, return nil, "timeout"
281 lua_pushnil(L_);
282 luaW_pushstring(L_, "timeout");
283 return 2;
284 }
285 return _nbPushed;
286 }
287
288 case CancelRequest::Soft:
289 // if user wants to soft-cancel, the call returns nil, kCancelError
290 lua_pushnil(L_);
291 kCancelError.pushKey(L_);
292 return 2;
293
294 case CancelRequest::Hard:
295 // raise an error interrupting execution only in case of hard cancel
296 raise_cancel_error(L_); // raises an error and doesn't return
297
298 default:
299 raise_luaL_error(L_, "internal error: unknown cancel request");
300 }
301 }
302
303 // #############################################################################################
128 // ############################################################################################# 304 // #############################################################################################
129} // namespace 305} // namespace
130// ################################################################################################# 306// #################################################################################################
@@ -138,9 +314,10 @@ LUAG_FUNC(linda);
138// ################################################################################################# 314// #################################################################################################
139// ################################################################################################# 315// #################################################################################################
140 316
141Linda::Linda(Universe* const U_, LindaGroup const group_, std::string_view const& name_) 317Linda::Linda(Universe* const U_, std::string_view const& name_, lua_Duration const wake_period_, LindaGroup const group_)
142: DeepPrelude{ LindaFactory::Instance } 318: DeepPrelude{ LindaFactory::Instance }
143, U{ U_ } 319, U{ U_ }
320, wakePeriod{ wake_period_ }
144, keeperIndex{ group_ % U_->keepers.getNbKeepers() } 321, keeperIndex{ group_ % U_->keepers.getNbKeepers() }
145{ 322{
146 setName(name_); 323 setName(name_);
@@ -161,6 +338,7 @@ Keeper* Linda::acquireKeeper() const
161 Keeper* const _keeper{ whichKeeper() }; 338 Keeper* const _keeper{ whichKeeper() };
162 if (_keeper) { 339 if (_keeper) {
163 _keeper->mutex.lock(); 340 _keeper->mutex.lock();
341 keeperOperationCount.fetch_add(1, std::memory_order_seq_cst);
164 } 342 }
165 return _keeper; 343 return _keeper;
166} 344}
@@ -172,13 +350,17 @@ Linda* Linda::CreateTimerLinda(lua_State* const L_)
172 STACK_CHECK_START_REL(L_, 0); // L_: 350 STACK_CHECK_START_REL(L_, 0); // L_:
173 // Initialize 'timerLinda'; a common Linda object shared by all states 351 // Initialize 'timerLinda'; a common Linda object shared by all states
174 lua_pushcfunction(L_, LG_linda); // L_: lanes.linda 352 lua_pushcfunction(L_, LG_linda); // L_: lanes.linda
175 luaG_pushstring(L_, "lanes-timer"); // L_: lanes.linda "lanes-timer" 353 lua_createtable(L_, 0, 3); // L_: lanes.linda {}
176 lua_pushinteger(L_, 0); // L_: lanes.linda "lanes-timer" 0 354 luaW_pushstring(L_, "lanes-timer"); // L_: lanes.linda {} "lanes-timer"
177 lua_call(L_, 2, 1); // L_: linda 355 luaW_setfield(L_, StackIndex{ -2 }, std::string_view{ "name" }); // L_: lanes.linda { .name="lanes-timer" }
356 lua_pushinteger(L_, 0); // L_: lanes.linda { .name="lanes-timer" } 0
357 luaW_setfield(L_, StackIndex{ -2 }, std::string_view{ "group" }); // L_: lanes.linda { .name="lanes-timer" .group = 0 }
358 // note that wake_period is not set (will default to the value in the universe)
359 lua_call(L_, 1, 1); // L_: linda
178 STACK_CHECK(L_, 1); 360 STACK_CHECK(L_, 1);
179 361
180 // Proxy userdata contents is only a 'DeepPrelude*' pointer 362 // Proxy userdata contents is only a 'DeepPrelude*' pointer
181 auto const _timerLinda{ *luaG_tofulluserdata<Linda*>(L_, kIdxTop) }; 363 auto const _timerLinda{ *luaW_tofulluserdata<Linda*>(L_, kIdxTop) };
182 // increment refcount so that this linda remains alive as long as the universe exists. 364 // increment refcount so that this linda remains alive as long as the universe exists.
183 _timerLinda->refcount.fetch_add(1, std::memory_order_relaxed); 365 _timerLinda->refcount.fetch_add(1, std::memory_order_relaxed);
184 lua_pop(L_, 1); // L_: 366 lua_pop(L_, 1); // L_:
@@ -241,7 +423,6 @@ int Linda::ProtectedCall(lua_State* const L_, lua_CFunction const f_)
241 // doing LindaFactory::deleteDeepObjectInternal -> keeper_call(clear) 423 // doing LindaFactory::deleteDeepObjectInternal -> keeper_call(clear)
242 lua_gc(L_, LUA_GCSTOP, 0); 424 lua_gc(L_, LUA_GCSTOP, 0);
243 425
244 LUA_ASSERT_CODE(auto const _koip{ _linda->startKeeperOperation(L_) });
245 // if we didn't do anything wrong, the keeper stack should be clean 426 // if we didn't do anything wrong, the keeper stack should be clean
246 LUA_ASSERT(L_, lua_gettop(_K) == 0); 427 LUA_ASSERT(L_, lua_gettop(_K) == 0);
247 428
@@ -249,7 +430,7 @@ int Linda::ProtectedCall(lua_State* const L_, lua_CFunction const f_)
249 lua_pushcfunction(L_, f_); 430 lua_pushcfunction(L_, f_);
250 lua_insert(L_, 1); 431 lua_insert(L_, 1);
251 // do a protected call 432 // do a protected call
252 LuaError const _rc{ lua_pcall(L_, lua_gettop(L_) - 1, LUA_MULTRET, 0) }; 433 LuaError const _rc{ ToLuaError(lua_pcall(L_, lua_gettop(L_) - 1, LUA_MULTRET, 0)) };
253 // whatever happens, the keeper state stack must be empty when we are done 434 // whatever happens, the keeper state stack must be empty when we are done
254 lua_settop(_K, 0); 435 lua_settop(_K, 0);
255 436
@@ -271,7 +452,7 @@ int Linda::ProtectedCall(lua_State* const L_, lua_CFunction const f_)
271 452
272void Linda::pushCancelString(lua_State* L_) const 453void Linda::pushCancelString(lua_State* L_) const
273{ 454{
274 luaG_pushstring(L_, cancelStatus == Status::Cancelled ? "cancelled" : "active"); 455 luaW_pushstring(L_, cancelStatus == Status::Cancelled ? "cancelled" : "active");
275} 456}
276 457
277// ################################################################################################# 458// #################################################################################################
@@ -280,6 +461,7 @@ void Linda::releaseKeeper(Keeper* const keeper_) const
280{ 461{
281 if (keeper_) { // can be nullptr if we tried to acquire during shutdown 462 if (keeper_) { // can be nullptr if we tried to acquire during shutdown
282 assert(keeper_ == whichKeeper()); 463 assert(keeper_ == whichKeeper());
464 keeperOperationCount.fetch_sub(1, std::memory_order_seq_cst);
283 keeper_->mutex.unlock(); 465 keeper_->mutex.unlock();
284 } 466 }
285} 467}
@@ -323,7 +505,7 @@ void Linda::setName(std::string_view const& name_)
323LUAG_FUNC(linda_cancel) 505LUAG_FUNC(linda_cancel)
324{ 506{
325 Linda* const _linda{ ToLinda<false>(L_, StackIndex{ 1 }) }; 507 Linda* const _linda{ ToLinda<false>(L_, StackIndex{ 1 }) };
326 std::string_view const _who{ luaG_optstring(L_, StackIndex{ 2 }, "both") }; 508 std::string_view const _who{ luaW_optstring(L_, StackIndex{ 2 }, "both") };
327 // make sure we got 2 arguments: the linda and the cancellation mode 509 // make sure we got 2 arguments: the linda and the cancellation mode
328 luaL_argcheck(L_, lua_gettop(L_) <= 2, 2, "wrong number of arguments"); 510 luaL_argcheck(L_, lua_gettop(L_) <= 2, 2, "wrong number of arguments");
329 511
@@ -411,13 +593,13 @@ static int linda_index_string(lua_State* L_)
411 Linda* const _linda{ ToLinda<false>(L_, kIdxSelf) }; 593 Linda* const _linda{ ToLinda<false>(L_, kIdxSelf) };
412 LUA_ASSERT(L_, lua_gettop(L_) == 2); // L_: linda "key" 594 LUA_ASSERT(L_, lua_gettop(L_) == 2); // L_: linda "key"
413 595
414 std::string_view const _keystr{ luaG_tostring(L_, kIdxKey) }; 596 std::string_view const _keystr{ luaW_tostring(L_, kIdxKey) };
415 lua_settop(L_, 2); // keep only our original arguments on the stack 597 lua_settop(L_, 2); // keep only our original arguments on the stack
416 598
417 // look in metatable first 599 // look in metatable first
418 lua_getmetatable(L_, kIdxSelf); // L_: linda "key" mt 600 lua_getmetatable(L_, kIdxSelf); // L_: linda "key" mt
419 lua_replace(L_, -3); // L_: mt "key" 601 lua_replace(L_, -3); // L_: mt "key"
420 if (luaG_rawget(L_, StackIndex{ -2 }) != LuaType::NIL) { // found something? // L_: mt value 602 if (luaW_rawget(L_, StackIndex{ -2 }) != LuaType::NIL) { // found something? // L_: mt value
421 return 1; // done 603 return 1; // done
422 } 604 }
423 605
@@ -437,12 +619,12 @@ static LUAG_FUNC(linda_index)
437 static constexpr StackIndex kIdxKey{ 2 }; 619 static constexpr StackIndex kIdxKey{ 2 };
438 LUA_ASSERT(L_, lua_gettop(L_) == 2); 620 LUA_ASSERT(L_, lua_gettop(L_) == 2);
439 621
440 switch (luaG_type(L_, kIdxKey)) { 622 switch (luaW_type(L_, kIdxKey)) {
441 case LuaType::STRING: 623 case LuaType::STRING:
442 return linda_index_string(L_); // stack modification is undefined, returned value is at the top 624 return linda_index_string(L_); // stack modification is undefined, returned value is at the top
443 625
444 default: // unknown key 626 default: // unknown key
445 raise_luaL_error(L_, "Unsupported linda indexing key type %s", luaG_typename(L_, kIdxKey).data()); 627 raise_luaL_error(L_, "Unsupported linda indexing key type %s", luaW_typename(L_, kIdxKey).data());
446 } 628 }
447} 629}
448 630
@@ -585,7 +767,7 @@ LUAG_FUNC(linda_limit)
585 int const _nargs{ lua_gettop(L_) }; 767 int const _nargs{ lua_gettop(L_) };
586 luaL_argcheck(L_, _nargs == 2 || _nargs == 3, 2, "wrong number of arguments"); 768 luaL_argcheck(L_, _nargs == 2 || _nargs == 3, 2, "wrong number of arguments");
587 // make sure we got a numeric limit, or "unlimited", (or nothing) 769 // make sure we got a numeric limit, or "unlimited", (or nothing)
588 bool const _unlimited{ luaG_tostring(L_, StackIndex{ 3 }) == "unlimited" }; 770 bool const _unlimited{ luaW_tostring(L_, StackIndex{ 3 }) == "unlimited" };
589 LindaLimit const _val{ _unlimited ? std::numeric_limits<LindaLimit::type>::max() : static_cast<LindaLimit::type>(luaL_optinteger(L_, 3, 0)) }; 771 LindaLimit const _val{ _unlimited ? std::numeric_limits<LindaLimit::type>::max() : static_cast<LindaLimit::type>(luaL_optinteger(L_, 3, 0)) };
590 if (_val < 0) { 772 if (_val < 0) {
591 raise_luaL_argerror(L_, StackIndex{ 3 }, "limit must be >= 0"); 773 raise_luaL_argerror(L_, StackIndex{ 3 }, "limit must be >= 0");
@@ -596,23 +778,23 @@ LUAG_FUNC(linda_limit)
596 KeeperCallResult _pushed; 778 KeeperCallResult _pushed;
597 if (_linda->cancelStatus == Linda::Active) { 779 if (_linda->cancelStatus == Linda::Active) {
598 if (_unlimited) { 780 if (_unlimited) {
599 LUA_ASSERT(L_, lua_gettop(L_) == 3 && luaG_tostring(L_, StackIndex{ 3 }) == "unlimited"); 781 LUA_ASSERT(L_, lua_gettop(L_) == 3 && luaW_tostring(L_, StackIndex{ 3 }) == "unlimited");
600 // inside the Keeper, unlimited is signified with a -1 limit (can't use nil because of nil kNilSentinel conversions!) 782 // inside the Keeper, unlimited is signified with a -1 limit (can't use nil because of nil kNilSentinel conversions!)
601 lua_pop(L_, 1); // L_: linda slot 783 lua_pop(L_, 1); // L_: linda slot
602 lua_pushinteger(L_, -1); // L_: linda slot nil 784 lua_pushinteger(L_, -1); // L_: linda slot nil
603 } 785 }
604 Keeper* const _keeper{ _linda->whichKeeper() }; 786 Keeper* const _keeper{ _linda->whichKeeper() };
605 _pushed = keeper_call(_keeper->K, KEEPER_API(limit), L_, _linda, StackIndex{ 2 }); 787 _pushed = keeper_call(_keeper->K, KEEPER_API(limit), L_, _linda, StackIndex{ 2 });
606 LUA_ASSERT(L_, _pushed.has_value() && (_pushed.value() == 2) && luaG_type(L_, kIdxTop) == LuaType::STRING); 788 LUA_ASSERT(L_, _pushed.has_value() && (_pushed.value() == 2) && luaW_type(L_, kIdxTop) == LuaType::STRING);
607 if (_nargs == 3) { // 3 args: setting the limit 789 if (_nargs == 3) { // 3 args: setting the limit
608 // changing the limit: no error, boolean value saying if we should wake blocked writer threads 790 // changing the limit: no error, boolean value saying if we should wake blocked writer threads
609 LUA_ASSERT(L_, luaG_type(L_, StackIndex{ -2 }) == LuaType::BOOLEAN); // L_: bool string 791 LUA_ASSERT(L_, luaW_type(L_, StackIndex{ -2 }) == LuaType::BOOLEAN); // L_: bool string
610 if (lua_toboolean(L_, -2)) { 792 if (lua_toboolean(L_, -2)) {
611 _linda->readHappened.notify_all(); // To be done from within the 'K' locking area 793 _linda->readHappened.notify_all(); // To be done from within the 'K' locking area
612 } 794 }
613 } else { // 2 args: reading the limit 795 } else { // 2 args: reading the limit
614 // reading the limit: a number >=0 or "unlimited" 796 // reading the limit: a number >=0 or "unlimited"
615 LUA_ASSERT(L_, luaG_type(L_, StackIndex{ -2 }) == LuaType::NUMBER || luaG_tostring(L_, StackIndex{ -2 }) == "unlimited"); 797 LUA_ASSERT(L_, luaW_type(L_, StackIndex{ -2 }) == LuaType::NUMBER || luaW_tostring(L_, StackIndex{ -2 }) == "unlimited");
616 } 798 }
617 } else { // linda is cancelled 799 } else { // linda is cancelled
618 // do nothing and return nil,lanes.cancel_error 800 // do nothing and return nil,lanes.cancel_error
@@ -630,163 +812,25 @@ LUAG_FUNC(linda_limit)
630// ################################################################################################# 812// #################################################################################################
631 813
632/* 814/*
633 * 2 modes of operation 815 * [val, slot] = linda:receive([timeout_secs_num=nil], key_num|str|bool|lightuserdata [, ...] )
634 * [val, slot]= linda:receive([timeout_secs_num=nil], key_num|str|bool|lightuserdata [, ...] )
635 * Consumes a single value from the Linda, in any slot. 816 * Consumes a single value from the Linda, in any slot.
636 * Returns: received value (which is consumed from the slot), and the slot which had it 817 * Returns: received value (which is consumed from the slot), and the slot which had it
637
638 * [val1, ... valCOUNT]= linda_receive( linda_ud, [timeout_secs_num=-1], linda.batched, key_num|str|bool|lightuserdata, min_COUNT[, max_COUNT])
639 * Consumes between min_COUNT and max_COUNT values from the linda, from a single slot.
640 * returns the actual consumed values, or nil if there weren't enough values to consume
641 */ 818 */
642LUAG_FUNC(linda_receive) 819LUAG_FUNC(linda_receive)
643{ 820{
644 static constexpr lua_CFunction _receive{ 821 return Linda::ProtectedCall(L_, [](lua_State* const L_) { return ReceiveInternal(L_, false); });
645 +[](lua_State* const L_) { 822}
646 Linda* const _linda{ ToLinda<false>(L_, StackIndex{ 1 }) };
647 StackIndex _key_i{ 2 }; // index of first slot, if timeout not there
648
649 std::chrono::time_point<std::chrono::steady_clock> _until{ std::chrono::time_point<std::chrono::steady_clock>::max() };
650 if (luaG_type(L_, StackIndex{ 2 }) == LuaType::NUMBER) { // we don't want to use lua_isnumber() because of autocoercion
651 lua_Duration const _duration{ lua_tonumber(L_, 2) };
652 if (_duration.count() >= 0.0) {
653 _until = std::chrono::steady_clock::now() + std::chrono::duration_cast<std::chrono::steady_clock::duration>(_duration);
654 } else {
655 raise_luaL_argerror(L_, StackIndex{ 2 }, "duration cannot be < 0");
656 }
657 ++_key_i;
658 } else if (lua_isnil(L_, 2)) { // alternate explicit "infinite timeout" by passing nil before the slot
659 ++_key_i;
660 }
661
662 keeper_api_t _selected_keeper_receive{ nullptr };
663 int _expected_pushed_min{ 0 }, _expected_pushed_max{ 0 };
664 // are we in batched mode?
665 if (kLindaBatched.equals(L_, _key_i)) {
666 // no need to pass linda.batched in the keeper state
667 ++_key_i;
668 // make sure the keys are of a valid type
669 CheckKeyTypes(L_, _key_i, _key_i);
670 // receive multiple values from a single slot
671 _selected_keeper_receive = KEEPER_API(receive_batched);
672 // we expect a user-defined amount of return value
673 _expected_pushed_min = (int) luaL_checkinteger(L_, _key_i + 1);
674 if (_expected_pushed_min < 1) {
675 raise_luaL_argerror(L_, StackIndex{ _key_i + 1 }, "bad min count");
676 }
677 _expected_pushed_max = (int) luaL_optinteger(L_, _key_i + 2, _expected_pushed_min);
678 // don't forget to count the slot in addition to the values
679 ++_expected_pushed_min;
680 ++_expected_pushed_max;
681 if (_expected_pushed_min > _expected_pushed_max) {
682 raise_luaL_argerror(L_, StackIndex{ _key_i + 2 }, "batched min/max error");
683 }
684 } else {
685 // make sure the keys are of a valid type
686 CheckKeyTypes(L_, _key_i, StackIndex{ lua_gettop(L_) });
687 // receive a single value, checking multiple slots
688 _selected_keeper_receive = KEEPER_API(receive);
689 // we expect a single (value, slot) pair of returned values
690 _expected_pushed_min = _expected_pushed_max = 2;
691 }
692
693 Lane* const _lane{ kLanePointerRegKey.readLightUserDataValue<Lane>(L_) };
694 Keeper* const _keeper{ _linda->whichKeeper() };
695 KeeperState const _K{ _keeper ? _keeper->K : KeeperState{ static_cast<lua_State*>(nullptr) } };
696 if (_K == nullptr)
697 return 0;
698
699 CancelRequest _cancel{ CancelRequest::None };
700 KeeperCallResult _pushed{};
701 STACK_CHECK_START_REL(_K, 0);
702 for (bool _try_again{ true };;) {
703 if (_lane != nullptr) {
704 _cancel = _lane->cancelRequest.load(std::memory_order_relaxed);
705 }
706 _cancel = (_cancel != CancelRequest::None)
707 ? _cancel
708 : ((_linda->cancelStatus == Linda::Cancelled) ? CancelRequest::Soft : CancelRequest::None);
709 // if user wants to cancel, or looped because of a timeout, the call returns without sending anything
710 if (!_try_again || _cancel != CancelRequest::None) {
711 _pushed.emplace(0);
712 break;
713 }
714
715 // all arguments of receive() but the first are passed to the keeper's receive function
716 _pushed = keeper_call(_K, _selected_keeper_receive, L_, _linda, _key_i);
717 if (!_pushed.has_value()) {
718 break;
719 }
720 if (_pushed.value() > 0) {
721 LUA_ASSERT(L_, _pushed.value() >= _expected_pushed_min && _pushed.value() <= _expected_pushed_max);
722 if (kRestrictedChannel.equals(L_, StackIndex{ kIdxTop })) {
723 raise_luaL_error(L_, "Key is restricted");
724 }
725 _linda->readHappened.notify_all();
726 break;
727 }
728
729 if (std::chrono::steady_clock::now() >= _until) {
730 break; /* instant timeout */
731 }
732
733 // nothing received, wait until timeout or signalled that we should try again
734 {
735 Lane::Status _prev_status{ Lane::Error }; // prevent 'might be used uninitialized' warnings
736 if (_lane != nullptr) {
737 // change status of lane to "waiting"
738 _prev_status = _lane->status.load(std::memory_order_acquire); // Running, most likely
739 LUA_ASSERT(L_, _prev_status == Lane::Running); // but check, just in case
740 LUA_ASSERT(L_, _lane->waiting_on == nullptr);
741 _lane->waiting_on = &_linda->writeHappened;
742 _lane->status.store(Lane::Waiting, std::memory_order_release);
743 }
744 // not enough data to read: wakeup when data was sent, or when timeout is reached
745 std::unique_lock<std::mutex> _guard{ _keeper->mutex, std::adopt_lock };
746 std::cv_status const _status{ _linda->writeHappened.wait_until(_guard, _until) };
747 _guard.release(); // we don't want to unlock the mutex on exit!
748 _try_again = (_status == std::cv_status::no_timeout); // detect spurious wakeups
749 if (_lane != nullptr) {
750 _lane->waiting_on = nullptr;
751 _lane->status.store(_prev_status, std::memory_order_release);
752 }
753 }
754 }
755 STACK_CHECK(_K, 0);
756
757 if (!_pushed.has_value()) {
758 raise_luaL_error(L_, "tried to copy unsupported types");
759 }
760
761 switch (_cancel) {
762 case CancelRequest::None:
763 {
764 int const _nbPushed{ _pushed.value() };
765 if (_nbPushed == 0) {
766 // not enough data in the linda slot to fulfill the request, return nil, "timeout"
767 lua_pushnil(L_);
768 luaG_pushstring(L_, "timeout");
769 return 2;
770 }
771 return _nbPushed;
772 }
773
774 case CancelRequest::Soft:
775 // if user wants to soft-cancel, the call returns nil, kCancelError
776 lua_pushnil(L_);
777 kCancelError.pushKey(L_);
778 return 2;
779 823
780 case CancelRequest::Hard: 824// #################################################################################################
781 // raise an error interrupting execution only in case of hard cancel
782 raise_cancel_error(L_); // raises an error and doesn't return
783 825
784 default: 826/*
785 raise_luaL_error(L_, "internal error: unknown cancel request"); 827 * [val1, ... valCOUNT] = linda_receive_batched( linda_ud, [timeout_secs_num=-1], key_num|str|bool|lightuserdata, min_COUNT[, max_COUNT])
786 } 828 * Consumes between min_COUNT and max_COUNT values from the linda, from a single slot.
787 } 829 * returns the actual consumed values, or nil if there weren't enough values to consume
788 }; 830 */
789 return Linda::ProtectedCall(L_, _receive); 831LUAG_FUNC(linda_receive_batched)
832{
833 return Linda::ProtectedCall(L_, [](lua_State* const L_) { return ReceiveInternal(L_, true); });
790} 834}
791 835
792// ################################################################################################# 836// #################################################################################################
@@ -806,7 +850,7 @@ LUAG_FUNC(linda_restrict)
806 int const _nargs{ lua_gettop(L_) }; 850 int const _nargs{ lua_gettop(L_) };
807 luaL_argcheck(L_, _nargs == 2 || _nargs == 3, 2, "wrong number of arguments"); 851 luaL_argcheck(L_, _nargs == 2 || _nargs == 3, 2, "wrong number of arguments");
808 // make sure we got a known restrict mode, (or nothing) 852 // make sure we got a known restrict mode, (or nothing)
809 std::string_view const _mode{ luaG_tostring(L_, StackIndex{ 3 }) }; 853 std::string_view const _mode{ luaW_tostring(L_, StackIndex{ 3 }) };
810 if (!_mode.empty() && (_mode != "none" && _mode != "set/get" && _mode != "send/receive")) { 854 if (!_mode.empty() && (_mode != "none" && _mode != "set/get" && _mode != "send/receive")) {
811 raise_luaL_argerror(L_, StackIndex{ 3 }, "unknown restrict mode"); 855 raise_luaL_argerror(L_, StackIndex{ 3 }, "unknown restrict mode");
812 } 856 }
@@ -818,7 +862,7 @@ LUAG_FUNC(linda_restrict)
818 Keeper* const _keeper{ _linda->whichKeeper() }; 862 Keeper* const _keeper{ _linda->whichKeeper() };
819 _pushed = keeper_call(_keeper->K, KEEPER_API(restrict), L_, _linda, StackIndex{ 2 }); 863 _pushed = keeper_call(_keeper->K, KEEPER_API(restrict), L_, _linda, StackIndex{ 2 });
820 // we should get a single return value: the string describing the previous restrict mode 864 // we should get a single return value: the string describing the previous restrict mode
821 LUA_ASSERT(L_, _pushed.has_value() && (_pushed.value() == 1) && luaG_type(L_, kIdxTop) == LuaType::STRING); 865 LUA_ASSERT(L_, _pushed.has_value() && (_pushed.value() == 1) && luaW_type(L_, kIdxTop) == LuaType::STRING);
822 } else { // linda is cancelled 866 } else { // linda is cancelled
823 // do nothing and return nil,lanes.cancel_error 867 // do nothing and return nil,lanes.cancel_error
824 lua_pushnil(L_); 868 lua_pushnil(L_);
@@ -848,20 +892,8 @@ LUAG_FUNC(linda_send)
848 static constexpr lua_CFunction _send{ 892 static constexpr lua_CFunction _send{
849 +[](lua_State* const L_) { 893 +[](lua_State* const L_) {
850 Linda* const _linda{ ToLinda<false>(L_, StackIndex{ 1 }) }; 894 Linda* const _linda{ ToLinda<false>(L_, StackIndex{ 1 }) };
851 StackIndex _key_i{ 2 }; // index of first slot, if timeout not there
852 895
853 std::chrono::time_point<std::chrono::steady_clock> _until{ std::chrono::time_point<std::chrono::steady_clock>::max() }; 896 auto const [_key_i, _until] = ProcessTimeoutArg(L_);
854 if (luaG_type(L_, StackIndex{ 2 }) == LuaType::NUMBER) { // we don't want to use lua_isnumber() because of autocoercion
855 lua_Duration const _duration{ lua_tonumber(L_, 2) };
856 if (_duration.count() >= 0.0) {
857 _until = std::chrono::steady_clock::now() + std::chrono::duration_cast<std::chrono::steady_clock::duration>(_duration);
858 } else {
859 raise_luaL_argerror(L_, StackIndex{ 2 }, "duration cannot be < 0");
860 }
861 ++_key_i;
862 } else if (lua_isnil(L_, 2)) { // alternate explicit "infinite timeout" by passing nil before the slot
863 ++_key_i;
864 }
865 897
866 // make sure the slot is of a valid type 898 // make sure the slot is of a valid type
867 CheckKeyTypes(L_, _key_i, _key_i); 899 CheckKeyTypes(L_, _key_i, _key_i);
@@ -873,78 +905,60 @@ LUAG_FUNC(linda_send)
873 raise_luaL_error(L_, "no data to send"); 905 raise_luaL_error(L_, "no data to send");
874 } 906 }
875 907
908 Lane* const _lane{ kLanePointerRegKey.readLightUserDataValue<Lane>(L_) };
909 Keeper* const _keeper{ _linda->whichKeeper() };
910 KeeperState const _K{ _keeper ? _keeper->K : KeeperState{ static_cast<lua_State*>(nullptr) } };
911 if (_K == nullptr)
912 return 0;
913
876 bool _ret{ false }; 914 bool _ret{ false };
877 CancelRequest _cancel{ CancelRequest::None }; 915 CancelRequest _cancel{ CancelRequest::None };
878 KeeperCallResult _pushed; 916 KeeperCallResult _pushed{};
879 {
880 Lane* const _lane{ kLanePointerRegKey.readLightUserDataValue<Lane>(L_) };
881 Keeper* const _keeper{ _linda->whichKeeper() };
882 KeeperState const _K{ _keeper ? _keeper->K : KeeperState{ static_cast<lua_State*>(nullptr) } };
883 if (_K == nullptr)
884 return 0;
885
886 STACK_CHECK_START_REL(_K, 0);
887 for (bool _try_again{ true };;) {
888 if (_lane != nullptr) {
889 _cancel = _lane->cancelRequest.load(std::memory_order_relaxed);
890 }
891 _cancel = (_cancel != CancelRequest::None)
892 ? _cancel
893 : ((_linda->cancelStatus == Linda::Cancelled) ? CancelRequest::Soft : CancelRequest::None);
894 // if user wants to cancel, or looped because of a timeout, the call returns without sending anything
895 if (!_try_again || _cancel != CancelRequest::None) {
896 _pushed.emplace(0);
897 break;
898 }
899 917
900 STACK_CHECK(_K, 0); 918 STACK_CHECK_START_REL(_K, 0);
901 _pushed = keeper_call(_K, KEEPER_API(send), L_, _linda, _key_i); 919 for (bool _try_again{ true };;) {
902 if (!_pushed.has_value()) { 920 if (_lane != nullptr) {
903 break; 921 _cancel = _lane->cancelRequest.load(std::memory_order_relaxed);
904 } 922 }
905 LUA_ASSERT(L_, _pushed.value() == 1); 923 _cancel = (_cancel != CancelRequest::None)
924 ? _cancel
925 : ((_linda->cancelStatus == Linda::Cancelled) ? CancelRequest::Soft : CancelRequest::None);
906 926
907 if (kRestrictedChannel.equals(L_, StackIndex{ kIdxTop })) { 927 // if user wants to cancel, or looped because of a timeout, the call returns without sending anything
908 raise_luaL_error(L_, "Key is restricted"); 928 if (!_try_again || _cancel != CancelRequest::None) {
909 } 929 _pushed.emplace(0);
910 _ret = lua_toboolean(L_, -1) ? true : false; 930 break;
911 lua_pop(L_, 1); 931 }
912 932
913 if (_ret) { 933 // all arguments of send() but the first are passed to the keeper's send function
914 // Wake up ALL waiting threads 934 STACK_CHECK(_K, 0);
915 _linda->writeHappened.notify_all(); 935 _pushed = keeper_call(_K, KEEPER_API(send), L_, _linda, _key_i);
916 break; 936 if (!_pushed.has_value()) {
917 } 937 break;
938 }
939 LUA_ASSERT(L_, _pushed.value() == 1);
918 940
919 // instant timout to bypass the wait syscall 941 if (kRestrictedChannel.equals(L_, StackIndex{ kIdxTop })) {
920 if (std::chrono::steady_clock::now() >= _until) { 942 raise_luaL_error(L_, "Key is restricted");
921 break; /* no wait; instant timeout */ 943 }
922 } 944 _ret = lua_toboolean(L_, -1) ? true : false;
945 lua_pop(L_, 1);
923 946
924 // storage limit hit, wait until timeout or signalled that we should try again 947 if (_ret) {
925 { 948 // Wake up ALL waiting threads
926 Lane::Status _prev_status{ Lane::Error }; // prevent 'might be used uninitialized' warnings 949 _linda->writeHappened.notify_all();
927 if (_lane != nullptr) { 950 break;
928 // change status of lane to "waiting"
929 _prev_status = _lane->status.load(std::memory_order_acquire); // Running, most likely
930 LUA_ASSERT(L_, _prev_status == Lane::Running); // but check, just in case
931 LUA_ASSERT(L_, _lane->waiting_on == nullptr);
932 _lane->waiting_on = &_linda->readHappened;
933 _lane->status.store(Lane::Waiting, std::memory_order_release);
934 }
935 // could not send because no room: wait until some data was read before trying again, or until timeout is reached
936 std::unique_lock<std::mutex> _guard{ _keeper->mutex, std::adopt_lock };
937 std::cv_status const status{ _linda->readHappened.wait_until(_guard, _until) };
938 _guard.release(); // we don't want to unlock the mutex on exit!
939 _try_again = (status == std::cv_status::no_timeout); // detect spurious wakeups
940 if (_lane != nullptr) {
941 _lane->waiting_on = nullptr;
942 _lane->status.store(_prev_status, std::memory_order_release);
943 }
944 }
945 } 951 }
946 STACK_CHECK(_K, 0); 952
953 // instant timout to bypass the wait syscall
954 if (std::chrono::steady_clock::now() >= _until) {
955 break; /* no wait; instant timeout */
956 }
957
958 // storage limit hit, wait until timeout or signalled that we should try again
959 _try_again = WaitInternal(L_, _lane, _linda, _keeper, _linda->readHappened, _until);
947 } 960 }
961 STACK_CHECK(_K, 0);
948 962
949 if (!_pushed.has_value()) { 963 if (!_pushed.has_value()) {
950 raise_luaL_error(L_, "tried to copy unsupported types"); 964 raise_luaL_error(L_, "tried to copy unsupported types");
@@ -968,7 +982,7 @@ LUAG_FUNC(linda_send)
968 } else { 982 } else {
969 // not enough room in the Linda slot to fulfill the request, return nil, "timeout" 983 // not enough room in the Linda slot to fulfill the request, return nil, "timeout"
970 lua_pushnil(L_); 984 lua_pushnil(L_);
971 luaG_pushstring(L_, "timeout"); 985 luaW_pushstring(L_, "timeout");
972 return 2; 986 return 2;
973 } 987 }
974 } 988 }
@@ -1003,7 +1017,7 @@ LUAG_FUNC(linda_set)
1003 if (kRestrictedChannel.equals(L_, kIdxTop)) { 1017 if (kRestrictedChannel.equals(L_, kIdxTop)) {
1004 raise_luaL_error(L_, "Key is restricted"); 1018 raise_luaL_error(L_, "Key is restricted");
1005 } 1019 }
1006 LUA_ASSERT(L_, _pushed.value() == 2 && luaG_type(L_, kIdxTop) == LuaType::STRING && luaG_type(L_, StackIndex{ -2 }) == LuaType::BOOLEAN); 1020 LUA_ASSERT(L_, _pushed.value() == 2 && luaW_type(L_, kIdxTop) == LuaType::STRING && luaW_type(L_, StackIndex{ -2 }) == LuaType::BOOLEAN);
1007 1021
1008 if (_has_data) { 1022 if (_has_data) {
1009 // we put some data in the slot, tell readers that they should wake 1023 // we put some data in the slot, tell readers that they should wake
@@ -1065,7 +1079,7 @@ LUAG_FUNC(linda_towatch)
1065LUAG_FUNC(linda_wake) 1079LUAG_FUNC(linda_wake)
1066{ 1080{
1067 Linda* const _linda{ ToLinda<false>(L_, StackIndex{ 1 }) }; 1081 Linda* const _linda{ ToLinda<false>(L_, StackIndex{ 1 }) };
1068 std::string_view const _who{ luaG_optstring(L_, StackIndex{ 2 }, "both") }; 1082 std::string_view const _who{ luaW_optstring(L_, StackIndex{ 2 }, "both") };
1069 // make sure we got 2 arguments: the linda and the wake targets 1083 // make sure we got 2 arguments: the linda and the wake targets
1070 luaL_argcheck(L_, lua_gettop(L_) <= 2, 2, "wrong number of arguments"); 1084 luaL_argcheck(L_, lua_gettop(L_) <= 2, 2, "wrong number of arguments");
1071 1085
@@ -1104,6 +1118,7 @@ namespace {
1104 { "get", LG_linda_get }, 1118 { "get", LG_linda_get },
1105 { "limit", LG_linda_limit }, 1119 { "limit", LG_linda_limit },
1106 { "receive", LG_linda_receive }, 1120 { "receive", LG_linda_receive },
1121 { "receive_batched", LG_linda_receive_batched },
1107 { "restrict", LG_linda_restrict }, 1122 { "restrict", LG_linda_restrict },
1108 { "send", LG_linda_send }, 1123 { "send", LG_linda_send },
1109 { "set", LG_linda_set }, 1124 { "set", LG_linda_set },
@@ -1120,88 +1135,77 @@ namespace {
1120// ################################################################################################# 1135// #################################################################################################
1121 1136
1122/* 1137/*
1123 * ud = lanes.linda( [name[,group[,close_handler]]]) 1138 * ud = lanes.linda{.name = <string>, .group = <number>, .close_handler = <callable>, .wake_period = <number>}
1124 * 1139 *
1125 * returns a linda object, or raises an error if creation failed 1140 * returns a linda object, or raises an error if creation failed
1126 */ 1141 */
1127LUAG_FUNC(linda) 1142LUAG_FUNC(linda)
1128{ 1143{
1129 static constexpr StackIndex kLastArg{ LUA_VERSION_NUM >= 504 ? 3 : 2 }; 1144 // unpack the received table on the stack, putting name wake_period group close_handler in that order
1130 StackIndex const _top{ lua_gettop(L_) }; 1145 StackIndex const _top{ lua_gettop(L_) };
1131 luaL_argcheck(L_, _top <= kLastArg, _top, "too many arguments"); 1146 luaL_argcheck(L_, _top <= 1, _top, "too many arguments");
1132 StackIndex _closeHandlerIdx{}; 1147 if (_top == 0) {
1133 StackIndex _nameIdx{}; 1148 lua_settop(L_, 3); // L_: nil nil nil
1134 StackIndex _groupIdx{}; 1149 }
1135 for (StackIndex const _i : std::ranges::iota_view{ StackIndex{ 1 }, StackIndex{ _top + 1 }}) { 1150 else if (!lua_istable(L_, kIdxTop)) {
1136 switch (luaG_type(L_, _i)) { 1151 luaL_argerror(L_, 1, "expecting a table");
1152 } else {
1153 auto* const _U{ Universe::Get(L_) };
1154 lua_getfield(L_, 1, "wake_period"); // L_: {} wake_period
1155 if (lua_isnil(L_, kIdxTop)) {
1156 lua_pop(L_, 1);
1157 lua_pushnumber(L_, _U->lindaWakePeriod.count());
1158 } else if (luaW_type(L_, kIdxTop) == LuaType::STRING) {
1159 if (luaW_tostring(L_, kIdxTop) != "never") {
1160 luaL_argerror(L_, 1, "invalid wake_period");
1161 } else {
1162 lua_pop(L_, 1);
1163 lua_pushnumber(L_, 0);
1164 }
1165 }
1166 else {
1167 luaL_argcheck(L_, luaL_optnumber(L_, 2, 0) > 0, 1, "wake_period must be > 0");
1168 }
1169
1170 lua_getfield(L_, 1, "group"); // L_: {} wake_period group
1171 int const _nbKeepers{ _U->keepers.getNbKeepers() };
1172 if (lua_isnil(L_, kIdxTop)) {
1173 luaL_argcheck(L_, _nbKeepers < 2, 0, "Group is mandatory in multiple Keeper scenarios");
1174 } else {
1175 int const _group{ static_cast<int>(lua_tointeger(L_, kIdxTop)) };
1176 luaL_argcheck(L_, _group >= 0 && _group < _nbKeepers, 1, "group out of range");
1177 }
1178
1137#if LUA_VERSION_NUM >= 504 // to-be-closed support starts with Lua 5.4 1179#if LUA_VERSION_NUM >= 504 // to-be-closed support starts with Lua 5.4
1138 case LuaType::FUNCTION: 1180 lua_getfield(L_, 1, "close_handler"); // L_: {} wake_period group close_handler
1139 luaL_argcheck(L_, _closeHandlerIdx == 0, _i, "More than one __close handler"); 1181 LuaType const _handlerType{ luaW_type(L_, kIdxTop) };
1140 _closeHandlerIdx = _i; 1182 if (_handlerType == LuaType::NIL) {
1141 break; 1183 lua_pop(L_, 1); // L_: {} wake_period group
1142 1184 } else if (_handlerType == LuaType::USERDATA || _handlerType == LuaType::TABLE) {
1143 case LuaType::USERDATA: 1185 luaL_argcheck(L_, luaL_getmetafield(L_, kIdxTop, "__call") != 0, 1, "__close handler is not callable");
1144 case LuaType::TABLE:
1145 luaL_argcheck(L_, _closeHandlerIdx == 0, _i, "More than one __close handler");
1146 luaL_argcheck(L_, luaL_getmetafield(L_, _i, "__call") != 0, _i, "__close handler is not callable");
1147 lua_pop(L_, 1); // luaL_getmetafield() pushed the field, we need to pop it 1186 lua_pop(L_, 1); // luaL_getmetafield() pushed the field, we need to pop it
1148 _closeHandlerIdx = _i; 1187 } else {
1149 break; 1188 luaL_argcheck(L_, _handlerType == LuaType::FUNCTION, 1, "__close handler is not a function");
1189 }
1150#endif // LUA_VERSION_NUM >= 504 1190#endif // LUA_VERSION_NUM >= 504
1151 1191
1152 case LuaType::STRING: 1192 auto const _nameType{ luaW_getfield(L_, StackIndex{ 1 }, "name") }; // L_: {} wake_period group [close_handler] name
1153 luaL_argcheck(L_, _nameIdx == 0, _i, "More than one name"); 1193 luaL_argcheck(L_, _nameType == LuaType::NIL || _nameType == LuaType::STRING, 1, "name is not a string");
1154 _nameIdx = _i; 1194 lua_replace(L_, 1); // L_: name wake_period group [close_handler]
1155 break;
1156
1157 case LuaType::NUMBER:
1158 luaL_argcheck(L_, _groupIdx == 0, _i, "More than one group");
1159 _groupIdx = _i;
1160 break;
1161
1162 default:
1163 luaL_argcheck(L_, false, _i, "Bad argument type (should be a string, a number, or a callable type)");
1164 }
1165 }
1166
1167 int const _nbKeepers{ Universe::Get(L_)->keepers.getNbKeepers() };
1168 if (!_groupIdx) {
1169 luaL_argcheck(L_, _nbKeepers < 2, 0, "Group is mandatory in multiple Keeper scenarios");
1170 } else {
1171 int const _group{ static_cast<int>(lua_tointeger(L_, _groupIdx)) };
1172 luaL_argcheck(L_, _group >= 0 && _group < _nbKeepers, _groupIdx, "Group out of range");
1173 } 1195 }
1174 1196
1175 // done with argument checking, let's proceed 1197 // done with argument checking, let's proceed
1176 if constexpr (LUA_VERSION_NUM >= 504) { 1198 if (lua_gettop(L_) == 4) {
1177 // make sure we have kMaxArgs arguments on the stack for processing, with name, group, and handler, in that order
1178 lua_settop(L_, kLastArg); // L_: a b c
1179 // If either index is 0, lua_settop() adjusted the stack with a nil in slot kLastArg
1180 lua_pushvalue(L_, _closeHandlerIdx ? _closeHandlerIdx : kLastArg); // L_: a b c close_handler
1181 lua_pushvalue(L_, _groupIdx ? _groupIdx : kLastArg); // L_: a b c close_handler group
1182 lua_pushvalue(L_, _nameIdx ? _nameIdx : kLastArg); // L_: a b c close_handler group name
1183 lua_replace(L_, 1); // L_: name b c close_handler group
1184 lua_replace(L_, 2); // L_: name group c close_handler
1185 lua_replace(L_, 3); // L_: name group close_handler
1186
1187 // if we have a __close handler, we need a uservalue slot to store it 1199 // if we have a __close handler, we need a uservalue slot to store it
1188 UserValueCount const _nuv{ _closeHandlerIdx ? 1 : 0 }; 1200 LindaFactory::Instance.pushDeepUserdata(DestState{ L_ }, UserValueCount{ 1 }); // L_: name wake_period group [close_handler] linda
1189 LindaFactory::Instance.pushDeepUserdata(DestState{ L_ }, _nuv); // L_: name group close_handler linda 1201 lua_replace(L_, 3); // L_: name wake_period linda close_handler
1190 if (_closeHandlerIdx != 0) { 1202 lua_setiuservalue(L_, StackIndex{ 3 }, UserValueIndex{ 1 }); // L_: name wake_period linda
1191 lua_replace(L_, 2); // L_: name linda close_handler
1192 lua_setiuservalue(L_, StackIndex{ 2 }, UserValueIndex{ 1 }); // L_: name linda
1193 }
1194 // depending on whether we have a handler or not, the stack is not in the same state at this point 1203 // depending on whether we have a handler or not, the stack is not in the same state at this point
1195 // just make sure we have our Linda at the top 1204 // just make sure we have our Linda at the top
1196 LUA_ASSERT(L_, ToLinda<true>(L_, kIdxTop)); 1205 LUA_ASSERT(L_, ToLinda<true>(L_, kIdxTop));
1197 return 1; 1206 return 1;
1198 } else { // no to-be-closed support 1207 } else { // no to-be-closed support
1199 // ensure we have name, group in that order on the stack 1208 LindaFactory::Instance.pushDeepUserdata(DestState{ L_ }, UserValueCount{ 0 }); // L_: name wake_period group linda
1200 if (_nameIdx > _groupIdx) {
1201 lua_insert(L_, 1); // L_: name group
1202 }
1203 LindaFactory::Instance.pushDeepUserdata(DestState{ L_ }, UserValueCount{ 0 }); // L_: name group linda
1204 return 1; 1209 return 1;
1205 } 1210 }
1206
1207} 1211}
diff --git a/src/linda.hpp b/src/linda.hpp
index 01ca7e1..f02c46e 100644
--- a/src/linda.hpp
+++ b/src/linda.hpp
@@ -8,37 +8,12 @@ struct Keeper;
8 8
9// ################################################################################################# 9// #################################################################################################
10 10
11// xxh64 of string "kLindaBatched" generated at https://www.pelock.com/products/hash-calculator
12static constexpr UniqueKey kLindaBatched{ 0xB8234DF772646567ull, "linda.batched" };
13
14// #################################################################################################
15
16DECLARE_UNIQUE_TYPE(LindaGroup, int); 11DECLARE_UNIQUE_TYPE(LindaGroup, int);
17 12
18class Linda final 13class Linda final
19: public DeepPrelude // Deep userdata MUST start with this header 14: public DeepPrelude // Deep userdata MUST start with this header
20{ 15{
21 public: 16 public:
22 class [[nodiscard]] KeeperOperationInProgress final
23 {
24 private:
25 Linda& linda;
26 [[maybe_unused]] lua_State* const L; // just here for inspection while debugging
27
28 public:
29 KeeperOperationInProgress(Linda& linda_, lua_State* const L_)
30 : linda{ linda_ }
31 , L{ L_ }
32 {
33 [[maybe_unused]] UnusedInt const _prev{ linda.keeperOperationCount.fetch_add(1, std::memory_order_seq_cst) };
34 }
35
36 public:
37 ~KeeperOperationInProgress()
38 {
39 [[maybe_unused]] UnusedInt const _prev{ linda.keeperOperationCount.fetch_sub(1, std::memory_order_seq_cst) };
40 }
41 };
42 17
43 enum class [[nodiscard]] Status 18 enum class [[nodiscard]] Status
44 { 19 {
@@ -47,19 +22,21 @@ class Linda final
47 }; 22 };
48 using enum Status; 23 using enum Status;
49 24
50 private: 25 public:
26 Universe* const U{ nullptr }; // the universe this linda belongs to
51 27
28 private:
52 static constexpr size_t kEmbeddedNameLength = 24; 29 static constexpr size_t kEmbeddedNameLength = 24;
53 using EmbeddedName = std::array<char, kEmbeddedNameLength>; 30 using EmbeddedName = std::array<char, kEmbeddedNameLength>;
54 // depending on the name length, it is either embedded inside the Linda, or allocated separately 31 // depending on the name length, it is either embedded inside the Linda, or allocated separately
55 std::variant<std::string_view, EmbeddedName> nameVariant{}; 32 std::variant<std::string_view, EmbeddedName> nameVariant{};
56 // counts the keeper operations in progress 33 // counts the keeper operations in progress
57 std::atomic<int> keeperOperationCount{}; 34 mutable std::atomic<int> keeperOperationCount{};
35 lua_Duration wakePeriod{};
58 36
59 public: 37 public:
60 std::condition_variable readHappened{}; 38 std::condition_variable readHappened{};
61 std::condition_variable writeHappened{}; 39 std::condition_variable writeHappened{};
62 Universe* const U{ nullptr }; // the universe this linda belongs to
63 KeeperIndex const keeperIndex{ -1 }; // the keeper associated to this linda 40 KeeperIndex const keeperIndex{ -1 }; // the keeper associated to this linda
64 Status cancelStatus{ Status::Active }; 41 Status cancelStatus{ Status::Active };
65 42
@@ -73,7 +50,7 @@ class Linda final
73 static void operator delete(void* p_) { static_cast<Linda*>(p_)->U->internalAllocator.free(p_, sizeof(Linda)); } 50 static void operator delete(void* p_) { static_cast<Linda*>(p_)->U->internalAllocator.free(p_, sizeof(Linda)); }
74 51
75 ~Linda(); 52 ~Linda();
76 Linda(Universe* U_, LindaGroup group_, std::string_view const& name_); 53 Linda(Universe* U_, std::string_view const& name_, lua_Duration wake_period_, LindaGroup group_);
77 Linda() = delete; 54 Linda() = delete;
78 // non-copyable, non-movable 55 // non-copyable, non-movable
79 Linda(Linda const&) = delete; 56 Linda(Linda const&) = delete;
@@ -97,6 +74,8 @@ class Linda final
97 [[nodiscard]] 74 [[nodiscard]]
98 std::string_view getName() const; 75 std::string_view getName() const;
99 [[nodiscard]] 76 [[nodiscard]]
77 auto getWakePeriod() const { return wakePeriod; }
78 [[nodiscard]]
100 bool inKeeperOperation() const { return keeperOperationCount.load(std::memory_order_seq_cst) != 0; } 79 bool inKeeperOperation() const { return keeperOperationCount.load(std::memory_order_seq_cst) != 0; }
101 template <typename T = uintptr_t> 80 template <typename T = uintptr_t>
102 [[nodiscard]] 81 [[nodiscard]]
@@ -111,7 +90,5 @@ class Linda final
111 static int ProtectedCall(lua_State* L_, lua_CFunction f_); 90 static int ProtectedCall(lua_State* L_, lua_CFunction f_);
112 void pushCancelString(lua_State* L_) const; 91 void pushCancelString(lua_State* L_) const;
113 [[nodiscard]] 92 [[nodiscard]]
114 KeeperOperationInProgress startKeeperOperation(lua_State* const L_) { return KeeperOperationInProgress{ *this, L_ }; };
115 [[nodiscard]]
116 Keeper* whichKeeper() const { return U->keepers.getKeeper(keeperIndex); } 93 Keeper* whichKeeper() const { return U->keepers.getKeeper(keeperIndex); }
117}; 94};
diff --git a/src/lindafactory.cpp b/src/lindafactory.cpp
index 6e3f759..483037f 100644
--- a/src/lindafactory.cpp
+++ b/src/lindafactory.cpp
@@ -47,26 +47,22 @@ void LindaFactory::createMetatable(lua_State* L_) const
47 lua_newtable(L_); // L_: mt 47 lua_newtable(L_); // L_: mt
48 48
49 // protect metatable from external access 49 // protect metatable from external access
50 luaG_pushstring(L_, kLindaMetatableName); // L_: mt "<name>" 50 luaW_pushstring(L_, kLindaMetatableName); // L_: mt "<name>"
51 lua_setfield(L_, -2, "__metatable"); // L_: mt 51 lua_setfield(L_, -2, "__metatable"); // L_: mt
52 52
53 // the linda functions 53 // the linda functions
54 luaG_registerlibfuncs(L_, mLindaMT); 54 luaW_registerlibfuncs(L_, mLindaMT);
55
56 // some constants
57 kLindaBatched.pushKey(L_); // L_: mt kLindaBatched
58 lua_setfield(L_, -2, "batched"); // L_: mt
59 55
60 kNilSentinel.pushKey(L_); // L_: mt kNilSentinel 56 kNilSentinel.pushKey(L_); // L_: mt kNilSentinel
61 lua_setfield(L_, -2, "null"); // L_: mt 57 lua_setfield(L_, -2, "null"); // L_: mt
62 58
63 // if the metatable contains __index, leave it as is 59 // if the metatable contains __index, leave it as is
64 if (luaG_getfield(L_, kIdxTop, kIndex) != LuaType::NIL) { // L_: mt __index 60 if (luaW_getfield(L_, kIdxTop, kIndex) != LuaType::NIL) { // L_: mt __index
65 lua_pop(L_, 1); // L_: mt __index 61 lua_pop(L_, 1); // L_: mt __index
66 } else { 62 } else {
67 // metatable is its own index 63 // metatable is its own index
68 lua_pushvalue(L_, kIdxTop); // L_: mt mt 64 lua_pushvalue(L_, kIdxTop); // L_: mt mt
69 luaG_setfield(L_, StackIndex{ -2 }, kIndex); // L_: mt 65 luaW_setfield(L_, StackIndex{ -2 }, kIndex); // L_: mt
70 } 66 }
71 67
72 STACK_CHECK(L_, 1); 68 STACK_CHECK(L_, 1);
@@ -112,27 +108,30 @@ std::string_view LindaFactory::moduleName() const
112 108
113DeepPrelude* LindaFactory::newDeepObjectInternal(lua_State* const L_) const 109DeepPrelude* LindaFactory::newDeepObjectInternal(lua_State* const L_) const
114{ 110{
115 // we always expect name and group at the bottom of the stack (either can be nil). any extra stuff we ignore and keep unmodified 111 STACK_CHECK_START_REL(L_, 0);
116 std::string_view _linda_name{ luaG_tostring(L_, StackIndex{ 1 }) }; 112 // we always expect name, wake_period, group at the bottom of the stack (either can be nil). any extra stuff we ignore and keep unmodified
117 LindaGroup _linda_group{ static_cast<int>(lua_tointeger(L_, 2)) }; 113 std::string_view _linda_name{ luaW_tostring(L_, StackIndex{ 1 }) };
114 auto const _wake_period{ static_cast<lua_Duration>(lua_tonumber(L_, 2)) };
115 LindaGroup const _linda_group{ static_cast<int>(lua_tointeger(L_, 3)) };
118 116
119 // store in the linda the location of the script that created it 117 // store in the linda the location of the script that created it
120 if (_linda_name == "auto") { 118 if (_linda_name == "auto") {
121 lua_Debug _ar; 119 lua_Debug _ar;
122 if (lua_getstack(L_, 1, &_ar) == 1) { // 1 because we want the name of the function that called lanes.linda (where we currently are) 120 if (lua_getstack(L_, 1, &_ar) == 1) { // 1 because we want the name of the function that called lanes.linda (where we currently are)
123 lua_getinfo(L_, "Sln", &_ar); 121 lua_getinfo(L_, "Sln", &_ar);
124 _linda_name = luaG_pushstring(L_, "%s:%d", _ar.short_src, _ar.currentline); 122 _linda_name = luaW_pushstring(L_, "%s:%d", _ar.short_src, _ar.currentline);
125 } else { 123 } else {
126 _linda_name = luaG_pushstring(L_, "<unresolved>"); 124 _linda_name = luaW_pushstring(L_, "<unresolved>");
127 } 125 }
128 // since the name is not empty, it is at slot 1, and we can replace "auto" with the result, just in case 126 // since the name is not empty, it is at slot 1, and we can replace "auto" with the result, just in case
129 LUA_ASSERT(L_, luaG_tostring(L_, StackIndex{ 1 }) == "auto"); 127 LUA_ASSERT(L_, luaW_tostring(L_, StackIndex{ 1 }) == "auto");
130 lua_replace(L_, 1); 128 lua_replace(L_, 1);
131 } 129 }
132 130
133 // The deep data is allocated separately of Lua stack; we might no longer be around when last reference to it is being released. 131 // The deep data is allocated separately of Lua stack; we might no longer be around when last reference to it is being released.
134 // One can use any memory allocation scheme. Just don't use L's allocF because we don't know which state will get the honor of GCing the linda 132 // One can use any memory allocation scheme. Just don't use L's allocF because we don't know which state will get the honor of GCing the linda
135 Universe* const _U{ Universe::Get(L_) }; 133 Universe* const _U{ Universe::Get(L_) };
136 Linda* const _linda{ new (_U) Linda{ _U, _linda_group, _linda_name } }; 134 Linda* const _linda{ new (_U) Linda{ _U, _linda_name, _wake_period, _linda_group } };
135 STACK_CHECK(L_, 0);
137 return _linda; 136 return _linda;
138} 137}
diff --git a/src/macros_and_utils.hpp b/src/macros_and_utils.hpp
index 16011f7..1aca818 100644
--- a/src/macros_and_utils.hpp
+++ b/src/macros_and_utils.hpp
@@ -21,6 +21,7 @@ inline void STACK_GROW(lua_State* const L_, int const n_)
21 21
22// ################################################################################################# 22// #################################################################################################
23 23
24// 1 unit of lua_Duration lasts 1 second (using default period of std::ratio<1>)
24using lua_Duration = std::chrono::template duration<lua_Number>; 25using lua_Duration = std::chrono::template duration<lua_Number>;
25 26
26// ################################################################################################# 27// #################################################################################################
diff --git a/src/nameof.cpp b/src/nameof.cpp
index f236f73..992569b 100644
--- a/src/nameof.cpp
+++ b/src/nameof.cpp
@@ -52,25 +52,25 @@ FqnLength DiscoverObjectNameRecur(lua_State* const L_, FqnLength const shortest_
52 static constexpr auto _pushNameOnFQN = [](lua_State* const L_) { 52 static constexpr auto _pushNameOnFQN = [](lua_State* const L_) {
53 STACK_CHECK_START_REL(L_, 0); 53 STACK_CHECK_START_REL(L_, 0);
54 lua_pushvalue(L_, -2); // L_: o "r" {c} {fqn} ... k v k 54 lua_pushvalue(L_, -2); // L_: o "r" {c} {fqn} ... k v k
55 auto const _keyType{ luaG_type(L_, kIdxTop) }; 55 auto const _keyType{ luaW_type(L_, kIdxTop) };
56 if (_keyType != LuaType::STRING) { 56 if (_keyType != LuaType::STRING) {
57 lua_pop(L_, 1); // L_: o "r" {c} {fqn} ... k v 57 lua_pop(L_, 1); // L_: o "r" {c} {fqn} ... k v
58 luaG_pushstring(L_, "<%s>", luaG_typename(L_, _keyType).data()); // L_: o "r" {c} {fqn} ... k v "<type of k>" 58 luaW_pushstring(L_, "<%s>", luaW_typename(L_, _keyType).data()); // L_: o "r" {c} {fqn} ... k v "<type of k>"
59 } else { 59 } else {
60 // decorate the key string with something that tells us the type of the value 60 // decorate the key string with something that tells us the type of the value
61 switch (luaG_type(L_, StackIndex{ -2 })) { 61 switch (luaW_type(L_, StackIndex{ -2 })) {
62 default: 62 default:
63 LUA_ASSERT(L_, false); // there is something wrong if we end up here 63 LUA_ASSERT(L_, false); // there is something wrong if we end up here
64 luaG_pushstring(L_, "??"); // L_: o "r" {c} {fqn} ... k v "k" "??" 64 luaW_pushstring(L_, "??"); // L_: o "r" {c} {fqn} ... k v "k" "??"
65 break; 65 break;
66 case LuaType::FUNCTION: 66 case LuaType::FUNCTION:
67 luaG_pushstring(L_, "()"); // L_: o "r" {c} {fqn} ... k v "k" "()" 67 luaW_pushstring(L_, "()"); // L_: o "r" {c} {fqn} ... k v "k" "()"
68 break; 68 break;
69 case LuaType::TABLE: 69 case LuaType::TABLE:
70 luaG_pushstring(L_, "[]"); // L_: o "r" {c} {fqn} ... k v "k" "[]" 70 luaW_pushstring(L_, "[]"); // L_: o "r" {c} {fqn} ... k v "k" "[]"
71 break; 71 break;
72 case LuaType::USERDATA: 72 case LuaType::USERDATA:
73 luaG_pushstring(L_, "<>"); // L_: o "r" {c} {fqn} ... k v "k" "<>" 73 luaW_pushstring(L_, "<>"); // L_: o "r" {c} {fqn} ... k v "k" "<>"
74 break; 74 break;
75 } 75 }
76 lua_concat(L_, 2); // L_: o "r" {c} {fqn} ... k v "k??" 76 lua_concat(L_, 2); // L_: o "r" {c} {fqn} ... k v "k??"
@@ -92,7 +92,7 @@ FqnLength DiscoverObjectNameRecur(lua_State* const L_, FqnLength const shortest_
92 static constexpr auto _recurseThenPop = [](lua_State* const L_, FqnLength const shortest_) -> FqnLength { 92 static constexpr auto _recurseThenPop = [](lua_State* const L_, FqnLength const shortest_) -> FqnLength {
93 STACK_CHECK_START_REL(L_, 0); // L_: o "r" {c} {fqn} ... <> 93 STACK_CHECK_START_REL(L_, 0); // L_: o "r" {c} {fqn} ... <>
94 FqnLength r_{ shortest_ }; 94 FqnLength r_{ shortest_ };
95 auto const _type{ luaG_type(L_, kIdxTop) }; 95 auto const _type{ luaW_type(L_, kIdxTop) };
96 if (_type == LuaType::TABLE || _type == LuaType::USERDATA || _type == LuaType::FUNCTION) { 96 if (_type == LuaType::TABLE || _type == LuaType::USERDATA || _type == LuaType::FUNCTION) {
97 r_ = DiscoverObjectNameRecur(L_, shortest_); 97 r_ = DiscoverObjectNameRecur(L_, shortest_);
98 STACK_CHECK(L_, 0); 98 STACK_CHECK(L_, 0);
@@ -113,7 +113,7 @@ FqnLength DiscoverObjectNameRecur(lua_State* const L_, FqnLength const shortest_
113 STACK_CHECK_START_REL(L_, 0); // L_: o "r" {c} {fqn} ... k v 113 STACK_CHECK_START_REL(L_, 0); // L_: o "r" {c} {fqn} ... k v
114 114
115 // filter out uninteresting values 115 // filter out uninteresting values
116 auto const _valType{ luaG_type(L_, kIdxTop) }; 116 auto const _valType{ luaW_type(L_, kIdxTop) };
117 if (_valType == LuaType::NIL || _valType == LuaType::BOOLEAN || _valType == LuaType::LIGHTUSERDATA || _valType == LuaType::NUMBER || _valType == LuaType::STRING) { 117 if (_valType == LuaType::NIL || _valType == LuaType::BOOLEAN || _valType == LuaType::LIGHTUSERDATA || _valType == LuaType::NUMBER || _valType == LuaType::STRING) {
118 lua_pop(L_, 1); // L_: o "r" {c} {fqn} ... k 118 lua_pop(L_, 1); // L_: o "r" {c} {fqn} ... k
119 return _r; 119 return _r;
@@ -177,7 +177,7 @@ FqnLength DiscoverObjectNameRecur(lua_State* const L_, FqnLength const shortest_
177 177
178 UserValueIndex _uvi{ 0 }; 178 UserValueIndex _uvi{ 0 };
179 while (lua_getiuservalue(L_, kIdxTop, ++_uvi) != LUA_TNONE) { // L_: o "r" {c} {fqn} ... U uv 179 while (lua_getiuservalue(L_, kIdxTop, ++_uvi) != LUA_TNONE) { // L_: o "r" {c} {fqn} ... U uv
180 luaG_pushstring(L_, "<uv:%d>", _uvi); // L_: o "r" {c} {fqn} ... U uv name 180 luaW_pushstring(L_, "<uv:%d>", _uvi); // L_: o "r" {c} {fqn} ... U uv name
181 lua_insert(L_, -2); // L_: o "r" {c} {fqn} ... U name uv 181 lua_insert(L_, -2); // L_: o "r" {c} {fqn} ... U name uv
182 r_ = _processKeyValue(L_, r_); // L_: o "r" {c} {fqn} ... U name 182 r_ = _processKeyValue(L_, r_); // L_: o "r" {c} {fqn} ... U name
183 lua_pop(L_, 1); // L_: o "r" {c} {fqn} ... U 183 lua_pop(L_, 1); // L_: o "r" {c} {fqn} ... U
@@ -200,7 +200,7 @@ FqnLength DiscoverObjectNameRecur(lua_State* const L_, FqnLength const shortest_
200 _upname = "<C>"; 200 _upname = "<C>";
201 } 201 }
202 202
203 luaG_pushstring(L_, "upvalue:%s", _upname); // L_: o "r" {c} {fqn} ... F up name 203 luaW_pushstring(L_, "upvalue:%s", _upname); // L_: o "r" {c} {fqn} ... F up name
204 lua_insert(L_, -2); // L_: o "r" {c} {fqn} ... F name up 204 lua_insert(L_, -2); // L_: o "r" {c} {fqn} ... F name up
205 r_ = _processKeyValue(L_, r_); // L_: o "r" {c} {fqn} ... F name 205 r_ = _processKeyValue(L_, r_); // L_: o "r" {c} {fqn} ... F name
206 lua_pop(L_, 1); // L_: o "r" {c} {fqn} ... F 206 lua_pop(L_, 1); // L_: o "r" {c} {fqn} ... F
@@ -213,7 +213,7 @@ FqnLength DiscoverObjectNameRecur(lua_State* const L_, FqnLength const shortest_
213 STACK_GROW(L_, 2); 213 STACK_GROW(L_, 2);
214 STACK_CHECK_START_REL(L_, 0); 214 STACK_CHECK_START_REL(L_, 0);
215 // stack top contains the location to search in (table, function, userdata) 215 // stack top contains the location to search in (table, function, userdata)
216 [[maybe_unused]] auto const _typeWhere{ luaG_type(L_, kIdxTop) }; 216 [[maybe_unused]] auto const _typeWhere{ luaW_type(L_, kIdxTop) };
217 LUA_ASSERT(L_, _typeWhere == LuaType::TABLE || _typeWhere == LuaType::USERDATA || _typeWhere == LuaType::FUNCTION); 217 LUA_ASSERT(L_, _typeWhere == LuaType::TABLE || _typeWhere == LuaType::USERDATA || _typeWhere == LuaType::FUNCTION);
218 lua_pushvalue(L_, kIdxTop); // L_: o "r" {c} {fqn} ... <> <> 218 lua_pushvalue(L_, kIdxTop); // L_: o "r" {c} {fqn} ... <> <>
219 lua_rawget(L_, kCache); // L_: o "r" {c} {fqn} ... <> nil/N 219 lua_rawget(L_, kCache); // L_: o "r" {c} {fqn} ... <> nil/N
@@ -263,12 +263,12 @@ LUAG_FUNC(nameof)
263 263
264 // nil, boolean, light userdata, number and string aren't identifiable 264 // nil, boolean, light userdata, number and string aren't identifiable
265 static constexpr auto _isIdentifiable = [](lua_State* const L_) { 265 static constexpr auto _isIdentifiable = [](lua_State* const L_) {
266 auto const _valType{ luaG_type(L_, kIdxTop) }; 266 auto const _valType{ luaW_type(L_, kIdxTop) };
267 return _valType == LuaType::TABLE || _valType == LuaType::FUNCTION || _valType == LuaType::USERDATA || _valType == LuaType::THREAD; 267 return _valType == LuaType::TABLE || _valType == LuaType::FUNCTION || _valType == LuaType::USERDATA || _valType == LuaType::THREAD;
268 }; 268 };
269 269
270 if (!_isIdentifiable(L_)) { 270 if (!_isIdentifiable(L_)) {
271 luaG_pushstring(L_, luaG_typename(L_, kIdxTop)); // L_: o "type" 271 luaW_pushstring(L_, luaW_typename(L_, kIdxTop)); // L_: o "type"
272 lua_insert(L_, -2); // L_: "type" o 272 lua_insert(L_, -2); // L_: "type" o
273 return 2; 273 return 2;
274 } 274 }
@@ -282,15 +282,15 @@ LUAG_FUNC(nameof)
282 // push a table whose contents are strings that, when concatenated, produce unique name 282 // push a table whose contents are strings that, when concatenated, produce unique name
283 lua_newtable(L_); // L_: o nil {c} {fqn} 283 lua_newtable(L_); // L_: o nil {c} {fqn}
284 // {fqn}[1] = "_G" 284 // {fqn}[1] = "_G"
285 luaG_pushstring(L_, LUA_GNAME); // L_: o nil {c} {fqn} "_G" 285 luaW_pushstring(L_, LUA_GNAME); // L_: o nil {c} {fqn} "_G"
286 lua_rawseti(L_, -2, 1); // L_: o nil {c} {fqn} 286 lua_rawseti(L_, -2, 1); // L_: o nil {c} {fqn}
287 // this is where we start the search 287 // this is where we start the search
288 luaG_pushglobaltable(L_); // L_: o nil {c} {fqn} _G 288 luaW_pushglobaltable(L_); // L_: o nil {c} {fqn} _G
289 auto const _foundInG{ DiscoverObjectNameRecur(L_, FqnLength{ std::numeric_limits<FqnLength::type>::max() }) }; 289 auto const _foundInG{ DiscoverObjectNameRecur(L_, FqnLength{ std::numeric_limits<FqnLength::type>::max() }) };
290 if (lua_isnil(L_, 2)) { // try again with registry, just in case... 290 if (lua_isnil(L_, 2)) { // try again with registry, just in case...
291 LUA_ASSERT(L_, _foundInG == std::numeric_limits<FqnLength::type>::max()); 291 LUA_ASSERT(L_, _foundInG == std::numeric_limits<FqnLength::type>::max());
292 lua_pop(L_, 1); // L_: o nil {c} {fqn} 292 lua_pop(L_, 1); // L_: o nil {c} {fqn}
293 luaG_pushstring(L_, "_R"); // L_: o nil {c} {fqn} "_R" 293 luaW_pushstring(L_, "_R"); // L_: o nil {c} {fqn} "_R"
294 lua_rawseti(L_, -2, 1); // L_: o nil {c} {fqn} 294 lua_rawseti(L_, -2, 1); // L_: o nil {c} {fqn}
295 lua_pushvalue(L_, kIdxRegistry); // L_: o nil {c} {fqn} _R 295 lua_pushvalue(L_, kIdxRegistry); // L_: o nil {c} {fqn} _R
296 [[maybe_unused]] auto const _foundInR{ DiscoverObjectNameRecur(L_, FqnLength{ std::numeric_limits<FqnLength::type>::max() }) }; 296 [[maybe_unused]] auto const _foundInR{ DiscoverObjectNameRecur(L_, FqnLength{ std::numeric_limits<FqnLength::type>::max() }) };
diff --git a/src/state.cpp b/src/state.cpp
index fc7f5ef..2f64194 100644
--- a/src/state.cpp
+++ b/src/state.cpp
@@ -166,7 +166,7 @@ namespace state {
166 }; 166 };
167 167
168 if (_L == nullptr) { 168 if (_L == nullptr) {
169 raise_luaL_error(from_, "luaG_newstate() failed while creating state; out of memory"); 169 raise_luaL_error(from_, "luaW_newstate() failed while creating state; out of memory");
170 } 170 }
171 return _L; 171 return _L;
172 } 172 }
@@ -202,11 +202,11 @@ namespace state {
202 202
203 // neither libs (not even 'base') nor special init func: we are done 203 // neither libs (not even 'base') nor special init func: we are done
204 if (!libs_.has_value() && std::holds_alternative<std::nullptr_t>(U_->onStateCreateFunc)) { 204 if (!libs_.has_value() && std::holds_alternative<std::nullptr_t>(U_->onStateCreateFunc)) {
205 DEBUGSPEW_CODE(DebugSpew(U_) << "luaG_newstate(nullptr)" << std::endl); 205 DEBUGSPEW_CODE(DebugSpew(U_) << "luaW_newstate(nullptr)" << std::endl);
206 return _L; 206 return _L;
207 } 207 }
208 208
209 DEBUGSPEW_CODE(DebugSpew(U_) << "luaG_newstate()" << std::endl); 209 DEBUGSPEW_CODE(DebugSpew(U_) << "luaW_newstate()" << std::endl);
210 DEBUGSPEW_CODE(DebugSpewIndentScope _scope{ U_ }); 210 DEBUGSPEW_CODE(DebugSpewIndentScope _scope{ U_ });
211 211
212 // copy settings (for example because it may contain a Lua on_state_create function) 212 // copy settings (for example because it may contain a Lua on_state_create function)
@@ -239,7 +239,7 @@ namespace state {
239 lua_pop(_L, 1); 239 lua_pop(_L, 1);
240 } else { 240 } else {
241 lua_pushcfunction(_L, luaopen_base); 241 lua_pushcfunction(_L, luaopen_base);
242 luaG_pushstring(_L, ""); 242 luaW_pushstring(_L, "");
243 lua_call(_L, 1, 0); 243 lua_call(_L, 1, 0);
244 } 244 }
245 } 245 }
@@ -274,7 +274,7 @@ namespace state {
274 274
275 STACK_CHECK(_L, 0); 275 STACK_CHECK(_L, 0);
276 // after all this, register everything we find in our name<->function database 276 // after all this, register everything we find in our name<->function database
277 luaG_pushglobaltable(_L); // L: _G 277 luaW_pushglobaltable(_L); // L: _G
278 tools::PopulateFuncLookupTable(_L, kIdxTop, {}); 278 tools::PopulateFuncLookupTable(_L, kIdxTop, {});
279 lua_pop(_L, 1); // L: 279 lua_pop(_L, 1); // L:
280 STACK_CHECK(_L, 0); 280 STACK_CHECK(_L, 0);
@@ -286,19 +286,19 @@ namespace state {
286 kLookupRegKey.pushValue(_L); // L: {} 286 kLookupRegKey.pushValue(_L); // L: {}
287 lua_pushnil(_L); // L: {} nil 287 lua_pushnil(_L); // L: {} nil
288 while (lua_next(_L, -2)) { // L: {} k v 288 while (lua_next(_L, -2)) { // L: {} k v
289 luaG_pushstring(_L, "["); // L: {} k v "[" 289 luaW_pushstring(_L, "["); // L: {} k v "["
290 290
291 lua_getglobal(_L, "tostring"); // L: {} k v "[" tostring 291 lua_getglobal(_L, "tostring"); // L: {} k v "[" tostring
292 lua_pushvalue(_L, -4); // L: {} k v "[" tostring k 292 lua_pushvalue(_L, -4); // L: {} k v "[" tostring k
293 lua_call(_L, 1, 1); // L: {} k v "[" 'k' 293 lua_call(_L, 1, 1); // L: {} k v "[" 'k'
294 294
295 luaG_pushstring(_L, "] = "); // L: {} k v "[" 'k' "] = " 295 luaW_pushstring(_L, "] = "); // L: {} k v "[" 'k' "] = "
296 296
297 lua_getglobal(_L, "tostring"); // L: {} k v "[" 'k' "] = " tostring 297 lua_getglobal(_L, "tostring"); // L: {} k v "[" 'k' "] = " tostring
298 lua_pushvalue(_L, -5); // L: {} k v "[" 'k' "] = " tostring v 298 lua_pushvalue(_L, -5); // L: {} k v "[" 'k' "] = " tostring v
299 lua_call(_L, 1, 1); // L: {} k v "[" 'k' "] = " 'v' 299 lua_call(_L, 1, 1); // L: {} k v "[" 'k' "] = " 'v'
300 lua_concat(_L, 4); // L: {} k v "[k] = v" 300 lua_concat(_L, 4); // L: {} k v "[k] = v"
301 DEBUGSPEW_CODE(DebugSpew(U_) << luaG_tostring(_L, kIdxTop) << std::endl); 301 DEBUGSPEW_CODE(DebugSpew(U_) << luaW_tostring(_L, kIdxTop) << std::endl);
302 lua_pop(_L, 2); // L: {} k 302 lua_pop(_L, 2); // L: {} k
303 } // lua_next() // L: {} 303 } // lua_next() // L: {}
304 lua_pop(_L, 1); // L: 304 lua_pop(_L, 1); // L:
@@ -317,7 +317,7 @@ namespace state {
317 lua_newtable(L_); // L_: out 317 lua_newtable(L_); // L_: out
318 for (luaL_Reg const& _entry : local::sLibs) { 318 for (luaL_Reg const& _entry : local::sLibs) {
319 lua_pushboolean(L_, 1); // L_: out true 319 lua_pushboolean(L_, 1); // L_: out true
320 luaG_setfield(L_, StackIndex{ -2 }, std::string_view{ _entry.name }); // out[name] = true // L_: out 320 luaW_setfield(L_, StackIndex{ -2 }, std::string_view{ _entry.name }); // out[name] = true // L_: out
321 } 321 }
322 STACK_CHECK(L_, 1); 322 STACK_CHECK(L_, 1);
323 return 1; 323 return 1;
diff --git a/src/threading.cpp b/src/threading.cpp
index 3e594ff..4b27bed 100644
--- a/src/threading.cpp
+++ b/src/threading.cpp
@@ -49,6 +49,7 @@ THE SOFTWARE.
49 49
50#endif // __linux__ 50#endif // __linux__
51 51
52#include "compat.hpp"
52#include "threading.hpp" 53#include "threading.hpp"
53 54
54#if !defined(PLATFORM_XBOX) && !defined(PLATFORM_WIN32) && !defined(PLATFORM_POCKETPC) 55#if !defined(PLATFORM_XBOX) && !defined(PLATFORM_WIN32) && !defined(PLATFORM_POCKETPC)
@@ -82,25 +83,42 @@ THE SOFTWARE.
82#pragma warning(disable : 4054) 83#pragma warning(disable : 4054)
83#endif 84#endif
84 85
86static constexpr std::string_view StripFuncName(std::string_view const& where_)
87{
88 std::string_view funcname_{ where_ };
89
90 auto _args_pos{ funcname_.find_first_of('(') };
91 funcname_ = funcname_.substr(0, _args_pos);
92 auto _name_pos{ funcname_.find_last_of(' ') };
93 funcname_.remove_prefix(_name_pos + 1);
94 return funcname_;
95}
96
85/* 97/*
86 * FAIL is for unexpected API return values - essentially programming 98 * FAIL is for unexpected API return values - essentially programming
87 * error in _this_ code. 99 * error in _this_ code.
88 */ 100 */
89#if HAVE_WIN32 101#if HAVE_WIN32
90static void FAIL(char const* funcname_, DWORD const rc_) 102
103template <typename F, typename... ARGS>
104void Win32Invoke(lua_State* const L_, std::string_view const& where_, F& f_, ARGS... args_)
91{ 105{
106 auto const _ret{ std::invoke(f_, std::forward<ARGS>(args_)...) };
107 if (!_ret) {
108 auto const _rc{ GetLastError() };
109 std::string_view const _funcname{ StripFuncName(where_) };
110
92#if defined(PLATFORM_XBOX) 111#if defined(PLATFORM_XBOX)
93 fprintf(stderr, "%s() failed! (%d)\n", funcname_, rc_); 112 luaW_pushstring(L_, "%s() failed with code %d", _funcname.data(), _rc);
94#else // PLATFORM_XBOX 113#else // PLATFORM_XBOX
95 char buf[256]; 114 char _buf[256];
96 FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM, nullptr, rc_, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), buf, 256, nullptr); 115 FormatMessageA(FORMAT_MESSAGE_FROM_SYSTEM, nullptr, _rc, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), _buf, 256, nullptr);
97 fprintf(stderr, "%s() failed! [GetLastError() -> %lu] '%s'", funcname_, rc_, buf); 116 luaW_pushstring(L_, "%s() failed with code %d '%s'", _funcname.data(), _rc, _buf);
98#endif // PLATFORM_XBOX 117#endif // PLATFORM_XBOX
99#ifdef _MSC_VER 118 raise_lua_error(L_);
100 __debugbreak(); // give a chance to the debugger! 119 }
101#endif // _MSC_VER
102 abort();
103} 120}
121
104#endif // HAVE_WIN32 122#endif // HAVE_WIN32
105 123
106/*---=== Threading ===---*/ 124/*---=== Threading ===---*/
@@ -121,33 +139,35 @@ static int const gs_prio_remap[] = {
121 139
122// ################################################################################################# 140// #################################################################################################
123 141
124void THREAD_SET_PRIORITY(int prio_, [[maybe_unused]] bool sudo_) 142std::pair<int, int> THREAD_NATIVE_PRIOS()
125{ 143{
126 // prio range [-3,+3] was checked by the caller 144 return std::make_pair(THREAD_PRIORITY_IDLE, THREAD_PRIORITY_TIME_CRITICAL);
127 if (!SetThreadPriority(GetCurrentThread(), gs_prio_remap[prio_ + 3])) {
128 FAIL("THREAD_SET_PRIORITY", GetLastError());
129 }
130} 145}
131 146
132// ################################################################################################# 147// #################################################################################################
133 148
134void THREAD_SET_PRIORITY(std::thread& thread_, int prio_, [[maybe_unused]] bool sudo_) 149[[nodiscard]]
150void THREAD_SET_PRIORITY(lua_State* const L_, int const prio_, NativePrioFlag const native_, [[maybe_unused]] SudoFlag const sudo_)
135{ 151{
136 // prio range [-3,+3] was checked by the caller 152 // mapped prio range [-3,+3] was checked by the caller
137 // for some reason when building for mingw, native_handle() is an unsigned long long, but HANDLE is a void* 153 return Win32Invoke(L_, std::source_location::current().function_name(), SetThreadPriority, GetCurrentThread(), native_ ? prio_ : gs_prio_remap[prio_ + 3]);
138 // -> need a strong cast to make g++ happy
139 if (!SetThreadPriority(thread_.native_handle(), gs_prio_remap[prio_ + 3])) {
140 FAIL("THREAD_SET_PRIORITY", GetLastError());
141 }
142} 154}
143 155
144// ################################################################################################# 156// #################################################################################################
145 157
146void THREAD_SET_AFFINITY(unsigned int aff_) 158[[nodiscard]]
159void THREAD_SET_PRIORITY(lua_State* const L_, std::thread& thread_, int const prio_, NativePrioFlag const native_, [[maybe_unused]] SudoFlag const sudo_)
147{ 160{
148 if (!SetThreadAffinityMask(GetCurrentThread(), aff_)) { 161 // mapped prio range [-3,+3] was checked by the caller
149 FAIL("THREAD_SET_AFFINITY", GetLastError()); 162 return Win32Invoke(L_, std::source_location::current().function_name(), SetThreadPriority, thread_.native_handle(), native_ ? prio_ : gs_prio_remap[prio_ + 3]);
150 } 163}
164
165// #################################################################################################
166
167[[nodiscard]]
168void THREAD_SET_AFFINITY(lua_State* const L_, unsigned int aff_)
169{
170 return Win32Invoke(L_, std::source_location::current().function_name(), SetThreadAffinityMask, GetCurrentThread(), aff_);
151} 171}
152 172
153// ################################################################################################# 173// #################################################################################################
@@ -215,24 +235,24 @@ static int pthread_attr_setschedpolicy(pthread_attr_t* attr, int policy)
215#endif // pthread_attr_setschedpolicy() 235#endif // pthread_attr_setschedpolicy()
216#endif // defined(__MINGW32__) || defined(__MINGW64__) 236#endif // defined(__MINGW32__) || defined(__MINGW64__)
217 237
218static void _PT_FAIL(int rc, const char* name, const char* file, int line) 238template <typename F, typename... ARGS>
239void PthreadInvoke(lua_State* const L_, std::string_view const& where_, F& f_, ARGS... args_)
219{ 240{
220 const char* why = (rc == EINVAL) ? "EINVAL" 241 auto const _rc{ std::invoke(f_, std::forward<ARGS>(args_)...) };
221 : (rc == EBUSY) ? "EBUSY" 242 if (_rc) {
222 : (rc == EPERM) ? "EPERM" 243 std::string_view const _funcname{ StripFuncName(where_) };
223 : (rc == ENOMEM) ? "ENOMEM" 244
224 : (rc == ESRCH) ? "ESRCH" 245 char const* _why = (_rc == EINVAL) ? "EINVAL"
225 : (rc == ENOTSUP) ? "ENOTSUP" 246 : (_rc == EBUSY) ? "EBUSY"
226 : "<UNKNOWN>"; 247 : (_rc == EPERM) ? "EPERM"
227 fprintf(stderr, "%s %d: %s failed, %d %s\n", file, line, name, rc, why); 248 : (_rc == ENOMEM) ? "ENOMEM"
228 abort(); 249 : (_rc == ESRCH) ? "ESRCH"
229} 250 : (_rc == ENOTSUP) ? "ENOTSUP"
230#define PT_CALL(call) \ 251 : "<UNKNOWN>";
231 { \ 252
232 int rc = call; \ 253 raise_luaL_error(L_, "%s() failed with code %s", _funcname.data(), _why);
233 if (rc != 0) \
234 _PT_FAIL(rc, #call, __FILE__, __LINE__); \
235 } 254 }
255}
236 256
237// array of 7 thread priority values, hand-tuned by platform so that we offer a uniform [-3,+3] public priority range 257// array of 7 thread priority values, hand-tuned by platform so that we offer a uniform [-3,+3] public priority range
238static int const gs_prio_remap[] = { 258static int const gs_prio_remap[] = {
@@ -336,8 +356,8 @@ static int const gs_prio_remap[] = {
336// 356//
337#define _PRIO_MODE SCHED_OTHER 357#define _PRIO_MODE SCHED_OTHER
338#define _PRIO_SCOPE PTHREAD_SCOPE_PROCESS 358#define _PRIO_SCOPE PTHREAD_SCOPE_PROCESS
339#define _PRIO_HI 31 359#define _PRIO_HI 15
340#define _PRIO_0 15 360#define _PRIO_0 7
341#define _PRIO_LO 1 361#define _PRIO_LO 1
342#else 362#else
343#error "Unknown OS: not implemented!" 363#error "Unknown OS: not implemented!"
@@ -357,7 +377,18 @@ static int const gs_prio_remap[] = {
357#endif // _PRIO_0 377#endif // _PRIO_0
358}; 378};
359 379
360void THREAD_SET_PRIORITY(int prio_, [[maybe_unused]] bool sudo_) 380// #################################################################################################
381
382std::pair<int, int> THREAD_NATIVE_PRIOS()
383{
384 int const _prio_min{ sched_get_priority_min(_PRIO_MODE) };
385 int const _prio_max{ sched_get_priority_max(_PRIO_MODE) };
386 return std::make_pair(_prio_min, _prio_max);
387}
388
389// #################################################################################################
390
391void THREAD_SET_PRIORITY(lua_State* const L_, int const prio_, NativePrioFlag const native_, [[maybe_unused]] SudoFlag const sudo_)
361{ 392{
362#ifdef PLATFORM_LINUX 393#ifdef PLATFORM_LINUX
363 if (!sudo_) // only root-privileged process can change priorities 394 if (!sudo_) // only root-privileged process can change priorities
@@ -366,13 +397,13 @@ void THREAD_SET_PRIORITY(int prio_, [[maybe_unused]] bool sudo_)
366 397
367 struct sched_param sp; 398 struct sched_param sp;
368 // prio range [-3,+3] was checked by the caller 399 // prio range [-3,+3] was checked by the caller
369 sp.sched_priority = gs_prio_remap[prio_ + 3]; 400 sp.sched_priority = native_ ? prio_ : gs_prio_remap[prio_ + 3];
370 PT_CALL(pthread_setschedparam(pthread_self(), _PRIO_MODE, &sp)); 401 PthreadInvoke(L_, std::source_location::current().function_name(), pthread_setschedparam, pthread_self(), _PRIO_MODE, &sp);
371} 402}
372 403
373// ################################################################################################# 404// #################################################################################################
374 405
375void THREAD_SET_PRIORITY(std::thread& thread_, int prio_, [[maybe_unused]] bool sudo_) 406void THREAD_SET_PRIORITY(lua_State* const L_, std::thread& thread_, int const prio_, NativePrioFlag const native_, [[maybe_unused]] SudoFlag const sudo_)
376{ 407{
377#ifdef PLATFORM_LINUX 408#ifdef PLATFORM_LINUX
378 if (!sudo_) // only root-privileged process can change priorities 409 if (!sudo_) // only root-privileged process can change priorities
@@ -381,28 +412,26 @@ void THREAD_SET_PRIORITY(std::thread& thread_, int prio_, [[maybe_unused]] bool
381 412
382 struct sched_param sp; 413 struct sched_param sp;
383 // prio range [-3,+3] was checked by the caller 414 // prio range [-3,+3] was checked by the caller
384 sp.sched_priority = gs_prio_remap[prio_ + 3]; 415 sp.sched_priority = native_ ? prio_ : gs_prio_remap[prio_ + 3];
385 PT_CALL(pthread_setschedparam(thread_.native_handle(), _PRIO_MODE, &sp)); 416 PthreadInvoke(L_, std::source_location::current().function_name(), pthread_setschedparam, thread_.native_handle(), _PRIO_MODE, &sp);
386} 417}
387 418
388// ################################################################################################# 419// #################################################################################################
389 420
390#ifdef __PROSPERO__ 421#ifdef __PROSPERO__
391 422
392void THREAD_SET_AFFINITY(unsigned int aff_) 423void THREAD_SET_AFFINITY(lua_State* const L_, unsigned int aff_)
393{ 424{
394 scePthreadSetaffinity(scePthreadSelf(), aff_); 425 PthreadInvoke(L_, std::source_location::current().function_name(), scePthreadSetaffinity, scePthreadSelf(), aff_);
395} 426}
396 427
397#else // __PROSPERO__ 428#else // __PROSPERO__
398 429
399void THREAD_SET_AFFINITY(unsigned int aff_) 430void THREAD_SET_AFFINITY(lua_State* const L_, unsigned int aff_)
400{ 431{
401#if HAVE_WIN32 // "hybrid": Win32 API is available, and pthread too 432#if HAVE_WIN32 // "hybrid": Win32 API is available, and pthread too
402 // since pthread_setaffinity_np can be missing (for example mingw), use win32 api instead 433 // since pthread_setaffinity_np can be missing (for example mingw), use win32 api instead
403 if (!SetThreadAffinityMask(GetCurrentThread(), aff_)) { 434 Win32Invoke(L_, std::source_location::current().function_name(), SetThreadAffinityMask, GetCurrentThread(), aff_);
404 FAIL("THREAD_SET_AFFINITY", GetLastError());
405 }
406#else // pure pthread 435#else // pure pthread
407 int bit = 0; 436 int bit = 0;
408#ifdef __NetBSD__ 437#ifdef __NetBSD__
@@ -422,12 +451,13 @@ void THREAD_SET_AFFINITY(unsigned int aff_)
422 aff_ >>= 1; 451 aff_ >>= 1;
423 } 452 }
424#ifdef __ANDROID__ 453#ifdef __ANDROID__
425 PT_CALL(sched_setaffinity(pthread_self(), sizeof(cpu_set_t), &cpuset)); 454
455 PthreadInvoke(L_, std::source_location::current().function_name(), sched_setaffinity, pthread_self(), sizeof(cpu_set_t), &cpuset);
426#elif defined(__NetBSD__) 456#elif defined(__NetBSD__)
427 PT_CALL(pthread_setaffinity_np(pthread_self(), cpuset_size(cpuset), cpuset)); 457 PthreadInvoke(L_, std::source_location::current().function_name(), pthread_setaffinity_np, pthread_self(), cpuset_size(cpuset), cpuset);
428 cpuset_destroy(cpuset); 458 cpuset_destroy(cpuset);
429#else 459#else
430 PT_CALL(pthread_setaffinity_np(pthread_self(), sizeof(cpu_set_t), &cpuset)); 460 PthreadInvoke(L_, std::source_location::current().function_name(), pthread_setaffinity_np, pthread_self(), sizeof(cpu_set_t), &cpuset);
431#endif 461#endif
432#endif // PLATFORM_MINGW 462#endif // PLATFORM_MINGW
433} 463}
@@ -447,9 +477,11 @@ void THREAD_SETNAME(std::string_view const& name_)
447 477
448void THREAD_SETNAME(std::string_view const& name_) 478void THREAD_SETNAME(std::string_view const& name_)
449{ 479{
450 // exact API to set the thread name is platform-dependant 480 // exact API to set the thread name is platform-dependent
451 // if you need to fix the build, or if you know how to fill a hole, tell me (bnt.germain@gmail.com) so that I can submit the fix in github. 481 // if you need to fix the build, or if you know how to fill a hole, tell me (bnt.germain@gmail.com) so that I can submit the fix in github.
452#if defined PLATFORM_BSD && !defined __NetBSD__ 482#if defined PLATFORM_MINGW
483 pthread_setname_np(pthread_self(), name_.data());
484#elif defined PLATFORM_BSD && !defined __NetBSD__
453 pthread_set_name_np(pthread_self(), name_.data()); 485 pthread_set_name_np(pthread_self(), name_.data());
454#elif defined PLATFORM_BSD && defined __NetBSD__ 486#elif defined PLATFORM_BSD && defined __NetBSD__
455 pthread_setname_np(pthread_self(), "%s", (void*) name_.data()); 487 pthread_setname_np(pthread_self(), "%s", (void*) name_.data());
diff --git a/src/threading.hpp b/src/threading.hpp
index 912c28f..07c1ab3 100644
--- a/src/threading.hpp
+++ b/src/threading.hpp
@@ -1,6 +1,7 @@
1#pragma once 1#pragma once
2 2
3#include "platform.h" 3#include "platform.h"
4#include "unique.hpp"
4 5
5#define THREADAPI_WINDOWS 1 6#define THREADAPI_WINDOWS 1
6#define THREADAPI_PTHREAD 2 7#define THREADAPI_PTHREAD 2
@@ -73,8 +74,15 @@ static constexpr int kThreadPrioMax{ +3 };
73// ################################################################################################# 74// #################################################################################################
74// ################################################################################################# 75// #################################################################################################
75 76
77DECLARE_UNIQUE_TYPE(SudoFlag, bool);
78DECLARE_UNIQUE_TYPE(NativePrioFlag, bool);
79
80std::pair<int, int> THREAD_NATIVE_PRIOS();
81
76void THREAD_SETNAME(std::string_view const& name_); 82void THREAD_SETNAME(std::string_view const& name_);
77void THREAD_SET_PRIORITY(int prio_, bool sudo_);
78void THREAD_SET_AFFINITY(unsigned int aff_);
79 83
80void THREAD_SET_PRIORITY(std::thread& thread_, int prio_, bool sudo_); 84void THREAD_SET_PRIORITY(lua_State* L_, int prio_, NativePrioFlag native_, SudoFlag sudo_);
85
86void THREAD_SET_AFFINITY(lua_State* L_, unsigned int aff_);
87
88void THREAD_SET_PRIORITY(lua_State* L_, std::thread& thread_, int prio_, NativePrioFlag native_, SudoFlag sudo_);
diff --git a/src/tools.cpp b/src/tools.cpp
index cbfefb0..cd1c593 100644
--- a/src/tools.cpp
+++ b/src/tools.cpp
@@ -45,13 +45,29 @@ static constexpr RegistryUniqueKey kLookupCacheRegKey{ 0x9BF75F84E54B691Bull };
45 45
46// ################################################################################################# 46// #################################################################################################
47 47
48static constexpr int kWriterReturnCode{ 666 }; 48namespace {
49[[nodiscard]] 49 namespace local {
50static int dummy_writer([[maybe_unused]] lua_State* const L_, [[maybe_unused]] void const* p_, [[maybe_unused]] size_t sz_, [[maybe_unused]] void* ud_) 50 static int buf_writer([[maybe_unused]] lua_State* const L_, void const* b_, size_t size_, void* ud_)
51{ 51 {
52 // always fail with this code 52 auto* const _B{ static_cast<luaL_Buffer*>(ud_) };
53 return kWriterReturnCode; 53 if (b_ && size_) {
54} 54 luaL_addlstring(_B, static_cast<char const*>(b_), size_);
55 }
56 return 0;
57 }
58
59 static constexpr int kWriterReturnCode{ 666 };
60 [[nodiscard]]
61 static int dummy_writer([[maybe_unused]] lua_State* const L_, [[maybe_unused]] void const* p_, [[maybe_unused]] size_t sz_, [[maybe_unused]] void* ud_)
62 {
63 // always fail with this code
64 return kWriterReturnCode;
65 }
66
67 } // namespace local
68} // namespace
69
70// #################################################################################################
55 71
56/* 72/*
57 * differentiation between C, bytecode and JIT-fast functions 73 * differentiation between C, bytecode and JIT-fast functions
@@ -59,30 +75,28 @@ static int dummy_writer([[maybe_unused]] lua_State* const L_, [[maybe_unused]] v
59 * +-------------------+------------+----------+ 75 * +-------------------+------------+----------+
60 * | bytecode | C function | JIT-fast | 76 * | bytecode | C function | JIT-fast |
61 * +-----------------+-------------------+------------+----------+ 77 * +-----------------+-------------------+------------+----------+
62 * | lua_topointer | | | | 78 * | lua_tocfunction | nullptr | <some p> | nullptr |
63 * +-----------------+-------------------+------------+----------+ 79 * +-----------------+-------------------+------------+----------+
64 * | lua_tocfunction | nullptr | | nullptr | 80 * | luaW_dump | kWriterReturnCode | 1 | 1 |
65 * +-----------------+-------------------+------------+----------+
66 * | luaG_dump | kWriterReturnCode | 1 | 1 |
67 * +-----------------+-------------------+------------+----------+ 81 * +-----------------+-------------------+------------+----------+
68 */ 82 */
69 83
70[[nodiscard]] 84[[nodiscard]]
71FuncSubType luaG_getfuncsubtype(lua_State* const L_, StackIndex const i_) 85FuncSubType luaW_getfuncsubtype(lua_State* const L_, StackIndex const i_)
72{ 86{
73 if (lua_tocfunction(L_, i_)) { // nullptr for LuaJIT-fast && bytecode functions 87 if (lua_tocfunction(L_, i_)) { // nullptr for LuaJIT-fast && bytecode functions
74 return FuncSubType::Native; 88 return FuncSubType::Native;
75 } 89 }
76 90
77 // luaG_dump expects the function at the top of the stack 91 // luaW_dump expects the function at the top of the stack
78 int const _popCount{ (luaG_absindex(L_, i_) == lua_gettop(L_)) ? 0 : (lua_pushvalue(L_, i_), 1) }; 92 int const _popCount{ (luaW_absindex(L_, i_) == lua_gettop(L_)) ? 0 : (lua_pushvalue(L_, i_), 1) };
79 // here we either have a Lua bytecode or a LuaJIT-compiled function 93 // here we either have a Lua bytecode or a LuaJIT-compiled function
80 int const _dumpres{ luaG_dump(L_, dummy_writer, nullptr, 0) }; 94 int const _dumpres{ luaW_dump(L_, local::dummy_writer, nullptr, 0) };
81 if (_popCount > 0) { 95 if (_popCount > 0) {
82 lua_pop(L_, _popCount); 96 lua_pop(L_, _popCount);
83 } 97 }
84 if (_dumpres == kWriterReturnCode) { 98 if (_dumpres == local::kWriterReturnCode) {
85 // anytime we get kWriterReturnCode, this means that luaG_dump() attempted a dump 99 // anytime we get kWriterReturnCode, this means that luaW_dump() attempted a dump
86 return FuncSubType::Bytecode; 100 return FuncSubType::Bytecode;
87 } 101 }
88 // we didn't try to dump, therefore this is a LuaJIT-fast function 102 // we didn't try to dump, therefore this is a LuaJIT-fast function
@@ -92,7 +106,6 @@ FuncSubType luaG_getfuncsubtype(lua_State* const L_, StackIndex const i_)
92// ################################################################################################# 106// #################################################################################################
93 107
94namespace tools { 108namespace tools {
95
96 // inspired from tconcat() in ltablib.c 109 // inspired from tconcat() in ltablib.c
97 [[nodiscard]] 110 [[nodiscard]]
98 std::string_view PushFQN(lua_State* const L_, StackIndex const t_) 111 std::string_view PushFQN(lua_State* const L_, StackIndex const t_)
@@ -115,9 +128,23 @@ namespace tools {
115 // &b is popped at that point (-> replaced by the result) 128 // &b is popped at that point (-> replaced by the result)
116 luaL_pushresult(&_b); // L_: ... {} ... "<result>" 129 luaL_pushresult(&_b); // L_: ... {} ... "<result>"
117 STACK_CHECK(L_, 1); 130 STACK_CHECK(L_, 1);
118 return luaG_tostring(L_, kIdxTop); 131 return luaW_tostring(L_, kIdxTop);
119 } 132 }
120 133
134 // #############################################################################################
135
136 void PushFunctionBytecode(SourceState const L1_, DestState const L2_, int const strip_)
137 {
138 luaL_Buffer B{};
139 STACK_CHECK_START_REL(L1_, 0);
140 STACK_CHECK_START_REL(L2_, 0);
141 STACK_GROW(L2_, 2);
142 luaL_buffinit(L2_, &B); // L1_: ... f L2_: ... <B stuff>
143 luaW_dump(L1_, local::buf_writer, &B, strip_);
144 luaL_pushresult(&B); // L2_: ... "<bytecode>"
145 STACK_CHECK(L2_, 1);
146 STACK_CHECK(L1_, 0);
147 }
121} // namespace tools 148} // namespace tools
122 149
123// ################################################################################################# 150// #################################################################################################
@@ -145,10 +172,10 @@ static void update_lookup_entry(lua_State* const L_, StackIndex const ctxBase_,
145 // first, raise an error if the function is already known 172 // first, raise an error if the function is already known
146 lua_pushvalue(L_, -1); // L_: ... {bfc} k o o 173 lua_pushvalue(L_, -1); // L_: ... {bfc} k o o
147 lua_rawget(L_, _dest); // L_: ... {bfc} k o name? 174 lua_rawget(L_, _dest); // L_: ... {bfc} k o name?
148 std::string_view const _prevName{ luaG_tostring(L_, kIdxTop) }; // nullptr if we got nil (first encounter of this object) 175 std::string_view const _prevName{ luaW_tostring(L_, kIdxTop) }; // nullptr if we got nil (first encounter of this object)
149 // push name in fqn stack (note that concatenation will crash if name is a not string or a number) 176 // push name in fqn stack (note that concatenation will crash if name is a not string or a number)
150 lua_pushvalue(L_, -3); // L_: ... {bfc} k o name? k 177 lua_pushvalue(L_, -3); // L_: ... {bfc} k o name? k
151 LUA_ASSERT(L_, luaG_type(L_, kIdxTop) == LuaType::NUMBER || luaG_type(L_, kIdxTop) == LuaType::STRING); 178 LUA_ASSERT(L_, luaW_type(L_, kIdxTop) == LuaType::NUMBER || luaW_type(L_, kIdxTop) == LuaType::STRING);
152 TableIndex const _deeper{ depth_ + 1 }; 179 TableIndex const _deeper{ depth_ + 1 };
153 lua_rawseti(L_, _fqn, _deeper); // L_: ... {bfc} k o name? 180 lua_rawseti(L_, _fqn, _deeper); // L_: ... {bfc} k o name?
154 // generate name 181 // generate name
@@ -161,7 +188,7 @@ static void update_lookup_entry(lua_State* const L_, StackIndex const ctxBase_,
161 // Therefore, when we encounter an object for which a name was previously registered, we need to select a single name 188 // Therefore, when we encounter an object for which a name was previously registered, we need to select a single name
162 // based on some sorting order so that we end up with the same name in all databases whatever order the table walk yielded 189 // based on some sorting order so that we end up with the same name in all databases whatever order the table walk yielded
163 if (!_prevName.empty() && ((_prevName.size() < _newName.size()) || (_prevName <= _newName))) { 190 if (!_prevName.empty() && ((_prevName.size() < _newName.size()) || (_prevName <= _newName))) {
164 DEBUGSPEW_CODE(DebugSpew(_U) << luaG_typename(L_, StackIndex{ -3 }) << " '" << _newName << "' remains named '" << _prevName << "'" << std::endl); 191 DEBUGSPEW_CODE(DebugSpew(_U) << luaW_typename(L_, StackIndex{ -3 }) << " '" << _newName << "' remains named '" << _prevName << "'" << std::endl);
165 // the previous name is 'smaller' than the one we just generated: keep it! 192 // the previous name is 'smaller' than the one we just generated: keep it!
166 lua_pop(L_, 3); // L_: ... {bfc} k 193 lua_pop(L_, 3); // L_: ... {bfc} k
167 } else { 194 } else {
@@ -175,7 +202,7 @@ static void update_lookup_entry(lua_State* const L_, StackIndex const ctxBase_,
175 } else { 202 } else {
176 lua_remove(L_, -2); // L_: ... {bfc} k o "f.q.n" 203 lua_remove(L_, -2); // L_: ... {bfc} k o "f.q.n"
177 } 204 }
178 DEBUGSPEW_CODE(DebugSpew(_U) << luaG_typename(L_, StackIndex{ -2 }) << " '" << _newName << "'" << std::endl); 205 DEBUGSPEW_CODE(DebugSpew(_U) << luaW_typename(L_, StackIndex{ -2 }) << " '" << _newName << "'" << std::endl);
179 // prepare the stack for database feed 206 // prepare the stack for database feed
180 lua_pushvalue(L_, -1); // L_: ... {bfc} k o "f.q.n" "f.q.n" 207 lua_pushvalue(L_, -1); // L_: ... {bfc} k o "f.q.n" "f.q.n"
181 lua_pushvalue(L_, -3); // L_: ... {bfc} k o "f.q.n" "f.q.n" o 208 lua_pushvalue(L_, -3); // L_: ... {bfc} k o "f.q.n" "f.q.n" o
@@ -210,7 +237,7 @@ static void populate_lookup_table_recur(lua_State* const L_, StackIndex const db
210 STACK_CHECK_START_REL(L_, 0); // L_: ... {i_} 237 STACK_CHECK_START_REL(L_, 0); // L_: ... {i_}
211 238
212 // if object is a userdata, replace it by its metatable 239 // if object is a userdata, replace it by its metatable
213 if (luaG_type(L_, i_) == LuaType::USERDATA) { 240 if (luaW_type(L_, i_) == LuaType::USERDATA) {
214 lua_getmetatable(L_, i_); // L_: ... {i_} mt 241 lua_getmetatable(L_, i_); // L_: ... {i_} mt
215 lua_replace(L_, i_); // L_: ... {i_} 242 lua_replace(L_, i_); // L_: ... {i_}
216 } 243 }
@@ -239,7 +266,7 @@ static void populate_lookup_table_recur(lua_State* const L_, StackIndex const db
239 lua_pushnil(L_); // L_: ... {i_} {bfc} nil 266 lua_pushnil(L_); // L_: ... {i_} {bfc} nil
240 while (lua_next(L_, i_) != 0) { // L_: ... {i_} {bfc} k v 267 while (lua_next(L_, i_) != 0) { // L_: ... {i_} {bfc} k v
241 // just for debug, not actually needed 268 // just for debug, not actually needed
242 // std::string_view const _key{ (luaG_type(L_, -2) == LuaType::STRING) ? luaG_tostring(L_, -2) : "not a string" }; 269 // std::string_view const _key{ (luaW_type(L_, -2) == LuaType::STRING) ? luaW_tostring(L_, -2) : "not a string" };
243 // subtable: process it recursively 270 // subtable: process it recursively
244 if (lua_istable(L_, kIdxTop)) { // L_: ... {i_} {bfc} k {} 271 if (lua_istable(L_, kIdxTop)) { // L_: ... {i_} {bfc} k {}
245 // increment visit count to make sure we will actually scan it at this recursive level 272 // increment visit count to make sure we will actually scan it at this recursive level
@@ -256,11 +283,11 @@ static void populate_lookup_table_recur(lua_State* const L_, StackIndex const db
256 lua_rawset(L_, _breadthFirstCache); // L_: ... {i_} {bfc} k {} 283 lua_rawset(L_, _breadthFirstCache); // L_: ... {i_} {bfc} k {}
257 // generate a name, and if we already had one name, keep whichever is the shorter 284 // generate a name, and if we already had one name, keep whichever is the shorter
258 update_lookup_entry(L_, dbIdx_, depth_); // L_: ... {i_} {bfc} k 285 update_lookup_entry(L_, dbIdx_, depth_); // L_: ... {i_} {bfc} k
259 } else if (lua_isfunction(L_, kIdxTop) && (luaG_getfuncsubtype(L_, kIdxTop) != FuncSubType::Bytecode)) { 286 } else if (lua_isfunction(L_, kIdxTop) && (luaW_getfuncsubtype(L_, kIdxTop) != FuncSubType::Bytecode)) {
260 // generate a name, and if we already had one name, keep whichever is the shorter 287 // generate a name, and if we already had one name, keep whichever is the shorter
261 // this pops the function from the stack 288 // this pops the function from the stack
262 update_lookup_entry(L_, dbIdx_, depth_); // L_: ... {i_} {bfc} k 289 update_lookup_entry(L_, dbIdx_, depth_); // L_: ... {i_} {bfc} k
263 } else if (luaG_type(L_, kIdxTop) == LuaType::USERDATA) { 290 } else if (luaW_type(L_, kIdxTop) == LuaType::USERDATA) {
264 // generate a name, and if we already had one name, keep whichever is the shorter 291 // generate a name, and if we already had one name, keep whichever is the shorter
265 // this pops the userdata from the stack 292 // this pops the userdata from the stack
266 update_lookup_entry(L_, dbIdx_, depth_); // L_: ... {i_} {bfc} k 293 update_lookup_entry(L_, dbIdx_, depth_); // L_: ... {i_} {bfc} k
@@ -273,13 +300,13 @@ static void populate_lookup_table_recur(lua_State* const L_, StackIndex const db
273 TableIndex const _deeper{ depth_ + 1 }; 300 TableIndex const _deeper{ depth_ + 1 };
274 lua_pushnil(L_); // L_: ... {i_} {bfc} nil 301 lua_pushnil(L_); // L_: ... {i_} {bfc} nil
275 while (lua_next(L_, _breadthFirstCache) != 0) { // L_: ... {i_} {bfc} k {} 302 while (lua_next(L_, _breadthFirstCache) != 0) { // L_: ... {i_} {bfc} k {}
276 DEBUGSPEW_CODE(std::string_view const _key{ (luaG_type(L_, StackIndex{ -2 }) == LuaType::STRING) ? luaG_tostring(L_, StackIndex{ -2 }) : std::string_view{ "<not a string>" } }); 303 DEBUGSPEW_CODE(std::string_view const _key{ (luaW_type(L_, StackIndex{ -2 }) == LuaType::STRING) ? luaW_tostring(L_, StackIndex{ -2 }) : std::string_view{ "<not a string>" } });
277 DEBUGSPEW_CODE(DebugSpew(_U) << "table '"<< _key <<"'" << std::endl); 304 DEBUGSPEW_CODE(DebugSpew(_U) << "table '"<< _key <<"'" << std::endl);
278 DEBUGSPEW_CODE(DebugSpewIndentScope _scope2{ _U }); 305 DEBUGSPEW_CODE(DebugSpewIndentScope _scope2{ _U });
279 // un-visit this table in case we do need to process it 306 // un-visit this table in case we do need to process it
280 lua_pushvalue(L_, -1); // L_: ... {i_} {bfc} k {} {} 307 lua_pushvalue(L_, -1); // L_: ... {i_} {bfc} k {} {}
281 lua_rawget(L_, _cache); // L_: ... {i_} {bfc} k {} n 308 lua_rawget(L_, _cache); // L_: ... {i_} {bfc} k {} n
282 LUA_ASSERT(L_, luaG_type(L_, kIdxTop) == LuaType::NUMBER); 309 LUA_ASSERT(L_, luaW_type(L_, kIdxTop) == LuaType::NUMBER);
283 _visit_count = lua_tointeger(L_, -1) - 1; 310 _visit_count = lua_tointeger(L_, -1) - 1;
284 lua_pop(L_, 1); // L_: ... {i_} {bfc} k {} 311 lua_pop(L_, 1); // L_: ... {i_} {bfc} k {}
285 lua_pushvalue(L_, -1); // L_: ... {i_} {bfc} k {} {} 312 lua_pushvalue(L_, -1); // L_: ... {i_} {bfc} k {} {}
@@ -312,7 +339,7 @@ namespace tools {
312 // create a "fully.qualified.name" <-> function equivalence database 339 // create a "fully.qualified.name" <-> function equivalence database
313 void PopulateFuncLookupTable(lua_State* const L_, StackIndex const i_, std::string_view const& name_) 340 void PopulateFuncLookupTable(lua_State* const L_, StackIndex const i_, std::string_view const& name_)
314 { 341 {
315 StackIndex const _in_base{ luaG_absindex(L_, i_) }; 342 StackIndex const _in_base{ luaW_absindex(L_, i_) };
316 DEBUGSPEW_CODE(Universe* _U = Universe::Get(L_)); 343 DEBUGSPEW_CODE(Universe* _U = Universe::Get(L_));
317 std::string_view _name{ name_.empty() ? std::string_view{} : name_ }; 344 std::string_view _name{ name_.empty() ? std::string_view{} : name_ };
318 DEBUGSPEW_CODE(DebugSpew(_U) << L_ << ": PopulateFuncLookupTable('" << _name << "')" << std::endl); 345 DEBUGSPEW_CODE(DebugSpew(_U) << L_ << ": PopulateFuncLookupTable('" << _name << "')" << std::endl);
@@ -323,24 +350,24 @@ namespace tools {
323 StackIndex const _dbIdx{ lua_gettop(L_) }; 350 StackIndex const _dbIdx{ lua_gettop(L_) };
324 STACK_CHECK(L_, 1); 351 STACK_CHECK(L_, 1);
325 LUA_ASSERT(L_, lua_istable(L_, -1)); 352 LUA_ASSERT(L_, lua_istable(L_, -1));
326 LuaType const _moduleType{ luaG_type(L_, _in_base) }; 353 LuaType const _moduleType{ luaW_type(L_, _in_base) };
327 if ((_moduleType == LuaType::FUNCTION) || (_moduleType == LuaType::USERDATA)) { // for example when a module is a simple function 354 if ((_moduleType == LuaType::FUNCTION) || (_moduleType == LuaType::USERDATA)) { // for example when a module is a simple function
328 if (_name.empty()) { 355 if (_name.empty()) {
329 _name = "nullptr"; 356 _name = "nullptr";
330 } 357 }
331 lua_pushvalue(L_, _in_base); // L_: {} f 358 lua_pushvalue(L_, _in_base); // L_: {} f
332 luaG_pushstring(L_, _name); // L_: {} f name_ 359 luaW_pushstring(L_, _name); // L_: {} f name_
333 lua_rawset(L_, -3); // L_: {} 360 lua_rawset(L_, -3); // L_: {}
334 luaG_pushstring(L_, _name); // L_: {} name_ 361 luaW_pushstring(L_, _name); // L_: {} name_
335 lua_pushvalue(L_, _in_base); // L_: {} name_ f 362 lua_pushvalue(L_, _in_base); // L_: {} name_ f
336 lua_rawset(L_, -3); // L_: {} 363 lua_rawset(L_, -3); // L_: {}
337 lua_pop(L_, 1); // L_: 364 lua_pop(L_, 1); // L_:
338 } else if (luaG_type(L_, _in_base) == LuaType::TABLE) { 365 } else if (luaW_type(L_, _in_base) == LuaType::TABLE) {
339 lua_newtable(L_); // L_: {} {fqn} 366 lua_newtable(L_); // L_: {} {fqn}
340 TableIndex _startDepth{ 0 }; 367 TableIndex _startDepth{ 0 };
341 if (!_name.empty()) { 368 if (!_name.empty()) {
342 STACK_CHECK(L_, 2); 369 STACK_CHECK(L_, 2);
343 luaG_pushstring(L_, _name); // L_: {} {fqn} "name" 370 luaW_pushstring(L_, _name); // L_: {} {fqn} "name"
344 // generate a name, and if we already had one name, keep whichever is the shorter 371 // generate a name, and if we already had one name, keep whichever is the shorter
345 lua_pushvalue(L_, _in_base); // L_: {} {fqn} "name" t 372 lua_pushvalue(L_, _in_base); // L_: {} {fqn} "name" t
346 update_lookup_entry(L_, _dbIdx, _startDepth); // L_: {} {fqn} "name" 373 update_lookup_entry(L_, _dbIdx, _startDepth); // L_: {} {fqn} "name"
@@ -355,7 +382,7 @@ namespace tools {
355 lua_pop(L_, 3); // L_: 382 lua_pop(L_, 3); // L_:
356 } else { 383 } else {
357 lua_pop(L_, 1); // L_: 384 lua_pop(L_, 1); // L_:
358 raise_luaL_error(L_, "unsupported module type %s", luaG_typename(L_, _in_base).data()); 385 raise_luaL_error(L_, "unsupported module type %s", luaW_typename(L_, _in_base).data());
359 } 386 }
360 STACK_CHECK(L_, 0); 387 STACK_CHECK(L_, 0);
361 } 388 }
@@ -373,7 +400,7 @@ namespace tools {
373 +[](lua_State* L_) 400 +[](lua_State* L_)
374 { 401 {
375 int const _args{ lua_gettop(L_) }; // L_: args... 402 int const _args{ lua_gettop(L_) }; // L_: args...
376 //[[maybe_unused]] std::string_view const _modname{ luaG_checkstring(L_, 1) }; 403 //[[maybe_unused]] std::string_view const _modname{ luaW_checkstring(L_, 1) };
377 404
378 STACK_GROW(L_, 1); 405 STACK_GROW(L_, 1);
379 406
diff --git a/src/tools.hpp b/src/tools.hpp
index 420b5f8..c555344 100644
--- a/src/tools.hpp
+++ b/src/tools.hpp
@@ -21,7 +21,7 @@ enum class [[nodiscard]] FuncSubType
21}; 21};
22 22
23[[nodiscard]] 23[[nodiscard]]
24FuncSubType luaG_getfuncsubtype(lua_State* L_, StackIndex i_); 24FuncSubType luaW_getfuncsubtype(lua_State* L_, StackIndex i_);
25 25
26// ################################################################################################# 26// #################################################################################################
27 27
@@ -37,5 +37,6 @@ namespace tools {
37 void PopulateFuncLookupTable(lua_State* L_, StackIndex i_, std::string_view const& name_); 37 void PopulateFuncLookupTable(lua_State* L_, StackIndex i_, std::string_view const& name_);
38 [[nodiscard]] 38 [[nodiscard]]
39 std::string_view PushFQN(lua_State* L_, StackIndex t_); 39 std::string_view PushFQN(lua_State* L_, StackIndex t_);
40 void PushFunctionBytecode(SourceState L1_, DestState L2_, int strip_);
40 void SerializeRequire(lua_State* L_); 41 void SerializeRequire(lua_State* L_);
41} // namespace tools 42} // namespace tools
diff --git a/src/tracker.cpp b/src/tracker.cpp
index 8b06522..34866dd 100644
--- a/src/tracker.cpp
+++ b/src/tracker.cpp
@@ -96,7 +96,7 @@ int LaneTracker::pushThreadsTable(lua_State* L_) const
96 while (_lane != TRACKING_END) { 96 while (_lane != TRACKING_END) {
97 // insert a { name='<name>', status='<status>' } tuple, so that several lanes with the same name can't clobber each other 97 // insert a { name='<name>', status='<status>' } tuple, so that several lanes with the same name can't clobber each other
98 lua_createtable(L_, 0, 2); // L_: {} {} 98 lua_createtable(L_, 0, 2); // L_: {} {}
99 luaG_pushstring(L_, _lane->getDebugName()); // L_: {} {} "name" 99 luaW_pushstring(L_, _lane->getDebugName()); // L_: {} {} "name"
100 lua_setfield(L_, -2, "name"); // L_: {} {} 100 lua_setfield(L_, -2, "name"); // L_: {} {}
101 _lane->pushStatusString(L_); // L_: {} {} "<status>" 101 _lane->pushStatusString(L_); // L_: {} {} "<status>"
102 lua_setfield(L_, -2, "status"); // L_: {} {} 102 lua_setfield(L_, -2, "status"); // L_: {} {}
diff --git a/src/uniquekey.hpp b/src/uniquekey.hpp
index 4c9eb58..ace21c4 100644
--- a/src/uniquekey.hpp
+++ b/src/uniquekey.hpp
@@ -80,7 +80,7 @@ class RegistryUniqueKey final
80 STACK_GROW(L_, 1); 80 STACK_GROW(L_, 1);
81 STACK_CHECK_START_REL(L_, 0); 81 STACK_CHECK_START_REL(L_, 0);
82 pushValue(L_); // L_: ... {}|nil 82 pushValue(L_); // L_: ... {}|nil
83 T* const value{ luaG_tolightuserdata<T>(L_, kIdxTop) }; 83 T* const value{ luaW_tolightuserdata<T>(L_, kIdxTop) };
84 lua_pop(L_, 1); // L_: ... 84 lua_pop(L_, 1); // L_: ...
85 STACK_CHECK(L_, 0); 85 STACK_CHECK(L_, 0);
86 return value; 86 return value;
@@ -125,8 +125,8 @@ class RegistryUniqueKey final
125 if (!mode_.empty()) { 125 if (!mode_.empty()) {
126 STACK_GROW(L_, 3); 126 STACK_GROW(L_, 3);
127 lua_createtable(L_, 0, 1); // L_: {} mt 127 lua_createtable(L_, 0, 1); // L_: {} mt
128 luaG_pushstring(L_, "__mode"); // L_: {} mt "__mode" 128 luaW_pushstring(L_, "__mode"); // L_: {} mt "__mode"
129 luaG_pushstring(L_, mode_); // L_: {} mt "__mode" mode 129 luaW_pushstring(L_, mode_); // L_: {} mt "__mode" mode
130 lua_rawset(L_, -3); // L_: {} mt 130 lua_rawset(L_, -3); // L_: {} mt
131 lua_setmetatable(L_, -2); // L_: {} 131 lua_setmetatable(L_, -2); // L_: {}
132 } 132 }
diff --git a/src/universe.cpp b/src/universe.cpp
index 89ad02a..4db036b 100644
--- a/src/universe.cpp
+++ b/src/universe.cpp
@@ -51,6 +51,16 @@ static constexpr RegistryUniqueKey kUniverseFullRegKey{ 0x1C2D76870DD9DD9Full };
51 51
52// ################################################################################################# 52// #################################################################################################
53 53
54[[nodiscard]]
55void* ProtectedAllocator::Protected_lua_Alloc(void* const ud_, void* const ptr_, size_t const osize_, size_t const nsize_)
56{
57 ProtectedAllocator* const _allocator{ static_cast<ProtectedAllocator*>(ud_) };
58 std::lock_guard<std::mutex> _guard{ _allocator->mutex };
59 return _allocator->alloc(ptr_, osize_, nsize_);
60}
61
62// #################################################################################################
63
54Universe::Universe() 64Universe::Universe()
55{ 65{
56 //--- 66 //---
@@ -101,18 +111,18 @@ void Universe::callOnStateCreate(lua_State* const L_, lua_State* const from_, Lo
101 } 111 }
102 kConfigRegKey.pushValue(L_); // L_: config 112 kConfigRegKey.pushValue(L_); // L_: config
103 STACK_CHECK(L_, 1); 113 STACK_CHECK(L_, 1);
104 LuaType const _funcType{ luaG_getfield(L_, kIdxTop, kOnStateCreate) }; // L_: config on_state_create() 114 LuaType const _funcType{ luaW_getfield(L_, kIdxTop, kOnStateCreate) }; // L_: config on_state_create()
105 if (_funcType != LuaType::FUNCTION) { 115 if (_funcType != LuaType::FUNCTION) {
106 raise_luaL_error(L_, "INTERNAL ERROR: %s is a %s, not a function", kOnStateCreate.data(), luaG_typename(L_, _funcType).data()); 116 raise_luaL_error(L_, "INTERNAL ERROR: %s is a %s, not a function", kOnStateCreate.data(), luaW_typename(L_, _funcType).data());
107 } 117 }
108 lua_remove(L_, -2); // L_: on_state_create() 118 lua_remove(L_, -2); // L_: on_state_create()
109 } 119 }
110 STACK_CHECK(L_, 1); 120 STACK_CHECK(L_, 1);
111 // capture error and raise it in caller state 121 // capture error and raise it in caller state
112 std::string_view const _stateType{ mode_ == LookupMode::LaneBody ? "lane" : "keeper" }; 122 std::string_view const _stateType{ mode_ == LookupMode::LaneBody ? "lane" : "keeper" };
113 luaG_pushstring(L_, _stateType); // L_: on_state_create() "<type>" 123 luaW_pushstring(L_, _stateType); // L_: on_state_create() "<type>"
114 if (lua_pcall(L_, 1, 0, 0) != LUA_OK) { 124 if (lua_pcall(L_, 1, 0, 0) != LUA_OK) {
115 raise_luaL_error(from_, "%s failed in %s: \"%s\"", kOnStateCreate.data(), _stateType.data(), lua_isstring(L_, -1) ? luaG_tostring(L_, kIdxTop).data() : luaG_typename(L_, kIdxTop).data()); 125 raise_luaL_error(from_, "%s failed in %s: \"%s\"", kOnStateCreate.data(), _stateType.data(), lua_isstring(L_, -1) ? luaW_tostring(L_, kIdxTop).data() : luaW_typename(L_, kIdxTop).data());
116 } 126 }
117 STACK_CHECK(L_, 0); 127 STACK_CHECK(L_, 0);
118} 128}
@@ -127,14 +137,14 @@ Universe* Universe::Create(lua_State* const L_)
127 static constexpr StackIndex kIdxSettings{ 1 }; 137 static constexpr StackIndex kIdxSettings{ 1 };
128 LUA_ASSERT(L_, lua_gettop(L_) == 1 && lua_istable(L_, 1)); 138 LUA_ASSERT(L_, lua_gettop(L_) == 1 && lua_istable(L_, 1));
129 STACK_CHECK_START_REL(L_, 0); // L_: settings 139 STACK_CHECK_START_REL(L_, 0); // L_: settings
130 std::ignore = luaG_getfield(L_, kIdxSettings, "nb_user_keepers"); // L_: settings nb_user_keepers 140 std::ignore = luaW_getfield(L_, kIdxSettings, "nb_user_keepers"); // L_: settings nb_user_keepers
131 int const _nbUserKeepers{ static_cast<int>(lua_tointeger(L_, -1)) + 1}; 141 int const _nbUserKeepers{ static_cast<int>(lua_tointeger(L_, -1)) + 1};
132 lua_pop(L_, 1); // L_: settings 142 lua_pop(L_, 1); // L_: settings
133 if (_nbUserKeepers < 1) { 143 if (_nbUserKeepers < 1) {
134 raise_luaL_error(L_, "Bad number of additional keepers (%d)", _nbUserKeepers); 144 raise_luaL_error(L_, "Bad number of additional keepers (%d)", _nbUserKeepers);
135 } 145 }
136 STACK_CHECK(L_, 0); 146 STACK_CHECK(L_, 0);
137 std::ignore = luaG_getfield(L_, kIdxSettings, "keepers_gc_threshold"); // L_: settings keepers_gc_threshold 147 std::ignore = luaW_getfield(L_, kIdxSettings, "keepers_gc_threshold"); // L_: settings keepers_gc_threshold
138 int const _keepers_gc_threshold{ static_cast<int>(lua_tointeger(L_, -1)) }; 148 int const _keepers_gc_threshold{ static_cast<int>(lua_tointeger(L_, -1)) };
139 lua_pop(L_, 1); // L_: settings 149 lua_pop(L_, 1); // L_: settings
140 STACK_CHECK(L_, 0); 150 STACK_CHECK(L_, 0);
@@ -147,22 +157,30 @@ Universe* Universe::Create(lua_State* const L_)
147 157
148 DEBUGSPEW_CODE(DebugSpewIndentScope _scope{ _U }); 158 DEBUGSPEW_CODE(DebugSpewIndentScope _scope{ _U });
149 lua_createtable(L_, 0, 1); // L_: settings universe {mt} 159 lua_createtable(L_, 0, 1); // L_: settings universe {mt}
150 std::ignore = luaG_getfield(L_, kIdxSettings, "shutdown_timeout"); // L_: settings universe {mt} shutdown_timeout 160 std::ignore = luaW_getfield(L_, kIdxSettings, "shutdown_timeout"); // L_: settings universe {mt} shutdown_timeout
151 lua_pushcclosure(L_, UniverseGC, 1); // L_: settings universe {mt} UniverseGC 161 lua_pushcclosure(L_, UniverseGC, 1); // L_: settings universe {mt} UniverseGC
152 lua_setfield(L_, -2, "__gc"); // L_: settings universe {mt} 162 lua_setfield(L_, -2, "__gc"); // L_: settings universe {mt}
153 lua_setmetatable(L_, -2); // L_: settings universe 163 lua_setmetatable(L_, -2); // L_: settings universe
154 lua_pop(L_, 1); // L_: settings 164 lua_pop(L_, 1); // L_: settings
155 165
156 std::ignore = luaG_getfield(L_, kIdxSettings, "strip_functions"); // L_: settings strip_functions 166 std::ignore = luaW_getfield(L_, kIdxSettings, "linda_wake_period"); // L_: settings linda_wake_period
167 if (luaW_type(L_, kIdxTop) == LuaType::NUMBER) {
168 _U->lindaWakePeriod = lua_Duration{ lua_tonumber(L_, kIdxTop) };
169 } else {
170 LUA_ASSERT(L_, luaW_tostring(L_, kIdxTop) == "never");
171 }
172 lua_pop(L_, 1); // L_: settings
173
174 std::ignore = luaW_getfield(L_, kIdxSettings, "strip_functions"); // L_: settings strip_functions
157 _U->stripFunctions = lua_toboolean(L_, -1) ? true : false; 175 _U->stripFunctions = lua_toboolean(L_, -1) ? true : false;
158 lua_pop(L_, 1); // L_: settings 176 lua_pop(L_, 1); // L_: settings
159 177
160 std::ignore = luaG_getfield(L_, kIdxSettings, "verbose_errors"); // L_: settings verbose_errors 178 std::ignore = luaW_getfield(L_, kIdxSettings, "verbose_errors"); // L_: settings verbose_errors
161 _U->verboseErrors = lua_toboolean(L_, -1) ? true : false; 179 _U->verboseErrors = lua_toboolean(L_, -1) ? true : false;
162 lua_pop(L_, 1); // L_: settings 180 lua_pop(L_, 1); // L_: settings
163 181
164 // tracking 182 // tracking
165 std::ignore = luaG_getfield(L_, kIdxSettings, "track_lanes"); // L_: settings track_lanes 183 std::ignore = luaW_getfield(L_, kIdxSettings, "track_lanes"); // L_: settings track_lanes
166 if (lua_toboolean(L_, -1)) { 184 if (lua_toboolean(L_, -1)) {
167 _U->tracker.activate(); 185 _U->tracker.activate();
168 } 186 }
@@ -170,8 +188,8 @@ Universe* Universe::Create(lua_State* const L_)
170 188
171 // Linked chains handling 189 // Linked chains handling
172 _U->selfdestructFirst = SELFDESTRUCT_END; 190 _U->selfdestructFirst = SELFDESTRUCT_END;
173 _U->initializeAllocatorFunction(L_); 191 _U->initializeAllocatorFunction(L_); // this can raise an error
174 _U->initializeOnStateCreate(L_); 192 _U->initializeOnStateCreate(L_); // this can raise an error
175 _U->keepers.initialize(*_U, L_, static_cast<size_t>(_nbUserKeepers), _keepers_gc_threshold); 193 _U->keepers.initialize(*_U, L_, static_cast<size_t>(_nbUserKeepers), _keepers_gc_threshold);
176 STACK_CHECK(L_, 0); 194 STACK_CHECK(L_, 0);
177 195
@@ -199,7 +217,7 @@ static void* libc_lua_Alloc([[maybe_unused]] void* const ud_, [[maybe_unused]] v
199// ################################################################################################# 217// #################################################################################################
200 218
201[[nodiscard]] 219[[nodiscard]]
202static int luaG_provide_protected_allocator(lua_State* const L_) 220static int luaW_provide_protected_allocator(lua_State* const L_)
203{ 221{
204 Universe* const _U{ Universe::Get(L_) }; 222 Universe* const _U{ Universe::Get(L_) };
205 // push a new full userdata on the stack, giving access to the universe's protected allocator 223 // push a new full userdata on the stack, giving access to the universe's protected allocator
@@ -209,9 +227,9 @@ static int luaG_provide_protected_allocator(lua_State* const L_)
209 227
210// ################################################################################################# 228// #################################################################################################
211 229
230// already called under protection of selfdestructMutex
212void Universe::flagDanglingLanes() const 231void Universe::flagDanglingLanes() const
213{ 232{
214 std::lock_guard<std::mutex> _guard{ selfdestructMutex };
215 Lane* _lane{ selfdestructFirst }; 233 Lane* _lane{ selfdestructFirst };
216 while (_lane != SELFDESTRUCT_END) { 234 while (_lane != SELFDESTRUCT_END) {
217 _lane->flaggedAfterUniverseGC.store(true, std::memory_order_relaxed); 235 _lane->flaggedAfterUniverseGC.store(true, std::memory_order_relaxed);
@@ -227,17 +245,17 @@ void Universe::initializeAllocatorFunction(lua_State* const L_)
227 // start by just grabbing whatever allocator was provided to the master state 245 // start by just grabbing whatever allocator was provided to the master state
228 protectedAllocator.initFrom(L_); 246 protectedAllocator.initFrom(L_);
229 STACK_CHECK_START_REL(L_, 1); // L_: settings 247 STACK_CHECK_START_REL(L_, 1); // L_: settings
230 switch (luaG_getfield(L_, kIdxTop, "allocator")) { // L_: settings allocator|nil|"protected" 248 switch (luaW_getfield(L_, kIdxTop, "allocator")) { // L_: settings allocator|nil|"protected"
231 case LuaType::NIL: 249 case LuaType::NIL:
232 // nothing else to do 250 // nothing else to do
233 break; 251 break;
234 252
235 case LuaType::STRING: 253 case LuaType::STRING:
236 LUA_ASSERT(L_, luaG_tostring(L_, kIdxTop) == "protected"); 254 LUA_ASSERT(L_, luaW_tostring(L_, kIdxTop) == "protected");
237 // set the original allocator to call from inside protection by the mutex 255 // set the original allocator to call from inside protection by the mutex
238 protectedAllocator.installIn(L_); 256 protectedAllocator.installIn(L_);
239 // before a state is created, this function will be called to obtain the allocator 257 // before a state is created, this function will be called to obtain the allocator
240 provideAllocator = luaG_provide_protected_allocator; 258 provideAllocator = luaW_provide_protected_allocator;
241 break; 259 break;
242 260
243 case LuaType::FUNCTION: 261 case LuaType::FUNCTION:
@@ -258,14 +276,14 @@ void Universe::initializeAllocatorFunction(lua_State* const L_)
258 break; 276 break;
259 277
260 default: // should be filtered out in lanes.lua 278 default: // should be filtered out in lanes.lua
261 raise_luaL_error(L_, "Bad config.allocator type %s", luaG_typename(L_, kIdxTop).data()); 279 raise_luaL_error(L_, "Bad config.allocator type %s", luaW_typename(L_, kIdxTop).data());
262 } 280 }
263 lua_pop(L_, 1); // L_: settings 281 lua_pop(L_, 1); // L_: settings
264 STACK_CHECK(L_, 1); 282 STACK_CHECK(L_, 1);
265 283
266 std::ignore = luaG_getfield(L_, kIdxTop, "internal_allocator"); // L_: settings "libc"|"allocator" 284 std::ignore = luaW_getfield(L_, kIdxTop, "internal_allocator"); // L_: settings "libc"|"allocator"
267 LUA_ASSERT(L_, lua_isstring(L_, kIdxTop)); // should be the case due to lanes.lua parameter validation 285 LUA_ASSERT(L_, lua_isstring(L_, kIdxTop)); // should be the case due to lanes.lua parameter validation
268 std::string_view const _allocator{ luaG_tostring(L_, kIdxTop) }; 286 std::string_view const _allocator{ luaW_tostring(L_, kIdxTop) };
269 // use whatever the provider provides. This performs validation of what provideAllocator is giving 287 // use whatever the provider provides. This performs validation of what provideAllocator is giving
270 // we do this even if _allocator == "libc", to have the validation part 288 // we do this even if _allocator == "libc", to have the validation part
271 internalAllocator = resolveAndValidateAllocator(L_, "internal"); 289 internalAllocator = resolveAndValidateAllocator(L_, "internal");
@@ -287,7 +305,7 @@ int Universe::InitializeFinalizer(lua_State* const L_)
287 305
288 // make sure we are only called from the Master Lua State! 306 // make sure we are only called from the Master Lua State!
289 kUniverseFullRegKey.pushValue(L_); // L_: f U 307 kUniverseFullRegKey.pushValue(L_); // L_: f U
290 if (luaG_type(L_, kIdxTop) != LuaType::USERDATA) { 308 if (luaW_type(L_, kIdxTop) != LuaType::USERDATA) {
291 raise_luaL_error(L_, "lanes.%s called from inside a lane", kFinally); 309 raise_luaL_error(L_, "lanes.%s called from inside a lane", kFinally);
292 } 310 }
293 lua_pop(L_, 1); // L_: f 311 lua_pop(L_, 1); // L_: f
@@ -303,8 +321,8 @@ int Universe::InitializeFinalizer(lua_State* const L_)
303void Universe::initializeOnStateCreate(lua_State* const L_) 321void Universe::initializeOnStateCreate(lua_State* const L_)
304{ 322{
305 STACK_CHECK_START_REL(L_, 0); // L_: settings 323 STACK_CHECK_START_REL(L_, 0); // L_: settings
306 if (luaG_getfield(L_, kIdxTop, kOnStateCreate) != LuaType::NIL) { // L_: settings on_state_create|nil 324 if (luaW_getfield(L_, kIdxTop, kOnStateCreate) != LuaType::NIL) { // L_: settings on_state_create|nil
307 LUA_ASSERT(L_, luaG_type(L_, kIdxTop) == LuaType::FUNCTION); // ensured by lanes.lua parameter validation 325 LUA_ASSERT(L_, luaW_type(L_, kIdxTop) == LuaType::FUNCTION); // ensured by lanes.lua parameter validation
308 // store C function pointer in an internal variable 326 // store C function pointer in an internal variable
309 lua_CFunction const _func{ lua_tocfunction(L_, -1) }; // L_: settings on_state_create 327 lua_CFunction const _func{ lua_tocfunction(L_, -1) }; // L_: settings on_state_create
310 if (_func) { 328 if (_func) {
@@ -317,7 +335,7 @@ void Universe::initializeOnStateCreate(lua_State* const L_)
317 // remove this C function from the config table so that it doesn't cause problems 335 // remove this C function from the config table so that it doesn't cause problems
318 // when we transfer the config table in newly created Lua states 336 // when we transfer the config table in newly created Lua states
319 lua_pushnil(L_); // L_: settings on_state_create nil 337 lua_pushnil(L_); // L_: settings on_state_create nil
320 luaG_setfield(L_, StackIndex{ -3 }, kOnStateCreate); // L_: settings on_state_create 338 luaW_setfield(L_, StackIndex{ -3 }, kOnStateCreate); // L_: settings on_state_create
321 } else { 339 } else {
322 // the function is still in the config table. we indicate this with the uintptr_t alternative (actual value is irrelevant) 340 // the function is still in the config table. we indicate this with the uintptr_t alternative (actual value is irrelevant)
323 onStateCreateFunc.emplace<uintptr_t>(std::bit_cast<uintptr_t>(kOnStateCreate.data())); 341 onStateCreateFunc.emplace<uintptr_t>(std::bit_cast<uintptr_t>(kOnStateCreate.data()));
@@ -340,7 +358,7 @@ lanes::AllocatorDefinition Universe::resolveAndValidateAllocator(lua_State* cons
340 358
341 STACK_CHECK_START_REL(L_, 0); // here, we have a function we can call to obtain an allocator 359 STACK_CHECK_START_REL(L_, 0); // here, we have a function we can call to obtain an allocator
342 lua_pushcclosure(L_, provideAllocator, 0); // L_: provideAllocator() 360 lua_pushcclosure(L_, provideAllocator, 0); // L_: provideAllocator()
343 luaG_pushstring(L_, hint_); // L_: provideAllocator() "<hint>" 361 luaW_pushstring(L_, hint_); // L_: provideAllocator() "<hint>"
344 lua_call(L_, 1, 1); // L_: result 362 lua_call(L_, 1, 1); // L_: result
345 // make sure we have a valid AllocatorDefinition on the stack (an error is raised instead if it is not the case) 363 // make sure we have a valid AllocatorDefinition on the stack (an error is raised instead if it is not the case)
346 _ret = lanes::AllocatorDefinition::Validated(L_, kIdxTop); 364 _ret = lanes::AllocatorDefinition::Validated(L_, kIdxTop);
@@ -415,7 +433,7 @@ int Universe::UniverseGC(lua_State* const L_)
415{ 433{
416 lua_Duration const _shutdown_timeout{ lua_tonumber(L_, lua_upvalueindex(1)) }; 434 lua_Duration const _shutdown_timeout{ lua_tonumber(L_, lua_upvalueindex(1)) };
417 STACK_CHECK_START_ABS(L_, 1); 435 STACK_CHECK_START_ABS(L_, 1);
418 Universe* const _U{ luaG_tofulluserdata<Universe>(L_, StackIndex{ 1 }) }; // L_: U 436 Universe* const _U{ luaW_tofulluserdata<Universe>(L_, StackIndex{ 1 }) }; // L_: U
419 437
420 // attempt to terminate all lanes with increasingly stronger cancel methods 438 // attempt to terminate all lanes with increasingly stronger cancel methods
421 bool const _allLanesTerminated{ 439 bool const _allLanesTerminated{
@@ -429,7 +447,7 @@ int Universe::UniverseGC(lua_State* const L_)
429 if (!lua_isnil(L_, -1)) { 447 if (!lua_isnil(L_, -1)) {
430 lua_pushboolean(L_, _allLanesTerminated); // L_: U finalizer bool 448 lua_pushboolean(L_, _allLanesTerminated); // L_: U finalizer bool
431 // no protection. Lua rules for errors in finalizers apply normally: 449 // no protection. Lua rules for errors in finalizers apply normally:
432 // Lua 5.4: error is propagated in the warn system 450 // Lua 5.4+: error is propagated in the warn system
433 // older: error is swallowed 451 // older: error is swallowed
434 lua_call(L_, 1, 1); // L_: U msg? 452 lua_call(L_, 1, 1); // L_: U msg?
435 // phew, no error in finalizer, since we reached that point 453 // phew, no error in finalizer, since we reached that point
@@ -438,24 +456,31 @@ int Universe::UniverseGC(lua_State* const L_)
438 if (lua_isnil(L_, kIdxTop)) { 456 if (lua_isnil(L_, kIdxTop)) {
439 lua_pop(L_, 1); // L_: U 457 lua_pop(L_, 1); // L_: U
440 // no finalizer, or it returned no value: push some default message on the stack, in case it is necessary 458 // no finalizer, or it returned no value: push some default message on the stack, in case it is necessary
441 luaG_pushstring(L_, "uncooperative lanes detected at shutdown"); // L_: U "msg" 459 luaW_pushstring(L_, "uncooperative lanes detected at shutdown"); // L_: U "msg"
442 } 460 }
443 STACK_CHECK(L_, 2); 461 STACK_CHECK(L_, 2);
444 462
445 // now, all remaining lanes are flagged. if they crash because we remove keepers and the Universe from under them, it is their fault 463 {
446 bool const _detectedUncooperativeLanes{ _U->selfdestructFirst != SELFDESTRUCT_END }; 464 std::lock_guard<std::mutex> _guard{ _U->selfdestructMutex };
447 if (_detectedUncooperativeLanes) { 465 // now, all remaining lanes are flagged. if they crash because we remove keepers and the Universe from under them, it is their fault
448 _U->flagDanglingLanes(); 466 bool const _detectedUncooperativeLanes{ _U->selfdestructFirst != SELFDESTRUCT_END };
449 if (luaG_tostring(L_, kIdxTop) == "freeze") { 467 if (_detectedUncooperativeLanes) {
450 std::this_thread::sleep_until(std::chrono::time_point<std::chrono::steady_clock>::max()); 468 _U->flagDanglingLanes();
469 if (luaW_tostring(L_, kIdxTop) == "freeze") {
470 std::this_thread::sleep_until(std::chrono::time_point<std::chrono::steady_clock>::max());
471 } else {
472 // take the value returned by the finalizer (or our default message) and throw it as an error
473 // since we are inside Lua's GCTM, it will be propagated through the warning system (Lua 5.4) or swallowed silently
474 // IMPORTANT: lua_error() is used here instead of the wrapper raise_lua_error() to circumvent what looks like a MSVC compiler bug
475 // that manifests as a crash inside ntdll!longjmp() function, in optimized builds only
476 lua_error(L_);
477 }
451 } else { 478 } else {
452 // take the value returned by the finalizer (or our default message) and throw it as an error 479 // we didn't use the error message, let's keep a clean stack
453 // since we are inside Lua's GCTM, it will be propagated through the warning system (Lua 5.4) or swallowed silently 480 lua_pop(L_, 1); // L_: U
454 // IMPORTANT: lua_error() is used here instead of the wrapper raise_lua_error() to circumvent what looks like a MSVC compiler bug
455 // that manifests as a crash inside ntdll!longjmp() function, in optimized builds only
456 lua_error(L_);
457 } 481 }
458 } 482 }
483 STACK_CHECK(L_, 1);
459 484
460 // --------------------------------------------------------- 485 // ---------------------------------------------------------
461 // we don't reach that point if some lanes are still running 486 // we don't reach that point if some lanes are still running
@@ -464,7 +489,9 @@ int Universe::UniverseGC(lua_State* const L_)
464 // no need to mutex-protect this as all lanes in the universe are gone at that point 489 // no need to mutex-protect this as all lanes in the universe are gone at that point
465 Linda::DeleteTimerLinda(L_, std::exchange(_U->timerLinda, nullptr), PK); 490 Linda::DeleteTimerLinda(L_, std::exchange(_U->timerLinda, nullptr), PK);
466 491
467 _U->keepers.close(); 492 if (!_U->keepers.close()) {
493 raise_luaL_error(L_, "INTERNAL ERROR: Keepers closed more than once");
494 }
468 495
469 // remove the protected allocator, if any 496 // remove the protected allocator, if any
470 _U->protectedAllocator.removeFrom(L_); 497 _U->protectedAllocator.removeFrom(L_);
diff --git a/src/universe.hpp b/src/universe.hpp
index 42a3d83..f781e92 100644
--- a/src/universe.hpp
+++ b/src/universe.hpp
@@ -4,6 +4,7 @@
4#include "cancel.hpp" 4#include "cancel.hpp"
5#include "keeper.hpp" 5#include "keeper.hpp"
6#include "lanesconf.h" 6#include "lanesconf.h"
7#include "threading.hpp"
7#include "tracker.hpp" 8#include "tracker.hpp"
8#include "uniquekey.hpp" 9#include "uniquekey.hpp"
9 10
@@ -27,12 +28,7 @@ class ProtectedAllocator final
27 std::mutex mutex; 28 std::mutex mutex;
28 29
29 [[nodiscard]] 30 [[nodiscard]]
30 static void* protected_lua_Alloc(void* const ud_, void* const ptr_, size_t const osize_, size_t const nsize_) 31 static void* Protected_lua_Alloc(void* const ud_, void* const ptr_, size_t const osize_, size_t const nsize_);
31 {
32 ProtectedAllocator* const allocator{ static_cast<ProtectedAllocator*>(ud_) };
33 std::lock_guard<std::mutex> guard{ allocator->mutex };
34 return allocator->alloc(ptr_, osize_, nsize_);
35 }
36 32
37 public: 33 public:
38 // we are not like our base class: we can't be created inside a full userdata (or we would have to install a metatable and __gc handler to destroy ourselves properly) 34 // we are not like our base class: we can't be created inside a full userdata (or we would have to install a metatable and __gc handler to destroy ourselves properly)
@@ -42,13 +38,13 @@ class ProtectedAllocator final
42 38
43 AllocatorDefinition makeDefinition() 39 AllocatorDefinition makeDefinition()
44 { 40 {
45 return AllocatorDefinition{ protected_lua_Alloc, this }; 41 return AllocatorDefinition{ Protected_lua_Alloc, this };
46 } 42 }
47 43
48 void installIn(lua_State* const L_) const 44 void installIn(lua_State* const L_) const
49 { 45 {
50 // install our replacement allocator function (this is a C function, we need to deconst ourselves) 46 // install our replacement allocator function (this is a C function, we need to deconst ourselves)
51 lua_setallocf(L_, protected_lua_Alloc, static_cast<void*>(const_cast<ProtectedAllocator*>(this))); 47 lua_setallocf(L_, Protected_lua_Alloc, static_cast<void*>(const_cast<ProtectedAllocator*>(this)));
52 } 48 }
53 49
54 void removeFrom(lua_State* const L_) const 50 void removeFrom(lua_State* const L_) const
@@ -75,9 +71,9 @@ class Universe final
75 71
76#ifdef PLATFORM_LINUX 72#ifdef PLATFORM_LINUX
77 // Linux needs to check, whether it's been run as root 73 // Linux needs to check, whether it's been run as root
78 bool const sudo{ geteuid() == 0 }; 74 SudoFlag const sudo{ geteuid() == 0 };
79#else 75#else
80 bool const sudo{ false }; 76 SudoFlag const sudo{ false };
81#endif // PLATFORM_LINUX 77#endif // PLATFORM_LINUX
82 78
83 // for verbose errors 79 // for verbose errors
@@ -99,6 +95,8 @@ class Universe final
99 95
100 Keepers keepers; 96 Keepers keepers;
101 97
98 lua_Duration lindaWakePeriod{};
99
102 // Initialized by 'init_once_LOCKED()': the deep userdata Linda object 100 // Initialized by 'init_once_LOCKED()': the deep userdata Linda object
103 // used for timers (each lane will get a proxy to this) 101 // used for timers (each lane will get a proxy to this)
104 Linda* timerLinda{ nullptr }; 102 Linda* timerLinda{ nullptr };
@@ -130,7 +128,7 @@ class Universe final
130 128
131 public: 129 public:
132 [[nodiscard]] 130 [[nodiscard]]
133 static void* operator new([[maybe_unused]] size_t const size_, lua_State* const L_) noexcept { return luaG_newuserdatauv<Universe>(L_, UserValueCount{ 0 }); }; 131 static void* operator new([[maybe_unused]] size_t const size_, lua_State* const L_) noexcept { return luaW_newuserdatauv<Universe>(L_, UserValueCount{ 0 }); };
134 // can't actually delete the operator because the compiler generates stack unwinding code that could call it in case of exception 132 // can't actually delete the operator because the compiler generates stack unwinding code that could call it in case of exception
135 static void operator delete([[maybe_unused]] void* const p_, [[maybe_unused]] lua_State* const L_) {} // nothing to do, as nothing is allocated independently 133 static void operator delete([[maybe_unused]] void* const p_, [[maybe_unused]] lua_State* const L_) {} // nothing to do, as nothing is allocated independently
136 134
diff --git a/tests/appendud.lua b/tests/appendud.lua
index f6f99c1..2a8c8ce 100644
--- a/tests/appendud.lua
+++ b/tests/appendud.lua
@@ -49,7 +49,7 @@ assert(not err)
49-- test 49-- test
50-- print("t:join()") 50-- print("t:join()")
51a,b,c = t[1],t[2],t[3] -- Need to explicitly wait for the thread, since 'ipairs()' does not 51a,b,c = t[1],t[2],t[3] -- Need to explicitly wait for the thread, since 'ipairs()' does not
52--a,b,c = t:join() -- Need to explicitly wait for the thread, since 'ipairs()' does not 52--r,a,b,c = t:join() -- Need to explicitly wait for the thread, since 'ipairs()' does not
53 -- value the '__index' metamethod (wouldn't it be cool if it did..?) 53 -- value the '__index' metamethod (wouldn't it be cool if it did..?)
54 54
55print(a,b,c) 55print(a,b,c)
diff --git a/tests/basic.lua b/tests/basic.lua
index 068dc25..f393175 100644
--- a/tests/basic.lua
+++ b/tests/basic.lua
@@ -163,7 +163,7 @@ PRINT(" "..st)
163assert(st == "cancelled", "st is '" .. st .. "' instead of 'cancelled'") 163assert(st == "cancelled", "st is '" .. st .. "' instead of 'cancelled'")
164 164
165-- cancellation of lanes waiting on a linda 165-- cancellation of lanes waiting on a linda
166local limited = lanes_linda("limited") 166local limited = lanes_linda{name = "limited"}
167assert.fails(function() limited:limit("key", -1) end) 167assert.fails(function() limited:limit("key", -1) end)
168assert.failsnot(function() limited:limit("key", 1) end) 168assert.failsnot(function() limited:limit("key", 1) end)
169-- [[################################################ 169-- [[################################################
@@ -173,42 +173,51 @@ for k, v in pairs(limited:dump()) do
173end 173end
174local wait_send = function() 174local wait_send = function()
175 local a,b 175 local a,b
176 set_finalizer(function() print("wait_send", a, b) end) 176 set_finalizer(function(err, stack_tbl) print("wait_send", a, b, " -> ", tostring(err)) end)
177 print("in wait_send")
177 a,b = limited:send("key", "bybye") -- infinite timeout, returns only when lane is cancelled 178 a,b = limited:send("key", "bybye") -- infinite timeout, returns only when lane is cancelled
178end 179end
179 180
180local wait_send_lane = lanes.gen("*", { name = 'auto' }, wait_send)() 181local wait_send_lane = lanes.gen("*", { name = 'auto' }, wait_send)()
181repeat until wait_send_lane.status == "waiting" 182repeat
182print "wait_send_lane is waiting" 183 io.stderr:write('!')
184 -- currently mingw64 builds can deadlock if we cancel the lane too early (before the linda blocks, at it causes the linda condvar not to be signalled)
185 lanes.sleep(0.1)
186until wait_send_lane.status == "waiting"
187PRINT "wait_send_lane is waiting"
183wait_send_lane:cancel() -- hard cancel, 0 timeout 188wait_send_lane:cancel() -- hard cancel, 0 timeout
184repeat until wait_send_lane.status == "cancelled" 189repeat until wait_send_lane.status == "cancelled"
185print "wait_send_lane is cancelled" 190PRINT "wait_send_lane is cancelled"
186--################################################]] 191--################################################]]
187local wait_receive = function() 192local wait_receive = function()
188 local k, v 193 local k, v
189 set_finalizer(function() print("wait_receive", k, v) end) 194 set_finalizer(function(err, stack_tbl) print("wait_receive", k, v, " -> ", tostring(err)) end)
190 k, v = limited:receive("dummy") -- infinite timeout, returns only when lane is cancelled 195 k, v = limited:receive("dummy") -- infinite timeout, returns only when lane is cancelled
191end 196end
192 197
193local wait_receive_lane = lanes.gen("*", { name = 'auto' }, wait_receive)() 198local wait_receive_lane = lanes.gen("*", { name = 'auto' }, wait_receive)()
194repeat until wait_receive_lane.status == "waiting" 199repeat
195print "wait_receive_lane is waiting" 200 io.stderr:write('!')
201 -- currently mingw64 builds can deadlock if we cancel the lane too early (before the linda blocks, at it causes the linda condvar not to be signalled)
202 lanes.sleep(0.1)
203until wait_receive_lane.status == "waiting"
204PRINT "wait_receive_lane is waiting"
196wait_receive_lane:cancel() -- hard cancel, 0 timeout 205wait_receive_lane:cancel() -- hard cancel, 0 timeout
197repeat until wait_receive_lane.status == "cancelled" 206repeat until wait_receive_lane.status == "cancelled"
198print "wait_receive_lane is cancelled" 207PRINT "wait_receive_lane is cancelled"
199--################################################]] 208--################################################]]
200local wait_receive_batched = function() 209local wait_receive_batched = function()
201 local k, v1, v2 210 local k, v1, v2
202 set_finalizer(function() print("wait_receive_batched", k, v1, v2) end) 211 set_finalizer(function() print("wait_receive_batched", k, v1, v2) end)
203 k, v1, v2 = limited:receive(limited.batched, "dummy", 2) -- infinite timeout, returns only when lane is cancelled 212 k, v1, v2 = limited:receive_batched("dummy", 2) -- infinite timeout, returns only when lane is cancelled
204end 213end
205 214
206local wait_receive_batched_lane = lanes.gen("*", { name = 'auto' }, wait_receive_batched)() 215local wait_receive_batched_lane = lanes.gen("*", { name = 'auto' }, wait_receive_batched)()
207repeat until wait_receive_batched_lane.status == "waiting" 216repeat until wait_receive_batched_lane.status == "waiting"
208print "wait_receive_batched_lane is waiting" 217PRINT "wait_receive_batched_lane is waiting"
209wait_receive_batched_lane:cancel() -- hard cancel, 0 timeout 218wait_receive_batched_lane:cancel() -- hard cancel, 0 timeout
210repeat until wait_receive_batched_lane.status == "cancelled" 219repeat until wait_receive_batched_lane.status == "cancelled"
211print "wait_receive_batched_lane is cancelled" 220PRINT "wait_receive_batched_lane is cancelled"
212--################################################]] 221--################################################]]
213 222
214-- ################################################################################################## 223-- ##################################################################################################
@@ -246,7 +255,7 @@ local chunk= function(linda)
246 WR("chunk ", "Lane ends!\n") 255 WR("chunk ", "Lane ends!\n")
247end 256end
248 257
249local linda = lanes_linda("communications") 258local linda = lanes_linda{name = "communications"}
250assert(type(linda) == "userdata" and tostring(linda) == "Linda: communications") 259assert(type(linda) == "userdata" and tostring(linda) == "Linda: communications")
251 -- 260 --
252 -- ["->"] master -> slave 261 -- ["->"] master -> slave
@@ -264,7 +273,7 @@ local b,x,y,z,w = linda:get("<->", 4)
264assert(b == 3 and x == "x" and y == "y" and z == "z" and w == nil) 273assert(b == 3 and x == "x" and y == "y" and z == "z" and w == nil)
265local k, x = linda:receive("<->") 274local k, x = linda:receive("<->")
266assert(k == "<->" and x == "x") 275assert(k == "<->" and x == "x")
267local k,y,z = linda:receive(linda.batched, "<->", 2) 276local k,y,z = linda:receive_batched("<->", 2)
268assert(k == "<->" and y == "y" and z == "z") 277assert(k == "<->" and y == "y" and z == "z")
269linda:set("<->") 278linda:set("<->")
270local b,x,y,z,w = linda:get("<->", 4) 279local b,x,y,z,w = linda:get("<->", 4)
@@ -401,7 +410,7 @@ local tc = lanes.gen("io", { name = 'auto', gc_cb = gc_cb },
401 end 410 end
402) 411)
403 412
404local linda= lanes_linda("criss cross") 413local linda= lanes_linda{name = "criss cross"}
405 414
406local a,b= tc(linda, "A","B"), tc(linda, "B","A") -- launching two lanes, twisted comms 415local a,b= tc(linda, "A","B"), tc(linda, "B","A") -- launching two lanes, twisted comms
407 416
@@ -437,7 +446,7 @@ local function chunk2(linda)
437 assert(config.strip_functions and info.short_src=="?" or string.match(info.short_src, "^.*basic.lua$"), "bad info.short_src") 446 assert(config.strip_functions and info.short_src=="?" or string.match(info.short_src, "^.*basic.lua$"), "bad info.short_src")
438 -- These vary so let's not be picky (they're there..) 447 -- These vary so let's not be picky (they're there..)
439 -- 448 --
440 assert(info.linedefined == 422, "bad linedefined") -- start of 'chunk2' 449 assert(info.linedefined == 431, "bad linedefined") -- start of 'chunk2'
441 assert(config.strip_functions and info.currentline==-1 or info.currentline > info.linedefined, "bad currentline") -- line of 'debug.getinfo' 450 assert(config.strip_functions and info.currentline==-1 or info.currentline > info.linedefined, "bad currentline") -- line of 'debug.getinfo'
442 assert(info.lastlinedefined > info.currentline, "bad lastlinedefined") -- end of 'chunk2' 451 assert(info.lastlinedefined > info.currentline, "bad lastlinedefined") -- end of 'chunk2'
443 local k,func= linda:receive("down") 452 local k,func= linda:receive("down")
@@ -452,7 +461,7 @@ local function chunk2(linda)
452 linda:send("up", function() return ":)" end, "ok2") 461 linda:send("up", function() return ":)" end, "ok2")
453end 462end
454 463
455local linda = lanes_linda("auto") 464local linda = lanes_linda{name = "auto"}
456local t2 = lanes.gen("debug,string,io", { name = 'auto', gc_cb = gc_cb }, chunk2)(linda) -- prepare & launch 465local t2 = lanes.gen("debug,string,io", { name = 'auto', gc_cb = gc_cb }, chunk2)(linda) -- prepare & launch
457linda:send("down", function(linda) linda:send("up", "ready!") end, 466linda:send("down", function(linda) linda:send("up", "ready!") end,
458 "ok") 467 "ok")
@@ -460,7 +469,7 @@ linda:send("down", function(linda) linda:send("up", "ready!") end,
460-- 469--
461local k,s= linda:receive(1, "up") 470local k,s= linda:receive(1, "up")
462if t2.status == "error" then 471if t2.status == "error" then
463 print("t2 error: " , t2:join()) 472 PRINT("t2 error: " , t2:join())
464end 473end
465PRINT(s) 474PRINT(s)
466assert(s=="ready!") 475assert(s=="ready!")
@@ -498,19 +507,20 @@ local S = lanes.gen("table", { name = 'auto', gc_cb = gc_cb },
498 return (unpack or table.unpack)(aux) 507 return (unpack or table.unpack)(aux)
499end) 508end)
500 509
501h= S { 12, 13, 14 } -- execution starts, h[1..3] will get the return values 510h = S { 12, 13, 14 } -- execution starts, h[1..3] will get the return values
502-- wait a bit so that the lane has a chance to set its debug name 511-- wait a bit so that the lane has a chance to set its debug name
503SLEEP(0.5) 512SLEEP(0.5)
504print("joining with '" .. h:get_threadname() .. "'") 513print("joining with '" .. h:get_threadname() .. "'")
505local a,b,c,d= h:join() 514local r,a,b,c,d= h:join()
506if h.status == "error" then 515if h.status == "error" then
507 print(h:get_threadname(), "error: " , a, b, c, d) 516 print(h:get_threadname(), "error: " , r, a, b, c, d)
508else 517else
509 print(h:get_threadname(), a,b,c,d) 518 print(h:get_threadname(), r,a,b,c,d)
510 assert(a==14) 519 assert(r == true)
511 assert(b==13) 520 assert(a == 14)
512 assert(c==12) 521 assert(b == 13)
513 assert(d==nil) 522 assert(c == 12)
523 assert(d == nil)
514end 524end
515 525
516local nameof_type, nameof_name = lanes.nameof(print) 526local nameof_type, nameof_name = lanes.nameof(print)
diff --git a/tests/cancel.lua b/tests/cancel.lua
index 80e6c6a..66957c3 100644
--- a/tests/cancel.lua
+++ b/tests/cancel.lua
@@ -148,7 +148,7 @@ local protectedBody = function(...)
148 local paramLessClosure = function() laneBody(unpack(params)) end 148 local paramLessClosure = function() laneBody(unpack(params)) end
149 local status, message = xpcall(paramLessClosure, errorHandler) 149 local status, message = xpcall(paramLessClosure, errorHandler)
150 if status == false then 150 if status == false then
151 print(" error handler rethrowing '" .. (ce == message and "cancel_error"or tostring(message)) .. "'") 151 print(" protectedBody rethrowing '" .. (ce == message and "cancel_error" or tostring(message)) .. "'")
152 -- if the error isn't rethrown, the lane's finalizer won't get it 152 -- if the error isn't rethrown, the lane's finalizer won't get it
153 error(message) 153 error(message)
154 end 154 end
diff --git a/tests/deadlock.lua b/tests/deadlock.lua
index d028e83..9b93e3b 100644
--- a/tests/deadlock.lua
+++ b/tests/deadlock.lua
@@ -16,7 +16,7 @@ print "let's begin"
16local do_extra_stuff = true 16local do_extra_stuff = true
17 17
18if do_extra_stuff then 18if do_extra_stuff then
19 local linda = lanes.linda "deadlock_linda" 19 local linda = lanes.linda{name = "deadlock_linda"}
20 -- just something to make send() succeed and receive() fail 20 -- just something to make send() succeed and receive() fail
21 local payload = { io.flush } 21 local payload = { io.flush }
22 22
diff --git a/tests/errhangtest.lua b/tests/errhangtest.lua
index fff0dee..5b3f0c0 100644
--- a/tests/errhangtest.lua
+++ b/tests/errhangtest.lua
@@ -19,7 +19,6 @@ end
19if true then 19if true then
20 print "\n#### reserved sentinels" 20 print "\n#### reserved sentinels"
21 print(pcall(linda.set, linda, lanes.cancel_error)) 21 print(pcall(linda.set, linda, lanes.cancel_error))
22 print(pcall(linda.set, linda, linda.batched))
23 local _count, _val = linda:get("test") 22 local _count, _val = linda:get("test")
24 assert(_count == 0 and _val == nil) 23 assert(_count == 0 and _val == nil)
25 print "OK" 24 print "OK"
@@ -28,13 +27,13 @@ end
28-- get/set a few values 27-- get/set a few values
29if true then 28if true then
30 print "\n#### set 3 -> receive batched" 29 print "\n#### set 3 -> receive batched"
31 assert.fails(function() linda:receive(linda.batched, "some key", -1, 1) end) 30 assert.fails(function() linda:receive_batched("some key", -1, 1) end)
32 assert.fails(function() linda:receive(linda.batched, "some key", 2, 1) end) 31 assert.fails(function() linda:receive_batched("some key", 2, 1) end)
33 assert.failsnot(function() linda:receive(0, linda.batched, "some key", 1, 3) end) 32 assert.failsnot(function() linda:receive_batched(0, "some key", 1, 3) end)
34 local fun = function() print "function test ok" end 33 local fun = function() print "function test ok" end
35 print(pcall(linda.set, linda, 'test', true, nil, fun)) 34 print(pcall(linda.set, linda, 'test', true, nil, fun))
36 -- read back the contents 35 -- read back the contents
37 local k,b,n,f = linda:receive(linda.batched, 'test', 3) 36 local k,b,n,f = linda:receive_batched('test', 3)
38 local _count, _val = linda:get("test") 37 local _count, _val = linda:get("test")
39 assert(_count == 0 and _val == nil) 38 assert(_count == 0 and _val == nil)
40 -- check they are ok 39 -- check they are ok
diff --git a/tests/error.lua b/tests/error.lua
index 306c51d..76ceea4 100644
--- a/tests/error.lua
+++ b/tests/error.lua
@@ -106,11 +106,11 @@ end
106 106
107local lane_error_as_string = "'lane error as string'" 107local lane_error_as_string = "'lane error as string'"
108local lane_error_as_table = setmetatable({"lane error as table"}, make_table_error_mt()) 108local lane_error_as_table = setmetatable({"lane error as table"}, make_table_error_mt())
109local lane_error_as_linda = lanes.linda("'lane error'") 109local lane_error_as_linda = lanes.linda{name = "'lane error'"}
110 110
111local finalizer_error_as_string = "'finalizer error as string'" 111local finalizer_error_as_string = "'finalizer error as string'"
112local finalizer_error_as_table = setmetatable({"finalizer error as table"}, make_table_error_mt()) 112local finalizer_error_as_table = setmetatable({"finalizer error as table"}, make_table_error_mt())
113local finalizer_error_as_linda = lanes.linda("'finalizer error'") 113local finalizer_error_as_linda = lanes.linda{name = "'finalizer error'"}
114 114
115local test_settings = {} 115local test_settings = {}
116local configure_tests = function() 116local configure_tests = function()
@@ -173,8 +173,7 @@ local do_error_catching_test = function(error_reporting_mode_, error_value_, fin
173 local h = start_lane(error_reporting_mode_, error_value_, finalizer_, finalizer_error_value_) 173 local h = start_lane(error_reporting_mode_, error_value_, finalizer_, finalizer_error_value_)
174 local ret,err,stack= h:join() -- wait for the lane (no automatic error propagation) 174 local ret,err,stack= h:join() -- wait for the lane (no automatic error propagation)
175 WR("Processing results for {", error_reporting_mode_, error_value_, finalizer_, finalizer_error_value_, "}") 175 WR("Processing results for {", error_reporting_mode_, error_value_, finalizer_, finalizer_error_value_, "}")
176 if err then 176 if ret == nil then
177 assert(ret == nil)
178 assert(error_reporting_mode_ == "minimal" or type(stack)=="table") -- only true if lane was configured with error_trace_level ~= "minimal" 177 assert(error_reporting_mode_ == "minimal" or type(stack)=="table") -- only true if lane was configured with error_trace_level ~= "minimal"
179 if err == error_value_ then 178 if err == error_value_ then
180 WR("Lane regular error: ", err) 179 WR("Lane regular error: ", err)
@@ -198,8 +197,8 @@ local do_error_catching_test = function(error_reporting_mode_, error_value_, fin
198 end 197 end
199 end 198 end
200 else -- no error 199 else -- no error
201 assert(ret == "success") 200 assert(ret == true and err == "success")
202 WR("No error in lane: ", ret) 201 WR("No error in lane: ", err, ret)
203 end 202 end
204 WR "TEST OK" 203 WR "TEST OK"
205end 204end
diff --git a/tests/fifo.lua b/tests/fifo.lua
index 9efcbd9..1317a9f 100644
--- a/tests/fifo.lua
+++ b/tests/fifo.lua
@@ -6,10 +6,10 @@
6 6
7local lanes = require "lanes".configure{shutdown_timeout=3,with_timers=true} 7local lanes = require "lanes".configure{shutdown_timeout=3,with_timers=true}
8 8
9local atomic_linda = lanes.linda( "atom") 9local atomic_linda = lanes.linda{name = "atom"}
10local atomic_inc= lanes.genatomic( atomic_linda, "FIFO_n") 10local atomic_inc= lanes.genatomic( atomic_linda, "FIFO_n")
11 11
12local fifo_linda = lanes.linda( "fifo") 12local fifo_linda = lanes.linda{name = "fifo"}
13 13
14-- Lua 5.1 support 14-- Lua 5.1 support
15local table_unpack = table.unpack or unpack 15local table_unpack = table.unpack or unpack
diff --git a/tests/finalizer.lua b/tests/finalizer.lua
index ac5ce8b..9fa12dc 100644
--- a/tests/finalizer.lua
+++ b/tests/finalizer.lua
@@ -77,8 +77,8 @@ local do_test = function(error_)
77 77
78 local h = lgen(error_) 78 local h = lgen(error_)
79 79
80 local _,err,stack = h:join() -- wait for the lane (no automatic error propagation) 80 local r,err,stack = h:join() -- wait for the lane (no automatic error propagation)
81 if err then 81 if not r then
82 assert(stack, "no stack trace on error, check 'error_trace_level'") 82 assert(stack, "no stack trace on error, check 'error_trace_level'")
83 io.stderr:write( "Lane error: "..tostring(err).."\n" ) 83 io.stderr:write( "Lane error: "..tostring(err).."\n" )
84 io.stderr:write( "\t", table.concat(stack,"\t\n"), "\n" ) 84 io.stderr:write( "\t", table.concat(stack,"\t\n"), "\n" )
diff --git a/tests/func_is_string.lua b/tests/func_is_string.lua
index 5de4c60..3c91603 100644
--- a/tests/func_is_string.lua
+++ b/tests/func_is_string.lua
@@ -21,16 +21,17 @@ end
21 21
22local options = {globals = { b = 666 }} 22local options = {globals = { b = 666 }}
23 23
24local gen1 = lanes.gen("*", { name = 'auto' }, "return true, dofile('fibonacci.lua')") 24local gen1 = lanes.gen("*", { name = 'auto' }, "return true, error('bob')")
25local gen2 = lanes.gen(options, { name = 'auto' }, "return b")
26 25
27fibLane = gen1() 26fibLane = gen1()
28lanes.sleep(0.1) 27lanes.sleep(0.1)
29print(fibLane, fibLane.status) 28print(fibLane, fibLane.status)
30local _status, _err = fibLane:join() 29local _r, _err, _stk = fibLane:join()
31print(_status, _err) 30assert(_r == nil, "got " .. tostring(_r) .. " " .. tostring(_err) .. " " .. tostring(_stk))
32 31
33retLane1, retLane2 = gen2(), gen2() 32local gen2 = lanes.gen(options, { name = 'auto' }, "return b")
33local retLane1, retLane2 = gen2(), gen2()
34 34
35print( retLane1[1], retLane2[1]) 35print( retLane1[1], retLane2[1])
36print "TEST OK" \ No newline at end of file 36assert(retLane1[1] == 666 and retLane2[1] == 666)
37print "TEST OK"
diff --git a/tests/irayo_closure.lua b/tests/irayo_closure.lua
index 705b85e..40c586d 100644
--- a/tests/irayo_closure.lua
+++ b/tests/irayo_closure.lua
@@ -5,7 +5,7 @@
5"Another issue I've noticed is trying to pass a table with a function 5"Another issue I've noticed is trying to pass a table with a function
6that uses closures in it as a global variable into a new lane. This 6that uses closures in it as a global variable into a new lane. This
7causes a segmentation fault and it appears to be related to the 7causes a segmentation fault and it appears to be related to the
8luaG_inter_move function near line 835-836 or so in lanes.c, but I 8luaW_inter_move function near line 835-836 or so in lanes.c, but I
9haven't investigated further. 9haven't investigated further.
10e.g. { globals = { data = 1, func = function() useclosurehere() end } }" 10e.g. { globals = { data = 1, func = function() useclosurehere() end } }"
11]] 11]]
diff --git a/tests/keeper.lua b/tests/keeper.lua
index f566927..4742732 100644
--- a/tests/keeper.lua
+++ b/tests/keeper.lua
@@ -40,14 +40,14 @@ if true then
40 end 40 end
41 41
42 -- should succeed 42 -- should succeed
43 assert.failsnot(function() createLinda("zero", 0) end) 43 assert.failsnot(function() createLinda{name = "zero", group = 0} end)
44 assert.failsnot(function() createLinda("one", 1) end) 44 assert.failsnot(function() createLinda{name = "one", group = 1} end)
45 assert.failsnot(function() createLinda("two", 2) end) 45 assert.failsnot(function() createLinda{name = "two", group = 2} end)
46 assert.failsnot(function() createLinda("three", 3) end) 46 assert.failsnot(function() createLinda{name = "three", group = 3} end)
47 -- should fail (and not create the lindas) 47 -- should fail (and not create the lindas)
48 assert.fails(function() createLinda("minus 1", -1) end) 48 assert.fails(function() createLinda{name = "minus 1", group = -1} end)
49 assert.fails(function() createLinda("none") end) 49 assert.fails(function() createLinda{name = "none"} end)
50 assert.fails(function() createLinda("four", 4) end) 50 assert.fails(function() createLinda{name = "four", group = 4} end)
51 51
52end 52end
53-- should only collect the 4 successfully created lindas 53-- should only collect the 4 successfully created lindas
@@ -58,11 +58,11 @@ DONE()
58if true then 58if true then
59 PRINT "=========================================================================================" 59 PRINT "========================================================================================="
60 PRINT "Linda names test:" 60 PRINT "Linda names test:"
61 local unnamedLinda1 = lanes.linda(1) 61 local unnamedLinda1 = lanes.linda{group = 1}
62 local unnamedLinda2 = lanes.linda("", 2) 62 local unnamedLinda2 = lanes.linda{name = "", group = 2}
63 local veeeerrrryyyylooongNamedLinda3 = lanes.linda( "veeeerrrryyyylooongNamedLinda", 3) 63 local veeeerrrryyyylooongNamedLinda3 = lanes.linda{ name = "veeeerrrryyyylooongNamedLinda", group = 3}
64 assert(tostring(veeeerrrryyyylooongNamedLinda3) == "Linda: veeeerrrryyyylooongNamedLinda") 64 assert(tostring(veeeerrrryyyylooongNamedLinda3) == "Linda: veeeerrrryyyylooongNamedLinda")
65 local shortNamedLinda0 = lanes.linda( "short", 0) 65 local shortNamedLinda0 = lanes.linda{name = "short", group = 0}
66 assert(tostring(shortNamedLinda0) == "Linda: short") 66 assert(tostring(shortNamedLinda0) == "Linda: short")
67 PRINT(shortNamedLinda0, unnamedLinda1, unnamedLinda2, veeeerrrryyyylooongNamedLinda3) 67 PRINT(shortNamedLinda0, unnamedLinda1, unnamedLinda2, veeeerrrryyyylooongNamedLinda3)
68end 68end
@@ -74,12 +74,12 @@ DONE()
74if true then 74if true then
75 PRINT "=========================================================================================" 75 PRINT "========================================================================================="
76 PRINT "Linda GC test:" 76 PRINT "Linda GC test:"
77 local a = lanes.linda("A", 1) 77 local a = lanes.linda{name = "A", group = 1}
78 local b = lanes.linda("B", 2) 78 local b = lanes.linda{name = "B", group = 2}
79 local c = lanes.linda("C", 3) 79 local c = lanes.linda{name = "C", group = 3}
80 80
81 -- store lindas in each other and in themselves 81 -- store lindas in each other and in themselves
82 a:set("here", lanes.linda("temporary linda", 0)) 82 a:set("here", lanes.linda{name = "temporary linda", group = 0})
83 b:set("here", a, b, c) 83 b:set("here", a, b, c)
84 c:set("here", a, b, c) 84 c:set("here", a, b, c)
85 85
@@ -120,13 +120,13 @@ if true then
120 end 120 end
121 121
122 -- 122 --
123 local lindaA= lanes.linda( "A", 1) 123 local lindaA= lanes.linda{name = "A", group = 1}
124 local A= keeper( lindaA ) 124 local A= keeper( lindaA )
125 125
126 local lindaB= lanes.linda( "B", 2) 126 local lindaB= lanes.linda{name = "B", group = 2}
127 local B= keeper( lindaB ) 127 local B= keeper( lindaB )
128 128
129 local lindaC= lanes.linda( "C", 3) 129 local lindaC= lanes.linda{name = "C", group = 3}
130 local C= keeper( lindaC ) 130 local C= keeper( lindaC )
131 PRINT("Created", lindaA, lindaB, lindaC) 131 PRINT("Created", lindaA, lindaB, lindaC)
132 132
diff --git a/tests/launchtest.lua b/tests/launchtest.lua
index 57411e1..cdd6ffc 100644
--- a/tests/launchtest.lua
+++ b/tests/launchtest.lua
@@ -69,8 +69,8 @@ else
69 io.stderr:write( N.." lanes launched.\n" ) 69 io.stderr:write( N.." lanes launched.\n" )
70 70
71 for i=1,N do 71 for i=1,N do
72 local rc= t[i]:join() 72 local r,rc = t[i]:join()
73 assert( rc==i ) 73 assert( r == true and rc == i )
74 end 74 end
75 75
76 io.stderr:write( N.." lanes finished.\n" ) 76 io.stderr:write( N.." lanes finished.\n" )
diff --git a/tests/linda_perf.lua b/tests/linda_perf.lua
index bba1408..e68d552 100644
--- a/tests/linda_perf.lua
+++ b/tests/linda_perf.lua
@@ -22,7 +22,7 @@ if true then
22 do 22 do
23 print "############################################ tests get/set" 23 print "############################################ tests get/set"
24 -- linda:get throughput 24 -- linda:get throughput
25 local l = lanes.linda("get/set", 1) 25 local l = lanes.linda{name = "get/set", group = 1}
26 local batch = {} 26 local batch = {}
27 for i = 1,1000 do 27 for i = 1,1000 do
28 table.insert(batch, i) 28 table.insert(batch, i)
@@ -56,7 +56,7 @@ local eater = function( l, loop)
56 -- print "loop is over" 56 -- print "loop is over"
57 key, val = l:receive( "done") 57 key, val = l:receive( "done")
58 print("eater: done ("..val..")") 58 print("eater: done ("..val..")")
59 return true 59 return "ate everything"
60end 60end
61 61
62-- ################################################################################################# 62-- #################################################################################################
@@ -68,13 +68,13 @@ local gobbler = function( l, loop, batch)
68 l:receive( "go") 68 l:receive( "go")
69 -- eat data in batches 69 -- eat data in batches
70 for i = 1, loop/batch do 70 for i = 1, loop/batch do
71 l:receive( l.batched, "key", batch) 71 l:receive_batched("key", batch)
72 -- print("gobbler:", batch) 72 -- print("gobbler:", batch)
73 end 73 end
74 print "loop is over" 74 print "loop is over"
75 key, val = l:receive( "done") 75 key, val = l:receive( "done")
76 print("gobbler: done ("..val..")") 76 print("gobbler: done ("..val..")")
77 return true 77 return "gobbled everything"
78end 78end
79 79
80-- ################################################################################################# 80-- #################################################################################################
@@ -90,7 +90,7 @@ local group_uid = 1
90local function ziva1( preloop, loop, batch) 90local function ziva1( preloop, loop, batch)
91 -- prefill the linda a bit to increase fifo stress 91 -- prefill the linda a bit to increase fifo stress
92 local top = math.max( preloop, loop) 92 local top = math.max( preloop, loop)
93 local l = lanes.linda("ziva1("..preloop..":"..loop..":"..batch..")", group_uid) 93 local l = lanes.linda{name = "ziva1("..preloop..":"..loop..":"..batch..")", group = group_uid}
94 group_uid = (group_uid % config.nb_user_keepers) + 1 94 group_uid = (group_uid % config.nb_user_keepers) + 1
95 local t1 = lanes.now_secs() 95 local t1 = lanes.now_secs()
96 for i = 1, preloop do 96 for i = 1, preloop do
@@ -123,7 +123,8 @@ local function ziva1( preloop, loop, batch)
123 end 123 end
124 end 124 end
125 l:send( "done" ,"are you happy?") 125 l:send( "done" ,"are you happy?")
126 lane:join() 126 local r, ret = lane:join()
127 assert(r == true and type(ret) == "string", "got " .. tostring(r) .. " " .. tostring(ret))
127 return lanes.now_secs() - t1 128 return lanes.now_secs() - t1
128end 129end
129 130
@@ -165,12 +166,12 @@ end
165 166
166-- sequential write/read (no parallelization involved) 167-- sequential write/read (no parallelization involved)
167local function ziva2( preloop, loop, batch) 168local function ziva2( preloop, loop, batch)
168 local l = lanes.linda("ziva2("..preloop..":"..loop..":"..tostring(batch)..")", group_uid) 169 local l = lanes.linda{name = "ziva2("..preloop..":"..loop..":"..tostring(batch)..")", group = group_uid}
169 group_uid = (group_uid % config.nb_user_keepers) + 1 170 group_uid = (group_uid % config.nb_user_keepers) + 1
170 -- prefill the linda a bit to increase fifo stress 171 -- prefill the linda a bit to increase fifo stress
171 local top, step = math.max( preloop, loop), (l.batched and batch) and batch or 1 172 local top, step = math.max( preloop, loop), batch or 1
172 local batch_send, batch_read 173 local batch_send, batch_read
173 if l.batched and batch then 174 if batch then
174 local batch_values = {} 175 local batch_values = {}
175 for i = 1, batch do 176 for i = 1, batch do
176 table.insert( batch_values, i) 177 table.insert( batch_values, i)
@@ -180,7 +181,7 @@ local function ziva2( preloop, loop, batch)
180 l:send( "key", table_unpack( batch_values)) 181 l:send( "key", table_unpack( batch_values))
181 end 182 end
182 batch_read = function() 183 batch_read = function()
183 l:receive( l.batched, "key", batch) 184 l:receive_batched("key", batch)
184 end 185 end
185 else -- not batched 186 else -- not batched
186 batch_send = function() 187 batch_send = function()
diff --git a/tests/perftest.lua b/tests/perftest.lua
index fe43cca..35e164d 100644
--- a/tests/perftest.lua
+++ b/tests/perftest.lua
@@ -175,9 +175,9 @@ else
175 -- Make sure all lanes finished 175 -- Make sure all lanes finished
176 -- 176 --
177 for i=1,N do 177 for i=1,N do
178 local tmp= t[i]:join() 178 local r, tmp = t[i]:join()
179 -- this assert will trigger if you change M to values below 1000 in order to solve C stack overflow 179 -- this assert will trigger if you change M to values below 1000 in order to solve C stack overflow
180 assert( type(tmp)=="table" and tmp[1]==2 and tmp[168]==997 ) 180 assert( r == true and type(tmp) == "table" and tmp[1] == 2 and tmp[168] == 997 )
181 end 181 end
182end 182end
183 183
diff --git a/tests/pingpong.lua b/tests/pingpong.lua
index 06c0903..1ed5b9a 100644
--- a/tests/pingpong.lua
+++ b/tests/pingpong.lua
@@ -21,13 +21,15 @@ local pingpong = function(name, qr, qs, start)
21 q:send(qs, val) 21 q:send(qs, val)
22 count = count + 1 22 count = count + 1
23 end 23 end
24 return true 24 return "ping!"
25end 25end
26 26
27-- pingpong("L1", '0', '1', true) 27-- pingpong("L1", '0', '1', true)
28local t1, err1 = lanes.gen("*", { name = 'auto' }, pingpong)("L1", 'a', 'b', true) 28local t1, err1 = lanes.gen("*", { name = 'auto' }, pingpong)("L1", 'a', 'b', true)
29local t2, err2 = lanes.gen("*", { name = 'auto' }, pingpong)("L2", 'b', 'a', false) 29local t2, err2 = lanes.gen("*", { name = 'auto' }, pingpong)("L2", 'b', 'a', false)
30 30
31t1:join() 31local r1, ret1 = t1:join()
32t2:join() 32assert(r1 == true and ret1 == "ping!")
33local r2, ret2 = t2:join()
34assert(r2 == true and ret2 == "ping!")
33print "TEST OK" 35print "TEST OK"
diff --git a/tests/protect_allocator.lua b/tests/protect_allocator.lua
index e13a57c..325726a 100644
--- a/tests/protect_allocator.lua
+++ b/tests/protect_allocator.lua
@@ -52,7 +52,7 @@ end
52 52
53-- wait for completion 53-- wait for completion
54print "wait for completion" 54print "wait for completion"
55linda:receive( linda.batched, "key", COUNT) 55linda:receive_batched("key", COUNT)
56print "waiting a bit more ..." 56print "waiting a bit more ..."
57SLEEP(1) 57SLEEP(1)
58print "SUCCESS" 58print "SUCCESS"
diff --git a/tests/rupval.lua b/tests/rupval.lua
index ad5ad9d..c6743b3 100644
--- a/tests/rupval.lua
+++ b/tests/rupval.lua
@@ -26,17 +26,17 @@ end
26local g = lanes.gen( "base", { name = 'auto' }, a) 26local g = lanes.gen( "base", { name = 'auto' }, a)
27 27
28local l = g(7) 28local l = g(7)
29local r = l:join() 29local _, r = l:join()
30assert(r == y) 30assert(r == y)
31print(r) 31print(r)
32 32
33local l = g(8) 33local l = g(8)
34local r = l:join() 34local _, r = l:join()
35assert(r == z) 35assert(r == z)
36print(r) 36print(r)
37 37
38local l = g(9) 38local l = g(9)
39local r = l:join() 39local _, r = l:join()
40assert(r == x) 40assert(r == x)
41print(r) 41print(r)
42 42
diff --git a/tests/tobeclosed.lua b/tests/tobeclosed.lua
index ef09df3..fd157e2 100644
--- a/tests/tobeclosed.lua
+++ b/tests/tobeclosed.lua
@@ -36,7 +36,7 @@ do
36 WR("f closing ", linda_) 36 WR("f closing ", linda_)
37 closed_by_f = true 37 closed_by_f = true
38 end 38 end
39 local lf <close> = lanes.linda("closed by f", close_handler_f) 39 local lf <close> = lanes.linda{name = "closed by f", close_handler = close_handler_f}
40 40
41 local close_handler_t = setmetatable({}, 41 local close_handler_t = setmetatable({},
42 { 42 {
@@ -46,7 +46,7 @@ do
46 end 46 end
47 } 47 }
48 ) 48 )
49 local lt <close> = lanes.linda("closed by t", close_handler_t) 49 local lt <close> = lanes.linda{name = "closed by t", close_handler = close_handler_t}
50 end 50 end
51 assert(closed_by_f == true) 51 assert(closed_by_f == true)
52 assert(closed_by_t == true) 52 assert(closed_by_t == true)
@@ -58,13 +58,13 @@ end
58WR "================================================================================================" 58WR "================================================================================================"
59WR "Through Linda" 59WR "Through Linda"
60do 60do
61 local l = lanes.linda("channel") 61 local l = lanes.linda{name = "channel"}
62 62
63 local close_handler_f = function(linda_, err_) 63 local close_handler_f = function(linda_, err_)
64 WR("f closing ", linda_) 64 WR("f closing ", linda_)
65 linda_:set("closed", true) 65 linda_:set("closed", true)
66 end 66 end
67 local l_in = lanes.linda("voyager", close_handler_f) 67 local l_in = lanes.linda{name = "voyager", close_handler = close_handler_f}
68 l:set("trip", l_in) 68 l:set("trip", l_in)
69 69
70 do 70 do
@@ -99,14 +99,14 @@ end
99WR "================================================================================================" 99WR "================================================================================================"
100WR "Linda closing through Lane" 100WR "Linda closing through Lane"
101do 101do
102 local l = lanes.linda("channel") 102 local l = lanes.linda{name = "channel"}
103 local lane_body = function(l_arg_) 103 local lane_body = function(l_arg_)
104 WR "In lane body" 104 WR "In lane body"
105 -- linda obtained through a linda 105 -- linda obtained through a linda
106 local _count, l_out <close> = l:get("trip") 106 local _count, l_out <close> = l:get("trip")
107 -- linda from arguments 107 -- linda from arguments
108 local l_arg <close> = l_arg_ 108 local l_arg <close> = l_arg_
109 return true 109 return "done"
110 end 110 end
111 111
112 local close_handler_f = function(linda_, err_) 112 local close_handler_f = function(linda_, err_)
@@ -114,11 +114,12 @@ do
114 local _count, _closed = linda_:get("closed") 114 local _count, _closed = linda_:get("closed")
115 linda_:set("closed", (_closed or 0) + 1) 115 linda_:set("closed", (_closed or 0) + 1)
116 end 116 end
117 local l_in = lanes.linda("voyager", close_handler_f) 117 local l_in = lanes.linda{name = "voyager", close_handler = close_handler_f}
118 l:set("trip", l_in) 118 l:set("trip", l_in)
119 119
120 do 120 do
121 lanes.gen("*", { name = 'auto' }, lane_body)(l_in):join() 121 local r, ret = lanes.gen("*", { name = 'auto' }, lane_body)(l_in):join()
122 assert(r == true and ret == "done")
122 end 123 end
123 local _count, _closed = l_in:get("closed") 124 local _count, _closed = l_in:get("closed")
124 assert(_count == 1 and _closed == 2) 125 assert(_count == 1 and _closed == 2)
diff --git a/tests/track_lanes.lua b/tests/track_lanes.lua
index d1670ae..ef2ca06 100644
--- a/tests/track_lanes.lua
+++ b/tests/track_lanes.lua
@@ -59,8 +59,10 @@ local threads = track( "============= START", 2)
59-- two_seconds forever 59-- two_seconds forever
60assert(threads[1].status == 'waiting' and threads[2].status == 'waiting') 60assert(threads[1].status == 'waiting' and threads[2].status == 'waiting')
61 61
62-- wait until ephemeral1 has completed 62-- wait until ephemeral1 has completed, should take about 2 seconds
63SLEEP(2.1) 63repeat
64 SLEEP(0.1)
65until ephemeral1.status == "done"
64 66
65local threads = track( "============= two_seconds dead", 2) 67local threads = track( "============= two_seconds dead", 2)
66-- two_seconds forever 68-- two_seconds forever
diff --git a/unit_tests/UnitTests.vcxproj b/unit_tests/UnitTests.vcxproj
index 6ff1eb1..2093063 100644
--- a/unit_tests/UnitTests.vcxproj
+++ b/unit_tests/UnitTests.vcxproj
@@ -45,6 +45,30 @@
45 <Configuration>Debug 5.4</Configuration> 45 <Configuration>Debug 5.4</Configuration>
46 <Platform>Win32</Platform> 46 <Platform>Win32</Platform>
47 </ProjectConfiguration> 47 </ProjectConfiguration>
48 <ProjectConfiguration Include="Debug 5.5|Prospero">
49 <Configuration>Debug 5.5</Configuration>
50 <Platform>Prospero</Platform>
51 </ProjectConfiguration>
52 <ProjectConfiguration Include="Debug 5.5|Win32">
53 <Configuration>Debug 5.5</Configuration>
54 <Platform>Win32</Platform>
55 </ProjectConfiguration>
56 <ProjectConfiguration Include="Debug 5.5|x64">
57 <Configuration>Debug 5.5</Configuration>
58 <Platform>x64</Platform>
59 </ProjectConfiguration>
60 <ProjectConfiguration Include="Release 5.5|Prospero">
61 <Configuration>Release 5.5</Configuration>
62 <Platform>Prospero</Platform>
63 </ProjectConfiguration>
64 <ProjectConfiguration Include="Release 5.5|Win32">
65 <Configuration>Release 5.5</Configuration>
66 <Platform>Win32</Platform>
67 </ProjectConfiguration>
68 <ProjectConfiguration Include="Release 5.5|x64">
69 <Configuration>Release 5.5</Configuration>
70 <Platform>x64</Platform>
71 </ProjectConfiguration>
48 <ProjectConfiguration Include="Release LuaJIT|Prospero"> 72 <ProjectConfiguration Include="Release LuaJIT|Prospero">
49 <Configuration>Release LuaJIT</Configuration> 73 <Configuration>Release LuaJIT</Configuration>
50 <Platform>Prospero</Platform> 74 <Platform>Prospero</Platform>
@@ -125,7 +149,7 @@
125 <PropertyGroup Label="Globals"> 149 <PropertyGroup Label="Globals">
126 <ProjectGuid>{aed7f42f-139a-46ba-80fe-16e062ea1345}</ProjectGuid> 150 <ProjectGuid>{aed7f42f-139a-46ba-80fe-16e062ea1345}</ProjectGuid>
127 <Keyword>Win32Proj</Keyword> 151 <Keyword>Win32Proj</Keyword>
128 <WindowsTargetPlatformVersion>10.0.22621.0</WindowsTargetPlatformVersion> 152 <WindowsTargetPlatformVersion>10.0</WindowsTargetPlatformVersion>
129 <ConfigurationType>Application</ConfigurationType> 153 <ConfigurationType>Application</ConfigurationType>
130 <PlatformToolset>v143</PlatformToolset> 154 <PlatformToolset>v143</PlatformToolset>
131 <CharacterSet>Unicode</CharacterSet> 155 <CharacterSet>Unicode</CharacterSet>
@@ -143,6 +167,9 @@
143 <PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Debug 5.4|x64'"> 167 <PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Debug 5.4|x64'">
144 <UseDebugLibraries>true</UseDebugLibraries> 168 <UseDebugLibraries>true</UseDebugLibraries>
145 </PropertyGroup> 169 </PropertyGroup>
170 <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug 5.5|x64'" Label="Configuration">
171 <UseDebugLibraries>true</UseDebugLibraries>
172 </PropertyGroup>
146 <PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Release LuaJIT|x64'"> 173 <PropertyGroup Label="Configuration" Condition="'$(Configuration)|$(Platform)'=='Release LuaJIT|x64'">
147 <UseDebugLibraries>true</UseDebugLibraries> 174 <UseDebugLibraries>true</UseDebugLibraries>
148 </PropertyGroup> 175 </PropertyGroup>
@@ -155,103 +182,123 @@
155 <ImportGroup Label="PropertySheets" /> 182 <ImportGroup Label="PropertySheets" />
156 <PropertyGroup Label="UserMacros" /> 183 <PropertyGroup Label="UserMacros" />
157 <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug 5.4|Win32'"> 184 <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug 5.4|Win32'">
158 <OutDir>$(SolutionDir)_Output\$(ProjectName)\$(PlatformName)\$(Configuration)\</OutDir> 185 <OutDir>$(SolutionDir)_LuaVersions\$(PlatformName)\$(Configuration)\</OutDir>
186 <IntDir>$(SolutionDir)_Tmp\$(ProjectName)\$(PlatformName)\$(Configuration)\</IntDir>
187 <LinkIncremental>false</LinkIncremental>
188 </PropertyGroup>
189 <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug 5.5|Win32'">
190 <OutDir>$(SolutionDir)_LuaVersions\$(PlatformName)\$(Configuration)\</OutDir>
159 <IntDir>$(SolutionDir)_Tmp\$(ProjectName)\$(PlatformName)\$(Configuration)\</IntDir> 191 <IntDir>$(SolutionDir)_Tmp\$(ProjectName)\$(PlatformName)\$(Configuration)\</IntDir>
160 <LinkIncremental>false</LinkIncremental> 192 <LinkIncremental>false</LinkIncremental>
161 </PropertyGroup> 193 </PropertyGroup>
162 <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug 5.3|Win32'"> 194 <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug 5.3|Win32'">
163 <OutDir>$(SolutionDir)_Output\$(ProjectName)\$(PlatformName)\$(Configuration)\</OutDir> 195 <OutDir>$(SolutionDir)_LuaVersions\$(PlatformName)\$(Configuration)\</OutDir>
164 <IntDir>$(SolutionDir)_Tmp\$(ProjectName)\$(PlatformName)\$(Configuration)\</IntDir> 196 <IntDir>$(SolutionDir)_Tmp\$(ProjectName)\$(PlatformName)\$(Configuration)\</IntDir>
165 <LinkIncremental>false</LinkIncremental> 197 <LinkIncremental>false</LinkIncremental>
166 </PropertyGroup> 198 </PropertyGroup>
167 <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release 5.3|Win32'"> 199 <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release 5.3|Win32'">
168 <OutDir>$(SolutionDir)_Output\$(ProjectName)\$(PlatformName)\$(Configuration)\</OutDir> 200 <OutDir>$(SolutionDir)_LuaVersions\$(PlatformName)\$(Configuration)\</OutDir>
169 <IntDir>$(SolutionDir)_Tmp\$(ProjectName)\$(PlatformName)\$(Configuration)\</IntDir> 201 <IntDir>$(SolutionDir)_Tmp\$(ProjectName)\$(PlatformName)\$(Configuration)\</IntDir>
170 <LinkIncremental>false</LinkIncremental> 202 <LinkIncremental>false</LinkIncremental>
171 </PropertyGroup> 203 </PropertyGroup>
172 <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug 5.2|Win32'"> 204 <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug 5.2|Win32'">
173 <OutDir>$(SolutionDir)_Output\$(ProjectName)\$(PlatformName)\$(Configuration)\</OutDir> 205 <OutDir>$(SolutionDir)_LuaVersions\$(PlatformName)\$(Configuration)\</OutDir>
174 <IntDir>$(SolutionDir)_Tmp\$(ProjectName)\$(PlatformName)\$(Configuration)\</IntDir> 206 <IntDir>$(SolutionDir)_Tmp\$(ProjectName)\$(PlatformName)\$(Configuration)\</IntDir>
175 <LinkIncremental>false</LinkIncremental> 207 <LinkIncremental>false</LinkIncremental>
176 </PropertyGroup> 208 </PropertyGroup>
177 <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release 5.2|Win32'"> 209 <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release 5.2|Win32'">
178 <OutDir>$(SolutionDir)_Output\$(ProjectName)\$(PlatformName)\$(Configuration)\</OutDir> 210 <OutDir>$(SolutionDir)_LuaVersions\$(PlatformName)\$(Configuration)\</OutDir>
179 <IntDir>$(SolutionDir)_Tmp\$(ProjectName)\$(PlatformName)\$(Configuration)\</IntDir> 211 <IntDir>$(SolutionDir)_Tmp\$(ProjectName)\$(PlatformName)\$(Configuration)\</IntDir>
180 <LinkIncremental>false</LinkIncremental> 212 <LinkIncremental>false</LinkIncremental>
181 </PropertyGroup> 213 </PropertyGroup>
182 <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug 5.1|Win32'"> 214 <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug 5.1|Win32'">
183 <OutDir>$(SolutionDir)_Output\$(ProjectName)\$(PlatformName)\$(Configuration)\</OutDir> 215 <OutDir>$(SolutionDir)_LuaVersions\$(PlatformName)\$(Configuration)\</OutDir>
184 <IntDir>$(SolutionDir)_Tmp\$(ProjectName)\$(PlatformName)\$(Configuration)\</IntDir> 216 <IntDir>$(SolutionDir)_Tmp\$(ProjectName)\$(PlatformName)\$(Configuration)\</IntDir>
185 <LinkIncremental>false</LinkIncremental> 217 <LinkIncremental>false</LinkIncremental>
186 </PropertyGroup> 218 </PropertyGroup>
187 <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release 5.1|Win32'"> 219 <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release 5.1|Win32'">
188 <OutDir>$(SolutionDir)_Output\$(ProjectName)\$(PlatformName)\$(Configuration)\</OutDir> 220 <OutDir>$(SolutionDir)_LuaVersions\$(PlatformName)\$(Configuration)\</OutDir>
189 <IntDir>$(SolutionDir)_Tmp\$(ProjectName)\$(PlatformName)\$(Configuration)\</IntDir> 221 <IntDir>$(SolutionDir)_Tmp\$(ProjectName)\$(PlatformName)\$(Configuration)\</IntDir>
190 <LinkIncremental>false</LinkIncremental> 222 <LinkIncremental>false</LinkIncremental>
191 </PropertyGroup> 223 </PropertyGroup>
192 <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release LuaJIT|Win32'"> 224 <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release LuaJIT|Win32'">
193 <OutDir>$(SolutionDir)_Output\$(ProjectName)\$(PlatformName)\$(Configuration)\</OutDir> 225 <OutDir>$(SolutionDir)_LuaVersions\$(PlatformName)\$(Configuration)\</OutDir>
194 <IntDir>$(SolutionDir)_Tmp\$(ProjectName)\$(PlatformName)\$(Configuration)\</IntDir> 226 <IntDir>$(SolutionDir)_Tmp\$(ProjectName)\$(PlatformName)\$(Configuration)\</IntDir>
195 <LinkIncremental>false</LinkIncremental> 227 <LinkIncremental>false</LinkIncremental>
196 </PropertyGroup> 228 </PropertyGroup>
197 <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release MoonJIT|Win32'"> 229 <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release MoonJIT|Win32'">
198 <OutDir>$(SolutionDir)_Output\$(ProjectName)\$(PlatformName)\$(Configuration)\</OutDir> 230 <OutDir>$(SolutionDir)_LuaVersions\$(PlatformName)\$(Configuration)\</OutDir>
199 <IntDir>$(SolutionDir)_Tmp\$(ProjectName)\$(PlatformName)\$(Configuration)\</IntDir> 231 <IntDir>$(SolutionDir)_Tmp\$(ProjectName)\$(PlatformName)\$(Configuration)\</IntDir>
200 <LinkIncremental>false</LinkIncremental> 232 <LinkIncremental>false</LinkIncremental>
201 </PropertyGroup> 233 </PropertyGroup>
202 <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release 5.4|Win32'"> 234 <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release 5.4|Win32'">
203 <OutDir>$(SolutionDir)_Output\$(ProjectName)\$(PlatformName)\$(Configuration)\</OutDir> 235 <OutDir>$(SolutionDir)_LuaVersions\$(PlatformName)\$(Configuration)\</OutDir>
236 <IntDir>$(SolutionDir)_Tmp\$(ProjectName)\$(PlatformName)\$(Configuration)\</IntDir>
237 <LinkIncremental>false</LinkIncremental>
238 </PropertyGroup>
239 <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release 5.5|Win32'">
240 <OutDir>$(SolutionDir)_LuaVersions\$(PlatformName)\$(Configuration)\</OutDir>
204 <IntDir>$(SolutionDir)_Tmp\$(ProjectName)\$(PlatformName)\$(Configuration)\</IntDir> 241 <IntDir>$(SolutionDir)_Tmp\$(ProjectName)\$(PlatformName)\$(Configuration)\</IntDir>
205 <LinkIncremental>false</LinkIncremental> 242 <LinkIncremental>false</LinkIncremental>
206 </PropertyGroup> 243 </PropertyGroup>
207 <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug 5.4|x64'"> 244 <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug 5.4|x64'">
208 <OutDir>$(SolutionDir)_Output\$(ProjectName)\$(PlatformName)\$(Configuration)\</OutDir> 245 <OutDir>$(SolutionDir)_LuaVersions\$(PlatformName)\$(Configuration)\</OutDir>
246 <IntDir>$(SolutionDir)_Tmp\$(ProjectName)\$(PlatformName)\$(Configuration)\</IntDir>
247 <LinkIncremental>false</LinkIncremental>
248 </PropertyGroup>
249 <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug 5.5|x64'">
250 <OutDir>$(SolutionDir)_LuaVersions\$(PlatformName)\$(Configuration)\</OutDir>
209 <IntDir>$(SolutionDir)_Tmp\$(ProjectName)\$(PlatformName)\$(Configuration)\</IntDir> 251 <IntDir>$(SolutionDir)_Tmp\$(ProjectName)\$(PlatformName)\$(Configuration)\</IntDir>
210 <LinkIncremental>false</LinkIncremental> 252 <LinkIncremental>false</LinkIncremental>
211 </PropertyGroup> 253 </PropertyGroup>
212 <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug 5.4|Prospero'" /> 254 <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug 5.4|Prospero'" />
213 <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug 5.3|x64'"> 255 <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug 5.3|x64'">
214 <OutDir>$(SolutionDir)_Output\$(ProjectName)\$(PlatformName)\$(Configuration)\</OutDir> 256 <OutDir>$(SolutionDir)_LuaVersions\$(PlatformName)\$(Configuration)\</OutDir>
215 <IntDir>$(SolutionDir)_Tmp\$(ProjectName)\$(PlatformName)\$(Configuration)\</IntDir> 257 <IntDir>$(SolutionDir)_Tmp\$(ProjectName)\$(PlatformName)\$(Configuration)\</IntDir>
216 <LinkIncremental>false</LinkIncremental> 258 <LinkIncremental>false</LinkIncremental>
217 </PropertyGroup> 259 </PropertyGroup>
218 <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release 5.3|x64'"> 260 <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release 5.3|x64'">
219 <OutDir>$(SolutionDir)_Output\$(ProjectName)\$(PlatformName)\$(Configuration)\</OutDir> 261 <OutDir>$(SolutionDir)_LuaVersions\$(PlatformName)\$(Configuration)\</OutDir>
220 <IntDir>$(SolutionDir)_Tmp\$(ProjectName)\$(PlatformName)\$(Configuration)\</IntDir> 262 <IntDir>$(SolutionDir)_Tmp\$(ProjectName)\$(PlatformName)\$(Configuration)\</IntDir>
221 <LinkIncremental>false</LinkIncremental> 263 <LinkIncremental>false</LinkIncremental>
222 </PropertyGroup> 264 </PropertyGroup>
223 <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug 5.2|x64'"> 265 <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug 5.2|x64'">
224 <OutDir>$(SolutionDir)_Output\$(ProjectName)\$(PlatformName)\$(Configuration)\</OutDir> 266 <OutDir>$(SolutionDir)_LuaVersions\$(PlatformName)\$(Configuration)\</OutDir>
225 <IntDir>$(SolutionDir)_Tmp\$(ProjectName)\$(PlatformName)\$(Configuration)\</IntDir> 267 <IntDir>$(SolutionDir)_Tmp\$(ProjectName)\$(PlatformName)\$(Configuration)\</IntDir>
226 <LinkIncremental>false</LinkIncremental> 268 <LinkIncremental>false</LinkIncremental>
227 </PropertyGroup> 269 </PropertyGroup>
228 <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release 5.2|x64'"> 270 <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release 5.2|x64'">
229 <OutDir>$(SolutionDir)_Output\$(ProjectName)\$(PlatformName)\$(Configuration)\</OutDir> 271 <OutDir>$(SolutionDir)_LuaVersions\$(PlatformName)\$(Configuration)\</OutDir>
230 <IntDir>$(SolutionDir)_Tmp\$(ProjectName)\$(PlatformName)\$(Configuration)\</IntDir> 272 <IntDir>$(SolutionDir)_Tmp\$(ProjectName)\$(PlatformName)\$(Configuration)\</IntDir>
231 <LinkIncremental>false</LinkIncremental> 273 <LinkIncremental>false</LinkIncremental>
232 </PropertyGroup> 274 </PropertyGroup>
233 <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug 5.1|x64'"> 275 <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug 5.1|x64'">
234 <OutDir>$(SolutionDir)_Output\$(ProjectName)\$(PlatformName)\$(Configuration)\</OutDir> 276 <OutDir>$(SolutionDir)_LuaVersions\$(PlatformName)\$(Configuration)\</OutDir>
235 <IntDir>$(SolutionDir)_Tmp\$(ProjectName)\$(PlatformName)\$(Configuration)\</IntDir> 277 <IntDir>$(SolutionDir)_Tmp\$(ProjectName)\$(PlatformName)\$(Configuration)\</IntDir>
236 <LinkIncremental>false</LinkIncremental> 278 <LinkIncremental>false</LinkIncremental>
237 </PropertyGroup> 279 </PropertyGroup>
238 <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release 5.1|x64'"> 280 <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release 5.1|x64'">
239 <OutDir>$(SolutionDir)_Output\$(ProjectName)\$(PlatformName)\$(Configuration)\</OutDir> 281 <OutDir>$(SolutionDir)_LuaVersions\$(PlatformName)\$(Configuration)\</OutDir>
240 <IntDir>$(SolutionDir)_Tmp\$(ProjectName)\$(PlatformName)\$(Configuration)\</IntDir> 282 <IntDir>$(SolutionDir)_Tmp\$(ProjectName)\$(PlatformName)\$(Configuration)\</IntDir>
241 <LinkIncremental>false</LinkIncremental> 283 <LinkIncremental>false</LinkIncremental>
242 </PropertyGroup> 284 </PropertyGroup>
243 <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release LuaJIT|x64'"> 285 <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release LuaJIT|x64'">
244 <OutDir>$(SolutionDir)_Output\$(ProjectName)\$(PlatformName)\$(Configuration)\</OutDir> 286 <OutDir>$(SolutionDir)_LuaVersions\$(PlatformName)\$(Configuration)\</OutDir>
245 <IntDir>$(SolutionDir)_Tmp\$(ProjectName)\$(PlatformName)\$(Configuration)\</IntDir> 287 <IntDir>$(SolutionDir)_Tmp\$(ProjectName)\$(PlatformName)\$(Configuration)\</IntDir>
246 <LinkIncremental>false</LinkIncremental> 288 <LinkIncremental>false</LinkIncremental>
247 </PropertyGroup> 289 </PropertyGroup>
248 <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release MoonJIT|x64'"> 290 <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release MoonJIT|x64'">
249 <OutDir>$(SolutionDir)_Output\$(ProjectName)\$(PlatformName)\$(Configuration)\</OutDir> 291 <OutDir>$(SolutionDir)_LuaVersions\$(PlatformName)\$(Configuration)\</OutDir>
250 <IntDir>$(SolutionDir)_Tmp\$(ProjectName)\$(PlatformName)\$(Configuration)\</IntDir> 292 <IntDir>$(SolutionDir)_Tmp\$(ProjectName)\$(PlatformName)\$(Configuration)\</IntDir>
251 <LinkIncremental>false</LinkIncremental> 293 <LinkIncremental>false</LinkIncremental>
252 </PropertyGroup> 294 </PropertyGroup>
253 <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release 5.4|x64'"> 295 <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release 5.4|x64'">
254 <OutDir>$(SolutionDir)_Output\$(ProjectName)\$(PlatformName)\$(Configuration)\</OutDir> 296 <OutDir>$(SolutionDir)_LuaVersions\$(PlatformName)\$(Configuration)\</OutDir>
297 <IntDir>$(SolutionDir)_Tmp\$(ProjectName)\$(PlatformName)\$(Configuration)\</IntDir>
298 <LinkIncremental>false</LinkIncremental>
299 </PropertyGroup>
300 <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release 5.5|x64'">
301 <OutDir>$(SolutionDir)_LuaVersions\$(PlatformName)\$(Configuration)\</OutDir>
255 <IntDir>$(SolutionDir)_Tmp\$(ProjectName)\$(PlatformName)\$(Configuration)\</IntDir> 302 <IntDir>$(SolutionDir)_Tmp\$(ProjectName)\$(PlatformName)\$(Configuration)\</IntDir>
256 <LinkIncremental>false</LinkIncremental> 303 <LinkIncremental>false</LinkIncremental>
257 </PropertyGroup> 304 </PropertyGroup>
@@ -261,7 +308,26 @@
261 <PrecompiledHeader>Use</PrecompiledHeader> 308 <PrecompiledHeader>Use</PrecompiledHeader>
262 <PrecompiledHeaderFile>_pch.hpp</PrecompiledHeaderFile> 309 <PrecompiledHeaderFile>_pch.hpp</PrecompiledHeaderFile>
263 <Optimization>Disabled</Optimization> 310 <Optimization>Disabled</Optimization>
264 <PreprocessorDefinitions>WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions> 311 <PreprocessorDefinitions>LANES_DEBUG;WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
312 <BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>
313 <WarningLevel>Level3</WarningLevel>
314 <AdditionalIncludeDirectories>$(SolutionDir)/_LuaVersions/$(PlatformName)/$(ConfigurationName)/include;$(SolutionDir)..</AdditionalIncludeDirectories>
315 <LanguageStandard>stdcpp20</LanguageStandard>
316 <RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary>
317 </ClCompile>
318 <Link>
319 <GenerateDebugInformation>true</GenerateDebugInformation>
320 <SubSystem>Console</SubSystem>
321 <AdditionalDependencies>lua54.lib;$(CoreLibraryDependencies);%(AdditionalDependencies)</AdditionalDependencies>
322 <AdditionalLibraryDirectories>$(SolutionDir)_LuaVersions\$(PlatformName)\$(ConfigurationName)</AdditionalLibraryDirectories>
323 </Link>
324 </ItemDefinitionGroup>
325 <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug 5.5|Win32'">
326 <ClCompile>
327 <PrecompiledHeader>Use</PrecompiledHeader>
328 <PrecompiledHeaderFile>_pch.hpp</PrecompiledHeaderFile>
329 <Optimization>Disabled</Optimization>
330 <PreprocessorDefinitions>LANES_DEBUG;WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
265 <BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks> 331 <BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>
266 <WarningLevel>Level3</WarningLevel> 332 <WarningLevel>Level3</WarningLevel>
267 <AdditionalIncludeDirectories>$(SolutionDir)/_LuaVersions/$(PlatformName)/$(ConfigurationName)/include;$(SolutionDir)..</AdditionalIncludeDirectories> 333 <AdditionalIncludeDirectories>$(SolutionDir)/_LuaVersions/$(PlatformName)/$(ConfigurationName)/include;$(SolutionDir)..</AdditionalIncludeDirectories>
@@ -280,7 +346,7 @@
280 <PrecompiledHeader>Use</PrecompiledHeader> 346 <PrecompiledHeader>Use</PrecompiledHeader>
281 <PrecompiledHeaderFile>_pch.hpp</PrecompiledHeaderFile> 347 <PrecompiledHeaderFile>_pch.hpp</PrecompiledHeaderFile>
282 <Optimization>Disabled</Optimization> 348 <Optimization>Disabled</Optimization>
283 <PreprocessorDefinitions>WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions> 349 <PreprocessorDefinitions>LANES_DEBUG;WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
284 <BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks> 350 <BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>
285 <WarningLevel>Level3</WarningLevel> 351 <WarningLevel>Level3</WarningLevel>
286 <AdditionalIncludeDirectories>$(SolutionDir)/_LuaVersions/$(PlatformName)/$(ConfigurationName)/include;$(SolutionDir)..</AdditionalIncludeDirectories> 352 <AdditionalIncludeDirectories>$(SolutionDir)/_LuaVersions/$(PlatformName)/$(ConfigurationName)/include;$(SolutionDir)..</AdditionalIncludeDirectories>
@@ -299,7 +365,7 @@
299 <PrecompiledHeader>Use</PrecompiledHeader> 365 <PrecompiledHeader>Use</PrecompiledHeader>
300 <PrecompiledHeaderFile>_pch.hpp</PrecompiledHeaderFile> 366 <PrecompiledHeaderFile>_pch.hpp</PrecompiledHeaderFile>
301 <Optimization>Disabled</Optimization> 367 <Optimization>Disabled</Optimization>
302 <PreprocessorDefinitions>WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions> 368 <PreprocessorDefinitions>LANES_DEBUG;WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
303 <BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks> 369 <BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>
304 <WarningLevel>Level3</WarningLevel> 370 <WarningLevel>Level3</WarningLevel>
305 <AdditionalIncludeDirectories>$(SolutionDir)/_LuaVersions/$(PlatformName)/$(ConfigurationName)/include;$(SolutionDir)..</AdditionalIncludeDirectories> 371 <AdditionalIncludeDirectories>$(SolutionDir)/_LuaVersions/$(PlatformName)/$(ConfigurationName)/include;$(SolutionDir)..</AdditionalIncludeDirectories>
@@ -318,7 +384,7 @@
318 <PrecompiledHeader>Use</PrecompiledHeader> 384 <PrecompiledHeader>Use</PrecompiledHeader>
319 <PrecompiledHeaderFile>_pch.hpp</PrecompiledHeaderFile> 385 <PrecompiledHeaderFile>_pch.hpp</PrecompiledHeaderFile>
320 <Optimization>Disabled</Optimization> 386 <Optimization>Disabled</Optimization>
321 <PreprocessorDefinitions>WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions> 387 <PreprocessorDefinitions>LANES_DEBUG;WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
322 <BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks> 388 <BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>
323 <WarningLevel>Level3</WarningLevel> 389 <WarningLevel>Level3</WarningLevel>
324 <AdditionalIncludeDirectories>$(SolutionDir)/_LuaVersions/$(PlatformName)/$(ConfigurationName)/include;$(SolutionDir)..</AdditionalIncludeDirectories> 390 <AdditionalIncludeDirectories>$(SolutionDir)/_LuaVersions/$(PlatformName)/$(ConfigurationName)/include;$(SolutionDir)..</AdditionalIncludeDirectories>
@@ -337,7 +403,7 @@
337 <PrecompiledHeader>Use</PrecompiledHeader> 403 <PrecompiledHeader>Use</PrecompiledHeader>
338 <PrecompiledHeaderFile>_pch.hpp</PrecompiledHeaderFile> 404 <PrecompiledHeaderFile>_pch.hpp</PrecompiledHeaderFile>
339 <Optimization>Disabled</Optimization> 405 <Optimization>Disabled</Optimization>
340 <PreprocessorDefinitions>WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions> 406 <PreprocessorDefinitions>LANES_DEBUG;WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
341 <BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks> 407 <BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>
342 <WarningLevel>Level3</WarningLevel> 408 <WarningLevel>Level3</WarningLevel>
343 <AdditionalIncludeDirectories>$(SolutionDir)/_LuaVersions/$(PlatformName)/$(ConfigurationName)/include;$(SolutionDir)..</AdditionalIncludeDirectories> 409 <AdditionalIncludeDirectories>$(SolutionDir)/_LuaVersions/$(PlatformName)/$(ConfigurationName)/include;$(SolutionDir)..</AdditionalIncludeDirectories>
@@ -356,7 +422,7 @@
356 <PrecompiledHeader>Use</PrecompiledHeader> 422 <PrecompiledHeader>Use</PrecompiledHeader>
357 <PrecompiledHeaderFile>_pch.hpp</PrecompiledHeaderFile> 423 <PrecompiledHeaderFile>_pch.hpp</PrecompiledHeaderFile>
358 <Optimization>Disabled</Optimization> 424 <Optimization>Disabled</Optimization>
359 <PreprocessorDefinitions>WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions> 425 <PreprocessorDefinitions>LANES_DEBUG;WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
360 <BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks> 426 <BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>
361 <WarningLevel>Level3</WarningLevel> 427 <WarningLevel>Level3</WarningLevel>
362 <AdditionalIncludeDirectories>$(SolutionDir)/_LuaVersions/$(PlatformName)/$(ConfigurationName)/include;$(SolutionDir)..</AdditionalIncludeDirectories> 428 <AdditionalIncludeDirectories>$(SolutionDir)/_LuaVersions/$(PlatformName)/$(ConfigurationName)/include;$(SolutionDir)..</AdditionalIncludeDirectories>
@@ -375,7 +441,7 @@
375 <PrecompiledHeader>Use</PrecompiledHeader> 441 <PrecompiledHeader>Use</PrecompiledHeader>
376 <PrecompiledHeaderFile>_pch.hpp</PrecompiledHeaderFile> 442 <PrecompiledHeaderFile>_pch.hpp</PrecompiledHeaderFile>
377 <Optimization>Disabled</Optimization> 443 <Optimization>Disabled</Optimization>
378 <PreprocessorDefinitions>WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions> 444 <PreprocessorDefinitions>LANES_DEBUG;WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
379 <BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks> 445 <BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>
380 <WarningLevel>Level3</WarningLevel> 446 <WarningLevel>Level3</WarningLevel>
381 <AdditionalIncludeDirectories>$(SolutionDir)/_LuaVersions/$(PlatformName)/$(ConfigurationName)/include;$(SolutionDir)..</AdditionalIncludeDirectories> 447 <AdditionalIncludeDirectories>$(SolutionDir)/_LuaVersions/$(PlatformName)/$(ConfigurationName)/include;$(SolutionDir)..</AdditionalIncludeDirectories>
@@ -394,7 +460,7 @@
394 <PrecompiledHeader>Use</PrecompiledHeader> 460 <PrecompiledHeader>Use</PrecompiledHeader>
395 <PrecompiledHeaderFile>_pch.hpp</PrecompiledHeaderFile> 461 <PrecompiledHeaderFile>_pch.hpp</PrecompiledHeaderFile>
396 <Optimization>Disabled</Optimization> 462 <Optimization>Disabled</Optimization>
397 <PreprocessorDefinitions>WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions> 463 <PreprocessorDefinitions>LANES_DEBUG;WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
398 <BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks> 464 <BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>
399 <WarningLevel>Level3</WarningLevel> 465 <WarningLevel>Level3</WarningLevel>
400 <AdditionalIncludeDirectories>$(SolutionDir)/_LuaVersions/$(PlatformName)/$(ConfigurationName)/include;$(SolutionDir)..</AdditionalIncludeDirectories> 466 <AdditionalIncludeDirectories>$(SolutionDir)/_LuaVersions/$(PlatformName)/$(ConfigurationName)/include;$(SolutionDir)..</AdditionalIncludeDirectories>
@@ -413,7 +479,7 @@
413 <PrecompiledHeader>Use</PrecompiledHeader> 479 <PrecompiledHeader>Use</PrecompiledHeader>
414 <PrecompiledHeaderFile>_pch.hpp</PrecompiledHeaderFile> 480 <PrecompiledHeaderFile>_pch.hpp</PrecompiledHeaderFile>
415 <Optimization>Disabled</Optimization> 481 <Optimization>Disabled</Optimization>
416 <PreprocessorDefinitions>WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions> 482 <PreprocessorDefinitions>LANES_DEBUG;WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
417 <BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks> 483 <BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>
418 <WarningLevel>Level3</WarningLevel> 484 <WarningLevel>Level3</WarningLevel>
419 <AdditionalIncludeDirectories>$(SolutionDir)/_LuaVersions/$(PlatformName)/$(ConfigurationName)/include;$(SolutionDir)..</AdditionalIncludeDirectories> 485 <AdditionalIncludeDirectories>$(SolutionDir)/_LuaVersions/$(PlatformName)/$(ConfigurationName)/include;$(SolutionDir)..</AdditionalIncludeDirectories>
@@ -432,7 +498,7 @@
432 <PrecompiledHeader>Use</PrecompiledHeader> 498 <PrecompiledHeader>Use</PrecompiledHeader>
433 <PrecompiledHeaderFile>_pch.hpp</PrecompiledHeaderFile> 499 <PrecompiledHeaderFile>_pch.hpp</PrecompiledHeaderFile>
434 <Optimization>Disabled</Optimization> 500 <Optimization>Disabled</Optimization>
435 <PreprocessorDefinitions>X64;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions> 501 <PreprocessorDefinitions>LANES_DEBUG;X64;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
436 <BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks> 502 <BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>
437 <WarningLevel>Level3</WarningLevel> 503 <WarningLevel>Level3</WarningLevel>
438 <AdditionalIncludeDirectories>$(SolutionDir)/_LuaVersions/$(PlatformName)/$(ConfigurationName)/include;$(SolutionDir)..</AdditionalIncludeDirectories> 504 <AdditionalIncludeDirectories>$(SolutionDir)/_LuaVersions/$(PlatformName)/$(ConfigurationName)/include;$(SolutionDir)..</AdditionalIncludeDirectories>
@@ -448,6 +514,27 @@
448 </IgnoreSpecificDefaultLibraries> 514 </IgnoreSpecificDefaultLibraries>
449 </Link> 515 </Link>
450 </ItemDefinitionGroup> 516 </ItemDefinitionGroup>
517 <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug 5.5|x64'">
518 <ClCompile>
519 <PrecompiledHeader>Use</PrecompiledHeader>
520 <PrecompiledHeaderFile>_pch.hpp</PrecompiledHeaderFile>
521 <Optimization>Disabled</Optimization>
522 <PreprocessorDefinitions>LANES_DEBUG;X64;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
523 <BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>
524 <WarningLevel>Level3</WarningLevel>
525 <AdditionalIncludeDirectories>$(SolutionDir)/_LuaVersions/$(PlatformName)/$(ConfigurationName)/include;$(SolutionDir)..</AdditionalIncludeDirectories>
526 <LanguageStandard>stdcpp20</LanguageStandard>
527 <RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary>
528 </ClCompile>
529 <Link>
530 <GenerateDebugInformation>true</GenerateDebugInformation>
531 <SubSystem>Console</SubSystem>
532 <AdditionalLibraryDirectories>$(SolutionDir)_LuaVersions\$(PlatformName)\$(ConfigurationName)</AdditionalLibraryDirectories>
533 <AdditionalDependencies>lua55.lib;$(CoreLibraryDependencies);%(AdditionalDependencies)</AdditionalDependencies>
534 <IgnoreSpecificDefaultLibraries>
535 </IgnoreSpecificDefaultLibraries>
536 </Link>
537 </ItemDefinitionGroup>
451 <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug 5.4|Prospero'"> 538 <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug 5.4|Prospero'">
452 <ClCompile> 539 <ClCompile>
453 <PrecompiledHeader>Use</PrecompiledHeader> 540 <PrecompiledHeader>Use</PrecompiledHeader>
@@ -469,7 +556,7 @@
469 </IgnoreSpecificDefaultLibraries> 556 </IgnoreSpecificDefaultLibraries>
470 </Link> 557 </Link>
471 </ItemDefinitionGroup> 558 </ItemDefinitionGroup>
472 <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug 5.3|x64'"> 559 <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug 5.5|Prospero'">
473 <ClCompile> 560 <ClCompile>
474 <PrecompiledHeader>Use</PrecompiledHeader> 561 <PrecompiledHeader>Use</PrecompiledHeader>
475 <PrecompiledHeaderFile>_pch.hpp</PrecompiledHeaderFile> 562 <PrecompiledHeaderFile>_pch.hpp</PrecompiledHeaderFile>
@@ -477,6 +564,27 @@
477 <PreprocessorDefinitions>X64;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions> 564 <PreprocessorDefinitions>X64;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
478 <BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks> 565 <BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>
479 <WarningLevel>Level3</WarningLevel> 566 <WarningLevel>Level3</WarningLevel>
567 <AdditionalIncludeDirectories>$(SolutionDir)..\..\..\Lua54\include;$(SolutionDir)..</AdditionalIncludeDirectories>
568 <LanguageStandard>stdcpp20</LanguageStandard>
569 <RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary>
570 </ClCompile>
571 <Link>
572 <GenerateDebugInformation>true</GenerateDebugInformation>
573 <SubSystem>Console</SubSystem>
574 <AdditionalLibraryDirectories>$(SolutionDir)..\..\..\Lua54\bin\$(Platform)\Debug;$(SolutionDir)..\Microsoft.googletest.v140.windesktop.msvcstl.static.rt-dyn.1.8.1.7\lib\native\v140\windesktop\msvcstl\static\rt-dyn\x64\Debug</AdditionalLibraryDirectories>
575 <AdditionalDependencies>lua54.lib;$(CoreLibraryDependencies);%(AdditionalDependencies)</AdditionalDependencies>
576 <IgnoreSpecificDefaultLibraries>
577 </IgnoreSpecificDefaultLibraries>
578 </Link>
579 </ItemDefinitionGroup>
580 <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug 5.3|x64'">
581 <ClCompile>
582 <PrecompiledHeader>Use</PrecompiledHeader>
583 <PrecompiledHeaderFile>_pch.hpp</PrecompiledHeaderFile>
584 <Optimization>Disabled</Optimization>
585 <PreprocessorDefinitions>LANES_DEBUG;X64;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
586 <BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>
587 <WarningLevel>Level3</WarningLevel>
480 <AdditionalIncludeDirectories>$(SolutionDir)/_LuaVersions/$(PlatformName)/$(ConfigurationName)/include;$(SolutionDir)..</AdditionalIncludeDirectories> 588 <AdditionalIncludeDirectories>$(SolutionDir)/_LuaVersions/$(PlatformName)/$(ConfigurationName)/include;$(SolutionDir)..</AdditionalIncludeDirectories>
481 <LanguageStandard>stdcpp20</LanguageStandard> 589 <LanguageStandard>stdcpp20</LanguageStandard>
482 <RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary> 590 <RuntimeLibrary>MultiThreadedDebugDLL</RuntimeLibrary>
@@ -494,7 +602,7 @@
494 <ClCompile> 602 <ClCompile>
495 <PrecompiledHeader>Use</PrecompiledHeader> 603 <PrecompiledHeader>Use</PrecompiledHeader>
496 <PrecompiledHeaderFile>_pch.hpp</PrecompiledHeaderFile> 604 <PrecompiledHeaderFile>_pch.hpp</PrecompiledHeaderFile>
497 <PreprocessorDefinitions>X64;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions> 605 <PreprocessorDefinitions>LANES_DEBUG;X64;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
498 <WarningLevel>Level3</WarningLevel> 606 <WarningLevel>Level3</WarningLevel>
499 <AdditionalIncludeDirectories>$(SolutionDir)/_LuaVersions/$(PlatformName)/$(ConfigurationName)/include;$(SolutionDir)..</AdditionalIncludeDirectories> 607 <AdditionalIncludeDirectories>$(SolutionDir)/_LuaVersions/$(PlatformName)/$(ConfigurationName)/include;$(SolutionDir)..</AdditionalIncludeDirectories>
500 <LanguageStandard>stdcpp20</LanguageStandard> 608 <LanguageStandard>stdcpp20</LanguageStandard>
@@ -555,7 +663,7 @@
555 <PrecompiledHeader>Use</PrecompiledHeader> 663 <PrecompiledHeader>Use</PrecompiledHeader>
556 <PrecompiledHeaderFile>_pch.hpp</PrecompiledHeaderFile> 664 <PrecompiledHeaderFile>_pch.hpp</PrecompiledHeaderFile>
557 <Optimization>Disabled</Optimization> 665 <Optimization>Disabled</Optimization>
558 <PreprocessorDefinitions>X64;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions> 666 <PreprocessorDefinitions>LANES_DEBUG;X64;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
559 <BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks> 667 <BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>
560 <WarningLevel>Level3</WarningLevel> 668 <WarningLevel>Level3</WarningLevel>
561 <AdditionalIncludeDirectories>$(SolutionDir)/_LuaVersions/$(PlatformName)/$(ConfigurationName)/include;$(SolutionDir)..</AdditionalIncludeDirectories> 669 <AdditionalIncludeDirectories>$(SolutionDir)/_LuaVersions/$(PlatformName)/$(ConfigurationName)/include;$(SolutionDir)..</AdditionalIncludeDirectories>
@@ -575,7 +683,7 @@
575 <ClCompile> 683 <ClCompile>
576 <PrecompiledHeader>Use</PrecompiledHeader> 684 <PrecompiledHeader>Use</PrecompiledHeader>
577 <PrecompiledHeaderFile>_pch.hpp</PrecompiledHeaderFile> 685 <PrecompiledHeaderFile>_pch.hpp</PrecompiledHeaderFile>
578 <PreprocessorDefinitions>X64;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions> 686 <PreprocessorDefinitions>LANES_DEBUG;X64;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
579 <WarningLevel>Level3</WarningLevel> 687 <WarningLevel>Level3</WarningLevel>
580 <AdditionalIncludeDirectories>$(SolutionDir)/_LuaVersions/$(PlatformName)/$(ConfigurationName)/include;$(SolutionDir)..</AdditionalIncludeDirectories> 688 <AdditionalIncludeDirectories>$(SolutionDir)/_LuaVersions/$(PlatformName)/$(ConfigurationName)/include;$(SolutionDir)..</AdditionalIncludeDirectories>
581 <LanguageStandard>stdcpp20</LanguageStandard> 689 <LanguageStandard>stdcpp20</LanguageStandard>
@@ -636,7 +744,7 @@
636 <PrecompiledHeader>Use</PrecompiledHeader> 744 <PrecompiledHeader>Use</PrecompiledHeader>
637 <PrecompiledHeaderFile>_pch.hpp</PrecompiledHeaderFile> 745 <PrecompiledHeaderFile>_pch.hpp</PrecompiledHeaderFile>
638 <Optimization>Disabled</Optimization> 746 <Optimization>Disabled</Optimization>
639 <PreprocessorDefinitions>X64;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions> 747 <PreprocessorDefinitions>LANES_DEBUG;X64;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
640 <BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks> 748 <BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>
641 <WarningLevel>Level3</WarningLevel> 749 <WarningLevel>Level3</WarningLevel>
642 <AdditionalIncludeDirectories>$(SolutionDir)/_LuaVersions/$(PlatformName)/$(ConfigurationName)/include;$(SolutionDir)..</AdditionalIncludeDirectories> 750 <AdditionalIncludeDirectories>$(SolutionDir)/_LuaVersions/$(PlatformName)/$(ConfigurationName)/include;$(SolutionDir)..</AdditionalIncludeDirectories>
@@ -656,7 +764,7 @@
656 <ClCompile> 764 <ClCompile>
657 <PrecompiledHeader>Use</PrecompiledHeader> 765 <PrecompiledHeader>Use</PrecompiledHeader>
658 <PrecompiledHeaderFile>_pch.hpp</PrecompiledHeaderFile> 766 <PrecompiledHeaderFile>_pch.hpp</PrecompiledHeaderFile>
659 <PreprocessorDefinitions>X64;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions> 767 <PreprocessorDefinitions>LANES_DEBUG;X64;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
660 <WarningLevel>Level3</WarningLevel> 768 <WarningLevel>Level3</WarningLevel>
661 <AdditionalIncludeDirectories>$(SolutionDir)/_LuaVersions/$(PlatformName)/$(ConfigurationName)/include;$(SolutionDir)..</AdditionalIncludeDirectories> 769 <AdditionalIncludeDirectories>$(SolutionDir)/_LuaVersions/$(PlatformName)/$(ConfigurationName)/include;$(SolutionDir)..</AdditionalIncludeDirectories>
662 <LanguageStandard>stdcpp20</LanguageStandard> 770 <LanguageStandard>stdcpp20</LanguageStandard>
@@ -717,7 +825,7 @@
717 <PrecompiledHeader>Use</PrecompiledHeader> 825 <PrecompiledHeader>Use</PrecompiledHeader>
718 <PrecompiledHeaderFile>_pch.hpp</PrecompiledHeaderFile> 826 <PrecompiledHeaderFile>_pch.hpp</PrecompiledHeaderFile>
719 <Optimization>Disabled</Optimization> 827 <Optimization>Disabled</Optimization>
720 <PreprocessorDefinitions>X64;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions> 828 <PreprocessorDefinitions>LANES_DEBUG;X64;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
721 <BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks> 829 <BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>
722 <WarningLevel>Level3</WarningLevel> 830 <WarningLevel>Level3</WarningLevel>
723 <AdditionalIncludeDirectories>$(SolutionDir)/_LuaVersions/$(PlatformName)/$(ConfigurationName)/include;$(SolutionDir)..</AdditionalIncludeDirectories> 831 <AdditionalIncludeDirectories>$(SolutionDir)/_LuaVersions/$(PlatformName)/$(ConfigurationName)/include;$(SolutionDir)..</AdditionalIncludeDirectories>
@@ -738,7 +846,7 @@
738 <PrecompiledHeader>Use</PrecompiledHeader> 846 <PrecompiledHeader>Use</PrecompiledHeader>
739 <PrecompiledHeaderFile>_pch.hpp</PrecompiledHeaderFile> 847 <PrecompiledHeaderFile>_pch.hpp</PrecompiledHeaderFile>
740 <Optimization>Disabled</Optimization> 848 <Optimization>Disabled</Optimization>
741 <PreprocessorDefinitions>X64;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions> 849 <PreprocessorDefinitions>LANES_DEBUG;X64;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
742 <BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks> 850 <BasicRuntimeChecks>EnableFastChecks</BasicRuntimeChecks>
743 <WarningLevel>Level3</WarningLevel> 851 <WarningLevel>Level3</WarningLevel>
744 <AdditionalIncludeDirectories>$(SolutionDir)/_LuaVersions/$(PlatformName)/$(ConfigurationName)/include;$(SolutionDir)..</AdditionalIncludeDirectories> 852 <AdditionalIncludeDirectories>$(SolutionDir)/_LuaVersions/$(PlatformName)/$(ConfigurationName)/include;$(SolutionDir)..</AdditionalIncludeDirectories>
@@ -800,7 +908,26 @@
800 <ClCompile> 908 <ClCompile>
801 <PrecompiledHeader>Use</PrecompiledHeader> 909 <PrecompiledHeader>Use</PrecompiledHeader>
802 <PrecompiledHeaderFile>_pch.hpp</PrecompiledHeaderFile> 910 <PrecompiledHeaderFile>_pch.hpp</PrecompiledHeaderFile>
803 <PreprocessorDefinitions>WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions> 911 <PreprocessorDefinitions>LANES_DEBUG;WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
912 <WarningLevel>Level3</WarningLevel>
913 <DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
914 <LanguageStandard>stdcpp20</LanguageStandard>
915 <AdditionalIncludeDirectories>$(SolutionDir)/_LuaVersions/$(PlatformName)/$(ConfigurationName)/include;$(SolutionDir)..</AdditionalIncludeDirectories>
916 </ClCompile>
917 <Link>
918 <GenerateDebugInformation>true</GenerateDebugInformation>
919 <SubSystem>Console</SubSystem>
920 <OptimizeReferences>true</OptimizeReferences>
921 <EnableCOMDATFolding>true</EnableCOMDATFolding>
922 <AdditionalDependencies>lua54.lib;$(CoreLibraryDependencies);%(AdditionalDependencies)</AdditionalDependencies>
923 <AdditionalLibraryDirectories>$(SolutionDir)_LuaVersions\$(PlatformName)\$(ConfigurationName)</AdditionalLibraryDirectories>
924 </Link>
925 </ItemDefinitionGroup>
926 <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release 5.5|Win32'">
927 <ClCompile>
928 <PrecompiledHeader>Use</PrecompiledHeader>
929 <PrecompiledHeaderFile>_pch.hpp</PrecompiledHeaderFile>
930 <PreprocessorDefinitions>LANES_DEBUG;WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
804 <WarningLevel>Level3</WarningLevel> 931 <WarningLevel>Level3</WarningLevel>
805 <DebugInformationFormat>ProgramDatabase</DebugInformationFormat> 932 <DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
806 <LanguageStandard>stdcpp20</LanguageStandard> 933 <LanguageStandard>stdcpp20</LanguageStandard>
@@ -819,7 +946,7 @@
819 <ClCompile> 946 <ClCompile>
820 <PrecompiledHeader>Use</PrecompiledHeader> 947 <PrecompiledHeader>Use</PrecompiledHeader>
821 <PrecompiledHeaderFile>_pch.hpp</PrecompiledHeaderFile> 948 <PrecompiledHeaderFile>_pch.hpp</PrecompiledHeaderFile>
822 <PreprocessorDefinitions>X64;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions> 949 <PreprocessorDefinitions>LANES_DEBUG;X64;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
823 <WarningLevel>Level3</WarningLevel> 950 <WarningLevel>Level3</WarningLevel>
824 <LanguageStandard>stdcpp20</LanguageStandard> 951 <LanguageStandard>stdcpp20</LanguageStandard>
825 <AdditionalIncludeDirectories>$(SolutionDir)/_LuaVersions/$(PlatformName)/$(ConfigurationName)/include;$(SolutionDir)..</AdditionalIncludeDirectories> 952 <AdditionalIncludeDirectories>$(SolutionDir)/_LuaVersions/$(PlatformName)/$(ConfigurationName)/include;$(SolutionDir)..</AdditionalIncludeDirectories>
@@ -833,6 +960,24 @@
833 <AdditionalDependencies>lua54.lib;$(CoreLibraryDependencies);%(AdditionalDependencies)</AdditionalDependencies> 960 <AdditionalDependencies>lua54.lib;$(CoreLibraryDependencies);%(AdditionalDependencies)</AdditionalDependencies>
834 </Link> 961 </Link>
835 </ItemDefinitionGroup> 962 </ItemDefinitionGroup>
963 <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release 5.5|x64'">
964 <ClCompile>
965 <PrecompiledHeader>Use</PrecompiledHeader>
966 <PrecompiledHeaderFile>_pch.hpp</PrecompiledHeaderFile>
967 <PreprocessorDefinitions>LANES_DEBUG;X64;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
968 <WarningLevel>Level3</WarningLevel>
969 <LanguageStandard>stdcpp20</LanguageStandard>
970 <AdditionalIncludeDirectories>$(SolutionDir)/_LuaVersions/$(PlatformName)/$(ConfigurationName)/include;$(SolutionDir)..</AdditionalIncludeDirectories>
971 </ClCompile>
972 <Link>
973 <GenerateDebugInformation>true</GenerateDebugInformation>
974 <SubSystem>Console</SubSystem>
975 <OptimizeReferences>true</OptimizeReferences>
976 <EnableCOMDATFolding>true</EnableCOMDATFolding>
977 <AdditionalLibraryDirectories>$(SolutionDir)_LuaVersions\$(PlatformName)\$(ConfigurationName)</AdditionalLibraryDirectories>
978 <AdditionalDependencies>lua55.lib;$(CoreLibraryDependencies);%(AdditionalDependencies)</AdditionalDependencies>
979 </Link>
980 </ItemDefinitionGroup>
836 <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release 5.4|Prospero'"> 981 <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release 5.4|Prospero'">
837 <ClCompile> 982 <ClCompile>
838 <PrecompiledHeader>Use</PrecompiledHeader> 983 <PrecompiledHeader>Use</PrecompiledHeader>
@@ -852,6 +997,25 @@
852 <AdditionalDependencies>lua54.lib;$(CoreLibraryDependencies);%(AdditionalDependencies)</AdditionalDependencies> 997 <AdditionalDependencies>lua54.lib;$(CoreLibraryDependencies);%(AdditionalDependencies)</AdditionalDependencies>
853 </Link> 998 </Link>
854 </ItemDefinitionGroup> 999 </ItemDefinitionGroup>
1000 <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release 5.5|Prospero'">
1001 <ClCompile>
1002 <PrecompiledHeader>Use</PrecompiledHeader>
1003 <PrecompiledHeaderFile>_pch.hpp</PrecompiledHeaderFile>
1004 <PreprocessorDefinitions>X64;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
1005 <WarningLevel>Level3</WarningLevel>
1006 <DebugInformationFormat>ProgramDatabase</DebugInformationFormat>
1007 <LanguageStandard>stdcpp20</LanguageStandard>
1008 <AdditionalIncludeDirectories>$(SolutionDir)..\..\..\Lua54\include;$(SolutionDir)..</AdditionalIncludeDirectories>
1009 </ClCompile>
1010 <Link>
1011 <GenerateDebugInformation>true</GenerateDebugInformation>
1012 <SubSystem>Console</SubSystem>
1013 <OptimizeReferences>true</OptimizeReferences>
1014 <EnableCOMDATFolding>true</EnableCOMDATFolding>
1015 <AdditionalLibraryDirectories>$(SolutionDir)..\..\..\Lua54\bin\$(Platform)\Release;$(SolutionDir)..\Microsoft.googletest.v140.windesktop.msvcstl.static.rt-dyn.1.8.1.7\lib\native\v140\windesktop\msvcstl\static\rt-dyn\x64\Release</AdditionalLibraryDirectories>
1016 <AdditionalDependencies>lua54.lib;$(CoreLibraryDependencies);%(AdditionalDependencies)</AdditionalDependencies>
1017 </Link>
1018 </ItemDefinitionGroup>
855 <ItemGroup> 1019 <ItemGroup>
856 <ClInclude Include="..\src\compat.hpp" /> 1020 <ClInclude Include="..\src\compat.hpp" />
857 <ClInclude Include="..\src\deep.hpp" /> 1021 <ClInclude Include="..\src\deep.hpp" />
@@ -864,11 +1028,13 @@
864 <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug 5.3|Win32'">NotUsing</PrecompiledHeader> 1028 <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug 5.3|Win32'">NotUsing</PrecompiledHeader>
865 <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release 5.3|Win32'">NotUsing</PrecompiledHeader> 1029 <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release 5.3|Win32'">NotUsing</PrecompiledHeader>
866 <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug 5.4|Win32'">NotUsing</PrecompiledHeader> 1030 <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug 5.4|Win32'">NotUsing</PrecompiledHeader>
1031 <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug 5.5|Win32'">NotUsing</PrecompiledHeader>
867 <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug 5.1|Win32'">NotUsing</PrecompiledHeader> 1032 <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug 5.1|Win32'">NotUsing</PrecompiledHeader>
868 <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release 5.1|Win32'">NotUsing</PrecompiledHeader> 1033 <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release 5.1|Win32'">NotUsing</PrecompiledHeader>
869 <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release LuaJIT|Win32'">NotUsing</PrecompiledHeader> 1034 <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release LuaJIT|Win32'">NotUsing</PrecompiledHeader>
870 <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release MoonJIT|Win32'">NotUsing</PrecompiledHeader> 1035 <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release MoonJIT|Win32'">NotUsing</PrecompiledHeader>
871 <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release 5.4|Win32'">NotUsing</PrecompiledHeader> 1036 <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release 5.4|Win32'">NotUsing</PrecompiledHeader>
1037 <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release 5.5|Win32'">NotUsing</PrecompiledHeader>
872 <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug 5.2|Win32'">NotUsing</PrecompiledHeader> 1038 <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug 5.2|Win32'">NotUsing</PrecompiledHeader>
873 <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release 5.2|Win32'">NotUsing</PrecompiledHeader> 1039 <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release 5.2|Win32'">NotUsing</PrecompiledHeader>
874 <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug 5.3|x64'">NotUsing</PrecompiledHeader> 1040 <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug 5.3|x64'">NotUsing</PrecompiledHeader>
@@ -876,7 +1042,9 @@
876 <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug 5.3|Prospero'">NotUsing</PrecompiledHeader> 1042 <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug 5.3|Prospero'">NotUsing</PrecompiledHeader>
877 <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release 5.3|Prospero'">NotUsing</PrecompiledHeader> 1043 <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release 5.3|Prospero'">NotUsing</PrecompiledHeader>
878 <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug 5.4|x64'">NotUsing</PrecompiledHeader> 1044 <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug 5.4|x64'">NotUsing</PrecompiledHeader>
1045 <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug 5.5|x64'">NotUsing</PrecompiledHeader>
879 <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug 5.4|Prospero'">NotUsing</PrecompiledHeader> 1046 <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug 5.4|Prospero'">NotUsing</PrecompiledHeader>
1047 <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug 5.5|Prospero'">NotUsing</PrecompiledHeader>
880 <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug 5.1|x64'">NotUsing</PrecompiledHeader> 1048 <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug 5.1|x64'">NotUsing</PrecompiledHeader>
881 <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release 5.1|x64'">NotUsing</PrecompiledHeader> 1049 <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release 5.1|x64'">NotUsing</PrecompiledHeader>
882 <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug 5.1|Prospero'">NotUsing</PrecompiledHeader> 1050 <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug 5.1|Prospero'">NotUsing</PrecompiledHeader>
@@ -886,7 +1054,9 @@
886 <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release LuaJIT|Prospero'">NotUsing</PrecompiledHeader> 1054 <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release LuaJIT|Prospero'">NotUsing</PrecompiledHeader>
887 <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release MoonJIT|Prospero'">NotUsing</PrecompiledHeader> 1055 <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release MoonJIT|Prospero'">NotUsing</PrecompiledHeader>
888 <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release 5.4|x64'">NotUsing</PrecompiledHeader> 1056 <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release 5.4|x64'">NotUsing</PrecompiledHeader>
1057 <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release 5.5|x64'">NotUsing</PrecompiledHeader>
889 <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release 5.4|Prospero'">NotUsing</PrecompiledHeader> 1058 <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release 5.4|Prospero'">NotUsing</PrecompiledHeader>
1059 <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release 5.5|Prospero'">NotUsing</PrecompiledHeader>
890 <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug 5.2|x64'">NotUsing</PrecompiledHeader> 1060 <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug 5.2|x64'">NotUsing</PrecompiledHeader>
891 <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release 5.2|x64'">NotUsing</PrecompiledHeader> 1061 <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release 5.2|x64'">NotUsing</PrecompiledHeader>
892 <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug 5.2|Prospero'">NotUsing</PrecompiledHeader> 1062 <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug 5.2|Prospero'">NotUsing</PrecompiledHeader>
@@ -897,11 +1067,13 @@
897 <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug 5.3|Win32'">NotUsing</PrecompiledHeader> 1067 <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug 5.3|Win32'">NotUsing</PrecompiledHeader>
898 <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release 5.3|Win32'">NotUsing</PrecompiledHeader> 1068 <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release 5.3|Win32'">NotUsing</PrecompiledHeader>
899 <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug 5.4|Win32'">NotUsing</PrecompiledHeader> 1069 <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug 5.4|Win32'">NotUsing</PrecompiledHeader>
1070 <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug 5.5|Win32'">NotUsing</PrecompiledHeader>
900 <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug 5.1|Win32'">NotUsing</PrecompiledHeader> 1071 <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug 5.1|Win32'">NotUsing</PrecompiledHeader>
901 <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release 5.1|Win32'">NotUsing</PrecompiledHeader> 1072 <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release 5.1|Win32'">NotUsing</PrecompiledHeader>
902 <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release LuaJIT|Win32'">NotUsing</PrecompiledHeader> 1073 <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release LuaJIT|Win32'">NotUsing</PrecompiledHeader>
903 <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release MoonJIT|Win32'">NotUsing</PrecompiledHeader> 1074 <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release MoonJIT|Win32'">NotUsing</PrecompiledHeader>
904 <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release 5.4|Win32'">NotUsing</PrecompiledHeader> 1075 <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release 5.4|Win32'">NotUsing</PrecompiledHeader>
1076 <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release 5.5|Win32'">NotUsing</PrecompiledHeader>
905 <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug 5.2|Win32'">NotUsing</PrecompiledHeader> 1077 <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug 5.2|Win32'">NotUsing</PrecompiledHeader>
906 <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release 5.2|Win32'">NotUsing</PrecompiledHeader> 1078 <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release 5.2|Win32'">NotUsing</PrecompiledHeader>
907 <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug 5.3|x64'">NotUsing</PrecompiledHeader> 1079 <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug 5.3|x64'">NotUsing</PrecompiledHeader>
@@ -909,7 +1081,9 @@
909 <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug 5.3|Prospero'">NotUsing</PrecompiledHeader> 1081 <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug 5.3|Prospero'">NotUsing</PrecompiledHeader>
910 <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release 5.3|Prospero'">NotUsing</PrecompiledHeader> 1082 <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release 5.3|Prospero'">NotUsing</PrecompiledHeader>
911 <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug 5.4|x64'">NotUsing</PrecompiledHeader> 1083 <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug 5.4|x64'">NotUsing</PrecompiledHeader>
1084 <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug 5.5|x64'">NotUsing</PrecompiledHeader>
912 <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug 5.4|Prospero'">NotUsing</PrecompiledHeader> 1085 <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug 5.4|Prospero'">NotUsing</PrecompiledHeader>
1086 <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug 5.5|Prospero'">NotUsing</PrecompiledHeader>
913 <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug 5.1|x64'">NotUsing</PrecompiledHeader> 1087 <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug 5.1|x64'">NotUsing</PrecompiledHeader>
914 <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release 5.1|x64'">NotUsing</PrecompiledHeader> 1088 <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release 5.1|x64'">NotUsing</PrecompiledHeader>
915 <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug 5.1|Prospero'">NotUsing</PrecompiledHeader> 1089 <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug 5.1|Prospero'">NotUsing</PrecompiledHeader>
@@ -919,7 +1093,9 @@
919 <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release LuaJIT|Prospero'">NotUsing</PrecompiledHeader> 1093 <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release LuaJIT|Prospero'">NotUsing</PrecompiledHeader>
920 <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release MoonJIT|Prospero'">NotUsing</PrecompiledHeader> 1094 <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release MoonJIT|Prospero'">NotUsing</PrecompiledHeader>
921 <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release 5.4|x64'">NotUsing</PrecompiledHeader> 1095 <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release 5.4|x64'">NotUsing</PrecompiledHeader>
1096 <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release 5.5|x64'">NotUsing</PrecompiledHeader>
922 <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release 5.4|Prospero'">NotUsing</PrecompiledHeader> 1097 <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release 5.4|Prospero'">NotUsing</PrecompiledHeader>
1098 <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release 5.5|Prospero'">NotUsing</PrecompiledHeader>
923 <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug 5.2|x64'">NotUsing</PrecompiledHeader> 1099 <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug 5.2|x64'">NotUsing</PrecompiledHeader>
924 <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release 5.2|x64'">NotUsing</PrecompiledHeader> 1100 <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release 5.2|x64'">NotUsing</PrecompiledHeader>
925 <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug 5.2|Prospero'">NotUsing</PrecompiledHeader> 1101 <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug 5.2|Prospero'">NotUsing</PrecompiledHeader>
@@ -934,6 +1110,7 @@
934 <ClCompile Include="init_and_shutdown.cpp" /> 1110 <ClCompile Include="init_and_shutdown.cpp" />
935 <ClCompile Include="_pch.cpp"> 1111 <ClCompile Include="_pch.cpp">
936 <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug 5.4|Win32'">Create</PrecompiledHeader> 1112 <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug 5.4|Win32'">Create</PrecompiledHeader>
1113 <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug 5.5|Win32'">Create</PrecompiledHeader>
937 <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug 5.3|Win32'">Create</PrecompiledHeader> 1114 <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug 5.3|Win32'">Create</PrecompiledHeader>
938 <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release 5.3|Win32'">Create</PrecompiledHeader> 1115 <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release 5.3|Win32'">Create</PrecompiledHeader>
939 <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug 5.2|Win32'">Create</PrecompiledHeader> 1116 <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug 5.2|Win32'">Create</PrecompiledHeader>
@@ -943,8 +1120,11 @@
943 <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release LuaJIT|Win32'">Create</PrecompiledHeader> 1120 <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release LuaJIT|Win32'">Create</PrecompiledHeader>
944 <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release MoonJIT|Win32'">Create</PrecompiledHeader> 1121 <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release MoonJIT|Win32'">Create</PrecompiledHeader>
945 <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release 5.4|Win32'">Create</PrecompiledHeader> 1122 <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release 5.4|Win32'">Create</PrecompiledHeader>
1123 <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release 5.5|Win32'">Create</PrecompiledHeader>
946 <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug 5.4|x64'">Create</PrecompiledHeader> 1124 <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug 5.4|x64'">Create</PrecompiledHeader>
1125 <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug 5.5|x64'">Create</PrecompiledHeader>
947 <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug 5.4|Prospero'">Create</PrecompiledHeader> 1126 <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug 5.4|Prospero'">Create</PrecompiledHeader>
1127 <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug 5.5|Prospero'">Create</PrecompiledHeader>
948 <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug 5.3|x64'">Create</PrecompiledHeader> 1128 <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug 5.3|x64'">Create</PrecompiledHeader>
949 <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release 5.3|x64'">Create</PrecompiledHeader> 1129 <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release 5.3|x64'">Create</PrecompiledHeader>
950 <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug 5.3|Prospero'">Create</PrecompiledHeader> 1130 <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug 5.3|Prospero'">Create</PrecompiledHeader>
@@ -962,13 +1142,28 @@
962 <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release LuaJIT|Prospero'">Create</PrecompiledHeader> 1142 <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release LuaJIT|Prospero'">Create</PrecompiledHeader>
963 <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release MoonJIT|Prospero'">Create</PrecompiledHeader> 1143 <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release MoonJIT|Prospero'">Create</PrecompiledHeader>
964 <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release 5.4|x64'">Create</PrecompiledHeader> 1144 <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release 5.4|x64'">Create</PrecompiledHeader>
1145 <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release 5.5|x64'">Create</PrecompiledHeader>
965 <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release 5.4|Prospero'">Create</PrecompiledHeader> 1146 <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release 5.4|Prospero'">Create</PrecompiledHeader>
1147 <PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release 5.5|Prospero'">Create</PrecompiledHeader>
966 </ClCompile> 1148 </ClCompile>
967 </ItemGroup> 1149 </ItemGroup>
968 <ItemGroup> 1150 <ItemGroup>
969 <None Include="..\.runsettings" /> 1151 <None Include="..\.runsettings" />
1152 <None Include="scripts\coro\cancelling_suspended.lua" />
1153 <None Include="scripts\coro\collect_yielded_lane.lua" />
1154 <None Include="scripts\coro\join_suspended.lua" />
1155 <None Include="scripts\coro\linda_in_close_handler.lua" />
1156 <None Include="scripts\coro\regular_function.lua" />
1157 <None Include="scripts\coro\resume_basics.lua" />
1158 <None Include="scripts\coro\yielding_in_non_coro_errors.lua" />
1159 <None Include="scripts\lane\body_is_a_c_function.lua" />
1160 <None Include="scripts\lane\tasking_cancelling_with_hook.lua" />
1161 <None Include="scripts\linda\send_receive_func_and_string.lua" />
1162 <None Include="scripts\linda\wake_period.lua" />
1163 <None Include="scripts\misc\deeptest.lua" />
1164 <None Include="scripts\_utils54.lua" />
970 <None Include="UnitTests.makefile" /> 1165 <None Include="UnitTests.makefile" />
971 <None Include="scripts\coro\basics.lua" /> 1166 <None Include="scripts\coro\index_suspended.lua" />
972 <None Include="scripts\coro\error_handling.lua" /> 1167 <None Include="scripts\coro\error_handling.lua" />
973 <None Include="scripts\lane\cooperative_shutdown.lua" /> 1168 <None Include="scripts\lane\cooperative_shutdown.lua" />
974 <None Include="scripts\lane\stdlib_naming.lua" /> 1169 <None Include="scripts\lane\stdlib_naming.lua" />
diff --git a/unit_tests/UnitTests.vcxproj.filters b/unit_tests/UnitTests.vcxproj.filters
index 3b45009..df82447 100644
--- a/unit_tests/UnitTests.vcxproj.filters
+++ b/unit_tests/UnitTests.vcxproj.filters
@@ -54,6 +54,9 @@
54 <Filter Include="Make"> 54 <Filter Include="Make">
55 <UniqueIdentifier>{c62af5d9-9161-4ca1-9b58-6837e2907e35}</UniqueIdentifier> 55 <UniqueIdentifier>{c62af5d9-9161-4ca1-9b58-6837e2907e35}</UniqueIdentifier>
56 </Filter> 56 </Filter>
57 <Filter Include="Scripts\misc">
58 <UniqueIdentifier>{1fbb1341-2f93-4eaa-924c-1df79e083704}</UniqueIdentifier>
59 </Filter>
57 </ItemGroup> 60 </ItemGroup>
58 <ItemGroup> 61 <ItemGroup>
59 <None Include="scripts\linda\send_receive.lua"> 62 <None Include="scripts\linda\send_receive.lua">
@@ -95,7 +98,7 @@
95 <None Include="scripts\lane\tasking_join_test.lua"> 98 <None Include="scripts\lane\tasking_join_test.lua">
96 <Filter>Scripts\lane</Filter> 99 <Filter>Scripts\lane</Filter>
97 </None> 100 </None>
98 <None Include="scripts\coro\basics.lua"> 101 <None Include="scripts\coro\index_suspended.lua">
99 <Filter>Scripts\coro</Filter> 102 <Filter>Scripts\coro</Filter>
100 </None> 103 </None>
101 <None Include="scripts\coro\error_handling.lua"> 104 <None Include="scripts\coro\error_handling.lua">
@@ -113,5 +116,44 @@
113 <None Include="..\.runsettings"> 116 <None Include="..\.runsettings">
114 <Filter>Catch2</Filter> 117 <Filter>Catch2</Filter>
115 </None> 118 </None>
119 <None Include="scripts\lane\tasking_cancelling_with_hook.lua">
120 <Filter>Scripts\lane</Filter>
121 </None>
122 <None Include="scripts\linda\wake_period.lua">
123 <Filter>Scripts\linda</Filter>
124 </None>
125 <None Include="scripts\coro\collect_yielded_lane.lua">
126 <Filter>Scripts\coro</Filter>
127 </None>
128 <None Include="scripts\lane\body_is_a_c_function.lua">
129 <Filter>Scripts\lane</Filter>
130 </None>
131 <None Include="scripts\coro\regular_function.lua">
132 <Filter>Scripts\coro</Filter>
133 </None>
134 <None Include="scripts\coro\yielding_in_non_coro_errors.lua">
135 <Filter>Scripts\coro</Filter>
136 </None>
137 <None Include="scripts\coro\resume_basics.lua">
138 <Filter>Scripts\coro</Filter>
139 </None>
140 <None Include="scripts\coro\join_suspended.lua">
141 <Filter>Scripts\coro</Filter>
142 </None>
143 <None Include="scripts\_utils54.lua">
144 <Filter>Scripts</Filter>
145 </None>
146 <None Include="scripts\coro\linda_in_close_handler.lua">
147 <Filter>Scripts\coro</Filter>
148 </None>
149 <None Include="scripts\coro\cancelling_suspended.lua">
150 <Filter>Scripts\coro</Filter>
151 </None>
152 <None Include="scripts\linda\send_receive_func_and_string.lua">
153 <Filter>Scripts\linda</Filter>
154 </None>
155 <None Include="scripts\misc\deeptest.lua">
156 <Filter>Scripts\misc</Filter>
157 </None>
116 </ItemGroup> 158 </ItemGroup>
117</Project> \ No newline at end of file 159</Project> \ No newline at end of file
diff --git a/unit_tests/_pch.hpp b/unit_tests/_pch.hpp
index 1e98c5a..f6e5fff 100644
--- a/unit_tests/_pch.hpp
+++ b/unit_tests/_pch.hpp
@@ -1,5 +1,3 @@
1#pragma once
2
3#include <atomic> 1#include <atomic>
4#include <cassert> 2#include <cassert>
5#include <filesystem> 3#include <filesystem>
diff --git a/unit_tests/deep_tests.cpp b/unit_tests/deep_tests.cpp
index e21072c..f18ff81 100644
--- a/unit_tests/deep_tests.cpp
+++ b/unit_tests/deep_tests.cpp
@@ -92,4 +92,13 @@ TEST_CASE("misc.deep_userdata.example")
92 " assert(due.get_deep_count() == 0)" 92 " assert(due.get_deep_count() == 0)"
93 ); 93 );
94 } 94 }
95} \ No newline at end of file 95}
96
97#define MAKE_TEST_CASE(DIR, FILE, CONDITION) \
98 TEST_CASE("scripted_tests." #DIR "." #FILE) \
99 { \
100 FileRunner _runner(R"(.\unit_tests\scripts)"); \
101 _runner.performTest(FileRunnerParam{ #DIR "/" #FILE, TestType::CONDITION }); \
102 }
103
104MAKE_TEST_CASE(misc, deeptest, AssertNoLuaError)
diff --git a/unit_tests/embedded_tests.cpp b/unit_tests/embedded_tests.cpp
index 9a262d5..388548d 100644
--- a/unit_tests/embedded_tests.cpp
+++ b/unit_tests/embedded_tests.cpp
@@ -2,6 +2,7 @@
2#include "shared.h" 2#include "shared.h"
3#include "lanes/src/lanes.hpp" 3#include "lanes/src/lanes.hpp"
4 4
5#if defined __has_include && __has_include(<windows.h>)
5#include <windows.h> 6#include <windows.h>
6 7
7// ################################################################################################# 8// #################################################################################################
@@ -138,13 +139,13 @@ namespace
138 139
139// ################################################################################################# 140// #################################################################################################
140 141
141TEST_CASE("lanes.embedding.with default allocator") 142TEST_CASE("lanes.embedding.with_default_allocator")
142{ 143{
143 local::EmbeddedLuaState S; 144 local::EmbeddedLuaState S;
144 145
145 // --------------------------------------------------------------------------------------------- 146 // ---------------------------------------------------------------------------------------------
146 147
147 SECTION("single state") 148 SECTION("single_state")
148 { 149 {
149 // this sends data in a linda. current contents: 150 // this sends data in a linda. current contents:
150 // key: short string 151 // key: short string
@@ -157,7 +158,7 @@ TEST_CASE("lanes.embedding.with default allocator")
157 // function with an upvalue 158 // function with an upvalue
158 std::string_view const _script{ 159 std::string_view const _script{
159 " local lanes = require 'lanes'.configure{with_timers = false}" 160 " local lanes = require 'lanes'.configure{with_timers = false}"
160 " local l = lanes.linda'gleh'" 161 " local l = lanes.linda{name = 'gleh'}"
161 " local upvalue = 'oeauaoeuoeuaoeuaoeujaoefubycfjbycfybcfjybcfjybcfjbcf'" 162 " local upvalue = 'oeauaoeuoeuaoeuaoeujaoefubycfjbycfybcfjybcfjybcfjbcf'"
162 " local upvalued = function()" 163 " local upvalued = function()"
163 " return upvalue" 164 " return upvalue"
@@ -171,7 +172,7 @@ TEST_CASE("lanes.embedding.with default allocator")
171 172
172 // --------------------------------------------------------------------------------------------- 173 // ---------------------------------------------------------------------------------------------
173 174
174 SECTION("manual registration") 175 SECTION("manual_registration")
175 { 176 {
176 S.requireSuccess("require 'lanes'.configure{with_timers = false}"); 177 S.requireSuccess("require 'lanes'.configure{with_timers = false}");
177 178
@@ -183,7 +184,7 @@ TEST_CASE("lanes.embedding.with default allocator")
183 // try to send io.open into a linda, which fails if io base library is not loaded 184 // try to send io.open into a linda, which fails if io base library is not loaded
184 std::string_view const _script{ 185 std::string_view const _script{
185 " local lanes = require 'lanes'" 186 " local lanes = require 'lanes'"
186 " local l = lanes.linda'gleh'" 187 " local l = lanes.linda{name = 'gleh'}"
187 " l:set('yo', io.open)" 188 " l:set('yo', io.open)"
188 " return 'SUCCESS'" 189 " return 'SUCCESS'"
189 }; 190 };
@@ -191,7 +192,7 @@ TEST_CASE("lanes.embedding.with default allocator")
191 192
192 // try again after manual registration 193 // try again after manual registration
193 lua_pushcfunction(S, S.get_lanes_register()); // S: lanes_register 194 lua_pushcfunction(S, S.get_lanes_register()); // S: lanes_register
194 luaG_pushstring(S, LUA_IOLIBNAME); // S: lanes_register "io" 195 luaW_pushstring(S, LUA_IOLIBNAME); // S: lanes_register "io"
195 luaL_requiref(S, LUA_IOLIBNAME, luaopen_io, 1); // S: lanes_register "io" io 196 luaL_requiref(S, LUA_IOLIBNAME, luaopen_io, 1); // S: lanes_register "io" io
196 lua_call(S, 2, 0); // S: 197 lua_call(S, 2, 0); // S:
197 S.stackCheck(0); 198 S.stackCheck(0);
@@ -202,7 +203,8 @@ TEST_CASE("lanes.embedding.with default allocator")
202// ################################################################################################# 203// #################################################################################################
203 204
204// this is not really a test yet, just something sitting here until it is converted properly 205// this is not really a test yet, just something sitting here until it is converted properly
205TEST_CASE("lanes.embedding.with custom allocator") 206// currently it crashes with moonjit (but maybe I just need a more recent moonjit version)
207TEST_CASE("lanes.embedding.with_custom_allocator")
206{ 208{
207 static constexpr auto logPrint = +[](lua_State* L) { 209 static constexpr auto logPrint = +[](lua_State* L) {
208 lua_getglobal(L, "ID"); // ID 210 lua_getglobal(L, "ID"); // ID
@@ -218,7 +220,7 @@ TEST_CASE("lanes.embedding.with custom allocator")
218 220
219 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_) {
220 char script[500]; 222 char script[500];
221 lua_State* L = lua_newstate(local::allocf, nullptr); 223 lua_State* L = luaW_newstate(local::allocf, nullptr, luaL_makeseed(nullptr));
222 // _G.ID = id_ 224 // _G.ID = id_
223 luaL_openlibs(L); 225 luaL_openlibs(L);
224 luaL_dostring(L, "lanes = require 'lanes'"); 226 luaL_dostring(L, "lanes = require 'lanes'");
@@ -264,4 +266,6 @@ TEST_CASE("lanes.embedding.with custom allocator")
264 lua_close(L3); 266 lua_close(L3);
265 lua_close(L2); 267 lua_close(L2);
266 lua_close(L1); 268 lua_close(L1);
267} \ No newline at end of file 269}
270
271#endif // windows.h
diff --git a/unit_tests/init_and_shutdown.cpp b/unit_tests/init_and_shutdown.cpp
index b8174fd..69e4f1b 100644
--- a/unit_tests/init_and_shutdown.cpp
+++ b/unit_tests/init_and_shutdown.cpp
@@ -3,7 +3,7 @@
3 3
4// ################################################################################################# 4// #################################################################################################
5 5
6TEST_CASE("lanes.require 'lanes'") 6TEST_CASE("Lua.require_lanes")
7{ 7{
8 LuaState L{ LuaState::WithBaseLibs{ false }, LuaState::WithFixture{ false } }; 8 LuaState L{ LuaState::WithBaseLibs{ false }, LuaState::WithFixture{ false } };
9 9
@@ -58,7 +58,7 @@ TEST_CASE("lanes.require 'lanes'")
58// ################################################################################################# 58// #################################################################################################
59 59
60// allocator should be "protected", a C function returning a suitable userdata, or nil 60// allocator should be "protected", a C function returning a suitable userdata, or nil
61TEST_CASE("lanes.configure.allocator") 61TEST_CASE("lanes.configure.allocator/bool_number_table_string")
62{ 62{
63 LuaState L{ LuaState::WithBaseLibs{ true }, LuaState::WithFixture{ false } }; 63 LuaState L{ LuaState::WithBaseLibs{ true }, LuaState::WithFixture{ false } };
64 64
@@ -90,49 +90,33 @@ TEST_CASE("lanes.configure.allocator")
90 90
91 // --------------------------------------------------------------------------------------------- 91 // ---------------------------------------------------------------------------------------------
92 92
93 SECTION("allocator = <Lua function>")
94 {
95 L.requireFailure("require 'lanes'.configure{allocator = function() return {}, 12, 'yoy' end}");
96 }
97
98 // ---------------------------------------------------------------------------------------------
99
100 SECTION("allocator = <bad C function>")
101 {
102 // a C function that doesn't return what we expect should cause an error too
103 // TODO: for some reason, we use os.getenv here because using 'print' as the culprit, the tests deadlock in Release builds
104 L.requireFailure("return type(require 'lanes'.configure{allocator = os.getenv})");
105 }
106
107 // ---------------------------------------------------------------------------------------------
108
109 SECTION("allocator = <string with a typo>") 93 SECTION("allocator = <string with a typo>")
110 { 94 {
111 // oops, a typo 95 // oops, a typo
112 L.requireFailure("require 'lanes'.configure{allocator = 'Protected'}"); 96 L.requireFailure("require 'lanes'.configure{allocator = 'Protected'}");
113 } 97 }
98}
99
100// #################################################################################################
101
102TEST_CASE("lanes.configure.allocator/bad_functions")
103{
104 LuaState L{ LuaState::WithBaseLibs{ true }, LuaState::WithFixture{ false } };
114 105
115 // --------------------------------------------------------------------------------------------- 106 // ---------------------------------------------------------------------------------------------
116 107
117 SECTION("allocator = 'protected'") 108 SECTION("allocator = <Lua function>")
118 { 109 {
119 // no typo, should work 110 L.requireFailure("require 'lanes'.configure{allocator = function() return {}, 12, 'yoy' end}");
120 L.requireSuccess("require 'lanes'.configure{allocator = 'protected'}");
121 } 111 }
122 112
123 // --------------------------------------------------------------------------------------------- 113 // ---------------------------------------------------------------------------------------------
124 114
125 SECTION("allocator = <good custom C allocator>") 115 SECTION("allocator = <bad C function>")
126 { 116 {
127 // a function that provides what we expect is fine 117 // a C function that doesn't return what we expect should cause an error too
128 static constexpr lua_CFunction _provideAllocator = +[](lua_State* const L_) { 118 // TODO: for some reason, we use os.getenv here because using 'print' as the culprit, the tests deadlock in Release builds
129 lanes::AllocatorDefinition* const _def{ new (L_) lanes::AllocatorDefinition{} }; 119 L.requireFailure("return type(require 'lanes'.configure{allocator = os.getenv})");
130 _def->initFrom(L_);
131 return 1;
132 };
133 lua_pushcfunction(L, _provideAllocator);
134 lua_setglobal(L, "ProvideAllocator");
135 L.requireSuccess("require 'lanes'.configure{allocator = ProvideAllocator}");
136 } 120 }
137 121
138 // --------------------------------------------------------------------------------------------- 122 // ---------------------------------------------------------------------------------------------
@@ -191,6 +175,39 @@ TEST_CASE("lanes.configure.allocator")
191 175
192// ################################################################################################# 176// #################################################################################################
193 177
178TEST_CASE("lanes.configure.allocator/good_function")
179{
180 LuaState L{ LuaState::WithBaseLibs{ true }, LuaState::WithFixture{ false } };
181
182 SECTION("allocator = <good custom C allocator>")
183 {
184 // a function that provides what we expect is fine
185 static constexpr lua_CFunction _provideAllocator = +[](lua_State* const L_) {
186 lanes::AllocatorDefinition* const _def{ new (L_) lanes::AllocatorDefinition{} };
187 _def->initFrom(L_);
188 return 1;
189 };
190 lua_pushcfunction(L, _provideAllocator);
191 lua_setglobal(L, "ProvideAllocator");
192 L.requireSuccess("require 'lanes'.configure{allocator = ProvideAllocator}");
193 }
194}
195
196// #################################################################################################
197
198// TODO: investigate why this test crashes under AppVerifier on lanes_core.dll unload when running against Lua 5.1, 5.2 and 5.4 RELEASE ONLY!
199// apparently, the mutex of ProtectedAllocator is deemed still in use. Crash goes away if I don't use it in protected_lua_Alloc
200TEST_CASE(("lanes.configure.allocator/protected"))
201{
202 LuaState L{ LuaState::WithBaseLibs{ true }, LuaState::WithFixture{ false } };
203
204 // no typo, should work
205 L.requireSuccess("require 'lanes'.configure{allocator = 'protected'}");
206}
207
208
209// #################################################################################################
210
194TEST_CASE("lanes.configure.internal_allocator") 211TEST_CASE("lanes.configure.internal_allocator")
195{ 212{
196 LuaState L{ LuaState::WithBaseLibs{ true }, LuaState::WithFixture{ false } }; 213 LuaState L{ LuaState::WithBaseLibs{ true }, LuaState::WithFixture{ false } };
@@ -289,388 +306,467 @@ TEST_CASE("lanes.configure.keepers_gc_threshold")
289 306
290// ################################################################################################# 307// #################################################################################################
291 308
292TEST_CASE("lanes.configure.the rest") 309TEST_CASE("lanes.configure.linda_wake_period")
293{ 310{
294 LuaState L{ LuaState::WithBaseLibs{ true }, LuaState::WithFixture{ false } }; 311 LuaState L{ LuaState::WithBaseLibs{ true }, LuaState::WithFixture{ false } };
295 312
313 // linda_wake_period should be a number > 0, or 'never'
314
315 SECTION("linda_wake_period = <table>")
316 {
317 L.requireFailure("require 'lanes'.configure{linda_wake_period = {}}");
318 }
296 319
297 // --------------------------------------------------------------------------------------------- 320 // ---------------------------------------------------------------------------------------------
298 // nb_user_keepers should be a number in [0, 100]
299 321
300 SECTION("nb_user_keepers") 322 SECTION("linda_wake_period = <string>")
301 { 323 {
302 SECTION("nb_user_keepers = <table>") 324 L.requireFailure("require 'lanes'.configure{linda_wake_period = 'gluh'}");
303 { 325 }
304 L.requireFailure("require 'lanes'.configure{nb_user_keepers = {}}");
305 }
306 326
307 // ----------------------------------------------------------------------------------------- 327 // ---------------------------------------------------------------------------------------------
308 328
309 SECTION("nb_user_keepers = <string>") 329 SECTION("linda_wake_period = 'never'")
310 { 330 {
311 L.requireFailure("require 'lanes'.configure{nb_user_keepers = 'gluh'}"); 331 L.requireSuccess("require 'lanes'.configure{linda_wake_period = 'never'}");
312 } 332 }
313 333
314 // ----------------------------------------------------------------------------------------- 334 // ---------------------------------------------------------------------------------------------
315 335
316 SECTION("nb_user_keepers = -1") 336 SECTION("linda_wake_period = <negative number>")
317 { 337 {
318 L.requireFailure("require 'lanes'.configure{nb_user_keepers = -1}"); 338 L.requireFailure("require 'lanes'.configure{linda_wake_period = -0.001}");
319 } 339 }
320 340
321 // ----------------------------------------------------------------------------------------- 341 // ---------------------------------------------------------------------------------------------
322 342
323 SECTION("nb_user_keepers = 0") 343 SECTION("linda_wake_period = 0")
324 { 344 {
325 L.requireSuccess("require 'lanes'.configure{nb_user_keepers = 0}"); 345 L.requireFailure("require 'lanes'.configure{linda_wake_period = 0}");
326 } 346 }
327 347
328 // ----------------------------------------------------------------------------------------- 348 // ---------------------------------------------------------------------------------------------
329 349
330 SECTION("nb_user_keepers = 100") 350 SECTION("linda_wake_period = 0.0001s")
331 { 351 {
332 L.requireSuccess("require 'lanes'.configure{nb_user_keepers = 100}"); 352 L.requireSuccess("require 'lanes'.configure{linda_wake_period = 0.0001}");
333 } 353 }
334 354
335 // ----------------------------------------------------------------------------------------- 355 // ---------------------------------------------------------------------------------------------
336 356
337 SECTION("nb_user_keepers = 101") 357 SECTION("linda_wake_period = 1e30")
338 { 358 {
339 L.requireFailure("require 'lanes'.configure{nb_user_keepers = 101}"); 359 L.requireSuccess("require 'lanes'.configure{linda_wake_period = 1e30}");
340 } 360 }
361}
362
363// #################################################################################################
364
365TEST_CASE("lanes.configure.nb_user_keepers")
366{
367 LuaState L{ LuaState::WithBaseLibs{ true }, LuaState::WithFixture{ false } };
368
369 // nb_user_keepers should be a number in [0, 100]
370
371 SECTION("nb_user_keepers = <table>")
372 {
373 L.requireFailure("require 'lanes'.configure{nb_user_keepers = {}}");
341 } 374 }
342 375
343 // --------------------------------------------------------------------------------------------- 376 // ---------------------------------------------------------------------------------------------
344 // on_state_create should be a function, either C or Lua, without upvalues
345 377
346 SECTION("on_state_create") 378 SECTION("nb_user_keepers = <string>")
347 { 379 {
348 SECTION("on_state_create = <table>") 380 L.requireFailure("require 'lanes'.configure{nb_user_keepers = 'gluh'}");
349 { 381 }
350 L.requireFailure("require 'lanes'.configure{on_state_create = {}}");
351 }
352 382
353 // ----------------------------------------------------------------------------------------- 383 // ---------------------------------------------------------------------------------------------
354 384
355 SECTION("on_state_create = <string>") 385 SECTION("nb_user_keepers = -1")
356 { 386 {
357 L.requireFailure("require 'lanes'.configure{on_state_create = 'gluh'}"); 387 L.requireFailure("require 'lanes'.configure{nb_user_keepers = -1}");
358 } 388 }
359 389
360 // ----------------------------------------------------------------------------------------- 390 // ---------------------------------------------------------------------------------------------
361 391
362 SECTION("on_state_create = <number>") 392 SECTION("nb_user_keepers = 0")
363 { 393 {
364 L.requireFailure("require 'lanes'.configure{on_state_create = 1}"); 394 L.requireSuccess("require 'lanes'.configure{nb_user_keepers = 0}");
365 } 395 }
366 396
367 // ----------------------------------------------------------------------------------------- 397 // ---------------------------------------------------------------------------------------------
368 398
369 SECTION("on_state_create = false") 399 SECTION("nb_user_keepers = 1")
370 { 400 {
371 L.requireFailure("require 'lanes'.configure{on_state_create = false}"); 401 L.requireSuccess("require 'lanes'.configure{nb_user_keepers = 1}");
372 } 402 }
373 403
374 // ----------------------------------------------------------------------------------------- 404 // ---------------------------------------------------------------------------------------------
375 405
376 SECTION("on_state_create = true") 406 SECTION("nb_user_keepers = 100")
377 { 407 {
378 L.requireFailure("require 'lanes'.configure{on_state_create = true}"); 408 L.requireSuccess("require 'lanes'.configure{nb_user_keepers = 100}");
379 } 409 }
380 410
381 // ----------------------------------------------------------------------------------------- 411 // -----------------------------------------------------------------------------------------
382 412
383 SECTION("on_state_create = <Lua function>") 413 SECTION("nb_user_keepers = 101")
384 { 414 {
385 // on_state_create isn't called inside a Keeper state if it's a Lua function (which is good as print() doesn't exist there!) 415 L.requireFailure("require 'lanes'.configure{nb_user_keepers = 101}");
386 L.requireSuccess("local print = print; require 'lanes'.configure{on_state_create = function() print 'hello' end}"); 416 }
387 } 417}
388 418
389 // ----------------------------------------------------------------------------------------- 419// #################################################################################################
390 420
391 SECTION("on_state_create = <C function>") 421TEST_CASE("lanes.configure.on_state_create/configuration")
392 { 422{
393 // funnily enough, in Lua 5.3, print() uses global tostring(), that doesn't exist in a keeper since we didn't open libs -> "attempt to call a nil value" 423 LuaState L{ LuaState::WithBaseLibs{ true }, LuaState::WithFixture{ false } };
394 // conclusion, don't use print() as a fake on_state_create() callback! 424
395 // assert() should be fine since we pass a non-false argument to on_state_create 425 // on_state_create should be a function, either C or Lua, without upvalues
396 L.requireSuccess("require 'lanes'.configure{on_state_create = assert}"); 426
397 } 427 SECTION("on_state_create = <table>")
428 {
429 L.requireFailure("require 'lanes'.configure{on_state_create = {}}");
398 } 430 }
399 431
400 // --------------------------------------------------------------------------------------------- 432 // ---------------------------------------------------------------------------------------------
401 // shutdown_timeout should be a number in [0,3600]
402 433
403 SECTION("shutdown_timeout") 434 SECTION("on_state_create = <string>")
404 { 435 {
405 SECTION("shutdown_timeout = <table>") 436 L.requireFailure("require 'lanes'.configure{on_state_create = 'gluh'}");
406 { 437 }
407 L.requireFailure("require 'lanes'.configure{shutdown_timeout = {}}");
408 }
409 438
410 // ----------------------------------------------------------------------------------------- 439 // ---------------------------------------------------------------------------------------------
411 440
412 SECTION("shutdown_timeout = <string>") 441 SECTION("on_state_create = <number>")
413 { 442 {
414 L.requireFailure("require 'lanes'.configure{shutdown_timeout = 'gluh'}"); 443 L.requireFailure("require 'lanes'.configure{on_state_create = 1}");
415 } 444 }
416 445
417 // ----------------------------------------------------------------------------------------- 446 // ---------------------------------------------------------------------------------------------
418 447
419 SECTION("shutdown_timeout = <negative number>") 448 SECTION("on_state_create = false")
420 { 449 {
421 L.requireFailure("require 'lanes'.configure{shutdown_timeout = -0.001}"); 450 L.requireFailure("require 'lanes'.configure{on_state_create = false}");
422 } 451 }
423 452
424 // ----------------------------------------------------------------------------------------- 453 // ---------------------------------------------------------------------------------------------
425 454
426 SECTION("shutdown_timeout = 0") 455 SECTION("on_state_create = true")
427 { 456 {
428 L.requireSuccess("require 'lanes'.configure{shutdown_timeout = 0}"); 457 L.requireFailure("require 'lanes'.configure{on_state_create = true}");
429 } 458 }
430 459
431 // ----------------------------------------------------------------------------------------- 460 // ---------------------------------------------------------------------------------------------
432 461
433 SECTION("shutdown_timeout = 1s") 462 SECTION("on_state_create = <Lua function>")
434 { 463 {
435 L.requireSuccess("require 'lanes'.configure{shutdown_timeout = 1}"); 464 // on_state_create isn't called inside a Keeper state if it's a Lua function (which is good as print() doesn't exist there!)
436 } 465 L.requireSuccess("local print = print; require 'lanes'.configure{on_state_create = function() print 'hello' end}");
466 }
437 467
438 // ----------------------------------------------------------------------------------------- 468 // ---------------------------------------------------------------------------------------------
439 469
440 SECTION("shutdown_timeout = 3600s") 470 SECTION("on_state_create = <C function>")
441 { 471 {
442 L.requireSuccess("require 'lanes'.configure{shutdown_timeout = 3600}"); 472 // funnily enough, in Lua 5.3, print() uses global tostring(), that doesn't exist in a keeper since we didn't open libs -> "attempt to call a nil value"
443 } 473 // conclusion, don't use print() as a fake on_state_create() callback!
474 // assert() should be fine since we pass a non-false argument to on_state_create
475 L.requireSuccess("require 'lanes'.configure{on_state_create = assert}");
476 }
477}
444 478
445 // ----------------------------------------------------------------------------------------- 479// #################################################################################################
446 480
447 SECTION("shutdown_timeout = <too long>") 481TEST_CASE("lanes.configure.shutdown_timeout")
448 { 482{
449 L.requireFailure("require 'lanes'.configure{shutdown_timeout = 3600.001}"); 483 LuaState L{ LuaState::WithBaseLibs{ true }, LuaState::WithFixture{ false } };
450 } 484
485 // shutdown_timeout should be a number in [0,3600]
486
487 SECTION("shutdown_timeout = <table>")
488 {
489 L.requireFailure("require 'lanes'.configure{shutdown_timeout = {}}");
451 } 490 }
452 491
453 // --------------------------------------------------------------------------------------------- 492 // ---------------------------------------------------------------------------------------------
454 // strip_functions should be a boolean
455 493
456 SECTION("strip_functions") 494 SECTION("shutdown_timeout = <string>")
457 { 495 {
458 SECTION("strip_functions = <table>") 496 L.requireFailure("require 'lanes'.configure{shutdown_timeout = 'gluh'}");
459 { 497 }
460 L.requireFailure("require 'lanes'.configure{strip_functions = {}}");
461 }
462 498
463 // ----------------------------------------------------------------------------------------- 499 // ---------------------------------------------------------------------------------------------
464 500
465 SECTION("strip_functions = <string>") 501 SECTION("shutdown_timeout = <negative number>")
466 { 502 {
467 L.requireFailure("require 'lanes'.configure{strip_functions = 'gluh'}"); 503 L.requireFailure("require 'lanes'.configure{shutdown_timeout = -0.001}");
468 } 504 }
469 505
470 // ----------------------------------------------------------------------------------------- 506 // ---------------------------------------------------------------------------------------------
471 507
472 SECTION("strip_functions = <number>") 508 SECTION("shutdown_timeout = 0")
473 { 509 {
474 L.requireFailure("require 'lanes'.configure{strip_functions = 1}"); 510 L.requireSuccess("require 'lanes'.configure{shutdown_timeout = 0}");
475 } 511 }
476 512
477 // ----------------------------------------------------------------------------------------- 513 // ---------------------------------------------------------------------------------------------
478 514
479 SECTION("strip_functions = <C function>") 515 SECTION("shutdown_timeout = 1s")
480 { 516 {
481 L.requireFailure("require 'lanes'.configure{strip_functions = print}"); 517 L.requireSuccess("require 'lanes'.configure{shutdown_timeout = 1}");
482 } 518 }
483 519
484 // ----------------------------------------------------------------------------------------- 520 // ---------------------------------------------------------------------------------------------
485 521
486 SECTION("strip_functions = false") 522 SECTION("shutdown_timeout = 3600s")
487 { 523 {
488 L.requireSuccess("require 'lanes'.configure{strip_functions = false}"); 524 L.requireSuccess("require 'lanes'.configure{shutdown_timeout = 3600}");
489 } 525 }
490 526
491 // ----------------------------------------------------------------------------------------- 527 // ---------------------------------------------------------------------------------------------
492 528
493 SECTION("strip_functions = true") 529 SECTION("shutdown_timeout = <too long>")
494 { 530 {
495 L.requireSuccess("require 'lanes'.configure{strip_functions = true}"); 531 L.requireFailure("require 'lanes'.configure{shutdown_timeout = 3600.001}");
496 } 532 }
533}
534
535// #################################################################################################
536
537TEST_CASE("lanes.configure.strip_functions")
538{
539 LuaState L{ LuaState::WithBaseLibs{ true }, LuaState::WithFixture{ false } };
540
541 // strip_functions should be a boolean
542
543 SECTION("strip_functions = <table>")
544 {
545 L.requireFailure("require 'lanes'.configure{strip_functions = {}}");
497 } 546 }
498 547
499 // --------------------------------------------------------------------------------------------- 548 // ---------------------------------------------------------------------------------------------
500 // track_lanes should be a boolean
501 549
502 SECTION("track_lanes") 550 SECTION("strip_functions = <string>")
503 { 551 {
504 SECTION("track_lanes = <table>") 552 L.requireFailure("require 'lanes'.configure{strip_functions = 'gluh'}");
505 { 553 }
506 L.requireFailure("require 'lanes'.configure{track_lanes = {}}");
507 }
508 554
509 // ----------------------------------------------------------------------------------------- 555 // ---------------------------------------------------------------------------------------------
510 556
511 SECTION("track_lanes = <string>") 557 SECTION("strip_functions = <number>")
512 { 558 {
513 L.requireFailure("require 'lanes'.configure{track_lanes = 'gluh'}"); 559 L.requireFailure("require 'lanes'.configure{strip_functions = 1}");
514 } 560 }
515 561
516 // ----------------------------------------------------------------------------------------- 562 // ---------------------------------------------------------------------------------------------
517 563
518 SECTION("track_lanes = <number>") 564 SECTION("strip_functions = <C function>")
519 { 565 {
520 L.requireFailure("require 'lanes'.configure{track_lanes = 1}"); 566 L.requireFailure("require 'lanes'.configure{strip_functions = print}");
521 } 567 }
522 568
523 // ----------------------------------------------------------------------------------------- 569 // ---------------------------------------------------------------------------------------------
524 570
525 SECTION("track_lanes = <C function>") 571 SECTION("strip_functions = false")
526 { 572 {
527 L.requireFailure("require 'lanes'.configure{track_lanes = print}"); 573 L.requireSuccess("require 'lanes'.configure{strip_functions = false}");
528 } 574 }
529 575
530 // ----------------------------------------------------------------------------------------- 576 // ---------------------------------------------------------------------------------------------
531 577
532 SECTION("track_lanes = false") 578 SECTION("strip_functions = true")
533 { 579 {
534 L.requireSuccess("require 'lanes'.configure{track_lanes = false}"); 580 L.requireSuccess("require 'lanes'.configure{strip_functions = true}");
535 } 581 }
582}
536 583
537 // ----------------------------------------------------------------------------------------- 584// #################################################################################################
538 585
539 SECTION("track_lanes = true") 586TEST_CASE("lanes.configure.track_lanes")
540 { 587{
541 L.requireSuccess("require 'lanes'.configure{track_lanes = true}"); 588 LuaState L{ LuaState::WithBaseLibs{ true }, LuaState::WithFixture{ false } };
542 } 589
590 // track_lanes should be a boolean
591
592 SECTION("track_lanes = <table>")
593 {
594 L.requireFailure("require 'lanes'.configure{track_lanes = {}}");
543 } 595 }
544 596
545 // --------------------------------------------------------------------------------------------- 597 // ---------------------------------------------------------------------------------------------
546 // verbose_errors should be a boolean
547 598
548 SECTION("verbose_errors") 599 SECTION("track_lanes = <string>")
549 { 600 {
550 SECTION("verbose_errors = <table>") 601 L.requireFailure("require 'lanes'.configure{track_lanes = 'gluh'}");
551 { 602 }
552 L.requireFailure("require 'lanes'.configure{verbose_errors = {}}");
553 }
554 603
555 // ----------------------------------------------------------------------------------------- 604 // ---------------------------------------------------------------------------------------------
556 605
557 SECTION("verbose_errors = <string>") 606 SECTION("track_lanes = <number>")
558 { 607 {
559 L.requireFailure("require 'lanes'.configure{verbose_errors = 'gluh'}"); 608 L.requireFailure("require 'lanes'.configure{track_lanes = 1}");
560 } 609 }
561 610
562 // ----------------------------------------------------------------------------------------- 611 // ---------------------------------------------------------------------------------------------
563 612
564 SECTION("verbose_errors = <number>") 613 SECTION("track_lanes = <C function>")
565 { 614 {
566 L.requireFailure("require 'lanes'.configure{verbose_errors = 1}"); 615 L.requireFailure("require 'lanes'.configure{track_lanes = print}");
567 } 616 }
568 617
569 // ----------------------------------------------------------------------------------------- 618 // ---------------------------------------------------------------------------------------------
570 619
571 SECTION("verbose_errors = <C function>") 620 SECTION("track_lanes = false")
572 { 621 {
573 L.requireFailure("require 'lanes'.configure{verbose_errors = print}"); 622 L.requireSuccess("require 'lanes'.configure{track_lanes = false}");
574 } 623 }
575 624
576 // ----------------------------------------------------------------------------------------- 625 // ---------------------------------------------------------------------------------------------
577 626
578 SECTION("verbose_errors = false") 627 SECTION("track_lanes = true")
579 { 628 {
580 L.requireSuccess("require 'lanes'.configure{verbose_errors = false}"); 629 L.requireSuccess("require 'lanes'.configure{track_lanes = true}");
581 } 630 }
631}
582 632
583 // ----------------------------------------------------------------------------------------- 633// #################################################################################################
584 634
585 SECTION("verbose_errors = true") 635TEST_CASE("lanes.configure.verbose_errors")
586 { 636{
587 L.requireSuccess("require 'lanes'.configure{verbose_errors = true}"); 637 LuaState L{ LuaState::WithBaseLibs{ true }, LuaState::WithFixture{ false } };
588 } 638
639 // verbose_errors should be a boolean
640
641 SECTION("verbose_errors = <table>")
642 {
643 L.requireFailure("require 'lanes'.configure{verbose_errors = {}}");
589 } 644 }
590 645
591 // --------------------------------------------------------------------------------------------- 646 // ---------------------------------------------------------------------------------------------
592 // with_timers should be a boolean
593 647
594 SECTION("with_timers") 648 SECTION("verbose_errors = <string>")
595 { 649 {
596 SECTION("with_timers = <table>") 650 L.requireFailure("require 'lanes'.configure{verbose_errors = 'gluh'}");
597 { 651 }
598 L.requireFailure("require 'lanes'.configure{with_timers = {}}");
599 }
600 652
601 // ----------------------------------------------------------------------------------------- 653 // ---------------------------------------------------------------------------------------------
602 654
603 SECTION("with_timers = <string>") 655 SECTION("verbose_errors = <number>")
604 { 656 {
605 L.requireFailure("require 'lanes'.configure{with_timers = 'gluh'}"); 657 L.requireFailure("require 'lanes'.configure{verbose_errors = 1}");
606 } 658 }
607 659
608 // ----------------------------------------------------------------------------------------- 660 // ---------------------------------------------------------------------------------------------
609 661
610 SECTION("with_timers = <number>") 662 SECTION("verbose_errors = <C function>")
611 { 663 {
612 L.requireFailure("require 'lanes'.configure{with_timers = 1}"); 664 L.requireFailure("require 'lanes'.configure{verbose_errors = print}");
613 } 665 }
614 666
615 // ----------------------------------------------------------------------------------------- 667 // ---------------------------------------------------------------------------------------------
616 668
617 SECTION("with_timers = <C function>") 669 SECTION("verbose_errors = false")
618 { 670 {
619 L.requireFailure("require 'lanes'.configure{with_timers = print}"); 671 L.requireSuccess("require 'lanes'.configure{verbose_errors = false}");
620 } 672 }
621 673
622 // ----------------------------------------------------------------------------------------- 674 // ---------------------------------------------------------------------------------------------
623 675
624 SECTION("with_timers = false") 676 SECTION("verbose_errors = true")
625 { 677 {
626 L.requireSuccess("require 'lanes'.configure{with_timers = false}"); 678 L.requireSuccess("require 'lanes'.configure{verbose_errors = true}");
627 } 679 }
680}
628 681
629 // ----------------------------------------------------------------------------------------- 682// #################################################################################################
630 683
631 SECTION("with_timers = true") 684TEST_CASE("lanes.configure.with_timers")
632 { 685{
633 L.requireSuccess("require 'lanes'.configure{with_timers = true}"); 686 LuaState L{ LuaState::WithBaseLibs{ true }, LuaState::WithFixture{ false } };
634 } 687
688 // with_timers should be a boolean
689
690 SECTION("with_timers = <table>")
691 {
692 L.requireFailure("require 'lanes'.configure{with_timers = {}}");
693 }
694
695 // ---------------------------------------------------------------------------------------------
696
697 SECTION("with_timers = <string>")
698 {
699 L.requireFailure("require 'lanes'.configure{with_timers = 'gluh'}");
635 } 700 }
636 701
637 // --------------------------------------------------------------------------------------------- 702 // ---------------------------------------------------------------------------------------------
703
704 SECTION("with_timers = <number>")
705 {
706 L.requireFailure("require 'lanes'.configure{with_timers = 1}");
707 }
708
709 // ---------------------------------------------------------------------------------------------
710
711 SECTION("with_timers = <C function>")
712 {
713 L.requireFailure("require 'lanes'.configure{with_timers = print}");
714 }
715
716 // ---------------------------------------------------------------------------------------------
717
718 SECTION("with_timers = false")
719 {
720 L.requireSuccess("require 'lanes'.configure{with_timers = false}");
721 }
722
723 // ---------------------------------------------------------------------------------------------
724
725 SECTION("with_timers = true")
726 {
727 L.requireSuccess("require 'lanes'.configure{with_timers = true}");
728 }
729}
730
731// #################################################################################################
732
733TEST_CASE("lanes.configure.unknown_setting")
734{
735 LuaState L{ LuaState::WithBaseLibs{ true }, LuaState::WithFixture{ false } };
736
638 // any unknown setting should be rejected 737 // any unknown setting should be rejected
639 738
640 SECTION("unknown_setting") 739 SECTION("table setting")
641 { 740 {
642 SECTION("table setting") 741 L.requireFailure("require 'lanes'.configure{[{}] = {}}");
643 { 742 }
644 L.requireFailure("require 'lanes'.configure{[{}] = {}}");
645 }
646 743
647 // ----------------------------------------------------------------------------------------- 744 // ---------------------------------------------------------------------------------------------
648 745
649 SECTION("boolean setting") 746 SECTION("boolean setting")
650 { 747 {
651 L.requireFailure("require 'lanes'.configure{[true] = 'gluh'}"); 748 L.requireFailure("require 'lanes'.configure{[true] = 'gluh'}");
652 } 749 }
653 750
654 // ----------------------------------------------------------------------------------------- 751 // ---------------------------------------------------------------------------------------------
655 752
656 SECTION("function setting") 753 SECTION("function setting")
657 { 754 {
658 L.requireFailure("require 'lanes'.configure{[function() end] = 1}"); 755 L.requireFailure("require 'lanes'.configure{[function() end] = 1}");
659 } 756 }
660 757
661 // ----------------------------------------------------------------------------------------- 758 // ---------------------------------------------------------------------------------------------
662 759
663 SECTION("number setting") 760 SECTION("number setting")
664 { 761 {
665 L.requireFailure("require 'lanes'.configure{[1] = function() end}"); 762 L.requireFailure("require 'lanes'.configure{[1] = function() end}");
666 } 763 }
667 764
668 // ----------------------------------------------------------------------------------------- 765 // ---------------------------------------------------------------------------------------------
669 766
670 SECTION("unknown string setting") 767 SECTION("unknown string setting")
671 { 768 {
672 L.requireFailure("require 'lanes'.configure{['gluh'] = false}"); 769 L.requireFailure("require 'lanes'.configure{['gluh'] = false}");
673 }
674 } 770 }
675} 771}
676 772
@@ -679,7 +775,7 @@ TEST_CASE("lanes.configure.the rest")
679 775
680#if LUAJIT_FLAVOR() == 0 776#if LUAJIT_FLAVOR() == 0
681// TODO: this test crashes inside S.close() against LuaJIT. to be investigated 777// TODO: this test crashes inside S.close() against LuaJIT. to be investigated
682TEST_CASE("lanes.finally.no fixture") 778TEST_CASE("lanes.finally.no_fixture")
683{ 779{
684 LuaState S{ LuaState::WithBaseLibs{ true }, LuaState::WithFixture{ false } }; 780 LuaState S{ LuaState::WithBaseLibs{ true }, LuaState::WithFixture{ false } };
685 // we need Lanes to be up. Since we run several 'scripts', we store it as a global 781 // we need Lanes to be up. Since we run several 'scripts', we store it as a global
@@ -700,7 +796,7 @@ TEST_CASE("lanes.finally.no fixture")
700 796
701// ################################################################################################# 797// #################################################################################################
702 798
703TEST_CASE("lanes.finally.with fixture") 799TEST_CASE("lanes.finally.with_fixture")
704{ 800{
705 LuaState S{ LuaState::WithBaseLibs{ true }, LuaState::WithFixture{ true } }; 801 LuaState S{ LuaState::WithBaseLibs{ true }, LuaState::WithFixture{ true } };
706 802
@@ -718,7 +814,7 @@ TEST_CASE("lanes.finally.with fixture")
718 814
719// ################################################################################################# 815// #################################################################################################
720 816
721TEST_CASE("lanes.finally.shutdown with an uncooperative lane") 817TEST_CASE("lanes.finally.shutdown_with_an_uncooperative_lane")
722{ 818{
723 LuaState S{ LuaState::WithBaseLibs{ true }, LuaState::WithFixture{ true } }; 819 LuaState S{ LuaState::WithBaseLibs{ true }, LuaState::WithFixture{ true } };
724 S.requireSuccess("lanes = require 'lanes'.configure()"); 820 S.requireSuccess("lanes = require 'lanes'.configure()");
@@ -767,7 +863,7 @@ namespace
767 863
768// ################################################################################################# 864// #################################################################################################
769 865
770TEST_CASE("lanes.on_state_create setting") 866TEST_CASE("lanes.configure.on_state_create/details")
771{ 867{
772 LuaState S{ LuaState::WithBaseLibs{ true }, LuaState::WithFixture{ false } }; 868 LuaState S{ LuaState::WithBaseLibs{ true }, LuaState::WithFixture{ false } };
773 869
diff --git a/unit_tests/lane_tests.cpp b/unit_tests/lane_tests.cpp
index d6ef2e0..b6fb188 100644
--- a/unit_tests/lane_tests.cpp
+++ b/unit_tests/lane_tests.cpp
@@ -1,5 +1,7 @@
1#include "_pch.hpp" 1#include "_pch.hpp"
2
2#include "shared.h" 3#include "shared.h"
4#include "lanes/src/threading.hpp"
3 5
4// ################################################################################################# 6// #################################################################################################
5// ################################################################################################# 7// #################################################################################################
@@ -33,7 +35,77 @@ TEST_CASE("lanes.nameof")
33// ################################################################################################# 35// #################################################################################################
34// ################################################################################################# 36// #################################################################################################
35 37
36TEST_CASE("lanes.sleep.argument validation") 38TEST_CASE("lanes.thread_priority_range")
39{
40 LuaState S{ LuaState::WithBaseLibs{ true }, LuaState::WithFixture{ false } };
41 S.requireSuccess("lanes = require 'lanes'.configure()");
42
43 S.requireSuccess("a, b = lanes.thread_priority_range(); print(a, b)");
44 S.requireSuccess("assert(type(a) == 'number' and type(b) == 'number' and b > a)");
45 S.requireSuccess("c, d = lanes.thread_priority_range('native'); print(c, d)");
46 S.requireSuccess("assert(type(c) == 'number' and type(d) == 'number' and d > c)");
47
48 // can't really test the range of values from pthread as they are platform-dependent
49 if constexpr (THREADAPI == THREADAPI_WINDOWS) {
50 // windows constants THREAD_PRIORITY_IDLE and THREAD_PRIORITY_TIME_CRITICAL
51 S.requireSuccess("assert(c == -15 and d == 15)");
52 }
53}
54
55// #################################################################################################
56// #################################################################################################
57
58TEST_CASE("lanes.set_thread_priority")
59{
60 LuaState S{ LuaState::WithBaseLibs{ true }, LuaState::WithFixture{ false } };
61 S.requireSuccess("lanes = require 'lanes'.configure()");
62
63 SECTION("mapped priorities")
64 {
65 std::string_view const _script{
66 " min_prio, max_prio = lanes.thread_priority_range()"
67 " for prio = min_prio, max_prio do"
68 " lanes.set_thread_priority(prio)"
69 " end"
70 };
71 S.requireSuccess(_script);
72
73 S.requireFailure("lanes.set_thread_priority(min_prio - 1)");
74 S.requireFailure("lanes.set_thread_priority(max_prio + 1)");
75 }
76
77 SECTION("native priorities")
78 {
79 S.requireSuccess("min_prio, max_prio = lanes.thread_priority_range('native')");
80 if constexpr (THREADAPI == THREADAPI_WINDOWS) {
81 // Win32 range is -15 to 15, but only some values are accepted
82 S.requireSuccess("lanes.set_thread_priority(-15, 'native')"); // THREAD_PRIORITY_IDLE
83 S.requireFailure("lanes.set_thread_priority(-3, 'native')");
84 S.requireSuccess("lanes.set_thread_priority(-2, 'native')"); // THREAD_PRIORITY_LOWEST
85 S.requireSuccess("lanes.set_thread_priority(-1, 'native')"); // THREAD_PRIORITY_BELOW_NORMAL
86 S.requireSuccess("lanes.set_thread_priority(0, 'native')"); // THREAD_PRIORITY_NORMAL
87 S.requireSuccess("lanes.set_thread_priority(1, 'native')"); // THREAD_PRIORITY_ABOVE_NORMAL
88 S.requireSuccess("lanes.set_thread_priority(2, 'native')"); // THREAD_PRIORITY_HIGHEST
89 S.requireFailure("lanes.set_thread_priority(3, 'native')");
90 S.requireSuccess("lanes.set_thread_priority(-15, 'native')"); // THREAD_PRIORITY_TIME_CRITICAL
91 } else {
92 // until proven otherwise, the full set of values is supported by pthread
93 std::string_view const _script{
94 " for prio = min_prio, max_prio do"
95 " lanes.set_thread_priority(prio, 'native')"
96 " end"
97 };
98 S.requireSuccess(_script);
99 }
100 S.requireFailure("lanes.set_thread_priority(min_prio - 1)");
101 S.requireFailure("lanes.set_thread_priority(max_prio + 1)");
102 }
103}
104
105// #################################################################################################
106// #################################################################################################
107
108TEST_CASE("lanes.sleep.argument_validation/not_numbers")
37{ 109{
38 LuaState S{ LuaState::WithBaseLibs{ true }, LuaState::WithFixture{ false } }; 110 LuaState S{ LuaState::WithBaseLibs{ true }, LuaState::WithFixture{ false } };
39 S.requireSuccess("lanes = require 'lanes'.configure()"); 111 S.requireSuccess("lanes = require 'lanes'.configure()");
@@ -44,6 +116,14 @@ TEST_CASE("lanes.sleep.argument validation")
44 S.requireFailure("lanes.sleep('a string')"); 116 S.requireFailure("lanes.sleep('a string')");
45 S.requireFailure("lanes.sleep(lanes.null)"); 117 S.requireFailure("lanes.sleep(lanes.null)");
46 S.requireFailure("lanes.sleep(print)"); 118 S.requireFailure("lanes.sleep(print)");
119}
120
121// #################################################################################################
122
123TEST_CASE("lanes.sleep.argument_validation/numbers")
124{
125 LuaState S{ LuaState::WithBaseLibs{ true }, LuaState::WithFixture{ false } };
126 S.requireSuccess("lanes = require 'lanes'.configure()");
47 127
48 // negative durations are not supported 128 // negative durations are not supported
49 S.requireFailure("lanes.sleep(-1)"); 129 S.requireFailure("lanes.sleep(-1)");
@@ -97,88 +177,109 @@ TEST_CASE("lanes.sleep.interactions with timers")
97// ################################################################################################# 177// #################################################################################################
98// ################################################################################################# 178// #################################################################################################
99 179
100TEST_CASE("lanes.gen") 180TEST_CASE("lanes.gen.argument_checks")
101{ 181{
102 LuaState S{ LuaState::WithBaseLibs{ true }, LuaState::WithFixture{ false } }; 182 LuaState S{ LuaState::WithBaseLibs{ true }, LuaState::WithFixture{ false } };
103 S.requireSuccess("lanes = require 'lanes'.configure()"); 183 S.requireSuccess("lanes = require 'lanes'.configure()");
104 184
105 // --------------------------------------------------------------------------------------------- 185 // ---------------------------------------------------------------------------------------------
106 186
107 SECTION("argument checks") 187 // no argument is bad
108 { 188 S.requireFailure("lanes.gen()");
109 // no parameter is bad 189
110 S.requireFailure("lanes.gen()"); 190 // minimal generator needs a function
111 191 S.requireSuccess("lanes.gen(function() end)");
112 // minimal generator needs a function 192
113 S.requireSuccess("lanes.gen(function() end)"); 193 // acceptable arguments for the generator are strings, tables, nil, followed by the function body
114 194 S.requireSuccess("lanes.gen(nil, function() end)");
115 // acceptable parameters for the generator are strings, tables, nil, followed by the function body 195 S.requireSuccess("lanes.gen('', function() end)");
116 S.requireSuccess("lanes.gen(nil, function() end)"); 196 S.requireSuccess("lanes.gen({}, function() end)");
117 S.requireSuccess("lanes.gen('', function() end)"); 197 S.requireSuccess("lanes.gen('', {}, function() end)");
118 S.requireSuccess("lanes.gen({}, function() end)"); 198 S.requireSuccess("lanes.gen({}, '', function() end)");
119 S.requireSuccess("lanes.gen('', {}, function() end)"); 199 S.requireSuccess("lanes.gen('', '', function() end)");
120 S.requireSuccess("lanes.gen({}, '', function() end)"); 200 S.requireSuccess("lanes.gen({}, {}, function() end)");
121 S.requireSuccess("lanes.gen('', '', function() end)"); 201
122 S.requireSuccess("lanes.gen({}, {}, function() end)"); 202 // anything different should fail: booleans, numbers, any userdata
123 203 S.requireFailure("lanes.gen(false, function() end)");
124 // anything different should fail: booleans, numbers, any userdata 204 S.requireFailure("lanes.gen(true, function() end)");
125 S.requireFailure("lanes.gen(false, function() end)"); 205 S.requireFailure("lanes.gen(42, function() end)");
126 S.requireFailure("lanes.gen(true, function() end)"); 206 S.requireFailure("lanes.gen(io.stdin, function() end)");
127 S.requireFailure("lanes.gen(42, function() end)"); 207 S.requireFailure("lanes.gen(lanes.linda(), function() end)");
128 S.requireFailure("lanes.gen(io.stdin, function() end)"); 208 S.requireFailure("lanes.gen(lanes.linda():deep(), function() end)");
129 S.requireFailure("lanes.gen(lanes.linda(), function() end)"); 209
130 S.requireFailure("lanes.gen(lanes.linda():deep(), function() end)"); 210 // even if argument types are correct, the function must come last
131 211 S.requireFailure("lanes.gen(function() end, '')");
132 // even if parameter types are correct, the function must come last 212
133 S.requireFailure("lanes.gen(function() end, '')"); 213 // the strings should only list "known base libraries", in any order, or "*"
134 214 // if the particular Lua flavor we build for doesn't support them, they raise an error unless postfixed by '?'
135 // the strings should only list "known base libraries", in any order, or "*" 215 S.requireSuccess("lanes.gen('base', function() end)");
136 // if the particular Lua flavor we build for doesn't support them, they raise an error unless postfixed by '?' 216
137 S.requireSuccess("lanes.gen('base', function() end)"); 217 // bit, ffi, jit are LuaJIT-specific
138
139 // bit, ffi, jit are LuaJIT-specific
140#if LUAJIT_FLAVOR() == 0 218#if LUAJIT_FLAVOR() == 0
141 S.requireFailure("lanes.gen('bit,ffi,jit', function() end)"); 219 S.requireFailure("lanes.gen('bit,ffi,jit', function() end)");
142 S.requireSuccess("lanes.gen('bit?,ffi?,jit?', function() end)"); 220 S.requireSuccess("lanes.gen('bit?,ffi?,jit?', function() end)");
143#endif // LUAJIT_FLAVOR() 221#endif // LUAJIT_FLAVOR()
144 222
145 // bit32 library existed only in Lua 5.2, there is still a loader that will raise an error in Lua 5.3 223 // bit32 library existed only in Lua 5.2, there is still a loader that will raise an error in Lua 5.3
146#if LUA_VERSION_NUM == 502 || LUA_VERSION_NUM == 503 224#if LUA_VERSION_NUM == 502 || LUA_VERSION_NUM == 503
147 S.requireSuccess("lanes.gen('bit32', function() end)"); 225 S.requireSuccess("lanes.gen('bit32', function() end)");
148#else // LUA_VERSION_NUM == 502 || LUA_VERSION_NUM == 503 226#else // LUA_VERSION_NUM == 502 || LUA_VERSION_NUM == 503
149 S.requireFailure("lanes.gen('bit32', function() end)"); 227 S.requireFailure("lanes.gen('bit32', function() end)");
150 S.requireSuccess("lanes.gen('bit32?', function() end)"); 228 S.requireSuccess("lanes.gen('bit32?', function() end)");
151#endif // LUA_VERSION_NUM == 502 || LUA_VERSION_NUM == 503 229#endif // LUA_VERSION_NUM == 502 || LUA_VERSION_NUM == 503
152 230
153 // coroutine library appeared with Lua 5.2 231 // coroutine library appeared with Lua 5.2
154#if LUA_VERSION_NUM == 501 232#if LUA_VERSION_NUM == 501
155 S.requireFailure("lanes.gen('coroutine', function() end)"); 233 S.requireFailure("lanes.gen('coroutine', function() end)");
156 S.requireSuccess("lanes.gen('coroutine?', function() end)"); 234 S.requireSuccess("lanes.gen('coroutine?', function() end)");
157#endif // LUA_VERSION_NUM == 501 235#endif // LUA_VERSION_NUM == 501
158 236
159 S.requireSuccess("lanes.gen('debug', function() end)"); 237 S.requireSuccess("lanes.gen('debug', function() end)");
160 S.requireSuccess("lanes.gen('io', function() end)"); 238 S.requireSuccess("lanes.gen('io', function() end)");
161 S.requireSuccess("lanes.gen('math', function() end)"); 239 S.requireSuccess("lanes.gen('math', function() end)");
162 S.requireSuccess("lanes.gen('os', function() end)"); 240 S.requireSuccess("lanes.gen('os', function() end)");
163 S.requireSuccess("lanes.gen('package', function() end)"); 241 S.requireSuccess("lanes.gen('package', function() end)");
164 S.requireSuccess("lanes.gen('string', function() end)"); 242 S.requireSuccess("lanes.gen('string', function() end)");
165 S.requireSuccess("lanes.gen('table', function() end)"); 243 S.requireSuccess("lanes.gen('table', function() end)");
166 244
167 // utf8 library appeared with Lua 5.3 245 // utf8 library appeared with Lua 5.3
168#if LUA_VERSION_NUM < 503 246#if LUA_VERSION_NUM < 503
169 S.requireFailure("lanes.gen('utf8', function() end)"); 247 S.requireFailure("lanes.gen('utf8', function() end)");
170 S.requireSuccess("lanes.gen('utf8?', function() end)"); 248 S.requireSuccess("lanes.gen('utf8?', function() end)");
171#endif // LUA_VERSION_NUM < 503 249#endif // LUA_VERSION_NUM < 503
172 250
173 S.requireSuccess("lanes.gen('lanes_core', function() end)"); 251 S.requireSuccess("lanes.gen('lanes_core', function() end)");
174 // "*" repeated or combined with anything else is forbidden 252 // "*" repeated or combined with anything else is forbidden
175 S.requireFailure("lanes.gen('*', '*', function() end)"); 253 S.requireFailure("lanes.gen('*', '*', function() end)");
176 S.requireFailure("lanes.gen('base', '*', function() end)"); 254 S.requireFailure("lanes.gen('base', '*', function() end)");
177 // unknown names are forbidden 255 // unknown names are forbidden
178 S.requireFailure("lanes.gen('Base', function() end)"); 256 S.requireFailure("lanes.gen('Base', function() end)");
179 // repeating the same library more than once is forbidden 257 // repeating the same library more than once is forbidden
180 S.requireFailure("lanes.gen('base,base', function() end)"); 258 S.requireFailure("lanes.gen('base,base', function() end)");
181 } 259}
260
261// #################################################################################################
262// #################################################################################################
263
264TEST_CASE("lanes.gen.priority")
265{
266 LuaState S{ LuaState::WithBaseLibs{ true }, LuaState::WithFixture{ false } };
267 S.requireSuccess("lanes = require 'lanes'.configure()");
268
269 S.requireSuccess("lanes.gen({priority=1}, function() end)");
270 // AFAICT, 1 is accepted by all pthread flavors and win32 API
271 S.requireSuccess("lanes.gen({native_priority=1}, function() end)");
272 // shouldn't be able to provide 2 priority settings
273 S.requireFailure("lanes.gen({priority=1, native_priority=1}, function() end)");
274}
275
276// #################################################################################################
277// #################################################################################################
278
279TEST_CASE("lanes.gen.thread_naming")
280{
281 LuaState S{ LuaState::WithBaseLibs{ true }, LuaState::WithFixture{ false } };
282 S.requireSuccess("lanes = require 'lanes'.configure()");
182 283
183 // --------------------------------------------------------------------------------------------- 284 // ---------------------------------------------------------------------------------------------
184 285
@@ -319,19 +420,24 @@ TEST_CASE("lane.cancel")
319// unfortunately, VS Test adapter does not list individual sections, 420// unfortunately, VS Test adapter does not list individual sections,
320// so let's create a separate test case for each file with an ugly macro... 421// so let's create a separate test case for each file with an ugly macro...
321 422
322#define MAKE_TEST_CASE(DIR, FILE, CONDITION)\ 423#define MAKE_TEST_CASE(DIR, FILE, CONDITION) \
323TEST_CASE("scripted tests." #DIR "." #FILE) \ 424TEST_CASE("scripted_tests." #DIR "." #FILE) \
324{ \ 425{ \
325 FileRunner _runner(R"(.\unit_tests\scripts)"); \ 426 FileRunner _runner(R"(.\unit_tests\scripts)"); \
326 _runner.performTest(FileRunnerParam{ #DIR "/" #FILE, TestType::CONDITION }); \ 427 _runner.performTest(FileRunnerParam{ #DIR "/" #FILE, TestType::CONDITION }); \
327} 428}
328 429
329MAKE_TEST_CASE(lane, cooperative_shutdown, AssertNoLuaError) 430#if LUA_VERSION_NUM >= 504 // this makes use of to-be-closed variables, a Lua 5.4 feature
330#if LUA_VERSION_NUM >= 504 // // warnings are a Lua 5.4 feature 431#define MAKE_TEST_CASE_54(DIR, FILE, CONDITION) MAKE_TEST_CASE(DIR, FILE, CONDITION)
331// NOTE: when this test ends, there are resource leaks and a dangling thread 432#else // LUA_VERSION_NUM
332MAKE_TEST_CASE(lane, uncooperative_shutdown, AssertWarns) 433#define MAKE_TEST_CASE_54(DIR, FILE, CONDITION)
333#endif // LUA_VERSION_NUM 434#endif // LUA_VERSION_NUM
435
436MAKE_TEST_CASE(lane, body_is_a_c_function, AssertNoLuaError)
437MAKE_TEST_CASE(lane, cooperative_shutdown, AssertNoLuaError)
438MAKE_TEST_CASE_54(lane, uncooperative_shutdown, AssertWarns) // NOTE: when this test ends, there are resource leaks and a dangling thread
334MAKE_TEST_CASE(lane, tasking_basic, AssertNoLuaError) 439MAKE_TEST_CASE(lane, tasking_basic, AssertNoLuaError)
440MAKE_TEST_CASE(lane, tasking_cancelling_with_hook, AssertNoLuaError)
335MAKE_TEST_CASE(lane, tasking_cancelling, AssertNoLuaError) 441MAKE_TEST_CASE(lane, tasking_cancelling, AssertNoLuaError)
336MAKE_TEST_CASE(lane, tasking_comms_criss_cross, AssertNoLuaError) 442MAKE_TEST_CASE(lane, tasking_comms_criss_cross, AssertNoLuaError)
337MAKE_TEST_CASE(lane, tasking_communications, AssertNoLuaError) 443MAKE_TEST_CASE(lane, tasking_communications, AssertNoLuaError)
@@ -339,19 +445,27 @@ MAKE_TEST_CASE(lane, tasking_error, AssertNoLuaError)
339MAKE_TEST_CASE(lane, tasking_join_test, AssertNoLuaError) 445MAKE_TEST_CASE(lane, tasking_join_test, AssertNoLuaError)
340MAKE_TEST_CASE(lane, tasking_send_receive_code, AssertNoLuaError) 446MAKE_TEST_CASE(lane, tasking_send_receive_code, AssertNoLuaError)
341MAKE_TEST_CASE(lane, stdlib_naming, AssertNoLuaError) 447MAKE_TEST_CASE(lane, stdlib_naming, AssertNoLuaError)
342MAKE_TEST_CASE(coro, basics, AssertNoLuaError) 448MAKE_TEST_CASE(coro, cancelling_suspended, AssertNoLuaError)
449MAKE_TEST_CASE_54(coro, collect_yielded_lane, AssertNoLuaError)
343#if LUAJIT_FLAVOR() == 0 450#if LUAJIT_FLAVOR() == 0
344// TODO: for some reason, the test fails with LuaJIT. To be investigated 451// TODO: for some reason, the test fails with LuaJIT. To be investigated
345MAKE_TEST_CASE(coro, error_handling, AssertNoLuaError) 452MAKE_TEST_CASE(coro, error_handling, AssertNoLuaError)
346#endif // LUAJIT_FLAVOR() 453#endif // LUAJIT_FLAVOR()
454MAKE_TEST_CASE(coro, index_suspended, AssertNoLuaError)
455MAKE_TEST_CASE(coro, join_suspended, AssertNoLuaError)
456MAKE_TEST_CASE_54(coro, linda_in_close_handler, AssertNoLuaError)
457MAKE_TEST_CASE(coro, regular_function, AssertNoLuaError)
458MAKE_TEST_CASE(coro, resume_basics, AssertNoLuaError)
459MAKE_TEST_CASE(coro, yielding_in_non_coro_errors, AssertNoLuaError)
347 460
348/* 461/*
349TEST_CASE("lanes.scripted tests") 462TEST_CASE("lanes.scripted_tests")
350{ 463{
351 auto const& _testParam = GENERATE( 464 auto const& _testParam = GENERATE(
352 FileRunnerParam{ PUC_LUA_ONLY("lane/cooperative_shutdown"), TestType::AssertNoLuaError }, // 0 465 FileRunnerParam{ PUC_LUA_ONLY("lane/cooperative_shutdown"), TestType::AssertNoLuaError }, // 0
353 FileRunnerParam{ "lane/uncooperative_shutdown", TestType::AssertWarns }, 466 FileRunnerParam{ "lane/uncooperative_shutdown", TestType::AssertWarns },
354 FileRunnerParam{ "lane/tasking_basic", TestType::AssertNoLuaError }, // 2 467 FileRunnerParam{ "lane/tasking_basic", TestType::AssertNoLuaError }, // 2
468 FileRunnerParam{ "lane/tasking_cancelling_with_hook", TestType::AssertNoLuaError }, // 3
355 FileRunnerParam{ "lane/tasking_cancelling", TestType::AssertNoLuaError }, // 3 469 FileRunnerParam{ "lane/tasking_cancelling", TestType::AssertNoLuaError }, // 3
356 FileRunnerParam{ "lane/tasking_comms_criss_cross", TestType::AssertNoLuaError }, // 4 470 FileRunnerParam{ "lane/tasking_comms_criss_cross", TestType::AssertNoLuaError }, // 4
357 FileRunnerParam{ "lane/tasking_communications", TestType::AssertNoLuaError }, 471 FileRunnerParam{ "lane/tasking_communications", TestType::AssertNoLuaError },
diff --git a/unit_tests/legacy_tests.cpp b/unit_tests/legacy_tests.cpp
index 7f2f31d..84581d2 100644
--- a/unit_tests/legacy_tests.cpp
+++ b/unit_tests/legacy_tests.cpp
@@ -11,7 +11,7 @@
11// so let's create a separate test case for each file with an ugly macro... 11// so let's create a separate test case for each file with an ugly macro...
12 12
13#define MAKE_TEST_CASE(FILE) \ 13#define MAKE_TEST_CASE(FILE) \
14TEST_CASE("scripted tests.legacy." #FILE) \ 14TEST_CASE("scripted_tests.legacy." #FILE) \
15{ \ 15{ \
16 FileRunner _runner(R"(.\tests\)"); \ 16 FileRunner _runner(R"(.\tests\)"); \
17 _runner.performTest(FileRunnerParam{ #FILE, TestType::AssertNoLuaError }); \ 17 _runner.performTest(FileRunnerParam{ #FILE, TestType::AssertNoLuaError }); \
@@ -49,7 +49,7 @@ MAKE_TEST_CASE(tobeclosed)
49MAKE_TEST_CASE(track_lanes) 49MAKE_TEST_CASE(track_lanes)
50 50
51/* 51/*
52TEST_CASE("lanes.legacy scripted tests") 52TEST_CASE("lanes.legacy_scripted_tests")
53{ 53{
54 auto const& _testParam = GENERATE( 54 auto const& _testParam = GENERATE(
55 FileRunnerParam{ "appendud", TestType::AssertNoLuaError } // 0 55 FileRunnerParam{ "appendud", TestType::AssertNoLuaError } // 0
diff --git a/unit_tests/linda_tests.cpp b/unit_tests/linda_tests.cpp
index efdb8a5..90630a7 100644
--- a/unit_tests/linda_tests.cpp
+++ b/unit_tests/linda_tests.cpp
@@ -3,154 +3,216 @@
3 3
4// ################################################################################################# 4// #################################################################################################
5 5
6TEST_CASE("linda.single Keeper") 6TEST_CASE("linda.single_keeper.creation/no_argument")
7{ 7{
8 LuaState S{ LuaState::WithBaseLibs{ true }, LuaState::WithFixture{ true } }; 8 LuaState S{ LuaState::WithBaseLibs{ true }, LuaState::WithFixture{ true } };
9 S.requireSuccess("lanes = require 'lanes'"); 9 S.requireSuccess("lanes = require 'lanes'");
10 10
11 SECTION("Linda creation") 11 // no argument is ok
12 { 12 S.requireSuccess("lanes.linda()");
13 // no parameters is ok 13 S.requireNotReturnedString("return tostring(lanes.linda())", R"===(Linda: <not a string>)==="); // unspecified name should not result in <not a string>
14 S.requireSuccess("lanes.linda()"); 14}
15 S.requireNotReturnedString("return tostring(lanes.linda())", R"===(Linda: <not a string>)==="); // unspecified name should not result in <not a string>
16
17 // since we have only one keeper, only group 0 is authorized
18 S.requireFailure("lanes.linda(-1)");
19 S.requireSuccess("lanes.linda(0)");
20 S.requireFailure("lanes.linda(1)");
21
22 // any name is ok
23 S.requireSuccess("lanes.linda('')"); // an empty name results in a string conversion of the form "Linda: <some hex value>" that we can't test (but it works)
24 S.requireReturnedString("return tostring(lanes.linda('short name'))", R"===(Linda: short name)===");
25 S.requireReturnedString("return tostring(lanes.linda('very very very very very very long name'))", R"===(Linda: very very very very very very long name)===");
26 S.requireReturnedString("return tostring(lanes.linda('auto'))", R"===(Linda: [string "return tostring(lanes.linda('auto'))"]:1)===");
27
28 if constexpr (LUA_VERSION_NUM == 504) {
29 // a function is acceptable as a __close handler
30 S.requireSuccess("local l <close> = lanes.linda(function() end)");
31 // a callable table too (a callable full userdata as well, but I have none here)
32 S.requireSuccess("local l <close> = lanes.linda(setmetatable({}, {__call = function() end}))");
33 // if the function raises an error, we should get it
34 S.requireFailure("local l <close> = lanes.linda(function() error 'gluh' end)");
35 } else {
36 // no __close support before Lua 5.4
37 S.requireFailure("lanes.linda(function() end)");
38 S.requireFailure("lanes.linda(setmetatable({}, {__call = function() end}))");
39 }
40 15
41 // mixing parameters in any order is ok: 2 out of 3 16// #################################################################################################
42 S.requireSuccess("lanes.linda(0, 'name')");
43 S.requireSuccess("lanes.linda('name', 0)");
44 if constexpr (LUA_VERSION_NUM == 504) {
45 S.requireSuccess("lanes.linda(0, function() end)");
46 S.requireSuccess("lanes.linda(function() end, 0)");
47 S.requireSuccess("lanes.linda('name', function() end)");
48 S.requireSuccess("lanes.linda(function() end, 'name')");
49 }
50 17
51 // mixing parameters in any order is ok: 3 out of 3 18TEST_CASE("linda.single_keeper.creation/non_table_arguments")
52 if constexpr (LUA_VERSION_NUM == 504) { 19{
53 S.requireSuccess("lanes.linda(0, 'name', function() end)"); 20 LuaState S{ LuaState::WithBaseLibs{ true }, LuaState::WithFixture{ true } };
54 S.requireSuccess("lanes.linda(0, function() end, 'name')"); 21 S.requireSuccess("lanes = require 'lanes'");
55 S.requireSuccess("lanes.linda('name', 0, function() end)"); 22
56 S.requireSuccess("lanes.linda('name', function() end, 0)"); 23 // any argument that is not a table is not ok
57 S.requireSuccess("lanes.linda(function() end, 0, 'name')"); 24 S.requireFailure("lanes.linda(0)");
58 S.requireSuccess("lanes.linda(function() end, 'name', 0)"); 25 S.requireFailure("lanes.linda('bob')");
59 } 26 S.requireFailure("lanes.linda(false)");
27 S.requireFailure("lanes.linda(function() end)");
28 S.requireFailure("lanes.linda(lanes.cancel_error)");
29}
30
31// #################################################################################################
60 32
61 // unsupported parameters should fail 33TEST_CASE("linda.single_keeper.creation/close_handler")
62 S.requireFailure("lanes.linda(true)"); 34{
63 S.requireFailure("lanes.linda(false)"); 35 LuaState S{ LuaState::WithBaseLibs{ true }, LuaState::WithFixture{ true } };
64 // uncallable table or full userdata 36 S.requireSuccess("lanes = require 'lanes'");
65 S.requireFailure("lanes.linda({})"); 37
66 S.requireFailure("lanes.linda(lanes.linda())"); 38 if constexpr (LUA_VERSION_NUM >= 504) {
39 // a function is acceptable as a __close handler
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)
42 S.requireSuccess("local l <close> = lanes.linda{close_handler = setmetatable({}, {__call = function() end})}");
43 } else {
44 // no __close support before Lua 5.4, field is ignored (therefore invalid values are accepted too!)
45 S.requireSuccess("lanes.linda{close_handler = 'a string'}");
46 S.requireSuccess("lanes.linda{close_handler = function() end}");
47 S.requireSuccess("lanes.linda{close_handler = setmetatable({}, {__call = function() end})}");
67 } 48 }
49}
68 50
69 // --------------------------------------------------------------------------------------------- 51// #################################################################################################
52
53TEST_CASE("linda.single_keeper.creation/table_argument")
54{
55 LuaState S{ LuaState::WithBaseLibs{ true }, LuaState::WithFixture{ true } };
56 S.requireSuccess("lanes = require 'lanes'");
57
58 // one table is fine
59 S.requireSuccess("lanes.linda{}");
60 // anything beyond that is not
61 S.requireFailure("lanes.linda({},{})");
62 S.requireFailure("lanes.linda({},'bob')");
63 S.requireFailure("lanes.linda({},42)");
64}
65
66// #################################################################################################
67
68TEST_CASE("linda.single_keeper.creation/group")
69{
70 LuaState S{ LuaState::WithBaseLibs{ true }, LuaState::WithFixture{ true } };
71 S.requireSuccess("lanes = require 'lanes'");
72
73 // since we have only one keeper, only group 0 is authorized
74 S.requireFailure("lanes.linda{group = -1}");
75 S.requireSuccess("lanes.linda{group = 0}");
76 S.requireFailure("lanes.linda{group = 1}");
77}
78
79// #################################################################################################
80
81TEST_CASE("linda.single_keeper.creation/name")
82{
83 LuaState S{ LuaState::WithBaseLibs{ true }, LuaState::WithFixture{ true } };
84 S.requireSuccess("lanes = require 'lanes'");
85
86 // any name is ok
87 S.requireSuccess("lanes.linda{name = ''}"); // an empty name results in a string conversion of the form "Linda: <some hex value>" that we can't test (but it works)
88 S.requireReturnedString("return tostring(lanes.linda{name = 'short name'})", R"===(Linda: short name)===");
89 S.requireReturnedString("return tostring(lanes.linda{name = 'very very very very very very long name'})", R"===(Linda: very very very very very very long name)===");
90 S.requireReturnedString("return tostring(lanes.linda{name = 'auto'})", R"===(Linda: [string "return tostring(lanes.linda{name = 'auto'})"]:1)===");
91}
92
93// #################################################################################################
94
95TEST_CASE("linda.single_keeper.creation/wake_period")
96{
97 LuaState S{ LuaState::WithBaseLibs{ true }, LuaState::WithFixture{ true } };
98 S.requireSuccess("lanes = require 'lanes'");
99
100 // wake_period should be a number > 0
101 S.requireFailure("lanes.linda{wake_period = false}");
102 S.requireFailure("lanes.linda{wake_period = 'bob'}");
103 S.requireFailure("lanes.linda{wake_period = {}}");
104 S.requireFailure("lanes.linda{wake_period = -1}");
105 S.requireFailure("lanes.linda{wake_period = 0}");
106 S.requireSuccess("lanes.linda{wake_period = 0.0001}");
107 S.requireSuccess("lanes.linda{wake_period = 'never'}");
108}
109
110// #################################################################################################
70 111
71 SECTION("Linda indexing") 112TEST_CASE("linda.single_keeper.indexing")
113{
114 LuaState S{ LuaState::WithBaseLibs{ true }, LuaState::WithFixture{ true } };
115 S.requireSuccess("lanes = require 'lanes'.configure()");
116
117 // indexing the linda with an unknown string key should fail
118 S.requireFailure("return lanes.linda().gouikra");
119 // indexing the linda with an unsupported key type should fail
120 S.requireFailure("return lanes.linda()[5]");
121 S.requireFailure("return lanes.linda()[false]");
122 S.requireFailure("return lanes.linda()[{}]");
123 S.requireFailure("return lanes.linda()[function() end]");
124}
125
126// #################################################################################################
127
128TEST_CASE("linda.single_keeper.send()")
129{
130 LuaState S{ LuaState::WithBaseLibs{ true }, LuaState::WithFixture{ true } };
131 S.requireSuccess("lanes = require 'lanes'.configure()");
132
133 SECTION("timeout")
72 { 134 {
73 // indexing the linda with an unknown string key should fail 135 // timeout checks
74 S.requireFailure("return lanes.linda().gouikra"); 136 // linda:send() should fail if the timeout is bad
75 // indexing the linda with an unsupported key type should fail 137 S.requireFailure("lanes.linda():send(-1, 'k', 'v')");
76 S.requireFailure("return lanes.linda()[5]"); 138 // any positive value is ok
77 S.requireFailure("return lanes.linda()[false]"); 139 S.requireSuccess("lanes.linda():send(0, 'k', 'v')");
78 S.requireFailure("return lanes.linda()[{}]"); 140 S.requireSuccess("lanes.linda():send(1e20, 'k', 'v')");
79 S.requireFailure("return lanes.linda()[function() end]"); 141 // nil too (same as 'forever')
142 S.requireSuccess("lanes.linda():send(nil, 'k', 'v')");
80 } 143 }
81 144
82 // --------------------------------------------------------------------------------------------- 145 // -----------------------------------------------------------------------------------------
83 SECTION("linda:send()") 146
147 SECTION("fails on bad keys")
84 { 148 {
85 SECTION("timeout") 149 // key checks
86 { 150 // linda:send() should fail if the key is unsupported (nil, table, function, full userdata, reserved light userdata)
87 // timeout checks 151 S.requireFailure("lanes.linda():send(0, nil, 'v')");
88 // linda:send() should fail if the timeout is bad 152 S.requireFailure("lanes.linda():send(0, {}, 'v')");
89 S.requireFailure("lanes.linda():send(-1, 'k', 'v')"); 153 S.requireFailure("lanes.linda():send(0, function() end, 'v')");
90 // any positive value is ok 154 S.requireFailure("lanes.linda():send(0, io.stdin, 'v')");
91 S.requireSuccess("lanes.linda():send(0, 'k', 'v')"); 155 S.requireFailure("lanes.linda():send(0, lanes.null, 'v')");
92 S.requireSuccess("lanes.linda():send(1e20, 'k', 'v')"); 156 S.requireFailure("lanes.linda():send(0, lanes.cancel_error, 'v')");
93 // nil too (same as 'forever') 157 }
94 S.requireSuccess("lanes.linda():send(nil, 'k', 'v')");
95 }
96 158
97 // ----------------------------------------------------------------------------------------- 159 // -----------------------------------------------------------------------------------------
98 160
99 SECTION("fails on bad keys") 161 SECTION("succeeds on supported keys")
100 { 162 {
101 // key checks 163 // supported keys are ok: boolean, number, string, light userdata, deep userdata
102 // linda:send() should fail if the key is unsupported (nil, table, function, full userdata, reserved light userdata) 164 S.requireSuccess("lanes.linda():send(0, true, 'v')");
103 S.requireFailure("lanes.linda():send(0, nil, 'v')"); 165 S.requireSuccess("lanes.linda():send(0, false, 'v')");
104 S.requireFailure("lanes.linda():send(0, {}, 'v')"); 166 S.requireSuccess("lanes.linda():send(0, 99, 'v')");
105 S.requireFailure("lanes.linda():send(0, function() end, 'v')"); 167 S.requireSuccess("local l = lanes.linda(); l:send(0, l:deep(), 'v')");
106 S.requireFailure("lanes.linda():send(0, io.stdin, 'v')"); 168 }
107 S.requireFailure("lanes.linda():send(0, lanes.null, 'v')");
108 S.requireFailure("lanes.linda():send(0, lanes.cancel_error, 'v')");
109 S.requireFailure("local l = lanes.linda(); l:send(0, l.batched, 'v')");
110 }
111 169
112 // ----------------------------------------------------------------------------------------- 170 // -----------------------------------------------------------------------------------------
113 171
114 SECTION("succeeds on supported keys") 172 SECTION("succeeds on deep userdata key")
115 { 173 {
116 // supported keys are ok: boolean, number, string, light userdata, deep userdata 174 S.requireSuccess("local l = lanes.linda(); l:send(0, l, 'v')");
117 S.requireSuccess("lanes.linda():send(0, true, 'v')"); 175 }
118 S.requireSuccess("lanes.linda():send(0, false, 'v')");
119 S.requireSuccess("lanes.linda():send(0, 99, 'v')");
120 S.requireSuccess("local l = lanes.linda(); l:send(0, l:deep(), 'v')");
121 }
122 176
123 // ----------------------------------------------------------------------------------------- 177 // -----------------------------------------------------------------------------------------
124 178
125 SECTION("succeeds on deep userdata key") 179 SECTION(". fails")
126 { 180 {
127 S.requireSuccess("local l = lanes.linda(); l:send(0, l, 'v')"); 181 // misuse checks, . instead of :
128 } 182 S.requireFailure("lanes.linda().send(nil, 'k', 'v')");
183 }
129 184
130 // ----------------------------------------------------------------------------------------- 185 // -----------------------------------------------------------------------------------------
131 186
132 SECTION(". fails") 187 SECTION("unsupported values fail")
133 { 188 {
134 // misuse checks, . instead of : 189 // value checks
135 S.requireFailure("lanes.linda().send(nil, 'k', 'v')"); 190 // linda:send() should fail if we don't send anything
136 } 191 S.requireFailure("lanes.linda():send()");
192 S.requireFailure("lanes.linda():send(0)");
193 S.requireFailure("lanes.linda():send(0, 'k')");
194 // or non-deep userdata
195 S.requireFailure("lanes.linda():send(0, 'k', fixture.newuserdata())");
196 // or something with a converter that raises an error (maybe that should go to a dedicated __lanesconvert test!)
197 S.requireFailure("lanes.linda():send(0, 'k', setmetatable({}, {__lanesconvert = function(where_) error (where_ .. ': should not send me' end}))");
198 // but a registered non-deep userdata should work
199 S.requireSuccess("lanes.linda():send(0, 'k', io.stdin)");
200 }
201}
137 202
138 // ----------------------------------------------------------------------------------------- 203// #################################################################################################
139 204
140 SECTION("unsupported values fail") 205TEST_CASE("linda.single_keeper.the_rest")
141 { 206{
142 // value checks 207 LuaState S{ LuaState::WithBaseLibs{ true }, LuaState::WithFixture{ true } };
143 // linda:send() should fail if we don't send anything 208 S.requireSuccess("lanes = require 'lanes'");
144 S.requireFailure("lanes.linda():send()"); 209
145 S.requireFailure("lanes.linda():send(0)"); 210 // ---------------------------------------------------------------------------------------------
146 S.requireFailure("lanes.linda():send(0, 'k')"); 211
147 // or non-deep userdata 212 SECTION("error in close handler is propagated")
148 S.requireFailure("lanes.linda():send(0, 'k', fixture.newuserdata())"); 213 {
149 // or something with a converter that raises an error (maybe that should go to a dedicated __lanesconvert test!) 214 // if the function raises an error, we should get it
150 S.requireFailure("lanes.linda():send(0, 'k', setmetatable({}, {__lanesconvert = function(where_) error (where_ .. ': should not send me' end}))"); 215 S.requireFailure("local l <close> = lanes.linda{close_handler = function() error 'gluh' end}");
151 // but a registered non-deep userdata should work
152 S.requireSuccess("lanes.linda():send(0, 'k', io.stdin)");
153 }
154 } 216 }
155 217
156 // --------------------------------------------------------------------------------------------- 218 // ---------------------------------------------------------------------------------------------
@@ -312,12 +374,12 @@ TEST_CASE("linda.multi Keeper")
312 374
313 S.requireSuccess("lanes = require 'lanes'.configure{nb_user_keepers = 3}"); 375 S.requireSuccess("lanes = require 'lanes'.configure{nb_user_keepers = 3}");
314 376
315 S.requireFailure("lanes.linda(-1)"); 377 S.requireFailure("lanes.linda{group = -1}");
316 S.requireSuccess("lanes.linda(0)"); 378 S.requireSuccess("lanes.linda{group = 0}");
317 S.requireSuccess("lanes.linda(1)"); 379 S.requireSuccess("lanes.linda{group = 1}");
318 S.requireSuccess("lanes.linda(2)"); 380 S.requireSuccess("lanes.linda{group = 2}");
319 S.requireSuccess("lanes.linda(3)"); 381 S.requireSuccess("lanes.linda{group = 3}");
320 S.requireFailure("lanes.linda(4)"); 382 S.requireFailure("lanes.linda{group = 4}");
321} 383}
322 384
323// ################################################################################################# 385// #################################################################################################
@@ -327,23 +389,26 @@ TEST_CASE("linda.multi Keeper")
327// so let's create a separate test case for each file with an ugly macro... 389// so let's create a separate test case for each file with an ugly macro...
328 390
329#define MAKE_TEST_CASE(DIR, FILE) \ 391#define MAKE_TEST_CASE(DIR, FILE) \
330TEST_CASE("scripted tests." #DIR "." #FILE) \ 392TEST_CASE("scripted_tests." #DIR "." #FILE) \
331{ \ 393{ \
332 FileRunner _runner(R"(.\unit_tests\scripts)"); \ 394 FileRunner _runner(R"(.\unit_tests\scripts)"); \
333 _runner.performTest(FileRunnerParam{ #DIR "/" #FILE, TestType::AssertNoLuaError }); \ 395 _runner.performTest(FileRunnerParam{ #DIR "/" #FILE, TestType::AssertNoLuaError }); \
334} 396}
335 397
398MAKE_TEST_CASE(linda, multiple_keepers)
336MAKE_TEST_CASE(linda, send_receive) 399MAKE_TEST_CASE(linda, send_receive)
400MAKE_TEST_CASE(linda, send_receive_func_and_string)
337MAKE_TEST_CASE(linda, send_registered_userdata) 401MAKE_TEST_CASE(linda, send_registered_userdata)
338MAKE_TEST_CASE(linda, multiple_keepers) 402MAKE_TEST_CASE(linda, wake_period)
339 403
340/* 404/*
341TEST_CASE("linda.scripted tests") 405TEST_CASE("linda.scripted_tests")
342{ 406{
343 auto const& _testParam = GENERATE( 407 auto const& _testParam = GENERATE(
408 FileRunnerParam{ "linda/multiple_keepers", TestType::AssertNoLuaError },
344 FileRunnerParam{ "linda/send_receive", TestType::AssertNoLuaError }, 409 FileRunnerParam{ "linda/send_receive", TestType::AssertNoLuaError },
345 FileRunnerParam{ "linda/send_registered_userdata", TestType::AssertNoLuaError }, 410 FileRunnerParam{ "linda/send_registered_userdata", TestType::AssertNoLuaError },
346 FileRunnerParam{ "linda/multiple_keepers", TestType::AssertNoLuaError } 411 FileRunnerParam{ "linda/wake_period", TestType::AssertNoLuaError }
347 ); 412 );
348 413
349 FileRunner _runner(R"(.\unit_tests\scripts)"); 414 FileRunner _runner(R"(.\unit_tests\scripts)");
diff --git a/unit_tests/scripts/_utils.lua b/unit_tests/scripts/_utils.lua
index d710702..9f46237 100644
--- a/unit_tests/scripts/_utils.lua
+++ b/unit_tests/scripts/_utils.lua
@@ -68,8 +68,26 @@ local function dump_error_stack(error_reporting_mode_, stack)
68 end 68 end
69end 69end
70 70
71-- a function that yields back what got in, one element at a time
72local yield_one_by_one = function(...)
73 local PRINT = MAKE_PRINT()
74 PRINT "In lane"
75 for _i = 1, select('#', ...) do
76 local _val = select(_i, ...)
77 PRINT("yielding #", _i, _val)
78 local _ack = coroutine.yield(_val)
79 if cancel_test and cancel_test() then -- cancel_test does not exist when run immediately (not in a Lane)
80 return "cancelled!"
81 end
82 -- of course, if we are cancelled, we were not resumed, and yield() didn't return what we expect
83 assert(_ack == _i)
84 end
85 return "bye!"
86end
87
71return { 88return {
72 MAKE_PRINT = MAKE_PRINT, 89 MAKE_PRINT = MAKE_PRINT,
73 tables_match = tables_match, 90 tables_match = tables_match,
74 dump_error_stack = dump_error_stack 91 dump_error_stack = dump_error_stack,
92 yield_one_by_one = yield_one_by_one
75} 93}
diff --git a/unit_tests/scripts/_utils54.lua b/unit_tests/scripts/_utils54.lua
new file mode 100644
index 0000000..a511563
--- /dev/null
+++ b/unit_tests/scripts/_utils54.lua
@@ -0,0 +1,30 @@
1local utils = require "_utils"
2
3-- expand _utils module with Lua5.4 specific stuff
4
5-- a lane body that yields stuff
6utils.yielder_with_to_be_closed = function(out_linda_, wait_)
7 local fixture = assert(require "fixture")
8 -- here is a to-be-closed variable that, when closed, sends "Closed!" in the "out" slot of the provided linda
9 local t <close> = setmetatable(
10 { text = "Closed!" }, {
11 __close = function(self, err)
12 if wait_ then
13 fixture.block_for(wait_)
14 end
15 out_linda_:send("out", self.text)
16 end
17 }
18 )
19 -- yield forever, but be cancel-friendly
20 local n = 1
21 while true do
22 coroutine.yield("I yield!", n)
23 if cancel_test and cancel_test() then -- cancel_test does not exist when run immediately (not in a Lane)
24 return "I am cancelled"
25 end
26 n = n + 1
27 end
28end
29
30return utils
diff --git a/unit_tests/scripts/coro/basics.lua b/unit_tests/scripts/coro/basics.lua
deleted file mode 100644
index cd2f410..0000000
--- a/unit_tests/scripts/coro/basics.lua
+++ /dev/null
@@ -1,97 +0,0 @@
1local lanes = require "lanes"
2
3local fixture = require "fixture"
4lanes.finally(fixture.throwing_finalizer)
5
6local utils = lanes.require "_utils"
7local PRINT = utils.MAKE_PRINT()
8
9if true then
10 -- a lane body that just returns some value
11 local lane = function(msg_)
12 local utils = lanes.require "_utils"
13 local PRINT = utils.MAKE_PRINT()
14 PRINT "In lane"
15 assert(msg_ == "hi")
16 return "bye"
17 end
18
19 -- the generator
20 local g1 = lanes.coro("*", {name = "auto"}, lane)
21
22 -- launch lane
23 local h1 = g1("hi")
24
25 local r = h1[1]
26 assert(r == "bye")
27end
28
29-- a lane coroutine that yields back what got in, one element at a time
30local yielder = function(...)
31 local utils = lanes.require "_utils"
32 local PRINT = utils.MAKE_PRINT()
33 PRINT "In lane"
34 for _i = 1, select('#', ...) do
35 local _val = select(_i, ...)
36 PRINT("yielding #", _i, _val)
37 local _ack = coroutine.yield(_val)
38 assert(_ack == _i)
39 end
40 return "done!"
41end
42
43if true then
44 -- if we start a non-coroutine lane with a yielding function, we should get an error, right?
45 local fun_g = lanes.gen("*", { name = 'auto' }, yielder)
46 local h = fun_g("hello", "world", "!")
47 local err, status, stack = h:join()
48 PRINT(err, status, stack)
49 -- the actual error message is not the same for Lua 5.1
50 -- of course, it also has to be different for LuaJIT as well
51 -- also, LuaJIT prepends a file:line to the actual error message, which Lua5.1 does not.
52 local msgs = {
53 ["Lua 5.1"] = jit and "attempt to yield across C-call boundary" or "attempt to yield across metamethod/C-call boundary",
54 ["Lua 5.2"] = "attempt to yield from outside a coroutine",
55 ["Lua 5.3"] = "attempt to yield from outside a coroutine",
56 ["Lua 5.4"] = "attempt to yield from outside a coroutine"
57 }
58 local expected_msg = msgs[_VERSION]
59 PRINT("expected_msg = " .. expected_msg)
60 assert(err == nil and string.find(status, expected_msg, 1, true) and stack == nil, "status = " .. status)
61end
62
63-- the generator
64local coro_g = lanes.coro("*", {name = "auto"}, yielder)
65
66if true then
67 -- launch coroutine lane
68 local h2 = coro_g("hello", "world", "!")
69 -- read the yielded values, sending back the expected index
70 assert(h2:resume(1) == "hello")
71 assert(h2:resume(2) == "world")
72 assert(h2:resume(3) == "!")
73 -- the lane return value is available as usual
74 local r = h2[1]
75 assert(r == "done!")
76end
77
78if true then
79 -- another coroutine lane
80 local h3 = coro_g("hello", "world", "!")
81
82 -- yielded values are available as regular return values
83 assert(h3[1] == "hello" and h3.status == "suspended")
84 -- since we consumed the returned values, they should not be here when we resume
85 assert(h3:resume(1) == nil)
86
87 -- similarly, we can get them with join()
88 assert(h3:join() == "world" and h3.status == "suspended")
89 -- since we consumed the returned values, they should not be here when we resume
90 assert(h3:resume(2) == nil)
91
92 -- the rest should work as usual
93 assert(h3:resume(3) == "!")
94
95 -- the final return value of the lane body remains to be read
96 assert(h3:join() == "done!" and h3.status == "done")
97end
diff --git a/unit_tests/scripts/coro/cancelling_suspended.lua b/unit_tests/scripts/coro/cancelling_suspended.lua
new file mode 100644
index 0000000..3a29e55
--- /dev/null
+++ b/unit_tests/scripts/coro/cancelling_suspended.lua
@@ -0,0 +1,31 @@
1local fixture = require "fixture"
2local lanes = require "lanes".configure{on_state_create = fixture.on_state_create}
3
4local fixture = require "fixture"
5lanes.finally(fixture.throwing_finalizer)
6
7local utils = lanes.require "_utils"
8local PRINT = utils.MAKE_PRINT()
9
10--------------------------------------------------
11-- TEST: cancelling a suspended Lane should end it
12--------------------------------------------------
13if true then
14 -- the generator
15 local coro_g = lanes.coro("*", utils.yield_one_by_one)
16
17 -- start the lane
18 local h = coro_g("hello", "world", "!")
19 repeat until h.status == "suspended"
20
21 -- first cancellation attempt: don't wake the lane
22 local b, r = h:cancel("soft", 0.5)
23 -- the lane is still blocked in its suspended state
24 assert(b == false and r == "timeout" and h.status == "suspended", "got " .. tostring(b) .. " " .. tostring(r) .. " " .. h.status)
25
26 -- cancel the Lane again, this time waking it. it will resume, and yielder()'s will break out of its infinite loop
27 h:cancel("soft", nil, true)
28
29 -- lane should be done, because it returned cooperatively when detecting a soft cancel
30 assert(h.status == "done", "got " .. h.status)
31end
diff --git a/unit_tests/scripts/coro/collect_yielded_lane.lua b/unit_tests/scripts/coro/collect_yielded_lane.lua
new file mode 100644
index 0000000..2ee58f8
--- /dev/null
+++ b/unit_tests/scripts/coro/collect_yielded_lane.lua
@@ -0,0 +1,64 @@
1local fixture = require "fixture"
2local lanes = require "lanes".configure{on_state_create = fixture.on_state_create}
3
4local fixture = require "fixture"
5lanes.finally(fixture.throwing_finalizer)
6
7-- this test is only for Lua 5.4+
8local utils = lanes.require "_utils54"
9local PRINT = utils.MAKE_PRINT()
10
11local out_linda = lanes.linda()
12
13------------------------------------------------------------------------------
14-- TEST: to-be-closed variables are properly closed when the lane is collected
15------------------------------------------------------------------------------
16if true then
17 -- the generator
18 local coro_g = lanes.coro("*", utils.yielder_with_to_be_closed)
19
20 -- start the lane
21 local h = coro_g(out_linda)
22
23 -- join the lane. it should be done and give back the values resulting of the first yield point
24 local r, v1, v2 = h:join()
25 assert(r == true and v1 == "I yield!" and v2 == 1, "got " .. tostring(r) .. " " .. tostring(v1) .. " " .. tostring(v2))
26 assert(h.status == "done", "got " .. h.status)
27
28 -- force collection of the lane
29 h = nil
30 collectgarbage()
31
32 -- I want the to-be-closed variable of the coroutine linda to be properly closed
33 local s, r = out_linda:receive(0, "out")
34 assert(s == "out" and r == "Closed!", "coro got " .. tostring(s) .. " " .. tostring(r)) -- THIS TEST FAILS
35end
36
37---------------------------------------------------------------------------------------------------
38-- TEST: if a to-be-closed handler takes longer than the join timeout, everything works as expected
39---------------------------------------------------------------------------------------------------
40if true then
41 -- the generator
42 local coro_g = lanes.coro("*", utils.yielder_with_to_be_closed)
43
44 -- start the lane. The to-be-closed handler will sleep for 1 second
45 local h = coro_g(out_linda, 1)
46
47 -- first join attempt should timeout
48 local r, v = h:join(0.6)
49 assert(r == nil and v == "timeout", "got " .. tostring(r) .. " " .. tostring(v))
50 assert(h.status == "running", "got " .. h.status)
51
52 -- join the lane again. it should be done and give back the values resulting of the first yield point
53 local r, v1, v2 = h:join(0.6)
54 assert(r == true and v1 == "I yield!" and v2 == 1, "got " .. tostring(r) .. " " .. tostring(v1) .. " " .. tostring(v2))
55 assert(h.status == "done", "got " .. h.status)
56
57 -- force collection of the lane
58 h = nil
59 collectgarbage()
60
61 -- I want the to-be-closed variable of the coroutine linda to be properly closed
62 local s, r = out_linda:receive(0, "out")
63 assert(s == "out" and r == "Closed!", "coro got " .. tostring(s) .. " " .. tostring(r)) -- THIS TEST FAILS
64end
diff --git a/unit_tests/scripts/coro/error_handling.lua b/unit_tests/scripts/coro/error_handling.lua
index ba6cff6..1cfb8c8 100644
--- a/unit_tests/scripts/coro/error_handling.lua
+++ b/unit_tests/scripts/coro/error_handling.lua
@@ -38,15 +38,15 @@ local force_error_test = function(error_trace_level_)
38 utils.dump_error_stack(error_trace_level_, c) 38 utils.dump_error_stack(error_trace_level_, c)
39end 39end
40 40
41if false then 41if true then
42 force_error_test("minimal") 42 force_error_test("minimal")
43end 43end
44 44
45if false then 45if true then
46 force_error_test("basic") 46 force_error_test("basic")
47end 47end
48 48
49if false then 49if true then
50 force_error_test("extended") 50 force_error_test("extended")
51end 51end
52 52
diff --git a/unit_tests/scripts/coro/index_suspended.lua b/unit_tests/scripts/coro/index_suspended.lua
new file mode 100644
index 0000000..2cd8c28
--- /dev/null
+++ b/unit_tests/scripts/coro/index_suspended.lua
@@ -0,0 +1,28 @@
1local lanes = require "lanes"
2
3local fixture = require "fixture"
4lanes.finally(fixture.throwing_finalizer)
5
6local utils = lanes.require "_utils"
7local PRINT = utils.MAKE_PRINT()
8
9-- the coroutine generator
10local coro_g = lanes.coro("*", {name = "auto"}, utils.yield_one_by_one)
11
12-------------------------------------------------------------------------
13-- TEST: if we index a yielded lane, we should get the last yielded value
14-------------------------------------------------------------------------
15if true then
16 -- launch coroutine lane
17 local h = coro_g("hello", "world", "!")
18 -- read the first yielded value, sending back the expected index
19 assert(h:resume(1) == "hello")
20 -- indexing multiple times gives back the same us the same yielded value
21 local r1 = h[1]
22 local r2 = h[1]
23 local r3 = h[1]
24 assert(r1 == "world" and r2 == "world" and r3 == "world", "got " .. r1 .. " " .. r2 .. " " .. r3)
25 -- once the lane was indexed, it is no longer resumable (just like after join)
26 local b, e = pcall(h.resume, h, 2)
27 assert(b == false and e == "cannot resume non-suspended coroutine Lane")
28end
diff --git a/unit_tests/scripts/coro/join_suspended.lua b/unit_tests/scripts/coro/join_suspended.lua
new file mode 100644
index 0000000..33be406
--- /dev/null
+++ b/unit_tests/scripts/coro/join_suspended.lua
@@ -0,0 +1,24 @@
1local lanes = require "lanes"
2
3local fixture = require "fixture"
4lanes.finally(fixture.throwing_finalizer)
5
6local utils = lanes.require "_utils"
7local PRINT = utils.MAKE_PRINT()
8
9-- the coroutine generator
10local coro_g = lanes.coro("*", {name = "auto"}, utils.yield_one_by_one)
11
12---------------------------------------------------
13-- TEST: if we join a yielded lane, the lane aborts
14---------------------------------------------------
15if true then
16 -- launch coroutine lane
17 local h = coro_g("hello", "world", "!")
18 -- read the first yielded value, sending back the expected index
19 assert(h:resume(1) == "hello")
20 -- join the lane. since it will reach a yield point, it unblocks and ends. last yielded values are returned normally
21 local b, r = h:join(0.5)
22 local s = h.status
23 assert(s == "done" and b == true and r == "world", "got " .. s .. " " .. tostring(b) .. " " .. tostring(r))
24end
diff --git a/unit_tests/scripts/coro/linda_in_close_handler.lua b/unit_tests/scripts/coro/linda_in_close_handler.lua
new file mode 100644
index 0000000..8636f01
--- /dev/null
+++ b/unit_tests/scripts/coro/linda_in_close_handler.lua
@@ -0,0 +1,43 @@
1local fixture = require "fixture"
2local lanes = require "lanes".configure{on_state_create = fixture.on_state_create}
3
4local fixture = require "fixture"
5lanes.finally(fixture.throwing_finalizer)
6
7-- this test is only for Lua 5.4+
8local utils = lanes.require "_utils54"
9local PRINT = utils.MAKE_PRINT()
10
11local out_linda = lanes.linda()
12
13local test_close = function(what_, f_)
14 local c = coroutine.create(f_)
15 for i = 1, 10 do
16 local t, r1, r2 = coroutine.resume(c, out_linda) -- returns true + <yielded values>
17 assert(t == true and r1 == "I yield!" and r2 == i, "got " .. tostring(t) .. " " .. tostring(r1) .. " " .. tostring(r2))
18 local s = coroutine.status(c)
19 assert(s == "suspended")
20 end
21 local r, s = coroutine.close(c)
22 assert(r == true and s == nil)
23 -- the local variable inside the yielder body should be closed
24 local s, r = out_linda:receive(0, "out")
25 assert(s == "out" and r == "Closed!", what_ .. " got " .. tostring(s) .. " " .. tostring(r))
26end
27
28---------------------------------------------------------
29-- TEST: first, try the close mechanism outside of a lane
30---------------------------------------------------------
31if true then
32 assert(type(utils.yielder_with_to_be_closed) == "function")
33 test_close("base", utils.yielder_with_to_be_closed)
34end
35
36---------------------------------------------------------------
37-- TEST: try again with a function obtained through dump/undump
38---------------------------------------------------------------
39if true then
40 -- note this means our yielder implementation can't have upvalues, as they are lost in the process
41 test_close("dumped", load(string.dump(utils.yielder_with_to_be_closed)))
42end
43
diff --git a/unit_tests/scripts/coro/regular_function.lua b/unit_tests/scripts/coro/regular_function.lua
new file mode 100644
index 0000000..09aa3b7
--- /dev/null
+++ b/unit_tests/scripts/coro/regular_function.lua
@@ -0,0 +1,38 @@
1local lanes = require "lanes".configure()
2
3local utils = lanes.require "_utils"
4local PRINT = utils.MAKE_PRINT()
5
6-- a lane body that just returns some value
7local returner = function(msg_)
8 local utils = lanes.require "_utils"
9 local PRINT = utils.MAKE_PRINT()
10 PRINT "In lane"
11 assert(msg_ == "hi")
12 return "bye"
13end
14
15-- a function that returns some value can run in a coroutine
16if true then
17 -- the generator
18 local g = lanes.coro("*", {name = "auto"}, returner)
19
20 -- launch lane
21 local h = g("hi")
22
23 local r = h[1]
24 assert(r == "bye")
25end
26
27-- can't resume a coro after the lane body has returned
28if true then
29 -- the generator
30 local g = lanes.coro("*", {name = "auto"}, returner)
31
32 -- launch lane
33 local h = g("hi")
34
35 -- resuming a lane that terminated execution should raise an error
36 local b, e = pcall(h.resume, h)
37 assert(b == false and type(e) == "string")
38end
diff --git a/unit_tests/scripts/coro/resume_basics.lua b/unit_tests/scripts/coro/resume_basics.lua
new file mode 100644
index 0000000..5b124f5
--- /dev/null
+++ b/unit_tests/scripts/coro/resume_basics.lua
@@ -0,0 +1,40 @@
1local lanes = require "lanes"
2
3local fixture = require "fixture"
4lanes.finally(fixture.throwing_finalizer)
5
6local utils = lanes.require "_utils"
7local PRINT = utils.MAKE_PRINT()
8
9-- the coroutine generator
10local coro_g = lanes.coro("*", {name = "auto"}, utils.yield_one_by_one)
11
12-------------------------------------------------------------------------------------------------
13-- TEST: we can resume as many times as the lane yields, then read the returned value on indexing
14-------------------------------------------------------------------------------------------------
15if true then
16 -- launch coroutine lane
17 local h = coro_g("hello", "world", "!")
18 -- read the yielded values, sending back the expected index
19 assert(h:resume(1) == "hello")
20 assert(h:resume(2) == "world")
21 assert(h:resume(3) == "!")
22 -- the lane return value is available as usual
23 local r = h[1]
24 assert(r == "bye!")
25end
26
27---------------------------------------------------------------------------------------------
28-- TEST: we can resume as many times as the lane yields, then read the returned value on join
29---------------------------------------------------------------------------------------------
30if true then
31 -- launch coroutine lane
32 local h = coro_g("hello", "world", "!")
33 -- read the yielded values, sending back the expected index
34 assert(h:resume(1) == "hello")
35 assert(h:resume(2) == "world")
36 assert(h:resume(3) == "!")
37 -- the lane return value is available as usual
38 local s, r = h:join()
39 assert(h.status == "done" and s == true and r == "bye!")
40end
diff --git a/unit_tests/scripts/coro/yielding_in_non_coro_errors.lua b/unit_tests/scripts/coro/yielding_in_non_coro_errors.lua
new file mode 100644
index 0000000..fc0c072
--- /dev/null
+++ b/unit_tests/scripts/coro/yielding_in_non_coro_errors.lua
@@ -0,0 +1,28 @@
1local lanes = require "lanes"
2
3local fixture = require "fixture"
4lanes.finally(fixture.throwing_finalizer)
5
6local utils = lanes.require "_utils"
7local PRINT = utils.MAKE_PRINT()
8
9--------------------------------------------------------------------------------------------------
10-- TEST: if we start a non-coroutine lane with a yielding function, we should get an error, right?
11--------------------------------------------------------------------------------------------------
12local fun_g = lanes.gen("*", { name = 'auto' }, utils.yield_one_by_one)
13local h = fun_g("hello", "world", "!")
14local err, status, stack = h:join()
15PRINT(err, status, stack)
16-- the actual error message is not the same for Lua 5.1
17-- of course, it also has to be different for LuaJIT as well
18-- also, LuaJIT prepends a file:line to the actual error message, which Lua5.1 does not.
19local msgs = {
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",
22 ["Lua 5.3"] = "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"
25}
26local expected_msg = msgs[_VERSION]
27PRINT("expected_msg = " .. expected_msg)
28assert(err == nil and string.find(status, expected_msg, 1, true) and stack == nil, "status = " .. status)
diff --git a/unit_tests/scripts/lane/body_is_a_c_function.lua b/unit_tests/scripts/lane/body_is_a_c_function.lua
new file mode 100644
index 0000000..d8d329f
--- /dev/null
+++ b/unit_tests/scripts/lane/body_is_a_c_function.lua
@@ -0,0 +1,28 @@
1local lanes = require "lanes".configure()
2
3-- ##################################################################################################
4-- ##################################################################################################
5-- ##################################################################################################
6
7-- we can create a generator where the lane body is a C function
8do
9 local b, g = pcall(lanes.gen, "*", print)
10 assert(b == true and type(g) == "function")
11 -- we can start the lane
12 local b, h = pcall(g, "hello")
13 -- the lane runs normally
14 h:join()
15 assert(h.status == "done")
16end
17
18-- we can create a generator where the lane body is a C function that raises an error
19do
20 local b, g = pcall(lanes.gen, "*", error)
21 assert(b == true and type(g) == "function")
22 -- we can start the lane
23 local b, h = pcall(g, "this is an error")
24 -- this provides the error that occurred in the lane
25 local s, e, t = h:join()
26 assert(h.status == "error")
27 assert(s == nil and e == "this is an error" and t == nil)
28end
diff --git a/unit_tests/scripts/lane/cooperative_shutdown.lua b/unit_tests/scripts/lane/cooperative_shutdown.lua
index 756e33c..0a0943e 100644
--- a/unit_tests/scripts/lane/cooperative_shutdown.lua
+++ b/unit_tests/scripts/lane/cooperative_shutdown.lua
@@ -1,10 +1,10 @@
1local lanes = require "lanes" 1local lanes = require "lanes".configure{on_state_create = require "fixture".on_state_create}
2 2
3-- launch lanes that cooperate properly with cancellation request 3-- launch lanes that cooperate properly with cancellation request
4 4
5local lane1 = function() 5local lane1 = function()
6 lane_threadname("lane1") 6 lane_threadname("lane1")
7 -- loop breaks on cancellation request 7 -- loop breaks on soft cancellation request
8 repeat 8 repeat
9 lanes.sleep(0) 9 lanes.sleep(0)
10 until cancel_test() 10 until cancel_test()
@@ -23,7 +23,6 @@ end
23local lane3 = function() 23local lane3 = function()
24 lane_threadname("lane3") 24 lane_threadname("lane3")
25 -- this one cooperates too, because of the hook cancellation modes that Lanes will be using 25 -- this one cooperates too, because of the hook cancellation modes that Lanes will be using
26 -- but not with LuaJIT, because the function is compiled, and we don't call anyone, so no hook triggers
27 local fixture = require "fixture" 26 local fixture = require "fixture"
28 repeat until fixture.give_me_back(false) 27 repeat until fixture.give_me_back(false)
29end 28end
@@ -43,7 +42,14 @@ local h2 = g2(linda)
43 42
44local h3 = g3() 43local h3 = g3()
45 44
46-- wait until they are both started 45lanes.sleep(0.1)
47repeat until h1.status == "running" and h2.status == "waiting" and h3.status == "running" 46
47local is_running = function(lane_h)
48 local status = lane_h.status
49 return status == "running" or status == "waiting"
50end
51
52-- wait until they are all started
53repeat until is_running(h1) and is_running(h2) and is_running(h3)
48 54
49-- let the script terminate, Lanes should not crash at shutdown 55-- let the script terminate, Lanes should not crash at shutdown
diff --git a/unit_tests/scripts/lane/tasking_cancelling.lua b/unit_tests/scripts/lane/tasking_cancelling.lua
index 85600ab..d153ffa 100644
--- a/unit_tests/scripts/lane/tasking_cancelling.lua
+++ b/unit_tests/scripts/lane/tasking_cancelling.lua
@@ -1,4 +1,7 @@
1local require_lanes_result_1, require_lanes_result_2 = require "lanes".configure(config).configure() 1local require_fixture_result_1, require_fixture_result_2 = require "fixture"
2local fixture = assert(require_fixture_result_1)
3
4local require_lanes_result_1, require_lanes_result_2 = require "lanes".configure{on_state_create = fixture.on_state_create}.configure()
2print("require_lanes_result:", require_lanes_result_1, require_lanes_result_2) 5print("require_lanes_result:", require_lanes_result_1, require_lanes_result_2)
3local lanes = require_lanes_result_1 6local lanes = require_lanes_result_1
4 7
@@ -15,69 +18,34 @@ local lanes_linda = assert(lanes.linda)
15-- ################################################################################################## 18-- ##################################################################################################
16-- ################################################################################################## 19-- ##################################################################################################
17 20
18local function task(a, b, c) 21-- cancellation of cooperating lanes
19 lane_threadname("task("..a..","..b..","..c..")") 22local cooperative = function()
20 --error "111" -- testing error messages 23 local fixture = assert(require "fixture")
21 assert(hey) 24 local which_cancel
22 local v=0 25 repeat
23 for i=a,b,c do 26 fixture.block_for(0.2)
24 v= v+i 27 which_cancel = cancel_test()
25 end 28 until which_cancel
26 return v, hey 29 return which_cancel
27end
28
29local gc_cb = function(name_, status_)
30 PRINT(" ---> lane '" .. name_ .. "' collected with status '" .. status_ .. "'")
31end 30end
31-- soft and hard are behaviorally equivalent when no blocking linda operation is involved
32local cooperative_lane_soft = lanes_gen("*", { name = 'auto' }, cooperative)()
33local a, b = cooperative_lane_soft:cancel("soft", 0) -- issue request, do not wait for lane to terminate
34assert(a == false and b == "timeout", "got " .. tostring(a) .. " " .. tostring(b))
35assert(cooperative_lane_soft[1] == "soft") -- return value of the lane body is the value returned by cancel_test()
36local cooperative_lane_hard = lanes_gen("*", { name = 'auto' }, cooperative)()
37local c, d = cooperative_lane_hard:cancel("hard", 0) -- issue request, do not wait for lane to terminate
38assert(a == false and b == "timeout", "got " .. tostring(c) .. " " .. tostring(d))
39assert(cooperative_lane_hard[1] == "hard") -- return value of the lane body is the value returned by cancel_test()
32 40
33-- ################################################################################################## 41-- ##################################################################################################
34-- ##################################################################################################
35-- ##################################################################################################
36
37PRINT("\n\n", "---=== Tasking (cancelling) ===---", "\n\n")
38
39local task_launch2 = lanes_gen("", { name = 'auto', globals={hey=true}, gc_cb = gc_cb }, task)
40
41local N=999999999
42local lane9= task_launch2(1,N,1) -- huuuuuuge...
43
44-- Wait until state changes "pending"->"running"
45--
46local st
47local t0= os.time()
48while os.time()-t0 < 5 do
49 st= lane9.status
50 io.stderr:write((i==1) and st.." " or '.')
51 if st~="pending" then break end
52end
53PRINT(" "..st)
54
55if st=="error" then
56 local _= lane9[0] -- propagate the error here
57end
58if st=="done" then
59 error("Looping to "..N.." was not long enough (cannot test cancellation)")
60end
61assert(st=="running", "st == " .. st)
62
63-- when running under luajit, the function is JIT-ed, and the instruction count isn't hit, so we need a different hook
64lane9:cancel(jit and "line" or "count", 100) -- 0 timeout, hook triggers cancelslation when reaching the specified count
65
66local t0= os.time()
67while os.time()-t0 < 5 do
68 st= lane9.status
69 io.stderr:write((i==1) and st.." " or '.')
70 if st~="running" then break end
71end
72PRINT(" "..st)
73assert(st == "cancelled", "st is '" .. st .. "' instead of 'cancelled'")
74 42
75-- cancellation of lanes waiting on a linda 43-- cancellation of lanes waiting on a linda
76local limited = lanes_linda("limited") 44local limited = lanes_linda{name = "limited"}
77assert.fails(function() limited:limit("key", -1) end) 45assert.fails(function() limited:limit("key", -1) end)
78assert.failsnot(function() limited:limit("key", 1) end) 46assert.failsnot(function() limited:limit("key", 1) end)
79-- [[################################################ 47-- [[################################################
80limited:send("key", "hello") -- saturate linda 48limited:send("key", "hello") -- saturate linda, so that subsequent sends will block
81for k, v in pairs(limited:dump()) do 49for k, v in pairs(limited:dump()) do
82 PRINT("limited[" .. tostring(k) .. "] = " .. tostring(v)) 50 PRINT("limited[" .. tostring(k) .. "] = " .. tostring(v))
83end 51end
@@ -88,11 +56,15 @@ local wait_send = function()
88end 56end
89 57
90local wait_send_lane = lanes_gen("*", { name = 'auto' }, wait_send)() 58local wait_send_lane = lanes_gen("*", { name = 'auto' }, wait_send)()
91repeat until wait_send_lane.status == "waiting" 59repeat
92print "wait_send_lane is waiting" 60 io.stderr:write('!')
61 -- currently mingw64 builds can deadlock if we cancel the lane too early (before the linda blocks, at it causes the linda condvar not to be signalled)
62 lanes.sleep(0.1)
63until wait_send_lane.status == "waiting"
64PRINT "wait_send_lane is waiting"
93wait_send_lane:cancel() -- hard cancel, 0 timeout 65wait_send_lane:cancel() -- hard cancel, 0 timeout
94repeat until wait_send_lane.status == "cancelled" 66repeat until wait_send_lane.status == "cancelled"
95print "wait_send_lane is cancelled" 67PRINT "wait_send_lane is cancelled"
96--################################################]] 68--################################################]]
97local wait_receive = function() 69local wait_receive = function()
98 local k, v 70 local k, v
@@ -101,22 +73,30 @@ local wait_receive = function()
101end 73end
102 74
103local wait_receive_lane = lanes_gen("*", { name = 'auto' }, wait_receive)() 75local wait_receive_lane = lanes_gen("*", { name = 'auto' }, wait_receive)()
104repeat until wait_receive_lane.status == "waiting" 76repeat
105print "wait_receive_lane is waiting" 77 io.stderr:write('!')
78 -- currently mingw64 builds can deadlock if we cancel the lane too early (before the linda blocks, at it causes the linda condvar not to be signalled)
79 lanes.sleep(0.1)
80until wait_receive_lane.status == "waiting"
81PRINT "wait_receive_lane is waiting"
106wait_receive_lane:cancel() -- hard cancel, 0 timeout 82wait_receive_lane:cancel() -- hard cancel, 0 timeout
107repeat until wait_receive_lane.status == "cancelled" 83repeat until wait_receive_lane.status == "cancelled"
108print "wait_receive_lane is cancelled" 84PRINT "wait_receive_lane is cancelled"
109--################################################]] 85--################################################]]
110local wait_receive_batched = function() 86local wait_receive_batched = function()
111 local k, v1, v2 87 local k, v1, v2
112 set_finalizer(function() print("wait_receive_batched", k, v1, v2) end) 88 set_finalizer(function() print("wait_receive_batched", k, v1, v2) end)
113 k, v1, v2 = limited:receive(limited.batched, "dummy", 2) -- infinite timeout, returns only when lane is cancelled 89 k, v1, v2 = limited:receive_batched("dummy", 2) -- infinite timeout, returns only when lane is cancelled
114end 90end
115 91
116local wait_receive_batched_lane = lanes_gen("*", { name = 'auto' }, wait_receive_batched)() 92local wait_receive_batched_lane = lanes_gen("*", { name = 'auto' }, wait_receive_batched)()
117repeat until wait_receive_batched_lane.status == "waiting" 93repeat
118print "wait_receive_batched_lane is waiting" 94 io.stderr:write('!')
95 -- currently mingw64 builds can deadlock if we cancel the lane too early (before the linda blocks, at it causes the linda condvar not to be signalled)
96 lanes.sleep(0.1)
97until wait_receive_batched_lane.status == "waiting"
98PRINT "wait_receive_batched_lane is waiting"
119wait_receive_batched_lane:cancel() -- hard cancel, 0 timeout 99wait_receive_batched_lane:cancel() -- hard cancel, 0 timeout
120repeat until wait_receive_batched_lane.status == "cancelled" 100repeat until wait_receive_batched_lane.status == "cancelled"
121print "wait_receive_batched_lane is cancelled" 101PRINT "wait_receive_batched_lane is cancelled"
122--################################################]] 102--################################################]]
diff --git a/unit_tests/scripts/lane/tasking_cancelling_with_hook.lua b/unit_tests/scripts/lane/tasking_cancelling_with_hook.lua
new file mode 100644
index 0000000..56b934f
--- /dev/null
+++ b/unit_tests/scripts/lane/tasking_cancelling_with_hook.lua
@@ -0,0 +1,68 @@
1local require_lanes_result_1, require_lanes_result_2 = require "lanes".configure(config).configure()
2print("require_lanes_result:", require_lanes_result_1, require_lanes_result_2)
3local lanes = require_lanes_result_1
4
5local require_assert_result_1, require_assert_result_2 = require "_assert"
6print("require_assert_result:", require_assert_result_1, require_assert_result_2)
7
8local utils = lanes.require "_utils"
9local PRINT = utils.MAKE_PRINT()
10
11-- ##################################################################################################
12-- ##################################################################################################
13-- ##################################################################################################
14
15local function task(a, b, c)
16 lane_threadname("task("..a..","..b..","..c..")")
17 --error "111" -- testing error messages
18 assert(hey)
19 local v=0
20 for i=a,b,c do
21 v= v+i
22 end
23 return v, hey
24end
25
26local gc_cb = function(name_, status_)
27 PRINT(" ---> lane '" .. name_ .. "' collected with status '" .. status_ .. "'")
28end
29
30-- ##################################################################################################
31-- ##################################################################################################
32-- ##################################################################################################
33
34local generator = lanes.gen("", { name = 'auto', globals={hey=true}, gc_cb = gc_cb }, task)
35
36local N = 999999999
37local lane_h = generator(1,N,1) -- huuuuuuge...
38
39-- Wait until state changes "pending"->"running"
40--
41local st
42local t0 = os.time()
43while os.time()-t0 < 5 do
44 st = lane_h.status
45 io.stderr:write((i==1) and st.." " or '.')
46 if st~="pending" then break end
47end
48PRINT(" "..st)
49
50if st == "error" then
51 local _ = lane_h[0] -- propagate the error here
52end
53if st == "done" then
54 error("Looping to "..N.." was not long enough (cannot test cancellation)")
55end
56assert(st == "running", "st == " .. st)
57
58-- when running under luajit, the function is JIT-ed, and the instruction count isn't hit, so we need a different hook
59lane_h:cancel(jit and "line" or "count", 100) -- 0 timeout, hook triggers cancelslation when reaching the specified count
60
61local t0 = os.time()
62while os.time()-t0 < 5 do
63 st = lane_h.status
64 io.stderr:write((i==1) and st.." " or '.')
65 if st~="running" then break end
66end
67PRINT(" "..st)
68assert(st == "cancelled", "st is '" .. st .. "' instead of 'cancelled'")
diff --git a/unit_tests/scripts/lane/tasking_comms_criss_cross.lua b/unit_tests/scripts/lane/tasking_comms_criss_cross.lua
index 497e81d..610da8b 100644
--- a/unit_tests/scripts/lane/tasking_comms_criss_cross.lua
+++ b/unit_tests/scripts/lane/tasking_comms_criss_cross.lua
@@ -42,7 +42,7 @@ local tc = lanes_gen("io", { name = 'auto', gc_cb = gc_cb },
42 end 42 end
43) 43)
44 44
45local linda= lanes_linda("criss cross") 45local linda= lanes_linda{name = "criss cross"}
46 46
47local a,b= tc(linda, "A","B"), tc(linda, "B","A") -- launching two lanes, twisted comms 47local a,b= tc(linda, "A","B"), tc(linda, "B","A") -- launching two lanes, twisted comms
48 48
diff --git a/unit_tests/scripts/lane/tasking_communications.lua b/unit_tests/scripts/lane/tasking_communications.lua
index 1fd43b0..01842b4 100644
--- a/unit_tests/scripts/lane/tasking_communications.lua
+++ b/unit_tests/scripts/lane/tasking_communications.lua
@@ -72,7 +72,7 @@ local chunk= function(linda)
72 WR("chunk ", "Lane ends!\n") 72 WR("chunk ", "Lane ends!\n")
73end 73end
74 74
75local linda = lanes_linda("communications") 75local linda = lanes_linda{name = "communications"}
76assert(type(linda) == "userdata" and tostring(linda) == "Linda: communications") 76assert(type(linda) == "userdata" and tostring(linda) == "Linda: communications")
77 -- 77 --
78 -- ["->"] master -> slave 78 -- ["->"] master -> slave
@@ -90,7 +90,7 @@ local b,x,y,z,w = linda:get("<->", 4)
90assert(b == 3 and x == "x" and y == "y" and z == "z" and w == nil) 90assert(b == 3 and x == "x" and y == "y" and z == "z" and w == nil)
91local k, x = linda:receive("<->") 91local k, x = linda:receive("<->")
92assert(k == "<->" and x == "x") 92assert(k == "<->" and x == "x")
93local k,y,z = linda:receive(linda.batched, "<->", 2) 93local k,y,z = linda:receive_batched("<->", 2)
94assert(k == "<->" and y == "y" and z == "z") 94assert(k == "<->" and y == "y" and z == "z")
95linda:set("<->") 95linda:set("<->")
96local b,x,y,z,w = linda:get("<->", 4) 96local b,x,y,z,w = linda:get("<->", 4)
diff --git a/unit_tests/scripts/lane/tasking_join_test.lua b/unit_tests/scripts/lane/tasking_join_test.lua
index 2fbce6c..495a709 100644
--- a/unit_tests/scripts/lane/tasking_join_test.lua
+++ b/unit_tests/scripts/lane/tasking_join_test.lua
@@ -30,14 +30,19 @@ end
30 30
31PRINT("---=== :join test ===---", "\n\n") 31PRINT("---=== :join test ===---", "\n\n")
32 32
33-- a lane body that returns nothing is successfully joined with true, nil
34local r, ret = lanes_gen(function() end)():join()
35assert(r == true and ret == nil)
36
33-- NOTE: 'unpack()' cannot be used on the lane handle; it will always return nil 37-- NOTE: 'unpack()' cannot be used on the lane handle; it will always return nil
34-- (unless [1..n] has been read earlier, in which case it would seemingly 38-- (unless [1..n] has been read earlier, in which case it would seemingly
35-- work). 39-- work).
36 40
37local S= lanes_gen("table", { name = 'auto', gc_cb = gc_cb }, 41local S = lanes_gen("table", { name = 'auto', gc_cb = gc_cb },
38 function(arg) 42 function(arg)
39 lane_threadname "join test lane" 43 lane_threadname "join test lane"
40 set_finalizer(function() end) 44 set_finalizer(function() end)
45 -- take arg table, reverse its contents in aux, then return the unpacked result
41 local aux= {} 46 local aux= {}
42 for i, v in ipairs(arg) do 47 for i, v in ipairs(arg) do
43 table.insert(aux, 1, v) 48 table.insert(aux, 1, v)
@@ -46,15 +51,16 @@ local S= lanes_gen("table", { name = 'auto', gc_cb = gc_cb },
46 return (unpack or table.unpack)(aux) 51 return (unpack or table.unpack)(aux)
47end) 52end)
48 53
49h= S { 12, 13, 14 } -- execution starts, h[1..3] will get the return values 54local h = S { 12, 13, 14 } -- execution starts, h[1..3] will get the return values
50-- wait a bit so that the lane has a chance to set its debug name 55-- wait a bit so that the lane has a chance to set its debug name
51SLEEP(0.5) 56SLEEP(0.5)
52print("joining with '" .. h:get_threadname() .. "'") 57print("joining with '" .. h:get_threadname() .. "'")
53local a,b,c,d= h:join() 58local r, a, b, c, d = h:join()
54if h.status == "error" then 59if h.status == "error" then
55 print(h:get_threadname(), "error: " , a, b, c, d) 60 print(h:get_threadname(), "error: " , r, a, b, c, d)
56else 61else
57 print(h:get_threadname(), a,b,c,d) 62 print(h:get_threadname(), r, a, b, c, d)
63 assert(r==true, "r == " .. tostring(r))
58 assert(a==14, "a == " .. tostring(a)) 64 assert(a==14, "a == " .. tostring(a))
59 assert(b==13, "b == " .. tostring(b)) 65 assert(b==13, "b == " .. tostring(b))
60 assert(c==12, "c == " .. tostring(c)) 66 assert(c==12, "c == " .. tostring(c))
diff --git a/unit_tests/scripts/lane/tasking_send_receive_code.lua b/unit_tests/scripts/lane/tasking_send_receive_code.lua
index e329a88..fdc2602 100644
--- a/unit_tests/scripts/lane/tasking_send_receive_code.lua
+++ b/unit_tests/scripts/lane/tasking_send_receive_code.lua
@@ -53,28 +53,26 @@ local function chunk2(linda)
53 assert(info.linedefined == 32, "bad linedefined") -- start of 'chunk2' 53 assert(info.linedefined == 32, "bad linedefined") -- start of 'chunk2'
54 assert(config.strip_functions and info.currentline==-1 or info.currentline > info.linedefined, "bad currentline") -- line of 'debug.getinfo' 54 assert(config.strip_functions and info.currentline==-1 or info.currentline > info.linedefined, "bad currentline") -- line of 'debug.getinfo'
55 assert(info.lastlinedefined > info.currentline, "bad lastlinedefined") -- end of 'chunk2' 55 assert(info.lastlinedefined > info.currentline, "bad lastlinedefined") -- end of 'chunk2'
56 local k,func= linda:receive("down") 56 assert(linda:count("down") == 2, "bad linda contents") -- function, "ok"
57 assert(type(func)=="function", "not a function") 57 local k,func,str= linda:receive_batched("down", 2)
58 assert(k=="down") 58 assert(k=="down")
59 assert(type(func)=="function", "not a function")
60 assert(str=="ok", "bad receive result: " .. tostring(k) .. " -> ".. tostring(str))
61 assert(linda:count("down") == 0, "bad linda contents") -- nothing
59 62
60 func(linda) 63 func(linda)
61
62 local k,str= linda:receive("down")
63 assert(str=="ok", "bad receive result")
64
65 linda:send("up", function() return ":)" end, "ok2") 64 linda:send("up", function() return ":)" end, "ok2")
66end 65end
67 66
68local linda = lanes_linda("auto") 67local linda = lanes_linda{name = "auto"}
69local t2= lanes_gen("debug,package,string,io", { name = 'auto', gc_cb = gc_cb }, chunk2)(linda) -- prepare & launch 68local t2= lanes_gen("debug,package,string,io", { name = 'auto', gc_cb = gc_cb }, chunk2)(linda) -- prepare & launch
70linda:send("down", function(linda) linda:send("up", "ready!") end, 69linda:send("down", function(linda) linda:send("up", "ready!") end, "ok")
71 "ok")
72-- wait to see if the tiny function gets executed 70-- wait to see if the tiny function gets executed
73-- 71--
74local k,s= linda:receive(1, "up") 72local k,s= linda:receive(1, "up")
75if t2.status == "error" then 73if t2.status == "error" then
76 PRINT("t2 error: " , t2:join()) 74 local n,err,s = t2:join()
77 assert(false) 75 assert(false, "t2 error: " .. err)
78end 76end
79PRINT(s) 77PRINT(s)
80assert(s=="ready!", s .. " is not 'ready!'") 78assert(s=="ready!", s .. " is not 'ready!'")
diff --git a/unit_tests/scripts/lane/uncooperative_shutdown.lua b/unit_tests/scripts/lane/uncooperative_shutdown.lua
index 89e1ff8..eb89ed3 100644
--- a/unit_tests/scripts/lane/uncooperative_shutdown.lua
+++ b/unit_tests/scripts/lane/uncooperative_shutdown.lua
@@ -8,7 +8,7 @@ local lanes = require "lanes".configure{shutdown_timeout = 0.001, on_state_creat
8-- launch lanes that blocks forever 8-- launch lanes that blocks forever
9local lane = function() 9local lane = function()
10 local fixture = require "fixture" 10 local fixture = require "fixture"
11 fixture.sleep_for() 11 fixture.block_for()
12end 12end
13 13
14-- the generator 14-- the generator
diff --git a/unit_tests/scripts/linda/multiple_keepers.lua b/unit_tests/scripts/linda/multiple_keepers.lua
index 8733087..267d874 100644
--- a/unit_tests/scripts/linda/multiple_keepers.lua
+++ b/unit_tests/scripts/linda/multiple_keepers.lua
@@ -2,9 +2,9 @@
2local require_lanes_result_1, require_lanes_result_2 = require "lanes".configure{nb_user_keepers = 3, keepers_gc_threshold = 500} 2local require_lanes_result_1, require_lanes_result_2 = require "lanes".configure{nb_user_keepers = 3, keepers_gc_threshold = 500}
3local lanes = require_lanes_result_1 3local lanes = require_lanes_result_1
4 4
5local a = lanes.linda("A", 1) 5local a = lanes.linda{name = "A", group = 1}
6local b = lanes.linda("B", 2) 6local b = lanes.linda{name = "B", group = 2}
7local c = lanes.linda("C", 3) 7local c = lanes.linda{name = "C", group = 3}
8 8
9-- store each linda in the other 2 9-- store each linda in the other 2
10do 10do
diff --git a/unit_tests/scripts/linda/send_receive_func_and_string.lua b/unit_tests/scripts/linda/send_receive_func_and_string.lua
new file mode 100644
index 0000000..188cfcd
--- /dev/null
+++ b/unit_tests/scripts/linda/send_receive_func_and_string.lua
@@ -0,0 +1,13 @@
1local lanes = require "lanes"
2
3-- a newly created linda doesn't contain anything
4local l = lanes.linda()
5
6-- send a function and a string, make sure that's what we read back
7l:send("k", function() end, "str")
8local c = l:count("k")
9assert(c == 2, "got " .. c)
10local k, v1, v2 = l:receive_batched("k", 2)
11local tv1, tv2 = type(v1), type(v2)
12assert(k == "k" and tv1 == "function" and tv2 == "string", "got " .. tv1 .. " " .. tv2)
13assert(l:count("k") == 0)
diff --git a/unit_tests/scripts/linda/send_registered_userdata.lua b/unit_tests/scripts/linda/send_registered_userdata.lua
index 2c0195a..90c05c9 100644
--- a/unit_tests/scripts/linda/send_registered_userdata.lua
+++ b/unit_tests/scripts/linda/send_registered_userdata.lua
@@ -1,5 +1,5 @@
1local lanes = require 'lanes'.configure{with_timers = false} 1local lanes = require 'lanes'.configure{with_timers = false}
2local l = lanes.linda'gleh' 2local l = lanes.linda{name = 'gleh'}
3l:set('yo', io.stdin) 3l:set('yo', io.stdin)
4local n, stdin_out = l:get('yo') 4local n, stdin_out = l:get('yo')
5assert(n == 1 and stdin_out == io.stdin, tostring(stdin_out) .. " ~= " .. tostring(io.stdin)) 5assert(n == 1 and stdin_out == io.stdin, tostring(stdin_out) .. " ~= " .. tostring(io.stdin))
diff --git a/unit_tests/scripts/linda/wake_period.lua b/unit_tests/scripts/linda/wake_period.lua
new file mode 100644
index 0000000..d2dccc3
--- /dev/null
+++ b/unit_tests/scripts/linda/wake_period.lua
@@ -0,0 +1,42 @@
1-- default wake period is 0.5 seconds
2local require_lanes_result_1, require_lanes_result_2 = require "lanes".configure{linda_wake_period = 0.5}
3local lanes = require_lanes_result_1
4
5-- a lane that performs a blocking operation for 2 seconds
6local body = function(linda_)
7 -- a blocking read that lasts longer than the tested wake_period values
8 linda_:receive(2, "empty_slot")
9 return "done"
10end
11
12-- if we don't cancel the lane, we should wait the whole duration
13local function check_wake_duration(linda_, expected_, do_cancel_)
14 local h = lanes.gen(body)(linda_)
15 -- wait until the linda is blocked
16 repeat until h.status == "waiting"
17 local t0 = lanes.now_secs()
18 -- soft cancel, no timeout, no waking
19 if do_cancel_ then
20 local result, reason = h:cancel('soft', 0, false)
21 -- should say there was a timeout, since the lane didn't actually cancel (normal since we did not wake it)
22 assert(result == false and reason == 'timeout', "unexpected cancel result")
23 end
24 -- this should wait until the linda wakes by itself before the actual receive timeout and sees the cancel request
25 local r, ret = h:join()
26 assert(r == true and ret == "done")
27 local t1 = lanes.now_secs()
28 local delta = t1 - t0
29 -- the linda should check for cancellation at about the expected period, not earlier
30 assert(delta >= expected_, tostring(linda_) .. " woke too early:" .. delta)
31 -- the lane shouldn't terminate too long after cancellation was processed
32 assert(delta <= expected_ * 1.1, tostring(linda_) .. " woke too late: " .. delta)
33end
34
35-- legacy behavior: linda waits until operation timeout
36check_wake_duration(lanes.linda{name = "A", wake_period = 'never'}, 2, true)
37-- early wake behavior: linda wakes after the expected time, sees a cancellation requests, and aborts the operation early
38check_wake_duration(lanes.linda{name = "B", wake_period = 0.25}, 0.25, true)
39check_wake_duration(lanes.linda{name = "C"}, 0.5, true) -- wake_period defaults to 0.5 (see above)
40check_wake_duration(lanes.linda{name = "D", wake_period = 1}, 1, true)
41-- even when there is a wake_period, the operation should reach full timeout if not cancelled early
42check_wake_duration(lanes.linda{name = "E", wake_period = 0.1}, 2, false)
diff --git a/unit_tests/scripts/misc/deeptest.lua b/unit_tests/scripts/misc/deeptest.lua
new file mode 100644
index 0000000..542c35b
--- /dev/null
+++ b/unit_tests/scripts/misc/deeptest.lua
@@ -0,0 +1,161 @@
1local fixture = require "fixture"
2local lanes = require("lanes").configure{on_state_create = fixture.on_state_create}
3local l = lanes.linda{name = "my linda"}
4
5local table_unpack = table.unpack or unpack -- Lua 5.1 support
6
7-- we will transfer userdata created by this module, so we need to make Lanes aware of it
8local dt = lanes.require "deep_userdata_example"
9
10-- set DEEP to any non-false value to run the Deep Userdata tests. "gc" selects a special test for debug purposes
11DEEP = DEEP or true
12-- set CLONABLE to any non-false value to run the Clonable Userdata tests
13CLONABLE = CLONABLE or true
14
15-- lua 5.1->5.2 support a single table uservalue
16-- lua 5.3->5.4 supports an arbitrary type uservalue
17local test_uvtype = (_VERSION == "Lua 5.4") and "function" or (_VERSION == "Lua 5.3") and "string" or "table"
18-- lua 5.4 supports multiple uservalues
19local nupvals = _VERSION == "Lua 5.4" and 3 or 1
20
21local makeUserValue = function( obj_)
22 if test_uvtype == "table" then
23 return {"some uservalue"}
24 elseif test_uvtype == "string" then
25 return "some uservalue"
26 elseif test_uvtype == "function" then
27 -- a function that pull the userdata as upvalue
28 local f = function()
29 return "-> '" .. tostring( obj_) .. "'"
30 end
31 return f
32 end
33end
34
35local printDeep = function( prefix_, obj_, t_)
36 print( prefix_, obj_)
37 for uvi = 1, nupvals do
38 local uservalue = obj_:getuv(uvi)
39 print ("uv #" .. uvi, type( uservalue), uservalue, type(uservalue) == "function" and uservalue() or "")
40 end
41 if t_ then
42 local count = 0
43 for k, v in ipairs( t_) do
44 print( "t["..tostring(k).."]", v)
45 count = count + 1
46 end
47 -- we should have only 2 indexed entries with the same value
48 assert(count == 2 and t_[1] == t_[2])
49 end
50 print()
51end
52
53local performTest = function( obj_)
54 -- setup the userdata with some value and a uservalue
55 obj_:set( 666)
56 obj_:setuv( 1, makeUserValue( obj_))
57 if nupvals > 1 then
58 -- keep uv #2 as nil
59 obj_:setuv( 3, "ENDUV")
60 end
61
62 local t =
63 {
64 -- two indices with an identical value: we should also have identical values on the other side (even if not the same as the original ones when they are clonables)
65 obj_,
66 obj_,
67 -- this one won't transfer because we don't support full uservalue as keys
68 [obj_] = "val"
69 }
70
71 -- read back the contents of the object
72 printDeep( "immediate:", obj_, t)
73
74 -- send the object in a linda, get it back out, read the contents
75 l:set( "key", obj_, t)
76 -- when obj_ is a deep userdata, out is the same userdata as obj_ (not another one pointing on the same deep memory block) because of an internal cache table [deep*] -> proxy)
77 -- when obj_ is a clonable userdata, we get a different clone everytime we cross a linda or lane barrier
78 local _n, _val1, _val2 = l:get( "key", 2)
79 assert(_n == (_val2 and 2 or 1))
80 printDeep( "out of linda:", _val1, _val2)
81
82 -- send the object in a lane through argument passing, the lane body returns it as return value, read the contents
83 local g = lanes.gen(
84 "package"
85 , {
86 name = 'auto',
87 required = { "deep_userdata_example"} -- we will transfer userdata created by this module, so we need to make this lane aware of it
88 }
89 , function( arg_, t_)
90 -- read contents inside lane: arg_ and t_ by argument
91 printDeep( "in lane, as arguments:", arg_, t_)
92 -- read contents inside lane: obj_ and t by upvalue
93 printDeep( "in lane, as upvalues:", obj_, t)
94 -- read contents inside lane: in linda
95 local _n, _val1, _val2 = l:get( "key", 2)
96 assert(_n == (_val2 and 2 or 1))
97 printDeep( "in lane, from linda:", _val1, _val2)
98 return arg_, t_
99 end
100 )
101 h = g( obj_, t)
102 -- when obj_ is a deep userdata, from_lane is the same userdata as obj_ (not another one pointing on the same deep memory block) because of an internal cache table [deep*] -> proxy)
103 -- when obj_ is a clonable userdata, we get a different clone everytime we cross a linda or lane barrier
104 printDeep( "from lane:", h[1], h[2])
105end
106
107if DEEP then
108 print "================================================================"
109 print "DEEP"
110 local d = dt.new_deep(nupvals)
111 if type(DEEP) == "string" then
112 local gc_tests = {
113 thrasher = function(repeat_, size_)
114 print "in thrasher"
115 -- result is a table of repeat_ tables, each containing size_ entries
116 local result = {}
117 for i = 1, repeat_ do
118 local batch_values = {}
119 for j = 1, size_ do
120 table.insert(batch_values, j)
121 end
122 table.insert(result, batch_values)
123 end
124 print "thrasher done"
125 return result
126 end,
127 stack_abuser = function(repeat_, size_)
128 print "in stack_abuser"
129 for i = 1, repeat_ do
130 local batch_values = {}
131 for j = 1, size_ do
132 table.insert(batch_values, j)
133 end
134 -- return size_ values
135 local _ = table_unpack(batch_values)
136 end
137 print "stack_abuser done"
138 return result
139 end
140 }
141 -- have the object call the function from inside one of its functions, to detect if it gets collected from there (while in use!)
142 local testf = gc_tests[DEEP]
143 if testf then
144 local r = d:invoke(gc_tests[DEEP], REPEAT or 10, SIZE or 10)
145 print("invoke -> ", tostring(r))
146 else
147 print("unknown test '" .. DEEP .. "'")
148 end
149 else
150 performTest(d)
151 end
152end
153
154if CLONABLE then
155 print "================================================================"
156 print "CLONABLE"
157 performTest( dt.new_clonable(nupvals))
158end
159
160print "================================================================"
161print "TEST OK" \ No newline at end of file
diff --git a/unit_tests/shared.cpp b/unit_tests/shared.cpp
index 2e2af73..9f3b08e 100644
--- a/unit_tests/shared.cpp
+++ b/unit_tests/shared.cpp
@@ -18,9 +18,9 @@ namespace
18 { 18 {
19 STACK_CHECK_START_REL(L_, 0); 19 STACK_CHECK_START_REL(L_, 0);
20 lua_getglobal(L_, "package"); // L_: package 20 lua_getglobal(L_, "package"); // L_: package
21 std::ignore = luaG_getfield(L_, kIdxTop, "preload"); // L_: package package.preload 21 std::ignore = luaW_getfield(L_, kIdxTop, "preload"); // L_: package package.preload
22 lua_pushcfunction(L_, openf_); // L_: package package.preload openf_ 22 lua_pushcfunction(L_, openf_); // L_: package package.preload openf_
23 luaG_setfield(L_, StackIndex{ -2 }, name_); // L_: package package.preload 23 luaW_setfield(L_, StackIndex{ -2 }, name_); // L_: package package.preload
24 lua_pop(L_, 2); 24 lua_pop(L_, 2);
25 STACK_CHECK(L_, 0); 25 STACK_CHECK(L_, 0);
26 } 26 }
@@ -32,7 +32,7 @@ namespace
32 lua_CFunction sFreezingFinalizer = +[](lua_State* const L_) { 32 lua_CFunction sFreezingFinalizer = +[](lua_State* const L_) {
33 std::lock_guard _guard{ sCallCountsLock }; 33 std::lock_guard _guard{ sCallCountsLock };
34 sFinalizerHits[L_].test_and_set(); 34 sFinalizerHits[L_].test_and_set();
35 luaG_pushstring(L_, "freeze"); // just freeze the thread in place so that it can be debugged 35 luaW_pushstring(L_, "freeze"); // just freeze the thread in place so that it can be debugged
36 return 1; 36 return 1;
37 }; 37 };
38 38
@@ -47,22 +47,22 @@ namespace
47 }; 47 };
48 48
49 lua_CFunction sNewUserData = +[](lua_State* const L_) { 49 lua_CFunction sNewUserData = +[](lua_State* const L_) {
50 std::ignore = luaG_newuserdatauv<int>(L_, UserValueCount{ 0 }); 50 std::ignore = luaW_newuserdatauv<int>(L_, UserValueCount{ 0 });
51 return 1; 51 return 1;
52 }; 52 };
53 53
54 // a function that enables any lane to require "fixture" 54 // a function that enables any lane to require "fixture" and "deep_userdata_example"
55 lua_CFunction sOnStateCreate = +[](lua_State* const L_) { 55 lua_CFunction sOnStateCreate = +[](lua_State* const L_) {
56 PreloadModule(L_, "fixture", luaopen_fixture); 56 PreloadModule(L_, "fixture", luaopen_fixture);
57 PreloadModule(L_, "deep_userdata_example", luaopen_deep_userdata_example); 57 PreloadModule(L_, "deep_userdata_example", luaopen_deep_userdata_example);
58 return 0; 58 return 0;
59 }; 59 };
60 60
61 // a function that sleeps for the specified duration (in seconds) 61 // a function that blocks for the specified duration (in seconds) by putting the current thread to sleep
62 lua_CFunction sSleepFor = +[](lua_State* const L_) { 62 lua_CFunction sBlockFor = +[](lua_State* const L_) {
63 std::chrono::time_point<std::chrono::steady_clock> _until{ std::chrono::time_point<std::chrono::steady_clock>::max() }; 63 std::chrono::time_point<std::chrono::steady_clock> _until{ std::chrono::time_point<std::chrono::steady_clock>::max() };
64 lua_settop(L_, 1); 64 lua_settop(L_, 1);
65 if (luaG_type(L_, kIdxTop) == LuaType::NUMBER) { // we don't want to use lua_isnumber() because of autocoercion 65 if (luaW_type(L_, kIdxTop) == LuaType::NUMBER) { // we don't want to use lua_isnumber() because of autocoercion
66 lua_Duration const _duration{ lua_tonumber(L_, kIdxTop) }; 66 lua_Duration const _duration{ lua_tonumber(L_, kIdxTop) };
67 if (_duration.count() >= 0.0) { 67 if (_duration.count() >= 0.0) {
68 _until = std::chrono::steady_clock::now() + std::chrono::duration_cast<std::chrono::steady_clock::duration>(_duration); 68 _until = std::chrono::steady_clock::now() + std::chrono::duration_cast<std::chrono::steady_clock::duration>(_duration);
@@ -82,17 +82,17 @@ namespace
82 std::lock_guard _guard{ sCallCountsLock }; 82 std::lock_guard _guard{ sCallCountsLock };
83 sFinalizerHits[L_].test_and_set(); 83 sFinalizerHits[L_].test_and_set();
84 bool const _allLanesTerminated = lua_toboolean(L_, kIdxTop); 84 bool const _allLanesTerminated = lua_toboolean(L_, kIdxTop);
85 luaG_pushstring(L_, "Finalizer%s", _allLanesTerminated ? "" : ": Uncooperative lanes detected"); 85 luaW_pushstring(L_, "Finalizer%s", _allLanesTerminated ? "" : ": Uncooperative lanes detected");
86 return 1; 86 return 1;
87 }; 87 };
88 88
89 static luaL_Reg const sFixture[] = { 89 static luaL_Reg const sFixture[] = {
90 { "freezing_finalizer", sFreezingFinalizer }, 90 { "freezing_finalizer", sFreezingFinalizer },
91 { "give_me_back()", sGiveMeBack }, 91 { "give_me_back", sGiveMeBack },
92 { "newlightuserdata", sNewLightUserData }, 92 { "newlightuserdata", sNewLightUserData },
93 { "newuserdata", sNewUserData }, 93 { "newuserdata", sNewUserData },
94 { "on_state_create", sOnStateCreate }, 94 { "on_state_create", sOnStateCreate },
95 { "sleep_for", sSleepFor }, 95 { "block_for", sBlockFor },
96 { "throwing_finalizer", sThrowingFinalizer }, 96 { "throwing_finalizer", sThrowingFinalizer },
97 { nullptr, nullptr } 97 { nullptr, nullptr }
98 }; 98 };
@@ -103,7 +103,7 @@ namespace
103 int luaopen_fixture(lua_State* L_) 103 int luaopen_fixture(lua_State* L_)
104 { 104 {
105 STACK_CHECK_START_REL(L_, 0); 105 STACK_CHECK_START_REL(L_, 0);
106 luaG_newlib<std::size(local::sFixture)>(L_, local::sFixture); // M 106 luaW_newlib<std::size(local::sFixture)>(L_, local::sFixture); // M
107 STACK_CHECK(L_, 1); 107 STACK_CHECK(L_, 1);
108 return 1; 108 return 1;
109 } 109 }
@@ -246,7 +246,7 @@ LuaError LuaState::doString(std::string_view const& str_) const
246 return _loadErr; 246 return _loadErr;
247 } 247 }
248 LuaError const _callErr{ lua_pcall(L, 0, 1, 0) }; // L: "<msg>"? 248 LuaError const _callErr{ lua_pcall(L, 0, 1, 0) }; // L: "<msg>"?
249 [[maybe_unused]] std::string_view const _out{ luaG_tostring(L, kIdxTop) }; 249 [[maybe_unused]] std::string_view const _out{ luaW_tostring(L, kIdxTop) };
250 STACK_CHECK(L, 1); 250 STACK_CHECK(L, 1);
251 return _callErr; 251 return _callErr;
252} 252}
@@ -257,8 +257,8 @@ std::string_view LuaState::doStringAndRet(std::string_view const& str_) const
257{ 257{
258 lua_settop(L, 0); 258 lua_settop(L, 0);
259 if (str_.empty()) { 259 if (str_.empty()) {
260 luaG_pushstring(L, ""); 260 luaW_pushstring(L, "");
261 return luaG_tostring(L, kIdxTop); 261 return luaW_tostring(L, kIdxTop);
262 } 262 }
263 STACK_CHECK_START_REL(L, 0); 263 STACK_CHECK_START_REL(L, 0);
264 LuaError const _loadErr{ luaL_loadstring(L, str_.data()) }; // L: chunk() 264 LuaError const _loadErr{ luaL_loadstring(L, str_.data()) }; // L: chunk()
@@ -268,7 +268,7 @@ std::string_view LuaState::doStringAndRet(std::string_view const& str_) const
268 } 268 }
269 [[maybe_unused]] LuaError const _callErr{ lua_pcall(L, 0, 1, 0) }; // L: "<msg>"?|retstring 269 [[maybe_unused]] LuaError const _callErr{ lua_pcall(L, 0, 1, 0) }; // L: "<msg>"?|retstring
270 STACK_CHECK(L, 1); 270 STACK_CHECK(L, 1);
271 return luaG_tostring(L, kIdxTop); 271 return luaW_tostring(L, kIdxTop);
272} 272}
273 273
274// ################################################################################################# 274// #################################################################################################
@@ -336,7 +336,7 @@ void LuaState::requireFailure(std::string_view const& script_)
336{ 336{
337 auto const _result{ doString(script_) }; 337 auto const _result{ doString(script_) };
338 if (_result == LuaError::OK) { 338 if (_result == LuaError::OK) {
339 WARN(luaG_tostring(L, kIdxTop)); 339 WARN(luaW_tostring(L, kIdxTop));
340 } 340 }
341 REQUIRE(_result != LuaError::OK); 341 REQUIRE(_result != LuaError::OK);
342 lua_settop(L, 0); 342 lua_settop(L, 0);
@@ -372,7 +372,7 @@ void LuaState::requireSuccess(std::string_view const& script_)
372{ 372{
373 auto const _result{ doString(script_) }; 373 auto const _result{ doString(script_) };
374 if (_result != LuaError::OK) { 374 if (_result != LuaError::OK) {
375 WARN(luaG_tostring(L, kIdxTop)); 375 WARN(luaW_tostring(L, kIdxTop));
376 } 376 }
377 REQUIRE(_result == LuaError::OK); 377 REQUIRE(_result == LuaError::OK);
378 lua_settop(L, 0); 378 lua_settop(L, 0);
@@ -384,7 +384,7 @@ void LuaState::requireSuccess(std::filesystem::path const& root_, std::string_vi
384{ 384{
385 auto const _result{ doFile(root_, path_) }; 385 auto const _result{ doFile(root_, path_) };
386 if (_result != LuaError::OK) { 386 if (_result != LuaError::OK) {
387 WARN(luaG_tostring(L, kIdxTop)); 387 WARN(luaW_tostring(L, kIdxTop));
388 } 388 }
389 REQUIRE(_result == LuaError::OK); 389 REQUIRE(_result == LuaError::OK);
390 lua_settop(L, 0); 390 lua_settop(L, 0);
@@ -407,20 +407,20 @@ TEST_CASE("LuaState.doString")
407{ 407{
408 LuaState _L{ LuaState::WithBaseLibs{ true }, LuaState::WithFixture{ false } }; 408 LuaState _L{ LuaState::WithBaseLibs{ true }, LuaState::WithFixture{ false } };
409 // if the script fails to load, we should find the error message at the top of the stack 409 // if the script fails to load, we should find the error message at the top of the stack
410 REQUIRE([&L = _L]() { std::ignore = L.doString("function end"); return lua_gettop(L) == 1 && luaG_type(L, StackIndex{1}) == LuaType::STRING; }()); 410 REQUIRE([&L = _L]() { std::ignore = L.doString("function end"); return lua_gettop(L) == 1 && luaW_type(L, StackIndex{1}) == LuaType::STRING; }());
411 411
412 // if the script runs, the stack should contain its return value 412 // if the script runs, the stack should contain its return value
413 REQUIRE([&L = _L]() { std::ignore = L.doString("return true"); return lua_gettop(L) == 1 && luaG_type(L, StackIndex{1}) == LuaType::BOOLEAN; }()); 413 REQUIRE([&L = _L]() { std::ignore = L.doString("return true"); return lua_gettop(L) == 1 && luaW_type(L, StackIndex{1}) == LuaType::BOOLEAN; }());
414 REQUIRE([&L = _L]() { std::ignore = L.doString("return 'hello'"); return lua_gettop(L) == 1 && luaG_tostring(L, StackIndex{1}) == "hello"; }()); 414 REQUIRE([&L = _L]() { std::ignore = L.doString("return 'hello'"); return lua_gettop(L) == 1 && luaW_tostring(L, StackIndex{1}) == "hello"; }());
415 // or nil if it didn't return anything 415 // or nil if it didn't return anything
416 REQUIRE([&L = _L]() { std::ignore = L.doString("return"); return lua_gettop(L) == 1 && luaG_type(L, StackIndex{1}) == LuaType::NIL; }()); 416 REQUIRE([&L = _L]() { std::ignore = L.doString("return"); return lua_gettop(L) == 1 && luaW_type(L, StackIndex{1}) == LuaType::NIL; }());
417 417
418 // on failure, doStringAndRet returns "", and the error message is on the stack 418 // on failure, doStringAndRet returns "", and the error message is on the stack
419 REQUIRE([&L = _L]() { return L.doStringAndRet("function end") == "" && lua_gettop(L) == 1 && luaG_type(L, StackIndex{ 1 }) == LuaType::STRING && luaG_tostring(L, StackIndex{ 1 }) != ""; }()); 419 REQUIRE([&L = _L]() { return L.doStringAndRet("function end") == "" && lua_gettop(L) == 1 && luaW_type(L, StackIndex{ 1 }) == LuaType::STRING && luaW_tostring(L, StackIndex{ 1 }) != ""; }());
420 // on success doStringAndRet returns the string returned by the script, that is also at the top of the stack 420 // on success doStringAndRet returns the string returned by the script, that is also at the top of the stack
421 REQUIRE([&L = _L]() { return L.doStringAndRet("return 'hello'") == "hello" && lua_gettop(L) == 1 && luaG_type(L, StackIndex{ 1 }) == LuaType::STRING && luaG_tostring(L, StackIndex{ 1 }) == "hello"; }()); 421 REQUIRE([&L = _L]() { return L.doStringAndRet("return 'hello'") == "hello" && lua_gettop(L) == 1 && luaW_type(L, StackIndex{ 1 }) == LuaType::STRING && luaW_tostring(L, StackIndex{ 1 }) == "hello"; }());
422 // if the returned value is not (convertible to) a string, we should get an empty string out of doStringAndRet 422 // if the returned value is not (convertible to) a string, we should get an empty string out of doStringAndRet
423 REQUIRE([&L = _L]() { return L.doStringAndRet("return function() end") == "" && lua_gettop(L) == 1 && luaG_type(L, StackIndex{ 1 }) == LuaType::FUNCTION && luaG_tostring(L, StackIndex{ 1 }) == ""; }()); 423 REQUIRE([&L = _L]() { return L.doStringAndRet("return function() end") == "" && lua_gettop(L) == 1 && luaW_type(L, StackIndex{ 1 }) == LuaType::FUNCTION && luaW_tostring(L, StackIndex{ 1 }) == ""; }());
424} 424}
425 425
426// ################################################################################################# 426// #################################################################################################
@@ -436,9 +436,9 @@ FileRunner::FileRunner(std::string_view const& where_)
436 // because the VS Test Explorer doesn't appreciate the text output of some scripts, so absorb them 436 // because the VS Test Explorer doesn't appreciate the text output of some scripts, so absorb them
437 if constexpr (1) { 437 if constexpr (1) {
438 auto const _nullprint = +[](lua_State* const L_) { return 0; }; 438 auto const _nullprint = +[](lua_State* const L_) { return 0; };
439 luaG_pushglobaltable(L); 439 luaW_pushglobaltable(L);
440 lua_pushcfunction(L, _nullprint); 440 lua_pushcfunction(L, _nullprint);
441 luaG_setfield(L, StackIndex{ -2 }, std::string_view{ "print" }); 441 luaW_setfield(L, StackIndex{ -2 }, std::string_view{ "print" });
442 lua_pop(L, 1); 442 lua_pop(L, 1);
443 stackCheck(0); 443 stackCheck(0);
444 } 444 }
@@ -476,6 +476,7 @@ void FileRunner::performTest(FileRunnerParam const& testParam_)
476 INFO(testParam_.script); 476 INFO(testParam_.script);
477 switch (testParam_.test) { 477 switch (testParam_.test) {
478 case TestType::AssertNoLuaError: 478 case TestType::AssertNoLuaError:
479 lua_atpanic(L, _atPanic);
479 requireSuccess(root, testParam_.script); 480 requireSuccess(root, testParam_.script);
480 break; 481 break;
481 482
diff --git a/unit_tests/shared.h b/unit_tests/shared.h
index b884df0..c6c3339 100644
--- a/unit_tests/shared.h
+++ b/unit_tests/shared.h
@@ -56,7 +56,7 @@ class LuaState
56 56
57 friend std::ostream& operator<<(std::ostream& os_, LuaState const& s_) 57 friend std::ostream& operator<<(std::ostream& os_, LuaState const& s_)
58 { 58 {
59 os_ << luaG_tostring(s_.L, kIdxTop); 59 os_ << luaW_tostring(s_.L, kIdxTop);
60 return os_; 60 return os_;
61 } 61 }
62}; 62};