diff options
-rw-r--r-- | docs/index.html | 211 | ||||
-rw-r--r-- | src/uniquekey.h | 2 |
2 files changed, 106 insertions, 107 deletions
diff --git a/docs/index.html b/docs/index.html index d24d3d7..3e535a6 100644 --- a/docs/index.html +++ b/docs/index.html | |||
@@ -64,13 +64,13 @@ | |||
64 | <font size="-1"> | 64 | <font size="-1"> |
65 | <p> | 65 | <p> |
66 | <br/> | 66 | <br/> |
67 | <i>Copyright © 2007-23 Asko Kauppi, Benoit Germain. All rights reserved.</i> | 67 | <i>Copyright © 2007-24 Asko Kauppi, Benoit Germain. All rights reserved.</i> |
68 | <br/> | 68 | <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. | 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 | </p> | 70 | </p> |
71 | 71 | ||
72 | <p> | 72 | <p> |
73 | This document was revised on 29-Mar-24, and applies to version <tt>4.0.0</tt>. | 73 | This document was revised on 9-Apr-24, and applies to version <tt>4.0.0</tt>. |
74 | </p> | 74 | </p> |
75 | </font> | 75 | </font> |
76 | </center> | 76 | </center> |
@@ -178,14 +178,14 @@ | |||
178 | <table border=1 bgcolor="#E0E0FF" cellpadding="10" style="width:50%"> | 178 | <table border=1 bgcolor="#E0E0FF" cellpadding="10" style="width:50%"> |
179 | <tr> | 179 | <tr> |
180 | <td> | 180 | <td> |
181 | <pre> extern void LANES_API luaopen_lanes_embedded( lua_State* L, lua_CFunction _luaopen_lanes);</pre> | 181 | <pre> extern void LANES_API luaopen_lanes_embedded(lua_State* L, lua_CFunction _luaopen_lanes);</pre> |
182 | </td> | 182 | </td> |
183 | </tr> | 183 | </tr> |
184 | </table> | 184 | </table> |
185 | <p> | 185 | <p> |
186 | <tt>luaopen_lanes_embedded</tt> leaves the module table on the stack. <tt>lanes.configure()</tt> must still be called in order to use Lanes. | 186 | <tt>luaopen_lanes_embedded</tt> leaves the module table on the stack. <tt>lanes.configure()</tt> must still be called in order to use Lanes. |
187 | <br/> | 187 | <br/> |
188 | If <tt>_luaopen_lanes</tt> is <tt>NULL</tt>, a default loader will simply attempt the equivalent of <tt>luaL_dofile( L, "lanes.lua")</tt>. | 188 | If <tt>_luaopen_lanes</tt> is <tt>NULL</tt>, a default loader will simply attempt the equivalent of <tt>luaL_dofile(L, "lanes.lua")</tt>. |
189 | </p> | 189 | </p> |
190 | 190 | ||
191 | <p> | 191 | <p> |
@@ -198,30 +198,30 @@ | |||
198 | <td> | 198 | <td> |
199 | <pre> #include "lanes.h"</pre> | 199 | <pre> #include "lanes.h"</pre> |
200 | <br/> | 200 | <br/> |
201 | <pre> int load_lanes_lua( lua_State* L)</pre> | 201 | <pre> int load_lanes_lua(lua_State* L)</pre> |
202 | <pre> {</pre> | 202 | <pre> {</pre> |
203 | <pre> // retrieve lanes.lua from wherever it is stored and return the result of its execution</pre> | 203 | <pre> // retrieve lanes.lua from wherever it is stored and return the result of its execution</pre> |
204 | <pre> // trivial example 1:</pre> | 204 | <pre> // trivial example 1:</pre> |
205 | <pre> luaL_dofile( L, "lanes.lua");</pre> | 205 | <pre> luaL_dofile(L, "lanes.lua");</pre> |
206 | <br/> | 206 | <br/> |
207 | <pre> // trivial example 2:</pre> | 207 | <pre> // trivial example 2:</pre> |
208 | <pre> luaL_dostring( L, bin2c_lanes_lua);</pre> | 208 | <pre> luaL_dostring(L, bin2c_lanes_lua);</pre> |
209 | <pre> }</pre> | 209 | <pre> }</pre> |
210 | <br/> | 210 | <br/> |
211 | <pre> void embed_lanes( lua_State* L)</pre> | 211 | <pre> void embed_lanes(lua_State* L)</pre> |
212 | <pre> {</pre> | 212 | <pre> {</pre> |
213 | <pre> // we need base libraries for Lanes for work</pre> | 213 | <pre> // we need base libraries for Lanes for work</pre> |
214 | <pre> luaL_openlibs( L);</pre> | 214 | <pre> luaL_openlibs(L);</pre> |
215 | <pre> ...</pre> | 215 | <pre> ...</pre> |
216 | <pre> // will attempt luaL_dofile( L, "lanes.lua");</pre> | 216 | <pre> // will attempt luaL_dofile(L, "lanes.lua");</pre> |
217 | <pre> luaopen_lanes_embedded( L, NULL);</pre> | 217 | <pre> luaopen_lanes_embedded(L, nullptr);</pre> |
218 | <pre> lua_pop( L, 1);</pre> | 218 | <pre> lua_pop(L, 1);</pre> |
219 | <pre> // another example with a custom loader</pre> | 219 | <pre> // another example with a custom loader</pre> |
220 | <pre> luaopen_lanes_embedded( L, load_lanes_lua);</pre> | 220 | <pre> luaopen_lanes_embedded(L, load_lanes_lua);</pre> |
221 | <pre> lua_pop( L, 1);</pre> | 221 | <pre> lua_pop(L, 1);</pre> |
222 | <br/> | 222 | <br/> |
223 | <pre> // a little test to make sure things work as expected</pre> | 223 | <pre> // a little test to make sure things work as expected</pre> |
224 | <pre> luaL_dostring( L, "local lanes = require 'lanes'.configure{with_timers = false}; local l = lanes.linda()");</pre> | 224 | <pre> luaL_dostring(L, "local lanes = require 'lanes'.configure{with_timers = false}; local l = lanes.linda()");</pre> |
225 | <pre> }</pre> | 225 | <pre> }</pre> |
226 | </td> | 226 | </td> |
227 | </tr> | 227 | </tr> |
@@ -266,7 +266,7 @@ | |||
266 | <table border="1" bgcolor="#E0E0FF" cellpadding="10" style="width:50%"> | 266 | <table border="1" bgcolor="#E0E0FF" cellpadding="10" style="width:50%"> |
267 | <tr> | 267 | <tr> |
268 | <td> | 268 | <td> |
269 | <pre> lanes.configure( [opt_tbl])</pre> | 269 | <pre> lanes.configure([opt_tbl])</pre> |
270 | </td> | 270 | </td> |
271 | </tr> | 271 | </tr> |
272 | </table> | 272 | </table> |
@@ -454,7 +454,7 @@ | |||
454 | <tr> | 454 | <tr> |
455 | <td> | 455 | <td> |
456 | <pre> local m = lanes.require "modname"</pre> | 456 | <pre> local m = lanes.require "modname"</pre> |
457 | <pre> lanes.register( "modname", module)</pre> | 457 | <pre> lanes.register("modname", module)</pre> |
458 | </td> | 458 | </td> |
459 | </tr> | 459 | </tr> |
460 | </table> | 460 | </table> |
@@ -471,11 +471,11 @@ | |||
471 | <td> | 471 | <td> |
472 | <pre> local lanes = require "lanes".configure()</pre> | 472 | <pre> local lanes = require "lanes".configure()</pre> |
473 | <br/> | 473 | <br/> |
474 | <pre> f = lanes.gen( function( n) return 2 * n end)</pre> | 474 | <pre> f = lanes.gen(function(n) return 2 * n end)</pre> |
475 | <pre> a = f( 1)</pre> | 475 | <pre> a = f(1)</pre> |
476 | <pre> b = f( 2)</pre> | 476 | <pre> b = f(2)</pre> |
477 | <br/> | 477 | <br/> |
478 | <pre> print( a[1], b[1] ) -- 2 4</pre> | 478 | <pre> print(a[1], b[1]) -- 2 4</pre> |
479 | </td> | 479 | </td> |
480 | </tr> | 480 | </tr> |
481 | </table> | 481 | </table> |
@@ -483,8 +483,8 @@ | |||
483 | <table border=1 bgcolor="#E0E0FF" cellpadding="10" style="width:50%"> | 483 | <table border=1 bgcolor="#E0E0FF" cellpadding="10" style="width:50%"> |
484 | <tr> | 484 | <tr> |
485 | <td> | 485 | <td> |
486 | <pre> func = lanes.gen( [libs_str | opt_tbl [, ...],] lane_func)</pre> | 486 | <pre> func = lanes.gen([libs_str | opt_tbl [, ...],] lane_func)</pre> |
487 | <pre> lane_h = func( ...)</pre> | 487 | <pre> lane_h = func(...)</pre> |
488 | </td> | 488 | </td> |
489 | </tr> | 489 | </tr> |
490 | </table> | 490 | </table> |
@@ -751,7 +751,7 @@ | |||
751 | <table border="1" bgcolor="#E0E0FF" cellpadding="10" style="width:50%"> | 751 | <table border="1" bgcolor="#E0E0FF" cellpadding="10" style="width:50%"> |
752 | <tr> | 752 | <tr> |
753 | <td> | 753 | <td> |
754 | <pre> "type", "name" = lanes.nameof( o)</pre> | 754 | <pre> "type", "name" = lanes.nameof(o)</pre> |
755 | </td> | 755 | </td> |
756 | </tr> | 756 | </tr> |
757 | </table> | 757 | </table> |
@@ -765,7 +765,7 @@ | |||
765 | <table border="1" bgcolor="#FFFFE0" cellpadding="10" style="width:50%"> | 765 | <table border="1" bgcolor="#FFFFE0" cellpadding="10" style="width:50%"> |
766 | <tr> | 766 | <tr> |
767 | <td> | 767 | <td> |
768 | <pre> lanes.gen( function( params) ... end ) ( ...)</pre> | 768 | <pre> lanes.gen(function(params) ... end ) (...)</pre> |
769 | </td> | 769 | </td> |
770 | </tr> | 770 | </tr> |
771 | </table> | 771 | </table> |
@@ -781,7 +781,7 @@ | |||
781 | <table border="1" bgcolor="#E0E0FF" cellpadding="10" style="width:50%"> | 781 | <table border="1" bgcolor="#E0E0FF" cellpadding="10" style="width:50%"> |
782 | <tr> | 782 | <tr> |
783 | <td> | 783 | <td> |
784 | <pre> lanes.set_thread_priority( prio)</pre> | 784 | <pre> lanes.set_thread_priority(prio)</pre> |
785 | </td> | 785 | </td> |
786 | </tr> | 786 | </tr> |
787 | </table> | 787 | </table> |
@@ -799,7 +799,7 @@ | |||
799 | <table border="1" bgcolor="#E0E0FF" cellpadding="10" style="width:50%"> | 799 | <table border="1" bgcolor="#E0E0FF" cellpadding="10" style="width:50%"> |
800 | <tr> | 800 | <tr> |
801 | <td> | 801 | <td> |
802 | <pre> lanes.set_thread_affinity( affinity)</pre> | 802 | <pre> lanes.set_thread_affinity(affinity)</pre> |
803 | </td> | 803 | </td> |
804 | </tr> | 804 | </tr> |
805 | </table> | 805 | </table> |
@@ -901,7 +901,7 @@ | |||
901 | <table border="1" bgcolor="#E0E0FF" cellpadding="10" style="width:50%"> | 901 | <table border="1" bgcolor="#E0E0FF" cellpadding="10" style="width:50%"> |
902 | <tr> | 902 | <tr> |
903 | <td> | 903 | <td> |
904 | <pre> {{name = "name", status = "status", ...}|nil = lanes.threads()</pre> | 904 | <pre> {name = "name", status = "status", ...}|nil = lanes.threads()</pre> |
905 | </td> | 905 | </td> |
906 | </tr> | 906 | </tr> |
907 | </table> | 907 | </table> |
@@ -918,7 +918,7 @@ | |||
918 | <h2 id="results">Results and errors</h2> | 918 | <h2 id="results">Results and errors</h2> |
919 | 919 | ||
920 | <table border="1" bgcolor="#E0E0FF" cellpadding="10" style="width:50%"><tr><td><pre> | 920 | <table border="1" bgcolor="#E0E0FF" cellpadding="10" style="width:50%"><tr><td><pre> |
921 | set_error_reporting( "basic"|"extended") | 921 | set_error_reporting("basic"|"extended") |
922 | </pre></td></tr></table> | 922 | </pre></td></tr></table> |
923 | 923 | ||
924 | <p> | 924 | <p> |
@@ -940,7 +940,7 @@ | |||
940 | </p> | 940 | </p> |
941 | 941 | ||
942 | <table border="1" bgcolor="#E0E0FF" cellpadding="10" style="width:50%"><tr><td><pre> | 942 | <table border="1" bgcolor="#E0E0FF" cellpadding="10" style="width:50%"><tr><td><pre> |
943 | [...]|[nil,err,stack_tbl]= lane_h:join( [timeout_secs] ) | 943 | [...]|[nil,err,stack_tbl]= lane_h:join([timeout_secs]) |
944 | </pre></td></tr></table> | 944 | </pre></td></tr></table> |
945 | 945 | ||
946 | <p> | 946 | <p> |
@@ -965,14 +965,14 @@ | |||
965 | <table border=1 bgcolor="#FFFFE0" cellpadding="10" style="width:50%"><tr><td><pre> | 965 | <table border=1 bgcolor="#FFFFE0" cellpadding="10" style="width:50%"><tr><td><pre> |
966 | require "lanes".configure() | 966 | require "lanes".configure() |
967 | 967 | ||
968 | f = lanes.gen( function() error "!!!" end) | 968 | f = lanes.gen(function() error "!!!" end) |
969 | a = f( 1) | 969 | a = f(1) |
970 | 970 | ||
971 | --print( a[1]) -- propagates error | 971 | --print(a[1]) -- propagates error |
972 | 972 | ||
973 | v, err = a:join() -- no propagation | 973 | v, err = a:join() -- no propagation |
974 | if v == nil then | 974 | if v == nil then |
975 | error( "'a' faced error"..tostring(err)) -- manual propagation | 975 | error("'a' faced error"..tostring(err)) -- manual propagation |
976 | end | 976 | end |
977 | </pre></td></tr></table> | 977 | </pre></td></tr></table> |
978 | 978 | ||
@@ -984,12 +984,12 @@ | |||
984 | require "lanes".configure() | 984 | require "lanes".configure() |
985 | 985 | ||
986 | local sync_linda = lanes.linda() | 986 | local sync_linda = lanes.linda() |
987 | f = lanes.gen( function() dostuff() sync_linda:send( "done", true) end) | 987 | f = lanes.gen(function() dostuff() sync_linda:send("done", true) end) |
988 | a = f() | 988 | a = f() |
989 | b = f() | 989 | b = f() |
990 | c = f() | 990 | c = f() |
991 | 991 | ||
992 | sync_linda:receive( nil, sync_linda.batched, "done", 3) -- wait for 3 lanes to write something in "done" slot of sync_linda | 992 | sync_linda:receive(nil, sync_linda.batched, "done", 3) -- wait for 3 lanes to write something in "done" slot of sync_linda |
993 | </pre></td></tr></table> | 993 | </pre></td></tr></table> |
994 | 994 | ||
995 | <!-- cancelling +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ --> | 995 | <!-- cancelling +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ --> |
@@ -997,9 +997,9 @@ | |||
997 | <h2 id="cancelling">Cancelling</h2> | 997 | <h2 id="cancelling">Cancelling</h2> |
998 | 998 | ||
999 | <table border="1" bgcolor="#E0E0FF" cellpadding="10" style="width:50%"><tr><td><pre> | 999 | <table border="1" bgcolor="#E0E0FF" cellpadding="10" style="width:50%"><tr><td><pre> |
1000 | bool[,reason] = lane_h:cancel( "soft" [, timeout] [, wake_lane]) | 1000 | bool[,reason] = lane_h:cancel("soft" [, timeout] [, wake_lane]) |
1001 | bool[,reason] = lane_h:cancel( "hard" [, timeout] [, wake_lane]) | 1001 | bool[,reason] = lane_h:cancel("hard" [, timeout] [, wake_lane]) |
1002 | bool[,reason] = lane_h:cancel( [mode, hookcount] [, timeout] [, wake_lane]) | 1002 | bool[,reason] = lane_h:cancel([mode, hookcount] [, timeout] [, wake_lane]) |
1003 | </pre></td></tr></table> | 1003 | </pre></td></tr></table> |
1004 | 1004 | ||
1005 | <p> | 1005 | <p> |
@@ -1041,9 +1041,9 @@ | |||
1041 | <h2 id="finalizers">Finalizers</h2> | 1041 | <h2 id="finalizers">Finalizers</h2> |
1042 | 1042 | ||
1043 | <table border="1" bgcolor="#E0E0FF" cellpadding="10" style="width:50%"><tr><td><pre> | 1043 | <table border="1" bgcolor="#E0E0FF" cellpadding="10" style="width:50%"><tr><td><pre> |
1044 | set_finalizer( finalizer_func) | 1044 | set_finalizer(finalizer_func) |
1045 | 1045 | ||
1046 | void = finalizer_func( [err, stack_tbl]) | 1046 | void = finalizer_func([err, stack_tbl]) |
1047 | </pre></td></tr></table> | 1047 | </pre></td></tr></table> |
1048 | 1048 | ||
1049 | <p> | 1049 | <p> |
@@ -1063,16 +1063,16 @@ | |||
1063 | 1063 | ||
1064 | <table border="1" bgcolor="#FFFFE0" cellpadding="10" style="width:50%"><tr><td><pre> | 1064 | <table border="1" bgcolor="#FFFFE0" cellpadding="10" style="width:50%"><tr><td><pre> |
1065 | local lane_body = function() | 1065 | local lane_body = function() |
1066 | set_finalizer( function( err, stk) | 1066 | set_finalizer(function(err, stk) |
1067 | if err and type( err) ~= "userdata" then | 1067 | if err and type(err) ~= "userdata" then |
1068 | -- no special error: true error | 1068 | -- no special error: true error |
1069 | print( " error: "..tostring(err)) | 1069 | print(" error: "..tostring(err)) |
1070 | elseif type( err) == "userdata" then | 1070 | elseif type(err) == "userdata" then |
1071 | -- lane <a href="#cancelling">cancellation</a> is performed by throwing a special userdata as error | 1071 | -- lane <a href="#cancelling">cancellation</a> is performed by throwing a special userdata as error |
1072 | print( "after cancel") | 1072 | print("after cancel") |
1073 | else | 1073 | else |
1074 | -- no error: we just got finalized | 1074 | -- no error: we just got finalized |
1075 | print( "finalized") | 1075 | print("finalized") |
1076 | end | 1076 | end |
1077 | end) | 1077 | end) |
1078 | end | 1078 | end |
@@ -1098,22 +1098,22 @@ | |||
1098 | 1098 | ||
1099 | local linda = lanes.linda() | 1099 | local linda = lanes.linda() |
1100 | 1100 | ||
1101 | local function loop( max) | 1101 | local function loop(max) |
1102 | for i = 1, max do | 1102 | for i = 1, max do |
1103 | print( "sending: " .. i) | 1103 | print("sending: " .. i) |
1104 | linda:send( "x", i) -- linda as upvalue | 1104 | linda:send("x", i) -- linda as upvalue |
1105 | end | 1105 | end |
1106 | end | 1106 | end |
1107 | 1107 | ||
1108 | a = lanes.gen( "", loop)( 10000) | 1108 | a = lanes.gen("", loop)(10000) |
1109 | 1109 | ||
1110 | while true do | 1110 | while true do |
1111 | local key, val = linda:receive( 3.0, "x") -- timeout in seconds | 1111 | local key, val = linda:receive(3.0, "x") -- timeout in seconds |
1112 | if val == nil then | 1112 | if val == nil then |
1113 | print( "timed out") | 1113 | print("timed out") |
1114 | break | 1114 | break |
1115 | end | 1115 | end |
1116 | print( tostring( linda) .. " received: " .. val) | 1116 | print(tostring(linda) .. " received: " .. val) |
1117 | end | 1117 | end |
1118 | </pre></td></tr></table> | 1118 | </pre></td></tr></table> |
1119 | 1119 | ||
@@ -1128,23 +1128,23 @@ | |||
1128 | <li>two producer-side methods: <tt>:send</tt> and <tt>:set</tt> (not out).</li> | 1128 | <li>two producer-side methods: <tt>:send</tt> and <tt>:set</tt> (not out).</li> |
1129 | <li><tt>send</tt> allows for sending multiple values -atomically- to a given key.</li> | 1129 | <li><tt>send</tt> allows for sending multiple values -atomically- to a given key.</li> |
1130 | <li><tt>receive</tt> can wait for multiple keys at once.</li> | 1130 | <li><tt>receive</tt> can wait for multiple keys at once.</li> |
1131 | <li><tt>receive</tt> has a batched mode to consume more than one value from a single key, as in <tt>linda:receive( 1.0, linda.batched, "key", 3, 6).</tt></li> | 1131 | <li><tt>receive</tt> has a batched mode to consume more than one value from a single key, as in <tt>linda:receive(1.0, linda.batched, "key", 3, 6).</tt></li> |
1132 | <li>individual keys' queue length can be limited, balancing speed differences in a producer/consumer scenario (making <tt>:send</tt> wait).</li> | 1132 | <li>individual keys' queue length can be limited, balancing speed differences in a producer/consumer scenario (making <tt>:send</tt> wait).</li> |
1133 | <li><tt>tostring( linda)</tt> returns a string of the form <tt>"Linda: <opt_name>"</tt></li> | 1133 | <li><tt>tostring(linda)</tt> returns a string of the form <tt>"Linda: <opt_name>"</tt></li> |
1134 | <li>several lindas may share the same keeper state. State assignation can be controlled with the linda's group (an integer). All lindas belonging to the same group will share the same keeper state. One keeper state may be shared by several groups.</li> | 1134 | <li>several lindas may share the same keeper state. State assignation can be controlled with the linda's group (an integer). All lindas belonging to the same group will share the same keeper state. One keeper state may be shared by several groups.</li> |
1135 | </ul> | 1135 | </ul> |
1136 | </p> | 1136 | </p> |
1137 | 1137 | ||
1138 | <table border="1" bgcolor="#E0E0FF" cellpadding="10" style="width:50%"><tr><td><pre> | 1138 | <table border="1" bgcolor="#E0E0FF" cellpadding="10" style="width:50%"><tr><td><pre> |
1139 | h = lanes.linda( [opt_name, [opt_group]]) | 1139 | h = lanes.linda([opt_name, [opt_group]]) |
1140 | 1140 | ||
1141 | [true|lanes.cancel_error] = h:send( [timeout_secs,] [h.null,] key, ...) | 1141 | [true|lanes.cancel_error] = h:send([timeout_secs,] [h.null,] key, ...) |
1142 | 1142 | ||
1143 | [key, val]|[lanes.cancel_error] = h:receive( [timeout_secs,] key [, ...]) | 1143 | [key, val]|[lanes.cancel_error] = h:receive([timeout_secs,] key [, ...]) |
1144 | 1144 | ||
1145 | [key, val [, ...]]|[lanes.cancel_error] = h:receive( timeout, h.batched, key, n_uint_min[, n_uint_max]) | 1145 | [key, val [, ...]]|[lanes.cancel_error] = h:receive(timeout, h.batched, key, n_uint_min[, n_uint_max]) |
1146 | 1146 | ||
1147 | [true|lanes.cancel_error] = h:limit( key, n_uint) | 1147 | [true|lanes.cancel_error] = h:limit(key, n_uint) |
1148 | </pre></td></tr></table> | 1148 | </pre></td></tr></table> |
1149 | 1149 | ||
1150 | <p> | 1150 | <p> |
@@ -1193,9 +1193,9 @@ | |||
1193 | </p> | 1193 | </p> |
1194 | 1194 | ||
1195 | <table border="1" bgcolor="#E0E0FF" cellpadding="10" style="width:50%"><tr><td><pre> | 1195 | <table border="1" bgcolor="#E0E0FF" cellpadding="10" style="width:50%"><tr><td><pre> |
1196 | bool|lanes.cancel_error = linda_h:set( key [, val [, ...]]) | 1196 | bool|lanes.cancel_error = linda_h:set(key [, val [, ...]]) |
1197 | 1197 | ||
1198 | [[val [, ...]]|lanes.cancel_error] = linda_h:get( key [, count = 1]) | 1198 | [[val [, ...]]|lanes.cancel_error] = linda_h:get(key [, count = 1]) |
1199 | </pre></td></tr></table> | 1199 | </pre></td></tr></table> |
1200 | 1200 | ||
1201 | <p> | 1201 | <p> |
@@ -1225,7 +1225,7 @@ | |||
1225 | </p> | 1225 | </p> |
1226 | 1226 | ||
1227 | <table border="1" bgcolor="#E0E0FF" cellpadding="10" style="width:50%"><tr><td><pre> | 1227 | <table border="1" bgcolor="#E0E0FF" cellpadding="10" style="width:50%"><tr><td><pre> |
1228 | [val] = linda_h:count( [key[,...]]) | 1228 | [val] = linda_h:count([key[,...]]) |
1229 | </pre></td></tr></table> | 1229 | </pre></td></tr></table> |
1230 | 1230 | ||
1231 | <p> | 1231 | <p> |
@@ -1315,7 +1315,7 @@ events to a common Linda, but... :).</font> | |||
1315 | <h2 id="timers">Timers</h2> | 1315 | <h2 id="timers">Timers</h2> |
1316 | 1316 | ||
1317 | <table border="1" bgcolor="#E0E0FF" cellpadding="10" style="width:50%"><tr><td><pre> | 1317 | <table border="1" bgcolor="#E0E0FF" cellpadding="10" style="width:50%"><tr><td><pre> |
1318 | void = lanes.timer( linda_h, key, date_tbl|first_secs [,period_secs]) | 1318 | void = lanes.timer(linda_h, key, date_tbl|first_secs [,period_secs]) |
1319 | </pre></td></tr></table> | 1319 | </pre></td></tr></table> |
1320 | 1320 | ||
1321 | <p> | 1321 | <p> |
@@ -1342,18 +1342,18 @@ events to a common Linda, but... :).</font> | |||
1342 | 1342 | ||
1343 | -- First timer once a second, not synchronized to wall clock | 1343 | -- First timer once a second, not synchronized to wall clock |
1344 | -- | 1344 | -- |
1345 | lanes.timer( linda, "sec", 1, 1) | 1345 | lanes.timer(linda, "sec", 1, 1) |
1346 | 1346 | ||
1347 | -- Timer to a future event (next even minute); wall clock synchronized | 1347 | -- Timer to a future event (next even minute); wall clock synchronized |
1348 | -- | 1348 | -- |
1349 | local t = os.date( "*t", os.time() + 60) -- now + 1min | 1349 | local t = os.date("*t", os.time() + 60) -- now + 1min |
1350 | t.sec = 0 | 1350 | t.sec = 0 |
1351 | 1351 | ||
1352 | lanes.timer( linda, "min", t, 60) -- reoccur every minute (sharp) | 1352 | lanes.timer(linda, "min", t, 60) -- reoccur every minute (sharp) |
1353 | 1353 | ||
1354 | while true do | 1354 | while true do |
1355 | local key, v = linda:receive( "sec", "min") | 1355 | local key, v = linda:receive("sec", "min") |
1356 | print( "Timer "..key..": "..v) | 1356 | print("Timer "..key..": "..v) |
1357 | end | 1357 | end |
1358 | </pre></td></tr></table> | 1358 | </pre></td></tr></table> |
1359 | 1359 | ||
@@ -1367,7 +1367,7 @@ events to a common Linda, but... :).</font> | |||
1367 | <td> | 1367 | <td> |
1368 | <font size="-1"> | 1368 | <font size="-1"> |
1369 | Having the API as <tt>lanes.timer()</tt> is intentional. Another alternative would be <tt>linda_h:timer()</tt> but timers are not traditionally seen to be part of Lindas. Also, it would mean any lane getting a Linda handle would be able to modify timers on it. | 1369 | Having the API as <tt>lanes.timer()</tt> is intentional. Another alternative would be <tt>linda_h:timer()</tt> but timers are not traditionally seen to be part of Lindas. Also, it would mean any lane getting a Linda handle would be able to modify timers on it. |
1370 | A third choice could be abstracting the timers out of Linda realm altogether (<tt>timer_h= lanes.timer( date|first_secs, period_secs )</tt>) but that would mean separate waiting functions for timers, and lindas. | 1370 | A third choice could be abstracting the timers out of Linda realm altogether (<tt>timer_h= lanes.timer(date|first_secs, period_secs )</tt>) but that would mean separate waiting functions for timers, and lindas. |
1371 | Even if a linda object and key was returned, that key couldn't be waited upon simultaneously with one's general linda events. | 1371 | Even if a linda object and key was returned, that key couldn't be waited upon simultaneously with one's general linda events. |
1372 | The current system gives maximum capabilities with minimum API, and any smoothenings can easily be crafted in Lua at the application level. | 1372 | The current system gives maximum capabilities with minimum API, and any smoothenings can easily be crafted in Lua at the application level. |
1373 | </font> | 1373 | </font> |
@@ -1386,7 +1386,7 @@ events to a common Linda, but... :).</font> | |||
1386 | </p> | 1386 | </p> |
1387 | 1387 | ||
1388 | <table border="1" bgcolor="#E0E0FF" cellpadding="10" style="width:50%"><tr><td><pre> | 1388 | <table border="1" bgcolor="#E0E0FF" cellpadding="10" style="width:50%"><tr><td><pre> |
1389 | void = lanes.sleep( [seconds|false]) | 1389 | void = lanes.sleep([seconds|false]) |
1390 | </pre></td></tr></table> | 1390 | </pre></td></tr></table> |
1391 | 1391 | ||
1392 | <p> | 1392 | <p> |
@@ -1411,11 +1411,11 @@ events to a common Linda, but... :).</font> | |||
1411 | </p> | 1411 | </p> |
1412 | 1412 | ||
1413 | <table border="1" bgcolor="#E0E0FF" cellpadding="10" style="width:50%"><tr><td><pre> | 1413 | <table border="1" bgcolor="#E0E0FF" cellpadding="10" style="width:50%"><tr><td><pre> |
1414 | lock_func|lanes.cancel_error = lanes.genlock( linda_h, key [,N_uint=1]) | 1414 | lock_func|lanes.cancel_error = lanes.genlock(linda_h, key [,N_uint=1]) |
1415 | 1415 | ||
1416 | bool|lanes.cancel_error = lock_func( M_uint [, "try"] ) -- acquire | 1416 | bool|lanes.cancel_error = lock_func(M_uint [, "try"] ) -- acquire |
1417 | .. | 1417 | .. |
1418 | bool|lanes.cancel_error = lock_func( -M_uint) -- release | 1418 | bool|lanes.cancel_error = lock_func(-M_uint) -- release |
1419 | </pre></td></tr></table> | 1419 | </pre></td></tr></table> |
1420 | 1420 | ||
1421 | <p> | 1421 | <p> |
@@ -1437,9 +1437,9 @@ events to a common Linda, but... :).</font> | |||
1437 | <p> | 1437 | <p> |
1438 | 1438 | ||
1439 | <table border="1" bgcolor="#E0E0FF" cellpadding="10" style="width:50%"><tr><td><pre> | 1439 | <table border="1" bgcolor="#E0E0FF" cellpadding="10" style="width:50%"><tr><td><pre> |
1440 | atomic_func|lanes.cancel_error = lanes.genatomic( linda_h, key [,initial_num=0.0]) | 1440 | atomic_func|lanes.cancel_error = lanes.genatomic(linda_h, key [,initial_num=0.0]) |
1441 | 1441 | ||
1442 | new_num|lanes.cancel_error = atomic_func( [diff_num=+1.0]) | 1442 | new_num|lanes.cancel_error = atomic_func([diff_num=+1.0]) |
1443 | </pre></td></tr></table> | 1443 | </pre></td></tr></table> |
1444 | 1444 | ||
1445 | <p> | 1445 | <p> |
@@ -1505,14 +1505,14 @@ events to a common Linda, but... :).</font> | |||
1505 | 1505 | ||
1506 | <table border="1" bgcolor="#FFFFE0" cellpadding="10" style="width:50%"><tr><td><pre> | 1506 | <table border="1" bgcolor="#FFFFE0" cellpadding="10" style="width:50%"><tr><td><pre> |
1507 | // expects a C function on top of the source Lua stack | 1507 | // expects a C function on top of the source Lua stack |
1508 | copy_func( lua_State *dest, lua_State* source) | 1508 | copy_func(lua_State *dest, lua_State* source) |
1509 | { | 1509 | { |
1510 | // extract C function pointer from source | 1510 | // extract C function pointer from source |
1511 | lua_CFunction func = lua_tocfunction( source, -1); | 1511 | lua_CFunction func = lua_tocfunction(source, -1); |
1512 | // transfer upvalues | 1512 | // transfer upvalues |
1513 | int nup = transfer_upvalues( dest, source); | 1513 | int nup = transfer_upvalues(dest, source); |
1514 | // dest Lua stack contains a copy of all upvalues | 1514 | // dest Lua stack contains a copy of all upvalues |
1515 | lua_pushcfunction( dest, func, nup); | 1515 | lua_pushcfunction(dest, func, nup); |
1516 | } | 1516 | } |
1517 | </pre></td></tr></table> | 1517 | </pre></td></tr></table> |
1518 | 1518 | ||
@@ -1524,12 +1524,12 @@ events to a common Linda, but... :).</font> | |||
1524 | 1524 | ||
1525 | <table border="1" bgcolor="#FFFFE0" cellpadding="10" style="width:50%"><tr><td><pre> | 1525 | <table border="1" bgcolor="#FFFFE0" cellpadding="10" style="width:50%"><tr><td><pre> |
1526 | // expects a C function on top of the source Lua stack | 1526 | // expects a C function on top of the source Lua stack |
1527 | copy_func( lua_State *dest, lua_State* source) | 1527 | copy_func(lua_State *dest, lua_State* source) |
1528 | { | 1528 | { |
1529 | // fetch function 'name' from source lookup database | 1529 | // fetch function 'name' from source lookup database |
1530 | char const* funcname = lookup_func_name( source, -1); | 1530 | char const* funcname = lookup_func_name(source, -1); |
1531 | // lookup a function bound to this name in the destination state, and push it on the stack | 1531 | // lookup a function bound to this name in the destination state, and push it on the stack |
1532 | push_resolved_func( dest, funcname); | 1532 | push_resolved_func(dest, funcname); |
1533 | } | 1533 | } |
1534 | </pre></td></tr></table> | 1534 | </pre></td></tr></table> |
1535 | 1535 | ||
@@ -1590,7 +1590,7 @@ events to a common Linda, but... :).</font> | |||
1590 | </p> | 1590 | </p> |
1591 | 1591 | ||
1592 | <table border="1" bgcolor="#FFFFE0" cellpadding="10" style="width:50%"><tr><td><pre> | 1592 | <table border="1" bgcolor="#FFFFE0" cellpadding="10" style="width:50%"><tr><td><pre> |
1593 | int luaopen_module( lua_State *L ) | 1593 | int luaopen_module(lua_State *L ) |
1594 | { | 1594 | { |
1595 | static char been_here; /* 0 by ANSI C */ | 1595 | static char been_here; /* 0 by ANSI C */ |
1596 | 1596 | ||
@@ -1607,26 +1607,26 @@ events to a common Linda, but... :).</font> | |||
1607 | <h3 id="clonable_userdata">Clonable full userdata in your own apps</h3> | 1607 | <h3 id="clonable_userdata">Clonable full userdata in your own apps</h3> |
1608 | <p> | 1608 | <p> |
1609 | An alternative way of passing full userdata across lanes uses a new <tt>__lanesclone</tt> metamethod. | 1609 | An alternative way of passing full userdata across lanes uses a new <tt>__lanesclone</tt> metamethod. |
1610 | When a deep userdata is cloned, Lanes calls <tt>__lanesclone</tt> once, in the context of the source lane.</br> | 1610 | When a deep userdata is cloned, Lanes calls <tt>__lanesclone</tt> once, in the context of the source lane.<br/> |
1611 | The call receives the clone and original as light userdata, plus the actual userdata size, as in <tt>clone:__lanesclone(original,size)</tt>, and should perform the actual cloning.</br> | 1611 | The call receives the clone and original as light userdata, plus the actual userdata size, as in <tt>clone:__lanesclone(original,size)</tt>, and should perform the actual cloning.<br/> |
1612 | A typical implementation would look like: | 1612 | A typical implementation would look like: |
1613 | <table border="1" bgcolor="#FFFFE0" cellpadding="10" style="width:50%"><tr><td><pre> | 1613 | <table border="1" bgcolor="#FFFFE0" cellpadding="10" style="width:50%"><tr><td><pre> |
1614 | static int clonable_lanesclone( lua_State* L) | 1614 | static int clonable_lanesclone(lua_State* L) |
1615 | { | 1615 | { |
1616 | switch( lua_gettop( L)) | 1616 | switch(lua_gettop(L)) |
1617 | { | 1617 | { |
1618 | case 3: | 1618 | case 3: |
1619 | { | 1619 | { |
1620 | struct s_MyClonableUserdata* self = lua_touserdata( L, 1); | 1620 | struct s_MyClonableUserdata* self = lua_touserdata(L, 1); |
1621 | struct s_MyClonableUserdata* from = lua_touserdata( L, 2); | 1621 | struct s_MyClonableUserdata* from = lua_touserdata(L, 2); |
1622 | size_t len = lua_tointeger( L, 3); | 1622 | size_t len = lua_tointeger(L, 3); |
1623 | assert( len == sizeof(struct s_MyClonableUserdata)); | 1623 | assert(len == sizeof(struct s_MyClonableUserdata)); |
1624 | *self = *from; | 1624 | *self = *from; |
1625 | } | 1625 | } |
1626 | return 0; | 1626 | return 0; |
1627 | 1627 | ||
1628 | default: | 1628 | default: |
1629 | (void) luaL_error( L, "Lanes called clonable_lanesclone with unexpected parameters"); | 1629 | std::ignore = luaL_error(L, "Lanes called clonable_lanesclone with unexpected parameters"); |
1630 | } | 1630 | } |
1631 | return 0; | 1631 | return 0; |
1632 | } | 1632 | } |
@@ -1639,20 +1639,20 @@ static int clonable_lanesclone( lua_State* L) | |||
1639 | <table border="1" bgcolor="#FFFFE0" cellpadding="10" style="width:50%"><tr><td><pre> | 1639 | <table border="1" bgcolor="#FFFFE0" cellpadding="10" style="width:50%"><tr><td><pre> |
1640 | int luaopen_deep_test(lua_State* L) | 1640 | int luaopen_deep_test(lua_State* L) |
1641 | { | 1641 | { |
1642 | luaL_newlib( L, deep_module); | 1642 | luaL_newlib(L, deep_module); |
1643 | 1643 | ||
1644 | // preregister the metatables for the types we can instanciate so that Lanes can know about them | 1644 | // preregister the metatables for the types we can instanciate so that Lanes can know about them |
1645 | if( luaL_newmetatable( L, "clonable")) | 1645 | if (luaL_newmetatable(L, "clonable")) |
1646 | { | 1646 | { |
1647 | luaL_setfuncs( L, clonable_mt, 0); | 1647 | luaL_setfuncs(L, clonable_mt, 0); |
1648 | lua_pushvalue(L, -1); | 1648 | lua_pushvalue(L, -1); |
1649 | lua_setfield(L, -2, "__index"); | 1649 | lua_setfield(L, -2, "__index"); |
1650 | } | 1650 | } |
1651 | lua_setfield(L, -2, "__clonableMT"); // actual name is not important | 1651 | lua_setfield(L, -2, "__clonableMT"); // actual name is not important |
1652 | 1652 | ||
1653 | if( luaL_newmetatable( L, "deep")) | 1653 | if (luaL_newmetatable(L, "deep")) |
1654 | { | 1654 | { |
1655 | luaL_setfuncs( L, deep_mt, 0); | 1655 | luaL_setfuncs(L, deep_mt, 0); |
1656 | lua_pushvalue(L, -1); | 1656 | lua_pushvalue(L, -1); |
1657 | lua_setfield(L, -2, "__index"); | 1657 | lua_setfield(L, -2, "__index"); |
1658 | } | 1658 | } |
@@ -1666,10 +1666,10 @@ int luaopen_deep_test(lua_State* L) | |||
1666 | <p> | 1666 | <p> |
1667 | Then a new clonable userdata instance can just do like any non-Lanes aware userdata, as long as its metatable contains the aforementionned <tt>__lanesclone</tt> method. | 1667 | Then a new clonable userdata instance can just do like any non-Lanes aware userdata, as long as its metatable contains the aforementionned <tt>__lanesclone</tt> method. |
1668 | <table border="1" bgcolor="#FFFFE0" cellpadding="10" style="width:50%"><tr><td><pre> | 1668 | <table border="1" bgcolor="#FFFFE0" cellpadding="10" style="width:50%"><tr><td><pre> |
1669 | int luaD_new_clonable( lua_State* L) | 1669 | int luaD_new_clonable(lua_State* L) |
1670 | { | 1670 | { |
1671 | lua_newuserdata( L, sizeof( struct s_MyClonableUserdata)); | 1671 | lua_newuserdata(L, sizeof(struct s_MyClonableUserdata)); |
1672 | luaL_setmetatable( L, "clonable"); | 1672 | luaL_setmetatable(L, "clonable"); |
1673 | return 1; | 1673 | return 1; |
1674 | } | 1674 | } |
1675 | </pre></td></tr></table> | 1675 | </pre></td></tr></table> |
@@ -1684,7 +1684,7 @@ int luaD_new_clonable( lua_State* L) | |||
1684 | <ol> | 1684 | <ol> |
1685 | <li> | 1685 | <li> |
1686 | Provide an <i>identity function</i> for your userdata, in C. This function is used for creation and deletion of your deep userdata (the shared resource), and for making metatables for the state-specific proxies for accessing it. The prototype is | 1686 | Provide an <i>identity function</i> for your userdata, in C. This function is used for creation and deletion of your deep userdata (the shared resource), and for making metatables for the state-specific proxies for accessing it. The prototype is |
1687 | <table border="1" bgcolor="#E0E0FF" cellpadding="10" style="width:50%"><tr><td><pre> void* idfunc( lua_State* L, DeepOp op_);</pre></td></tr></table> | 1687 | <table border="1" bgcolor="#E0E0FF" cellpadding="10" style="width:50%"><tr><td><pre> void* idfunc(lua_State* L, DeepOp op_);</pre></td></tr></table> |
1688 | <tt>op_</tt> can be one of: | 1688 | <tt>op_</tt> can be one of: |
1689 | <ul> | 1689 | <ul> |
1690 | <li><tt>DeepOp::New</tt>: requests the creation of a new object, whose pointer is returned. Said object must derive from <tt>DeepPrelude</tt>.</li> | 1690 | <li><tt>DeepOp::New</tt>: requests the creation of a new object, whose pointer is returned. Said object must derive from <tt>DeepPrelude</tt>.</li> |
@@ -1735,8 +1735,8 @@ int luaD_new_clonable( lua_State* L) | |||
1735 | In multithreaded scenarios, giving multiple parameters to <tt>print()</tt> or <tt>file:write()</tt> may cause them to be overlapped in the output, something like this: | 1735 | In multithreaded scenarios, giving multiple parameters to <tt>print()</tt> or <tt>file:write()</tt> may cause them to be overlapped in the output, something like this: |
1736 | 1736 | ||
1737 | <table border="1" bgcolor="#FFFFE0" cellpadding="10" style="width:50%"><tr><td><pre> | 1737 | <table border="1" bgcolor="#FFFFE0" cellpadding="10" style="width:50%"><tr><td><pre> |
1738 | A: print( 1, 2, 3, 4 ) | 1738 | A: print(1, 2, 3, 4 ) |
1739 | B: print( 'a', 'b', 'c', 'd' ) | 1739 | B: print('a', 'b', 'c', 'd' ) |
1740 | 1740 | ||
1741 | 1 a b 2 3 c d 4 | 1741 | 1 a b 2 3 c d 4 |
1742 | </pre></td></tr></table> | 1742 | </pre></td></tr></table> |
@@ -1803,4 +1803,3 @@ int luaD_new_clonable( lua_State* L) | |||
1803 | 1803 | ||
1804 | </body> | 1804 | </body> |
1805 | </html> | 1805 | </html> |
1806 | </pre> \ No newline at end of file | ||
diff --git a/src/uniquekey.h b/src/uniquekey.h index e592f0a..a89ecd3 100644 --- a/src/uniquekey.h +++ b/src/uniquekey.h | |||
@@ -13,7 +13,7 @@ class UniqueKey | |||
13 | 13 | ||
14 | public: | 14 | public: |
15 | 15 | ||
16 | constexpr UniqueKey(uint64_t val_) | 16 | constexpr explicit UniqueKey(uint64_t val_) |
17 | #if LUAJIT_FLAVOR() == 64 // building against LuaJIT headers for 64 bits, light userdata is restricted to 47 significant bits, because LuaJIT uses the other bits for internal optimizations | 17 | #if LUAJIT_FLAVOR() == 64 // building against LuaJIT headers for 64 bits, light userdata is restricted to 47 significant bits, because LuaJIT uses the other bits for internal optimizations |
18 | : m_storage{ static_cast<uintptr_t>(val_ & 0x7fffffffffffull) } | 18 | : m_storage{ static_cast<uintptr_t>(val_ & 0x7fffffffffffull) } |
19 | #else // LUAJIT_FLAVOR() | 19 | #else // LUAJIT_FLAVOR() |