aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBenoit Germain <bnt.germain@gmail.com>2012-06-27 14:07:55 +0200
committerBenoit Germain <bnt.germain@gmail.com>2012-06-27 14:07:55 +0200
commit6234c2113a2b52ddc9fa900e7848f2cd19bd9394 (patch)
treedeb14fd69b53b863b825c954b50a58667e1bc19c
parentccd465a1c7c7257e85eb04fcc6767b38e794dbbe (diff)
downloadlanes-6234c2113a2b52ddc9fa900e7848f2cd19bd9394.tar.gz
lanes-6234c2113a2b52ddc9fa900e7848f2cd19bd9394.tar.bz2
lanes-6234c2113a2b52ddc9fa900e7848f2cd19bd9394.zip
* when a transfered function is not found in source, guess its name to help the user find out what's wrongv3.1.4
* new function lanes.nameof()
-rw-r--r--CHANGES4
-rw-r--r--docs/index.html111
-rw-r--r--src/lanes.c1
-rw-r--r--src/lanes.lua1
-rw-r--r--src/tools.c139
-rw-r--r--src/tools.h2
6 files changed, 146 insertions, 112 deletions
diff --git a/CHANGES b/CHANGES
index 52b0349..95e0e70 100644
--- a/CHANGES
+++ b/CHANGES
@@ -1,6 +1,10 @@
1 1
2CHANGES: 2CHANGES:
3 3
4CHANGE 40: BGe 26-Jun-2012
5 * when a transfered function is not found in source, guess its name to help the user find out what's wrong
6 * new function lanes.nameof()
7
4CHANGE 39: BGe 23-Jun-2012 8CHANGE 39: BGe 23-Jun-2012
5 * lanes.timer() accepts a first_secs=nil to stop a timer 9 * lanes.timer() accepts a first_secs=nil to stop a timer
6 * timer lane catches errors and prints them 10 * timer lane catches errors and prints them
diff --git a/docs/index.html b/docs/index.html
index 52ba852..2d1c78e 100644
--- a/docs/index.html
+++ b/docs/index.html
@@ -56,7 +56,7 @@
56 56
57<p><br/><font size="-1"><i>Copyright &copy; 2007-12 Asko Kauppi, Benoit Germain. All rights reserved.</i> 57<p><br/><font size="-1"><i>Copyright &copy; 2007-12 Asko Kauppi, Benoit Germain. All rights reserved.</i>
58 <br>Lua Lanes is published under the same <A HREF="http://en.wikipedia.org/wiki/MIT_License">MIT license</A> as Lua 5.1. 58 <br>Lua Lanes is published under the same <A HREF="http://en.wikipedia.org/wiki/MIT_License">MIT license</A> as Lua 5.1.
59 </p><p>This document was revised on 23-Jun-12, and applies to version 3.1.4 59 </p><p>This document was revised on 26-Jun-12, and applies to version 3.1.4
60</font></p> 60</font></p>
61 61
62</center> 62</center>
@@ -360,6 +360,17 @@ also in the new lanes.
360 <p>Each lane also gets a function <tt>set_debug_threadname()</tt> that it can use anytime to do as the name says. 360 <p>Each lane also gets a function <tt>set_debug_threadname()</tt> that it can use anytime to do as the name says.
361Supported debuggers are Microsoft Visual Studio (for the C side) and Decoda (for the Lua side). 361Supported debuggers are Microsoft Visual Studio (for the C side) and Decoda (for the Lua side).
362</p> 362</p>
363 <p>
364 If a lane body pulls a C function imported by a module required before Lanes itself (thus not through a hooked <tt>require</tt>), the lane generator creation will raise an error.
365 The function name it shows is a path where it was found by scanning _G. As a utility, the name guessing functionality is exposed as such:
366<table border="1" bgcolor="#E0E0FF" cellpadding="10">
367 <tr>
368 <td>
369 <code>
370 "type", "name" = lanes.nameof( o)
371 </code>
372 </table>
373</p>
363 374
364<h3>Free running lanes</h3> 375<h3>Free running lanes</h3>
365 376
@@ -1089,103 +1100,7 @@ its actual value.
1089<h2 id="changes">Change log</h2> 1100<h2 id="changes">Change log</h2>
1090 1101
1091<p> 1102<p>
1092 Apr-2012 1103 See CHANGES.
1093 <ul>
1094 <li>improved LuaJIT2 compatibility by handling "*" library set through luaL_openlibs().</li>
1095 </ul>
1096
1097
1098 Feb-2012
1099 <ul>
1100 <li>Added support for an on_state_create callback invoked on a pristine Lua state created by Lanes.</li>
1101 <li>This required a change in the <tt>lanes.configure()</tt> signature, hence the minor version bump.</li>
1102 </ul>
1103
1104
1105 Nov-2011
1106 <ul>
1107 <li>process exit change: close everything at GC when main state closes, not when atexit() handlers are processed</li>
1108 <li>Lua 5.2-style module:</li>
1109 <ul>
1110 <li>module() is no longer used to implement lanes.lua</li>
1111 <li>a global "lanes" variable is no longer created when the module is required</li>
1112 <li>the Lanes module table is returned instead</li>
1113 </ul>
1114 <li>Lanes must be initialized before used:</li>
1115 <ul>
1116 <li>the first occurence of 'require "lanes"' produces a minimal interface that only contains a configure() function</li>
1117 <li>the remainder of the interface is made available once this function is called</li>
1118 <li>subsequent calls to configure() do nothing</li>
1119 <li>configure() controls the number of keeper states and the startup of timers</li>
1120 </ul>
1121 <li>* LuaJIT 2 compatibility</li>
1122 <ul>
1123 <li>non-Lua functions are no longer copied by creating a C closure from a C pointer, but through 2-way lookup tables</li>
1124 <li>this means that if a lane function body pulls non-Lua functions, the lane generator description must contain the list of libraries and modules that exports them</li>
1125 <li>introduces a change in configuration .globals management: contents are copied *after* std libs are loaded</li>
1126 <li>new .required configuration entry to list modules that must be require()'ed before lane body is transferred</li>
1127 </ul>
1128 <li>lane:cancel() wakes up waiting lindas like what is done at lane shutdown</li>
1129 <li>removed packagepath and packagecpath options, replaced by a package table, whose fields path, cpath, loaders, preload are transfered</li>
1130 </ul>
1131
1132 Mar-2011 (not yet versioned)
1133 <ul>
1134 <li>linda honors __tostring and __concat</li>
1135 <li>new accessor linda:count(), to get info about data stored inside a linda.</li>
1136 <li>new lanes options packagepath and packagecpath, in case one needs to set them differently than the default.</li>
1137 </ul>
1138
1139 Mar-2011 (2.1.0)
1140 <ul>
1141 <li>fixed potential crash at application shutdown when calling lua_close() on a killed thread's VM.</li>
1142 <li>exposed cancel_test() in the lanes to enable manual testing for cancellation requests.</li>
1143 <li>removed kludgy {globals={threadName}} support, replaced with a new function set_debug_threadname().</li>
1144</ul>
1145Feb-2011 (2.0.11):
1146 <ul>
1147 <li>Fixed bug where reference to Linda object was dropped for a short time (crashing if GC was run during that time).</li>
1148 <li>Changed the atexit code to trip the timer thread's write signal.</li>
1149 <li>Changed lanes.c to export functions as a module rather than writing them directly to the globals table.</li>
1150</ul>
1151
1152Jan-2011 (2.0.10):
1153<ul>
1154 <li>linda_send was waiting on the wrong signal</li>
1155 <li>buildfix when using i586-mingw32msvc-gcc cross compiler</li>
1156 <li>lanes_h:cancel() returns a boolean as it should</li>
1157 <li>timers could get blocked sometimes because they were initialized with negative values</li>
1158 <li>prepare_timeout could generate an illegal setting</li>
1159</ul>
1160
1161Dec-2010 (2.0.9):
1162<ul>
1163 <li>Fixed 'memory leak' in some situations where a free running lane is collected before application shutdown</li>
1164 <li>Fix LuaJIT2 incompatibility (no 'tostring' hijack anymore)</li>
1165 <li>Added support to generate a lane from a string</li>
1166</ul>
1167
1168Aug-2010 (2.0.6):
1169<ul>
1170<li>Fixed some memory leaks</li>
1171<li>Fixed error in passing parameters to finalizers</li>
1172<li>Fixed missing argument propagation in lane:cancel</li>
1173<li>Added thread name debugging in VS</li>
1174</ul>
1175
1176Jan-2009 (2.0.3):
1177<ul>
1178 <li>Added 'finalizer' to lane options. (TBD: not implemented yet!)
1179 </li>
1180 <li>Added call stack to errors coming from a lane.
1181 </li>
1182</ul>
1183
1184Jul-2008 (2.0):
1185<ul>
1186 <li>Too many changes to list (you'll need to re-read this manual)
1187 </li>
1188</ul>
1189</p> 1104</p>
1190 1105
1191<!-- footnotes +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ --> 1106<!-- footnotes +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -->
diff --git a/src/lanes.c b/src/lanes.c
index eebe06a..3e906c0 100644
--- a/src/lanes.c
+++ b/src/lanes.c
@@ -2303,6 +2303,7 @@ static const struct luaL_reg lanes_functions [] = {
2303 {"linda", LG_linda}, 2303 {"linda", LG_linda},
2304 {"now_secs", LG_now_secs}, 2304 {"now_secs", LG_now_secs},
2305 {"wakeup_conv", LG_wakeup_conv}, 2305 {"wakeup_conv", LG_wakeup_conv},
2306 {"nameof", luaG_nameof},
2306 {"_single", LG__single}, 2307 {"_single", LG__single},
2307 {NULL, NULL} 2308 {NULL, NULL}
2308}; 2309};
diff --git a/src/lanes.lua b/src/lanes.lua
index 5aeeaf4..d1082af 100644
--- a/src/lanes.lua
+++ b/src/lanes.lua
@@ -564,6 +564,7 @@ end
564 lanes.gen = gen 564 lanes.gen = gen
565 lanes.linda = mm.linda 565 lanes.linda = mm.linda
566 lanes.cancel_error = mm.cancel_error 566 lanes.cancel_error = mm.cancel_error
567 lanes.nameof = mm.nameof
567 lanes.timer = timer 568 lanes.timer = timer
568 lanes.genlock = genlock 569 lanes.genlock = genlock
569 lanes.genatomic = genatomic 570 lanes.genatomic = genatomic
diff --git a/src/tools.c b/src/tools.c
index ee2a1ca..65c70bf 100644
--- a/src/tools.c
+++ b/src/tools.c
@@ -1200,38 +1200,149 @@ static void push_cached_func( lua_State *L2, uint_t L2_cache_i, lua_State *L, ui
1200} 1200}
1201 1201
1202/* 1202/*
1203 * Return some name helping to identify an object
1204 */
1205int discover_object_name_recur( lua_State* L, int _shortest, int _length)
1206{
1207 int const what = 1; // o "r" {c} {fqn} ... {?}
1208 int const result = 2;
1209 int const cache = 3;
1210 int const fqn = 4;
1211 // no need to scan this table if the name we will discover is longer than one we already know
1212 if( _shortest <= _length + 1)
1213 {
1214 return _shortest;
1215 }
1216 STACK_GROW( L, 3);
1217 STACK_CHECK(L)
1218 // stack top contains the table to search in
1219 lua_pushvalue( L, -1); // o "r" {c} {fqn} ... {?} {?}
1220 lua_rawget( L, cache); // o "r" {c} {fqn} ... {?} nil/1
1221 // if table is already visited, we are done
1222 if( !lua_isnil( L, -1))
1223 {
1224 lua_pop( L, 1); // o "r" {c} {fqn} ... {?}
1225 return _shortest;
1226 }
1227 // examined table is not in the cache, add it now
1228 lua_pop( L, 1); // o "r" {c} {fqn} ... {?}
1229 lua_pushvalue( L, -1); // o "r" {c} {fqn} ... {?} {?}
1230 lua_pushinteger( L, 1); // o "r" {c} {fqn} ... {?} {?} 1
1231 lua_rawset( L, cache); // o "r" {c} {fqn} ... {?}
1232 // scan table contents
1233 lua_pushnil( L); // o "r" {c} {fqn} ... {?} nil
1234 while( lua_next( L, -2)) // o "r" {c} {fqn} ... {?} k v
1235 {
1236 //char const *const key = lua_tostring( L, -2); // only for debugging (BEWARE, IT MAY CHANGE THE VALUE IF IT IS CONVERTIBLE, AND WRECK THE LOOP ITERATION PROCESS!)
1237 // append key name to fqn stack
1238 ++ _length;
1239 lua_pushvalue( L, -2); // o "r" {c} {fqn} ... {?} k v k
1240 lua_rawseti( L, fqn, _length); // o "r" {c} {fqn} ... {?} k v
1241 if( lua_rawequal( L, -1, what)) // is it what we are looking for?
1242 {
1243 // update shortest name
1244 if( _length < _shortest)
1245 {
1246 _shortest = _length;
1247 luaG_pushFQN( L, fqn, _length); // o "r" {c} {fqn} ... {?} k v "fqn"
1248 lua_replace( L, result); // o "r" {c} {fqn} ... {?} k v
1249 }
1250 // no need to search further at this level
1251 lua_pop( L, 2); // o "r" {c} {fqn} ... {?}
1252 break;
1253 }
1254 else if( lua_istable( L, -1))
1255 {
1256 _shortest = discover_object_name_recur( L, _shortest, _length);
1257 }
1258 // make ready for next iteration
1259 lua_pop( L, 1); // o "r" {c} {fqn} ... {?} k
1260 // remove name from fqn stack
1261 lua_pushnil( L); // o "r" {c} {fqn} ... {?} k nil
1262 lua_rawseti( L, fqn, _length); // o "r" {c} {fqn} ... {?} k
1263 -- _length;
1264 } // o "r" {c} {fqn} ... {?}
1265 // remove the visited table from the cache, in case a shorter path to the searched object exists
1266 lua_pushvalue( L, -1); // o "r" {c} {fqn} ... {?} {?}
1267 lua_pushnil( L); // o "r" {c} {fqn} ... {?} {?} nil
1268 lua_rawset( L, cache); // o "r" {c} {fqn} ... {?}
1269 STACK_END( L, 0)
1270 return _shortest;
1271}
1272
1273/*
1274 * "type", "name" = lanes.nameof( o)
1275 */
1276int luaG_nameof( lua_State* L)
1277{
1278 int what = lua_gettop( L);
1279 if( what > 1)
1280 {
1281 luaL_argerror( L, what, "too many arguments.");
1282 }
1283
1284 // numbers, strings, booleans and nil can't be identified
1285 if( lua_type( L, 1) < LUA_TTABLE)
1286 {
1287 lua_pushstring( L, luaL_typename( L, 1)); // o "type"
1288 lua_insert( L, -2); // "type" o
1289 return 2;
1290 }
1291 STACK_GROW( L, 4);
1292 // this slot will contain the shortest name we found when we are done
1293 lua_pushnil( L); // o nil
1294 // push a cache that will contain all already visited tables
1295 lua_newtable( L); // o nil {c}
1296 // push a table whose contents are strings that, when concatenated, produce unique name
1297 lua_newtable( L); // o nil {c} {fqn}
1298 // this is where we start the search
1299 lua_pushvalue( L, LUA_GLOBALSINDEX); // o nil {c} {fqn} _G
1300 (void) discover_object_name_recur( L, 6666, 0);
1301 lua_pop( L, 3); // o "result"
1302 lua_pushstring( L, luaL_typename( L, 1)); // o "result" "type"
1303 lua_replace( L, -3); // "type" "result"
1304 return 2;
1305}
1306
1307/*
1203* Push a looked-up native/LuaJIT function. 1308* Push a looked-up native/LuaJIT function.
1204*/ 1309*/
1205static void lookup_native_func( lua_State *L2, lua_State *L, uint_t i) 1310static void lookup_native_func( lua_State *L2, lua_State *L, uint_t i)
1206{ 1311{
1207 char const *fqn; 1312 char const *fqn; // L // L2
1208 size_t len; 1313 size_t len;
1209 _ASSERT_L( L, lua_isfunction( L, i)); 1314 _ASSERT_L( L, lua_isfunction( L, i)); // ... f ...
1210 STACK_CHECK( L) 1315 STACK_CHECK( L)
1211 STACK_CHECK( L2)
1212 // fetch the name from the source state's lookup table 1316 // fetch the name from the source state's lookup table
1213 lua_getfield( L, LUA_REGISTRYINDEX, LOOKUP_KEY); // {} 1317 lua_getfield( L, LUA_REGISTRYINDEX, LOOKUP_KEY); // ... f ... {}
1214 _ASSERT_L( L, lua_istable( L, -1)); 1318 _ASSERT_L( L, lua_istable( L, -1));
1215 lua_pushvalue( L, i); // {} f 1319 lua_pushvalue( L, i); // ... f ... {} f
1216 lua_rawget( L, -2); // {} "f.q.n" 1320 lua_rawget( L, -2); // ... f ... {} "f.q.n"
1217 fqn = lua_tolstring( L, -1, &len); 1321 fqn = lua_tolstring( L, -1, &len);
1322 // popping doesn't invalidate the pointer since this is an interned string gotten from the lookup database
1323 lua_pop( L, 2); // ... f ...
1218 if( !fqn) 1324 if( !fqn)
1219 { 1325 {
1220 luaL_error( L, "function not found in origin transfer database."); 1326 lua_pushvalue( L, i); // ... f ... f
1327 // try to discover the name of the function we want to send
1328 luaG_nameof( L); // ... f ... "type" "name"
1329 (void) luaL_error( L, "%s %s not found in origin transfer database.", lua_tostring( L, -2), lua_tostring( L, -1));
1330 return;
1221 } 1331 }
1332 STACK_END( L, 0)
1222 // push the equivalent function in the destination's stack, retrieved from the lookup table 1333 // push the equivalent function in the destination's stack, retrieved from the lookup table
1223 lua_getfield( L2, LUA_REGISTRYINDEX, LOOKUP_KEY); // {} 1334 STACK_CHECK( L2)
1335 lua_getfield( L2, LUA_REGISTRYINDEX, LOOKUP_KEY); // {}
1224 _ASSERT_L( L2, lua_istable( L2, -1)); 1336 _ASSERT_L( L2, lua_istable( L2, -1));
1225 lua_pushlstring( L2, fqn, len); // {} "f.q.n" 1337 lua_pushlstring( L2, fqn, len); // {} "f.q.n"
1226 lua_pop( L, 2); // 1338 lua_rawget( L2, -2); // {} f
1227 lua_rawget( L2, -2); // {} f
1228 if( !lua_isfunction( L2, -1)) 1339 if( !lua_isfunction( L2, -1))
1229 { 1340 {
1230 luaL_error( L, "function %s not found in destination transfer database.", fqn); 1341 (void) luaL_error( L, "function %s not found in destination transfer database.", fqn);
1342 return;
1231 } 1343 }
1232 lua_remove( L2, -2); // f 1344 lua_remove( L2, -2); // f
1233 STACK_END( L2, 1) 1345 STACK_END( L2, 1)
1234 STACK_END( L, 0)
1235} 1346}
1236 1347
1237#define LOG_FUNC_INFO 0 1348#define LOG_FUNC_INFO 0
diff --git a/src/tools.h b/src/tools.h
index 67f9874..b8dc362 100644
--- a/src/tools.h
+++ b/src/tools.h
@@ -65,6 +65,8 @@ void luaG_push_proxy( lua_State *L, luaG_IdFunction idfunc, DEEP_PRELUDE *deep_u
65int luaG_inter_copy( lua_State *L, lua_State *L2, uint_t n); 65int luaG_inter_copy( lua_State *L, lua_State *L2, uint_t n);
66int luaG_inter_move( lua_State *L, lua_State *L2, uint_t n); 66int luaG_inter_move( lua_State *L, lua_State *L2, uint_t n);
67 67
68int luaG_nameof( lua_State* L);
69
68// Lock for reference counter inc/dec locks (to be initialized by outside code) 70// Lock for reference counter inc/dec locks (to be initialized by outside code)
69// 71//
70extern MUTEX_T deep_lock; 72extern MUTEX_T deep_lock;