aboutsummaryrefslogtreecommitdiff
path: root/src/lanes.c
diff options
context:
space:
mode:
authorBenoit Germain <b n t DOT g e r m a i n AT g m a i l DOT c o m>2013-10-22 19:11:57 +0200
committerBenoit Germain <b n t DOT g e r m a i n AT g m a i l DOT c o m>2013-10-22 19:11:57 +0200
commit162a8ed6d5abf8bb1e36a4f5794073f7870fd20c (patch)
tree1de1ff5e19d4cd0a34b41498194424bea61ea769 /src/lanes.c
parent44540b9335f3bbd2f6fda3e13329b28ec76b6d7a (diff)
downloadlanes-162a8ed6d5abf8bb1e36a4f5794073f7870fd20c.tar.gz
lanes-162a8ed6d5abf8bb1e36a4f5794073f7870fd20c.tar.bz2
lanes-162a8ed6d5abf8bb1e36a4f5794073f7870fd20c.zip
errors inside finalizers generate a full stack just like any other error
Diffstat (limited to 'src/lanes.c')
-rw-r--r--src/lanes.c160
1 files changed, 88 insertions, 72 deletions
diff --git a/src/lanes.c b/src/lanes.c
index 3a3cdf0..1c65614 100644
--- a/src/lanes.c
+++ b/src/lanes.c
@@ -52,7 +52,7 @@
52 * ... 52 * ...
53 */ 53 */
54 54
55char const* VERSION = "3.7.0"; 55char const* VERSION = "3.7.1";
56 56
57/* 57/*
58=============================================================================== 58===============================================================================
@@ -113,7 +113,7 @@ THE SOFTWARE.
113* 113*
114* TBD: The full stack feature does not seem to work (try 'make error'). 114* TBD: The full stack feature does not seem to work (try 'make error').
115*/ 115*/
116#define ERROR_FULL_STACK 116#define ERROR_FULL_STACK 1 // must be either 0 or 1 as we do some index arithmetics with it!
117 117
118/* 118/*
119 * Lane cancellation request modes 119 * Lane cancellation request modes
@@ -195,6 +195,11 @@ static void cancel_error( lua_State*L );
195#define CANCEL_TEST_KEY ((void*)cancel_test) // used as registry key 195#define CANCEL_TEST_KEY ((void*)cancel_test) // used as registry key
196#define CANCEL_ERROR ((void*)cancel_error) // 'cancel_error' sentinel 196#define CANCEL_ERROR ((void*)cancel_error) // 'cancel_error' sentinel
197 197
198#if ERROR_FULL_STACK
199static int lane_error( lua_State* L);
200#define STACK_TRACE_KEY ((void*)lane_error) // used as registry key
201#endif // ERROR_FULL_STACK
202
198/* 203/*
199* registry[FINALIZER_REG_KEY] is either nil (no finalizers) or a table 204* registry[FINALIZER_REG_KEY] is either nil (no finalizers) or a table
200* of functions that Lanes will call after the executing 'pcall' has ended. 205* of functions that Lanes will call after the executing 'pcall' has ended.
@@ -1084,7 +1089,7 @@ LUAG_FUNC( set_finalizer )
1084//--- 1089//---
1085// Run finalizers - if any - with the given parameters 1090// Run finalizers - if any - with the given parameters
1086// 1091//
1087// If 'rc' is nonzero, error message and stack index are available as: 1092// If 'rc' is nonzero, error message and stack index (the latter only when ERROR_FULL_STACK == 1) are available as:
1088// [-1]: stack trace (table) 1093// [-1]: stack trace (table)
1089// [-2]: error message (any type) 1094// [-2]: error message (any type)
1090// 1095//
@@ -1094,56 +1099,70 @@ LUAG_FUNC( set_finalizer )
1094// 1099//
1095// TBD: should we add stack trace on failing finalizer, wouldn't be hard.. 1100// TBD: should we add stack trace on failing finalizer, wouldn't be hard..
1096// 1101//
1097static int run_finalizers( lua_State*L, int lua_rc ) 1102static int run_finalizers( lua_State* L, int lua_rc)
1098{ 1103{
1099 unsigned error_index, tbl_index; 1104 int error_index, finalizers_index;
1100 unsigned n; 1105 int n;
1101 int rc= 0; 1106 int err_handler_index = 0;
1102 1107 int rc = 0; // [err_msg {stack_trace}]?
1103 if (!push_registry_table(L, FINALIZER_REG_KEY, FALSE /*don't create one*/))
1104 return 0; // no finalizers
1105 1108
1106 tbl_index= lua_gettop(L); 1109 if( !push_registry_table( L, FINALIZER_REG_KEY, FALSE)) // [err_msg {stack_trace}]? {func [, ...]}?
1107 error_index= (lua_rc!=0) ? tbl_index-2 : 0; // absolute indices 1110 {
1111 return 0; // no finalizers
1112 }
1108 1113
1109 STACK_GROW(L,4); 1114 STACK_GROW( L, 5);
1110 1115
1111 // [-1]: { func [, ...] } 1116 finalizers_index = lua_gettop( L);
1112 //
1113 for( n = (unsigned int)lua_rawlen( L, -1); n > 0; -- n)
1114 {
1115 unsigned args= 0;
1116 lua_pushinteger( L,n );
1117 lua_gettable( L, -2 );
1118
1119 // [-1]: function
1120 // [-2]: finalizers table
1121 1117
1122 if (error_index) { 1118#if ERROR_FULL_STACK
1123 lua_pushvalue( L, error_index ); 1119 lua_pushcfunction( L, lane_error); // [err_msg {stack_trace}]? {func [, ...]}? lane_error
1124 lua_pushvalue( L, error_index+1 ); // stack trace 1120 err_handler_index = lua_gettop( L);
1125 args= 2; 1121#endif // ERROR_FULL_STACK
1126 } 1122 error_index = (lua_rc != LUA_OK) ? finalizers_index - (1 + ERROR_FULL_STACK) : 0;
1127 1123
1128 rc= lua_pcall( L, args, 0 /*retvals*/, 0 /*no errfunc*/ ); 1124 for( n = lua_rawlen( L, finalizers_index); n > 0; -- n)
1129 // 1125 {
1130 // LUA_ERRRUN / LUA_ERRMEM 1126 int args = 0;
1131 1127 lua_pushinteger( L, n); // [err_msg {stack_trace}]? {func [, ...]}? lane_error n
1132 if( rc != LUA_OK) 1128 lua_gettable( L, finalizers_index); // [err_msg {stack_trace}]? {func [, ...]}? lane_error finalizer
1133 { 1129 ASSERT_L( lua_isfunction( L, -1));
1134 // [-1]: error message 1130 if( error_index)
1135 // 1131 {
1136 // If one finalizer fails, don't run the others. Return this 1132 char const* err_msg = lua_tostring( L, error_index);
1137 // as the 'real' error, preceding that we could have had (or not) 1133 lua_pushvalue( L, error_index); // [err_msg {stack_trace}]? {func [, ...]}? lane_error finalizer err_msg
1138 // from the actual code. 1134#if ERROR_FULL_STACK
1139 // 1135 lua_pushvalue( L, error_index + 1); // [err_msg {stack_trace}]? {func [, ...]}? lane_error finalizer err_msg {stack_trace}
1140 break; 1136#endif // ERROR_FULL_STACK
1141 } 1137 args = 1 + ERROR_FULL_STACK;
1142 } 1138 }
1143 1139
1144 lua_remove(L,tbl_index); // take finalizer table out of stack 1140 rc = lua_pcall( L, args, 0, err_handler_index); // [err_msg {stack_trace}]? {func [, ...]}? lane_error err_msg2?
1141 //
1142 // LUA_ERRRUN / LUA_ERRMEM
1143
1144 if( rc != LUA_OK)
1145 {
1146#if ERROR_FULL_STACK
1147 lua_pushlightuserdata( L, STACK_TRACE_KEY); // [err_msg {stack_trace}]? {func [, ...]}? lane_error err_msg2 STACK_TRACE_KEY
1148 lua_gettable( L, LUA_REGISTRYINDEX); // [err_msg {stack_trace}]? {func [, ...]}? lane_error err_msg2 {stack_trace2}
1149#endif // ERROR_FULL_STACK
1145 1150
1146 return rc; 1151 // If one finalizer fails, don't run the others. Return this
1152 // as the 'real' error, replacing what we could have had (or not)
1153 // from the actual code.
1154 //
1155 break;
1156 }
1157 }
1158
1159 // remove error handler function (if any) and finalizers table from the stack
1160#if ERROR_FULL_STACK
1161 lua_remove( L, err_handler_index); // [err_msg {stack_trace}]? {func [, ...]}? err_msg2 {stack_trace2}
1162#endif // ERROR_FULL_STACK
1163 lua_remove( L, finalizers_index); // [err_msg {stack_trace}]? err_msg2 {stack_trace2}
1164
1165 return rc;
1147} 1166}
1148 1167
1149/* 1168/*
@@ -1577,9 +1596,8 @@ LUAG_FUNC( set_singlethreaded)
1577* implement a Lanes-specific 'pcall' of our own that does this). TBD!!! :) 1596* implement a Lanes-specific 'pcall' of our own that does this). TBD!!! :)
1578* --AKa 22-Jan-2009 1597* --AKa 22-Jan-2009
1579*/ 1598*/
1580#ifdef ERROR_FULL_STACK 1599#if ERROR_FULL_STACK
1581 1600
1582# define STACK_TRACE_KEY ((void*)lane_error) // used as registry key
1583# define EXTENDED_STACK_TRACE_KEY ((void*)LG_set_error_reporting) // used as registry key 1601# define EXTENDED_STACK_TRACE_KEY ((void*)LG_set_error_reporting) // used as registry key
1584 1602
1585LUAG_FUNC( set_error_reporting) 1603LUAG_FUNC( set_error_reporting)
@@ -1619,10 +1637,10 @@ static int lane_error( lua_State* L)
1619 1637
1620 // Don't do stack survey for cancelled lanes. 1638 // Don't do stack survey for cancelled lanes.
1621 // 1639 //
1622#if 1
1623 if( lua_touserdata( L, 1) == CANCEL_ERROR) 1640 if( lua_touserdata( L, 1) == CANCEL_ERROR)
1641 {
1624 return 1; // just pass on 1642 return 1; // just pass on
1625#endif 1643 }
1626 1644
1627 lua_pushlightuserdata( L, EXTENDED_STACK_TRACE_KEY); 1645 lua_pushlightuserdata( L, EXTENDED_STACK_TRACE_KEY);
1628 lua_gettable( L, LUA_REGISTRYINDEX); 1646 lua_gettable( L, LUA_REGISTRYINDEX);
@@ -1681,7 +1699,7 @@ static int lane_error( lua_State* L)
1681 } 1699 }
1682 1700
1683 lua_pushlightuserdata( L, STACK_TRACE_KEY); 1701 lua_pushlightuserdata( L, STACK_TRACE_KEY);
1684 lua_insert( L ,-2); 1702 lua_insert( L, -2);
1685 lua_settable( L, LUA_REGISTRYINDEX); 1703 lua_settable( L, LUA_REGISTRYINDEX);
1686 1704
1687 assert( lua_gettop( L) == 1); 1705 assert( lua_gettop( L) == 1);
@@ -1771,7 +1789,7 @@ static THREAD_RETURN_T THREAD_CALLCONV lane_main( void *vs)
1771 lua_pushcfunction( L, LG_cancel_test); 1789 lua_pushcfunction( L, LG_cancel_test);
1772 lua_setglobal( L, "cancel_test"); 1790 lua_setglobal( L, "cancel_test");
1773 1791
1774#ifdef ERROR_FULL_STACK 1792#if ERROR_FULL_STACK
1775 // Tie "set_error_reporting()" to the state 1793 // Tie "set_error_reporting()" to the state
1776 // 1794 //
1777 lua_pushcfunction( L, LG_set_error_reporting); 1795 lua_pushcfunction( L, LG_set_error_reporting);
@@ -1810,17 +1828,17 @@ static THREAD_RETURN_T THREAD_CALLCONV lane_main( void *vs)
1810 // it through to the master. 1828 // it through to the master.
1811 } 1829 }
1812 1830
1813#else 1831#else // ERROR_FULL_STACK == 0
1814 // This code does not use 'lane_error' 1832 // This code does not use 'lane_error'
1815 // 1833 //
1816 // [1]: function to run 1834 // [1]: function to run
1817 // [2..top]: parameters 1835 // [2..top]: parameters
1818 // 1836 //
1819 rc= lua_pcall( L, lua_gettop(L)-1, LUA_MULTRET, 0 /*no error handler*/ ); 1837 rc = lua_pcall( L, lua_gettop( L) - 1, LUA_MULTRET, 0); // no error handler
1820 // LUA_OK(0): no error 1838 // LUA_OK(0): no error
1821 // LUA_ERRRUN(2): a runtime error (error pushed on stack) 1839 // LUA_ERRRUN(2): a runtime error (error pushed on stack)
1822 // LUA_ERRMEM(4): memory allocation error 1840 // LUA_ERRMEM(4): memory allocation error
1823#endif 1841#endif // ERROR_FULL_STACK
1824 1842
1825 DEBUGSPEW_CODE( fprintf( stderr, INDENT_BEGIN "Lane %p body: %s (%s)\n" INDENT_END, L, get_errcode_name( rc), (lua_touserdata(L,1)==CANCEL_ERROR) ? "cancelled" : lua_typename( L, lua_type( L, 1)))); 1843 DEBUGSPEW_CODE( fprintf( stderr, INDENT_BEGIN "Lane %p body: %s (%s)\n" INDENT_END, L, get_errcode_name( rc), (lua_touserdata(L,1)==CANCEL_ERROR) ? "cancelled" : lua_typename( L, lua_type( L, 1))));
1826 //STACK_DUMP(L); 1844 //STACK_DUMP(L);
@@ -1828,21 +1846,19 @@ static THREAD_RETURN_T THREAD_CALLCONV lane_main( void *vs)
1828 // 1846 //
1829 rc2 = run_finalizers( L, rc); 1847 rc2 = run_finalizers( L, rc);
1830 DEBUGSPEW_CODE( fprintf( stderr, INDENT_BEGIN "Lane %p finalizer: %s\n" INDENT_END, L, get_errcode_name( rc2))); 1848 DEBUGSPEW_CODE( fprintf( stderr, INDENT_BEGIN "Lane %p finalizer: %s\n" INDENT_END, L, get_errcode_name( rc2)));
1831 if( rc2 != LUA_OK) 1849 if( rc2 != LUA_OK) // Error within a finalizer!
1832 { 1850 {
1833 // Error within a finalizer! 1851 rc = rc2; // we're overruling the earlier script error or normal return
1834 // 1852 // the finalizer generated an error, the error message [and stack trace] are pushed on the stack
1835 // [-1]: error message 1853 // remove the rest so that only the error message [and stack trace] remain on the stack
1836 1854#if ERROR_FULL_STACK
1837 rc= rc2; // we're overruling the earlier script error or normal return 1855 lua_insert( L, 1);
1838 1856 lua_insert( L, 1);
1839 lua_insert( L,1 ); // make error message [1] 1857 lua_settop( L, 2);
1840 lua_settop( L,1 ); // remove all rest 1858#else // ERROR_FULL_STACK == 0
1841 1859 lua_insert( L, 1);
1842 // Place an empty stack table just to keep the API simple (always when 1860 lua_settop( L, 1);
1843 // there's an error, there's also stack table - though it may be empty). 1861#endif // ERROR_FULL_STACK
1844 //
1845 lua_newtable(L);
1846 } 1862 }
1847 s->waiting_on = NULL; // just in case 1863 s->waiting_on = NULL; // just in case
1848 if( selfdestruct_remove( s)) // check and remove (under lock!) 1864 if( selfdestruct_remove( s)) // check and remove (under lock!)
@@ -2317,7 +2333,7 @@ static int push_thread_status( lua_State*L, struct s_lane *s)
2317// 2333//
2318// timeout: returns nil 2334// timeout: returns nil
2319// done: returns return values (0..N) 2335// done: returns return values (0..N)
2320// error: returns nil + error value + stack table 2336// error: returns nil + error value [+ stack table]
2321// cancelled: returns nil 2337// cancelled: returns nil
2322// 2338//
2323LUAG_FUNC( thread_join) 2339LUAG_FUNC( thread_join)
@@ -2361,11 +2377,11 @@ LUAG_FUNC( thread_join)
2361 2377
2362 case ERROR_ST: 2378 case ERROR_ST:
2363 lua_pushnil( L); 2379 lua_pushnil( L);
2364 if( luaG_inter_move( L2, L, 2, eLM_LaneBody) != 0) // error message at [-2], stack trace at [-1] 2380 if( luaG_inter_move( L2, L, 1 + ERROR_FULL_STACK, eLM_LaneBody) != 0) // error message at [-2], stack trace at [-1]
2365 { 2381 {
2366 return luaL_error( L, "tried to copy unsupported types"); 2382 return luaL_error( L, "tried to copy unsupported types");
2367 } 2383 }
2368 ret= 3; 2384 ret = 2 + ERROR_FULL_STACK;
2369 break; 2385 break;
2370 2386
2371 case CANCELLED: 2387 case CANCELLED: