aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorBenoit Germain <bnt.germain@gmail.com>2011-11-05 17:31:02 +0100
committerBenoit Germain <bnt.germain@gmail.com>2011-11-05 17:31:02 +0100
commit053f7cff3c95acb915e6babfd306971f11bb7986 (patch)
treeee38c60b1119d34eb96aea1105ef033e851d266e /src
parent717eadee9c3644fabb32c7ee59949f2846143690 (diff)
downloadlanes-053f7cff3c95acb915e6babfd306971f11bb7986.tar.gz
lanes-053f7cff3c95acb915e6babfd306971f11bb7986.tar.bz2
lanes-053f7cff3c95acb915e6babfd306971f11bb7986.zip
* process exit change: close everything at GC when main state closes, not when atexit() handlers are processed
* Lua 5.2-style module: * module() is no longer used to implement lanes.lua * a global "lanes" variable is no longer created when the module is required * the Lanes module table is returned instead * Lanes must be initialized before used: * the first occurence of 'require "lanes"' produces a minimal interface that only contains a configure() function * the remainder of the interface is made available once this function is called * subsequent calls to configure() do nothing * configure() controls the number of keeper states and the startup of timers * LuaJIT 2 compatibility * non-Lua functions are no longer copied by creating a C closure from a C pointer, but through 2-way lookup tables * 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 * introduces a change in configuration .globals management: contents are copied *after* std libs are loaded * new .required configuration entry to list modules that must be require()'ed before lane body is transferred * lane:cancel() wakes up waiting lindas like what is done at lane shutdown
Diffstat (limited to 'src')
-rw-r--r--src/keeper.c112
-rw-r--r--src/keeper.h1
-rw-r--r--src/lanes.c311
-rw-r--r--src/lanes.lua79
-rw-r--r--src/threading.c1
-rw-r--r--src/tools.c649
-rw-r--r--src/tools.h9
7 files changed, 877 insertions, 285 deletions
diff --git a/src/keeper.c b/src/keeper.c
index 5b355cb..1f69d40 100644
--- a/src/keeper.c
+++ b/src/keeper.c
@@ -90,61 +90,119 @@ char const *init_keepers( int const _nbKeepers)
90 // Initialize Keeper states with bare minimum of libs (those required 90 // Initialize Keeper states with bare minimum of libs (those required
91 // by 'keeper.lua') 91 // by 'keeper.lua')
92 // 92 //
93 lua_State *L= luaL_newstate(); 93 lua_State *K = luaL_newstate();
94 if (!L) 94 if (!K)
95 return "out of memory"; 95 return "out of memory";
96 96
97 // to see VM name in Decoda debugger 97 // to see VM name in Decoda debugger
98 lua_pushliteral( L, "Keeper #"); 98 lua_pushliteral( K, "Keeper #");
99 lua_pushinteger( L, i + 1); 99 lua_pushinteger( K, i + 1);
100 lua_concat( L, 2); 100 lua_concat( K, 2);
101 lua_setglobal( L, "decoda_name"); 101 lua_setglobal( K, "decoda_name");
102
103 luaG_openlibs( L, "io,table,package" ); // 'io' for debugging messages, package because we need to require modules exporting idfuncs
104 serialize_require( L);
105 102
103 // 'io' for debugging messages, 'package' because we need to require modules exporting idfuncs
104 // the others because they export functions that we may store in a keeper for transfer between lanes
105 luaG_openlibs( K, "*");
106 serialize_require( K);
106 107
107 // Read in the preloaded chunk (and run it) 108 // Read in the preloaded chunk (and run it)
108 // 109 //
109 if (luaL_loadbuffer( L, keeper_chunk, sizeof(keeper_chunk), "@keeper.lua")) 110 if( luaL_loadbuffer( K, keeper_chunk, sizeof(keeper_chunk), "@keeper.lua"))
110 return "luaL_loadbuffer() failed"; // LUA_ERRMEM 111 return "luaL_loadbuffer() failed"; // LUA_ERRMEM
111 112
112 if (lua_pcall( L, 0 /*args*/, 0 /*results*/, 0 /*errfunc*/ )) 113 if( lua_pcall( K, 0 /*args*/, 0 /*results*/, 0 /*errfunc*/))
113 { 114 {
114 // LUA_ERRRUN / LUA_ERRMEM / LUA_ERRERR 115 // LUA_ERRRUN / LUA_ERRMEM / LUA_ERRERR
115 // 116 //
116 const char *err= lua_tostring(L,-1); 117 const char *err = lua_tostring(K, -1);
117 assert(err); 118 assert( err);
118 return err; 119 return err;
119 } 120 }
120 121
121 MUTEX_INIT( &GKeepers[i].lock_ ); 122 MUTEX_INIT( &GKeepers[i].lock_);
122 GKeepers[i].L= L; 123 GKeepers[i].L = K;
123 //GKeepers[i].count = 0; 124 //GKeepers[i].count = 0;
124 } 125 }
125 return NULL; // ok 126 return NULL; // ok
126} 127}
127 128
129// cause each keeper state to populate its database of transferable functions with those from the specified module
130void populate_keepers( lua_State *L)
131{
132 size_t name_len;
133 char const *name = luaL_checklstring( L, -1, &name_len);
134 size_t package_path_len;
135 char const *package_path;
136 size_t package_cpath_len;
137 char const *package_cpath;
138 int i;
139
140 // we need to make sure that package.path & package.cpath are the same in the keepers
141// than what is currently in use when the module is required in the caller's Lua state
142 STACK_CHECK(L)
143 STACK_GROW( L, 3);
144 lua_getglobal( L, "package");
145 lua_getfield( L, -1, "path");
146 package_path = luaL_checklstring( L, -1, &package_path_len);
147 lua_getfield( L, -2, "cpath");
148 package_cpath = luaL_checklstring( L, -1, &package_cpath_len);
149
150 for( i = 0; i < GNbKeepers; ++ i)
151 {
152 lua_State *K = GKeepers[i].L;
153 int res;
154 MUTEX_LOCK( &GKeepers[i].lock_);
155 STACK_CHECK(K)
156 STACK_GROW( K, 2);
157 lua_getglobal( K, "package");
158 lua_pushlstring( K, package_path, package_path_len);
159 lua_setfield( K, -2, "path");
160 lua_pushlstring( K, package_cpath, package_cpath_len);
161 lua_setfield( K, -2, "cpath");
162 lua_pop( K, 1);
163 lua_getglobal( K, "require");
164 lua_pushlstring( K, name, name_len);
165 res = lua_pcall( K, 1, 0, 0);
166 if( res != 0)
167 {
168 char const *err = luaL_checkstring( K, -1);
169 luaL_error( L, "error requiring '%s' in keeper state: %s", name, err);
170 }
171 STACK_END(K, 0)
172 MUTEX_UNLOCK( &GKeepers[i].lock_);
173 }
174 lua_pop( L, 3);
175 STACK_END(L, 0)
176}
177
128struct s_Keeper *keeper_acquire( const void *ptr) 178struct s_Keeper *keeper_acquire( const void *ptr)
129{ 179{
130 /* 180 // can be 0 if this happens during main state shutdown (lanes is being GC'ed -> no keepers)
131 * Any hashing will do that maps pointers to 0..GNbKeepers-1 181 if( GNbKeepers == 0)
132 * consistently. 182 {
133 * 183 return NULL;
134 * Pointers are often aligned by 8 or so - ignore the low order bits 184 }
135 */ 185 else
136 unsigned int i= ((unsigned long)(ptr) >> 3) % GNbKeepers; 186 {
137 struct s_Keeper *K= &GKeepers[i]; 187 /*
188 * Any hashing will do that maps pointers to 0..GNbKeepers-1
189 * consistently.
190 *
191 * Pointers are often aligned by 8 or so - ignore the low order bits
192 */
193 unsigned int i= ((unsigned long)(ptr) >> 3) % GNbKeepers;
194 struct s_Keeper *K= &GKeepers[i];
138 195
139 MUTEX_LOCK( &K->lock_); 196 MUTEX_LOCK( &K->lock_);
140 //++ K->count; 197 //++ K->count;
141 return K; 198 return K;
199 }
142} 200}
143 201
144void keeper_release( struct s_Keeper *K) 202void keeper_release( struct s_Keeper *K)
145{ 203{
146 //-- K->count; 204 //-- K->count;
147 MUTEX_UNLOCK( &K->lock_); 205 if( K) MUTEX_UNLOCK( &K->lock_);
148} 206}
149 207
150void keeper_toggle_nil_sentinels( lua_State *L, int _val_i, int _nil_to_sentinel) 208void keeper_toggle_nil_sentinels( lua_State *L, int _val_i, int _nil_to_sentinel)
diff --git a/src/keeper.h b/src/keeper.h
index 27a0f68..1bcb36b 100644
--- a/src/keeper.h
+++ b/src/keeper.h
@@ -9,6 +9,7 @@ struct s_Keeper
9}; 9};
10 10
11const char *init_keepers( int const _nbKeepers); 11const char *init_keepers( int const _nbKeepers);
12void populate_keepers( lua_State *L);
12struct s_Keeper *keeper_acquire( const void *ptr); 13struct s_Keeper *keeper_acquire( const void *ptr);
13void keeper_release( struct s_Keeper *K); 14void keeper_release( struct s_Keeper *K);
14void keeper_toggle_nil_sentinels( lua_State *L, int _val_i, int _nil_to_sentinel); 15void keeper_toggle_nil_sentinels( lua_State *L, int _val_i, int _nil_to_sentinel);
diff --git a/src/lanes.c b/src/lanes.c
index ed54b0f..44db625 100644
--- a/src/lanes.c
+++ b/src/lanes.c
@@ -51,7 +51,7 @@
51 * ... 51 * ...
52 */ 52 */
53 53
54const char *VERSION= "2.2.0"; 54const char *VERSION= "3.0-beta";
55 55
56/* 56/*
57=============================================================================== 57===============================================================================
@@ -787,10 +787,11 @@ static void linda_id( lua_State *L, char const * const which)
787 /* Clean associated structures in the keeper state. 787 /* Clean associated structures in the keeper state.
788 */ 788 */
789 K= keeper_acquire(s); 789 K= keeper_acquire(s);
790 if( K) // can be NULL if this happens during main state shutdown (lanes is GC'ed -> no keepers -> no need to cleanup)
790 { 791 {
791 keeper_call( K->L, "clear", L, s, 0 ); 792 keeper_call( K->L, "clear", L, s, 0 );
793 keeper_release(K);
792 } 794 }
793 keeper_release(K);
794 795
795 /* There aren't any lanes waiting on these lindas, since all proxies 796 /* There aren't any lanes waiting on these lindas, since all proxies
796 * have been gc'ed. Right? 797 * have been gc'ed. Right?
@@ -1028,9 +1029,9 @@ volatile DEEP_PRELUDE *timer_deep; // = NULL
1028/* 1029/*
1029* Process end; cancel any still free-running threads 1030* Process end; cancel any still free-running threads
1030*/ 1031*/
1031static void selfdestruct_atexit( void ) 1032static int selfdestruct_atexit( lua_State *L)
1032{ 1033{
1033 if (selfdestruct_first == SELFDESTRUCT_END) return; // no free-running threads 1034 if (selfdestruct_first == SELFDESTRUCT_END) return 0; // no free-running threads
1034 1035
1035 // Signal _all_ still running threads to exit (including the timer thread) 1036 // Signal _all_ still running threads to exit (including the timer thread)
1036 // 1037 //
@@ -1047,7 +1048,7 @@ static void selfdestruct_atexit( void )
1047 // signal the linda the wake up the thread so that it can react to the cancel query 1048 // signal the linda the wake up the thread so that it can react to the cancel query
1048 // let us hope we never land here with a pointer on a linda that has been destroyed... 1049 // let us hope we never land here with a pointer on a linda that has been destroyed...
1049 SIGNAL_T *waiting_on = s->waiting_on; 1050 SIGNAL_T *waiting_on = s->waiting_on;
1050 s->waiting_on = NULL; 1051 //s->waiting_on = NULL; // useful, or not?
1051 SIGNAL_ALL( waiting_on); 1052 SIGNAL_ALL( waiting_on);
1052 } 1053 }
1053 s = s->selfdestruct_next; 1054 s = s->selfdestruct_next;
@@ -1117,6 +1118,7 @@ static void selfdestruct_atexit( void )
1117 // 1118 //
1118 if ( selfdestruct_first != SELFDESTRUCT_END ) { 1119 if ( selfdestruct_first != SELFDESTRUCT_END ) {
1119 unsigned n=0; 1120 unsigned n=0;
1121#if 0
1120 MUTEX_LOCK( &selfdestruct_cs ); 1122 MUTEX_LOCK( &selfdestruct_cs );
1121 { 1123 {
1122 struct s_lane *s= selfdestruct_first; 1124 struct s_lane *s= selfdestruct_first;
@@ -1131,15 +1133,14 @@ static void selfdestruct_atexit( void )
1131 // and works without the block (so let's leave those lanes running) 1133 // and works without the block (so let's leave those lanes running)
1132 // 1134 //
1133//we want to free memory and such when we exit. 1135//we want to free memory and such when we exit.
1134#if 0
1135 // 2.0.2: at least timer lane is still here 1136 // 2.0.2: at least timer lane is still here
1136 // 1137 //
1137 DEBUGEXEC(fprintf( stderr, "Left %d lane(s) with cancel request at process end.\n", n )); 1138 DEBUGEXEC(fprintf( stderr, "Left %d lane(s) with cancel request at process end.\n", n ));
1139 n=0;
1138#else 1140#else
1139 // first thing we did was to raise the linda signals the threads were waiting on (if any) 1141 // first thing we did was to raise the linda signals the threads were waiting on (if any)
1140 // therefore, any well-behaved thread should be in CANCELLED state 1142 // therefore, any well-behaved thread should be in CANCELLED state
1141 // these are not running, and the state can be closed 1143 // these are not running, and the state can be closed
1142 n=0;
1143 MUTEX_LOCK( &selfdestruct_cs ); 1144 MUTEX_LOCK( &selfdestruct_cs );
1144 { 1145 {
1145 struct s_lane *s= selfdestruct_first; 1146 struct s_lane *s= selfdestruct_first;
@@ -1147,7 +1148,8 @@ static void selfdestruct_atexit( void )
1147 { 1148 {
1148 struct s_lane *next_s= s->selfdestruct_next; 1149 struct s_lane *next_s= s->selfdestruct_next;
1149 s->selfdestruct_next= NULL; // detach from selfdestruct chain 1150 s->selfdestruct_next= NULL; // detach from selfdestruct chain
1150 THREAD_KILL( &s->thread); 1151 if( s->thread) // can be NULL if previous 'soft' termination succeeded
1152 THREAD_KILL( &s->thread);
1151 // NO lua_close() in this case because we don't know where execution of the state was interrupted 1153 // NO lua_close() in this case because we don't know where execution of the state was interrupted
1152 free( s); 1154 free( s);
1153 s = next_s; 1155 s = next_s;
@@ -1161,6 +1163,7 @@ static void selfdestruct_atexit( void )
1161#endif 1163#endif
1162 } 1164 }
1163 close_keepers(); 1165 close_keepers();
1166 return 0;
1164} 1167}
1165 1168
1166 1169
@@ -1508,10 +1511,36 @@ LUAG_FUNC( set_debug_threadname)
1508// [prio_int=0], 1511// [prio_int=0],
1509// [globals_tbl], 1512// [globals_tbl],
1510// [packagepath], 1513// [packagepath],
1514// [required],
1511// [... args ...] ) 1515// [... args ...] )
1512// 1516//
1513// Upvalues: metatable to use for 'lane_ud' 1517// Upvalues: metatable to use for 'lane_ud'
1514// 1518//
1519
1520// helper function to require a module in the keeper states and in the target state
1521// source state contains module name at the top of the stack
1522static void require_one_module( lua_State *L, lua_State *L2, bool_t _fatal)
1523{
1524 size_t len;
1525 char const *name = lua_tolstring( L, -1, &len);
1526 // require the module in the target lane
1527 STACK_GROW( L2, 2);
1528 lua_getglobal( L2, "require");
1529 if( lua_isnil( L2, -1))
1530 {
1531 lua_pop( L2, 1);
1532 if( _fatal)
1533 luaL_error( L, "cannot pre-require modules without loading package library first");
1534 }
1535 else
1536 {
1537 lua_pushlstring( L2, name, len);
1538 lua_pcall( L2, 1, 0, 0);
1539 // we need to require this module in the keeper states as well
1540 populate_keepers( L);
1541 }
1542}
1543
1515LUAG_FUNC( thread_new ) 1544LUAG_FUNC( thread_new )
1516{ 1545{
1517 lua_State *L2; 1546 lua_State *L2;
@@ -1524,8 +1553,9 @@ LUAG_FUNC( thread_new )
1524 uint_t glob= luaG_isany(L,5) ? 5:0; 1553 uint_t glob= luaG_isany(L,5) ? 5:0;
1525 uint_t ppath = luaG_isany(L,6) ? 6:0; 1554 uint_t ppath = luaG_isany(L,6) ? 6:0;
1526 uint_t pcpath = luaG_isany(L,7) ? 7:0; 1555 uint_t pcpath = luaG_isany(L,7) ? 7:0;
1556 uint_t required = luaG_isany(L,8) ? 8:0;
1527 1557
1528#define FIXED_ARGS (7) 1558#define FIXED_ARGS (8)
1529 uint_t args= lua_gettop(L) - FIXED_ARGS; 1559 uint_t args= lua_gettop(L) - FIXED_ARGS;
1530 1560
1531 if (prio < THREAD_PRIO_MIN || prio > THREAD_PRIO_MAX) 1561 if (prio < THREAD_PRIO_MIN || prio > THREAD_PRIO_MAX)
@@ -1541,40 +1571,20 @@ LUAG_FUNC( thread_new )
1541 1571
1542 if (!L2) luaL_error( L, "'luaL_newstate()' failed; out of memory" ); 1572 if (!L2) luaL_error( L, "'luaL_newstate()' failed; out of memory" );
1543 1573
1544 STACK_GROW( L,2 ); 1574 STACK_GROW( L, 2);
1545
1546 // Setting the globals table (needs to be done before loading stdlibs,
1547 // and the lane function)
1548 //
1549 if (glob!=0)
1550 {
1551 STACK_CHECK(L)
1552 if (!lua_istable(L,glob))
1553 luaL_error( L, "Expected table, got %s", luaG_typename(L,glob) );
1554
1555 lua_pushvalue( L, glob );
1556
1557 luaG_inter_move( L, L2, 1); // moves the table to L2
1558
1559 // L2 [-1]: table of globals
1560
1561 // "You can change the global environment of a Lua thread using lua_replace"
1562 // (refman-5.0.pdf p. 30)
1563 //
1564 lua_replace( L2, LUA_GLOBALSINDEX );
1565 STACK_END(L,0)
1566 }
1567 1575
1568 // Selected libraries 1576 // Selected libraries
1569 // 1577 //
1570 if (libs) 1578 if (libs)
1571 { 1579 {
1572 const char *err= luaG_openlibs( L2, libs ); 1580 const char *err= luaG_openlibs( L2, libs);
1573 ASSERT_L( !err ); // bad libs should have been noticed by 'lanes.lua' 1581 ASSERT_L( !err ); // bad libs should have been noticed by 'lanes.lua'
1574 1582
1575 serialize_require( L2 ); 1583 serialize_require( L2);
1576 } 1584 }
1577 1585
1586 ASSERT_L( lua_gettop(L2) == 0);
1587
1578 // package.path 1588 // package.path
1579 STACK_CHECK(L2) 1589 STACK_CHECK(L2)
1580 if( ppath) 1590 if( ppath)
@@ -1582,15 +1592,17 @@ LUAG_FUNC( thread_new )
1582 if (lua_type(L,ppath) != LUA_TSTRING) 1592 if (lua_type(L,ppath) != LUA_TSTRING)
1583 luaL_error( L, "expected packagepath as string, got %s", luaG_typename(L,ppath)); 1593 luaL_error( L, "expected packagepath as string, got %s", luaG_typename(L,ppath));
1584 lua_getglobal( L2, "package"); 1594 lua_getglobal( L2, "package");
1585 if( lua_isnil( L2, -1)) 1595 if( lua_isnil( L2, -1)) // package library not loaded: do nothing
1586 { 1596 {
1587 lua_pop( L2, 1); 1597 lua_pop( L2, 1);
1588 luaL_error( L, "specifying a new path for packages, but lane doesn't load package library");
1589 } 1598 }
1590 lua_pushvalue( L, ppath); 1599 else
1591 luaG_inter_move( L, L2, 1); // moves the new path to L2 1600 {
1592 lua_setfield( L2, -2, "path"); // set package.path 1601 lua_pushvalue( L, ppath);
1593 lua_pop( L2, 1); 1602 luaG_inter_move( L, L2, 1); // moves the new path to L2
1603 lua_setfield( L2, -2, "path"); // set package.path
1604 lua_pop( L2, 1);
1605 }
1594 } 1606 }
1595 STACK_END(L2,0) 1607 STACK_END(L2,0)
1596 1608
@@ -1601,18 +1613,83 @@ LUAG_FUNC( thread_new )
1601 if (lua_type(L,pcpath) != LUA_TSTRING) 1613 if (lua_type(L,pcpath) != LUA_TSTRING)
1602 luaL_error( L, "expected packagecpath as string, got %s", luaG_typename(L,pcpath)); 1614 luaL_error( L, "expected packagecpath as string, got %s", luaG_typename(L,pcpath));
1603 lua_getglobal( L2, "package"); 1615 lua_getglobal( L2, "package");
1604 if( lua_isnil( L2, -1)) 1616 if( lua_isnil( L2, -1)) // // package library not loaded: do nothing
1605 { 1617 {
1606 lua_pop( L2, 1); 1618 lua_pop( L2, 1);
1607 luaL_error( L, "specifying a new cpath for packages, but lane doesn't load package library");
1608 } 1619 }
1609 lua_pushvalue( L, pcpath); 1620 else
1610 luaG_inter_move( L, L2, 1); // moves the new cpath to L2 1621 {
1611 lua_setfield( L2, -2, "cpath"); // set package.cpath 1622 lua_pushvalue( L, pcpath);
1612 lua_pop( L2, 1); 1623 luaG_inter_move( L, L2, 1); // moves the new cpath to L2
1624 lua_setfield( L2, -2, "cpath"); // set package.cpath
1625 lua_pop( L2, 1);
1626 }
1613 } 1627 }
1614 STACK_END(L2,0) 1628 STACK_END(L2,0)
1615 1629
1630 // modules to require in the target lane *before* the function is transfered!
1631
1632 //start by requiring lua51-lanes, since it is a bit special
1633 // it not fatal if 'require' isn't loaded, just ignore (may cause function transfer errors later on if the lane pulls the lanes module itself)
1634 STACK_CHECK(L)
1635 STACK_CHECK(L2)
1636 lua_pushliteral( L, "lua51-lanes");
1637 require_one_module( L, L2, FALSE);
1638 lua_pop( L, 1);
1639 STACK_END(L2,0)
1640 STACK_END(L,0)
1641
1642 STACK_CHECK(L)
1643 STACK_CHECK(L2)
1644 if( required)
1645 {
1646 int nbRequired = 1;
1647 // should not happen, was checked in lanes.lua before calling thread_new()
1648 if (lua_type(L, required) != LUA_TTABLE)
1649 luaL_error( L, "expected required module list as a table, got %s", luaG_typename( L, required));
1650 lua_pushnil( L);
1651 while( lua_next( L, required) != 0)
1652 {
1653 if (lua_type(L,-1) != LUA_TSTRING || lua_type(L,-2) != LUA_TNUMBER || lua_tonumber( L, -2) != nbRequired)
1654 {
1655 luaL_error( L, "required module list should be a list of strings.");
1656 }
1657 else
1658 {
1659 require_one_module( L, L2, TRUE);
1660 }
1661 lua_pop( L, 1);
1662 ++ nbRequired;
1663 }
1664 }
1665 STACK_END(L2,0)
1666 STACK_END(L,0)
1667
1668 // Appending the specified globals to the global environment
1669 // *after* stdlibs have been loaded and modules required, in case we transfer references to native functions they exposed...
1670 //
1671 if (glob!=0)
1672 {
1673 STACK_CHECK(L)
1674 STACK_CHECK(L2)
1675 if (!lua_istable(L,glob))
1676 luaL_error( L, "Expected table, got %s", luaG_typename(L,glob));
1677
1678 lua_pushnil( L);
1679 while( lua_next( L, glob))
1680 {
1681 luaG_inter_copy( L, L2, 2); // moves the key/value pair to the L2 stack
1682 // assign it in the globals table
1683 lua_rawset( L2, LUA_GLOBALSINDEX);
1684 lua_pop( L, 1);
1685 }
1686
1687 STACK_END(L2, 0)
1688 STACK_END(L, 0)
1689 }
1690
1691 ASSERT_L( lua_gettop(L2) == 0);
1692
1616 // Lane main function 1693 // Lane main function
1617 // 1694 //
1618 STACK_CHECK(L) 1695 STACK_CHECK(L)
@@ -1677,7 +1754,7 @@ LUAG_FUNC( thread_new )
1677 lua_newtable( L); 1754 lua_newtable( L);
1678 lua_setfenv( L, -2); 1755 lua_setfenv( L, -2);
1679 1756
1680 // Place 's' to registry, for 'cancel_test()' (even if 'cs'==0 we still 1757 // Place 's' in registry, for 'cancel_test()' (even if 'cs'==0 we still
1681 // do cancel tests at pending send/receive). 1758 // do cancel tests at pending send/receive).
1682 // 1759 //
1683 lua_pushlightuserdata( L2, CANCEL_TEST_KEY ); 1760 lua_pushlightuserdata( L2, CANCEL_TEST_KEY );
@@ -1792,6 +1869,17 @@ static bool_t thread_cancel( struct s_lane *s, double secs, bool_t force)
1792 // 1869 //
1793 if( s->status < DONE) 1870 if( s->status < DONE)
1794 { 1871 {
1872 // signal the linda the wake up the thread so that it can react to the cancel query
1873 // let us hope we never land here with a pointer on a linda that has been destroyed...
1874 //MUTEX_LOCK( &selfdestruct_cs );
1875 {
1876 SIGNAL_T *waiting_on = s->waiting_on;
1877 if( s->status == WAITING && waiting_on != NULL)
1878 {
1879 SIGNAL_ALL( waiting_on);
1880 }
1881 }
1882 //MUTEX_UNLOCK( &selfdestruct_cs );
1795 s->cancel_request = TRUE; // it's now signalled to stop 1883 s->cancel_request = TRUE; // it's now signalled to stop
1796 done= 1884 done=
1797#if (defined PLATFORM_WIN32) || (defined PLATFORM_POCKETPC) || (defined PTHREAD_TIMEDJOIN) 1885#if (defined PLATFORM_WIN32) || (defined PLATFORM_POCKETPC) || (defined PTHREAD_TIMEDJOIN)
@@ -1816,23 +1904,32 @@ static bool_t thread_cancel( struct s_lane *s, double secs, bool_t force)
1816 1904
1817LUAG_FUNC( thread_cancel) 1905LUAG_FUNC( thread_cancel)
1818{ 1906{
1819 struct s_lane *s= lua_toLane(L,1); 1907 if( lua_gettop( L) != 1 || lua_type( L, 1) != LUA_TUSERDATA)
1820 double secs= 0.0; 1908 {
1821 uint_t force_i=2; 1909 return luaL_error( L, "invalid argument #1, did you use ':' as you should?");
1822 bool_t force, done= TRUE; 1910 }
1911 else
1912 {
1913 struct s_lane *s = lua_toLane( L, 1);
1914 double secs = 0.0;
1915 uint_t force_i = 2;
1916 bool_t force, done= TRUE;
1823 1917
1824 if (lua_isnumber(L,2)) { 1918 if( lua_isnumber( L, 2))
1825 secs= lua_tonumber(L,2); 1919 {
1826 force_i++; 1920 secs = lua_tonumber( L, 2);
1827 } else if (lua_isnil(L,2)) 1921 ++ force_i;
1828 force_i++; 1922 }
1923 else if( lua_isnil( L, 2))
1924 ++ force_i;
1829 1925
1830 force= lua_toboolean(L,force_i); // FALSE if nothing there 1926 force = lua_toboolean( L, force_i); // FALSE if nothing there
1831 1927
1832 done = thread_cancel( s, secs, force); 1928 done = thread_cancel( s, secs, force);
1833 1929
1834 lua_pushboolean( L, done); 1930 lua_pushboolean( L, done);
1835 return 1; 1931 return 1;
1932 }
1836} 1933}
1837 1934
1838//--- 1935//---
@@ -2183,7 +2280,7 @@ static void init_once_LOCKED( lua_State *L, volatile DEEP_PRELUDE ** timer_deep_
2183 // Selfdestruct chain handling 2280 // Selfdestruct chain handling
2184 // 2281 //
2185 MUTEX_INIT( &selfdestruct_cs ); 2282 MUTEX_INIT( &selfdestruct_cs );
2186 atexit( selfdestruct_atexit ); 2283 //atexit( selfdestruct_atexit );
2187 2284
2188 //--- 2285 //---
2189 // Linux needs SCHED_RR to change thread priorities, and that is only 2286 // Linux needs SCHED_RR to change thread priorities, and that is only
@@ -2233,7 +2330,17 @@ static void init_once_LOCKED( lua_State *L, volatile DEEP_PRELUDE ** timer_deep_
2233 2330
2234 // The host Lua state must always have a reference to this Linda object in order for our 'timer_deep_ref' to be valid. 2331 // The host Lua state must always have a reference to this Linda object in order for our 'timer_deep_ref' to be valid.
2235 // So store a reference that we will never actually use. 2332 // So store a reference that we will never actually use.
2236 lua_pushlightuserdata(L, (void *)init_once_LOCKED); 2333 // at the same time, use this object as a 'desinit' marker:
2334 // when the main lua State is closed, this object will be GC'ed
2335 {
2336 lua_newuserdata( L, 1);
2337 lua_newtable( L);
2338 lua_pushcfunction( L, selfdestruct_atexit);
2339 lua_setfield( L, -2, "__gc");
2340 lua_pushliteral( L, "AtExit");
2341 lua_setfield( L, -2, "__metatable");
2342 lua_setmetatable( L, -2);
2343 }
2237 lua_insert(L, -2); // Swap key with the Linda object 2344 lua_insert(L, -2); // Swap key with the Linda object
2238 lua_rawset(L, LUA_REGISTRYINDEX); 2345 lua_rawset(L, LUA_REGISTRYINDEX);
2239 2346
@@ -2241,14 +2348,12 @@ static void init_once_LOCKED( lua_State *L, volatile DEEP_PRELUDE ** timer_deep_
2241 STACK_END(L,0) 2348 STACK_END(L,0)
2242} 2349}
2243 2350
2244int 2351static volatile long s_initCount = 0;
2245#if (defined PLATFORM_WIN32) || (defined PLATFORM_POCKETPC) 2352
2246__declspec(dllexport) 2353LUAG_FUNC( configure )
2247#endif
2248luaopen_lanes( lua_State *L )
2249{ 2354{
2250 static volatile int /*bool*/ go_ahead; // = 0 2355 char const *name = luaL_checkstring( L, lua_upvalueindex( 1));
2251 int const nbKeepers = luaL_optint( L, 2, 1); 2356 int const nbKeepers = luaL_optint( L, 1, 1);
2252 luaL_argcheck( L, nbKeepers > 0, 2, "Number of keeper states must be > 0"); 2357 luaL_argcheck( L, nbKeepers > 0, 2, "Number of keeper states must be > 0");
2253 /* 2358 /*
2254 * Making one-time initializations. 2359 * Making one-time initializations.
@@ -2259,31 +2364,29 @@ luaopen_lanes( lua_State *L )
2259 */ 2364 */
2260#ifdef PLATFORM_WIN32 2365#ifdef PLATFORM_WIN32
2261 { 2366 {
2262 // TBD: Someone please replace this with reliable Win32 API code. Problem is, 2367 static volatile int /*bool*/ go_ahead; // = 0
2263 // there's no autoinitializing locks (s.a. PTHREAD_MUTEX_INITIALIZER) in 2368 if( InterlockedCompareExchange( &s_initCount, 1, 0) == 0)
2264 // Windows so 'InterlockedIncrement' or something needs to be used. 2369 {
2265 // This is 99.9999% safe, though (and always safe if host is single-threaded)
2266 // -- AKa 24-Jun-2009
2267 //
2268 static volatile unsigned my_number; // = 0
2269
2270 if (my_number++ == 0) { // almost atomic
2271 init_once_LOCKED(L, &timer_deep, nbKeepers); 2370 init_once_LOCKED(L, &timer_deep, nbKeepers);
2272 go_ahead= 1; // let others pass 2371 go_ahead= 1; // let others pass
2273 } else { 2372 }
2373 else
2374 {
2274 while( !go_ahead ) { Sleep(1); } // changes threads 2375 while( !go_ahead ) { Sleep(1); } // changes threads
2275 } 2376 }
2276 } 2377 }
2277#else 2378#else
2278 if (!go_ahead) { 2379 if( s_initCount == 0)
2380 {
2279 static pthread_mutex_t my_lock= PTHREAD_MUTEX_INITIALIZER; 2381 static pthread_mutex_t my_lock= PTHREAD_MUTEX_INITIALIZER;
2280 pthread_mutex_lock(&my_lock); 2382 pthread_mutex_lock(&my_lock);
2281 { 2383 {
2282 // Recheck now that we're within the lock 2384 // Recheck now that we're within the lock
2283 // 2385 //
2284 if (!go_ahead) { 2386 if (s_initCount == 0)
2387 {
2285 init_once_LOCKED(L, &timer_deep, nbKeepers); 2388 init_once_LOCKED(L, &timer_deep, nbKeepers);
2286 go_ahead= 1; 2389 s_initCount = 1;
2287 } 2390 }
2288 } 2391 }
2289 pthread_mutex_unlock(&my_lock); 2392 pthread_mutex_unlock(&my_lock);
@@ -2292,7 +2395,10 @@ luaopen_lanes( lua_State *L )
2292 assert( timer_deep != 0 ); 2395 assert( timer_deep != 0 );
2293 2396
2294 // Create main module interface table 2397 // Create main module interface table
2295 lua_newtable(L); 2398 lua_pushvalue( L, lua_upvalueindex( 2));
2399 // remove configure() (this function) from the module interface
2400 lua_pushnil( L);
2401 lua_setfield( L, -2, "configure");
2296 luaL_register(L, NULL, lanes_functions); 2402 luaL_register(L, NULL, lanes_functions);
2297 2403
2298 // metatable for threads 2404 // metatable for threads
@@ -2313,7 +2419,7 @@ luaopen_lanes( lua_State *L )
2313 lua_setfield( L, -2, "join"); 2419 lua_setfield( L, -2, "join");
2314 lua_pushcfunction( L, LG_thread_cancel); 2420 lua_pushcfunction( L, LG_thread_cancel);
2315 lua_setfield( L, -2, "cancel"); 2421 lua_setfield( L, -2, "cancel");
2316 lua_pushboolean( L, 0); 2422 lua_pushliteral( L, "Lane");
2317 lua_setfield( L, -2, "__metatable"); 2423 lua_setfield( L, -2, "__metatable");
2318 2424
2319 lua_pushcclosure( L, LG_thread_new, 1 ); // metatable as closure param 2425 lua_pushcclosure( L, LG_thread_new, 1 ); // metatable as closure param
@@ -2331,8 +2437,41 @@ luaopen_lanes( lua_State *L )
2331 lua_pushlightuserdata( L, CANCEL_ERROR ); 2437 lua_pushlightuserdata( L, CANCEL_ERROR );
2332 lua_setfield(L, -2, "cancel_error"); 2438 lua_setfield(L, -2, "cancel_error");
2333 2439
2334 // Return the local module table 2440 // register all native functions found in that module in the transferable functions database
2335 return 1; 2441 // we process it before _G because we don't want to find the module when scanning _G (this would generate longer names)
2442 populate_func_lookup_table( L, -1, name);
2443 // record all existing C/JIT-fast functions
2444 populate_func_lookup_table( L, LUA_GLOBALSINDEX, NULL);
2445 // Return nothing
2446 lua_pop( L, 1);
2447 return 0;
2448}
2449
2450int
2451#if (defined PLATFORM_WIN32) || (defined PLATFORM_POCKETPC)
2452__declspec(dllexport)
2453#endif
2454luaopen_lanes( lua_State *L )
2455{
2456 // Create main module interface table
2457 // we only have 1 closure, which must be called to configure Lanes
2458 STACK_GROW( L, 3);
2459 STACK_CHECK( L)
2460 lua_newtable(L);
2461 lua_pushvalue(L, 1); // module name
2462 lua_pushvalue(L, -2); // module table
2463 lua_pushcclosure( L, LG_configure, 2);
2464 if( s_initCount == 0)
2465 {
2466 lua_setfield( L, -2, "configure");
2467 }
2468 else // already initialized: call it mmediately and be done
2469 {
2470 lua_pushinteger( L, 666); // any value will do, it will be ignored
2471 lua_call( L, 1, 0);
2472 }
2473 STACK_END( L, 1)
2474 return 1;
2336} 2475}
2337 2476
2338 2477
diff --git a/src/lanes.lua b/src/lanes.lua
index 252d151..8837e4b 100644
--- a/src/lanes.lua
+++ b/src/lanes.lua
@@ -39,11 +39,19 @@ THE SOFTWARE.
39=============================================================================== 39===============================================================================
40]]-- 40]]--
41 41
42module( "lanes", package.seeall ) 42-- Lua 5.1: module() creates a global variable
43-- Lua 5.2: module() might go away
44-- almost everything module() does is done by require()
45-- -> simply create a table, populate it, return it, and be done
46local lanes = {}
47
48lanes.configure = function( _nb_keepers, _timers)
43 49
44local mm = require "lua51-lanes" 50local mm = require "lua51-lanes"
45assert( type(mm)=="table" ) 51assert( type(mm)=="table" )
46 52
53-- configure() is available only the first time lua51-lanes is required process-wide, and we *must* call it to have the other functions in the interface
54if mm.configure then mm.configure( _nb_keepers) end
47 55
48local thread_new = assert(mm.thread_new) 56local thread_new = assert(mm.thread_new)
49 57
@@ -140,6 +148,7 @@ end
140-- 148--
141-- .globals: table of globals to set for a new thread (passed by value) 149-- .globals: table of globals to set for a new thread (passed by value)
142-- 150--
151-- .required: table of packages to require
143-- ... (more options may be introduced later) ... 152-- ... (more options may be introduced later) ...
144-- 153--
145-- Calling with a function parameter ('lane_func') ends the string/table 154-- Calling with a function parameter ('lane_func') ends the string/table
@@ -161,7 +170,8 @@ local valid_libs= {
161 ["*"]= true 170 ["*"]= true
162} 171}
163 172
164function gen( ... ) 173-- PUBLIC LANES API
174local function gen( ... )
165 local opt= {} 175 local opt= {}
166 local libs= nil 176 local libs= nil
167 local lev= 2 -- level for errors 177 local lev= 2 -- level for errors
@@ -204,27 +214,34 @@ function gen( ... )
204 end 214 end
205 end 215 end
206 216
207 local prio, cs, g_tbl, packagepath, packagecpath 217 local prio, cs, g_tbl, packagepath, packagecpath, required
208 218
209 for k,v in pairs(opt) do 219 for k,v in pairs(opt) do
210 if k=="priority" then prio= v 220 if k=="priority" then prio= v
211 elseif k=="cancelstep" then cs= (v==true) and 100 or 221 elseif k=="cancelstep" then
212 (v==false) and 0 or 222 cs = (v==true) and 100 or
213 type(v)=="number" and v or 223 (v==false) and 0 or
214 error( "Bad cancelstep: "..tostring(v), lev ) 224 type(v)=="number" and v or
225 error( "Bad cancelstep: "..tostring(v), lev )
215 elseif k=="globals" then g_tbl= v 226 elseif k=="globals" then g_tbl= v
216 elseif k=="packagepath" then packagepath= v 227 elseif k=="packagepath" then
217 elseif k=="packagecpath" then packagecpath= v 228 packagepath = (type( v) == "string") and v or error( "Bad packagepath: " .. tostring( v), lev)
229 elseif k=="packagecpath" then
230 packagecpath = (type( v) == "string") and v or error( "Bad packagecpath: " .. tostring( v), lev)
231 elseif k=="required" then
232 required= (type( v) == "table") and v or error( "Bad required: " .. tostring( v), lev)
218 --.. 233 --..
219 elseif k==1 then error( "unkeyed option: ".. tostring(v), lev ) 234 elseif k==1 then error( "unkeyed option: ".. tostring(v), lev )
220 else error( "Bad option: ".. tostring(k), lev ) 235 else error( "Bad option: ".. tostring(k), lev )
221 end 236 end
222 end 237 end
223 238
239 if not packagepath then packagepath = package.path end
240 if not packagecpath then packagecpath = package.cpath end
224 -- Lane generator 241 -- Lane generator
225 -- 242 --
226 return function(...) 243 return function(...)
227 return thread_new( func, libs, cs, prio, g_tbl, packagepath, packagecpath, ...) -- args 244 return thread_new( func, libs, cs, prio, g_tbl, packagepath, packagecpath, required, ...) -- args
228 end 245 end
229end 246end
230 247
@@ -235,12 +252,16 @@ end
235----- 252-----
236-- lanes.linda() -> linda_ud 253-- lanes.linda() -> linda_ud
237-- 254--
238linda = mm.linda 255-- PUBLIC LANES API
256local linda = mm.linda
239 257
240 258
241---=== Timers ===--- 259---=== Timers ===---
242local want_timers = true 260
243if want_timers then 261-- PUBLIC LANES API
262local timer = function() error "timers are not active" end
263
264if _timers ~= "NO_TIMERS" then
244 265
245local timer_gateway= assert( mm.timer_gateway ) 266local timer_gateway= assert( mm.timer_gateway )
246-- 267--
@@ -424,6 +445,8 @@ if first_time then
424 assert( key and wakeup_at and period ) 445 assert( key and wakeup_at and period )
425 446
426 set_timer( linda, key, wakeup_at, period>0 and period or nil ) 447 set_timer( linda, key, wakeup_at, period>0 and period or nil )
448 elseif secs == 0 then -- got no value while block-waiting?
449 WR( "timer lane: no linda, aborted?")
427 end 450 end
428 end 451 end
429 end )() 452 end )()
@@ -432,7 +455,8 @@ end
432----- 455-----
433-- = timer( linda_h, key_val, date_tbl|first_secs [,period_secs] ) 456-- = timer( linda_h, key_val, date_tbl|first_secs [,period_secs] )
434-- 457--
435function timer( linda, key, a, period ) 458-- PUBLIC LANES API
459timer = function( linda, key, a, period )
436 460
437 if a==0.0 then 461 if a==0.0 then
438 -- Caller expects to get current time stamp in Linda, on return 462 -- Caller expects to get current time stamp in Linda, on return
@@ -456,7 +480,7 @@ function timer( linda, key, a, period )
456 timer_gateway:send( TGW_KEY, linda, key, wakeup_at, period ) 480 timer_gateway:send( TGW_KEY, linda, key, wakeup_at, period )
457end 481end
458 482
459end -- want_timers 483end -- _timers
460 484
461---=== Lock & atomic generators ===--- 485---=== Lock & atomic generators ===---
462 486
@@ -473,7 +497,8 @@ end -- want_timers
473-- Returns an access function that allows 'N' simultaneous entries between 497-- Returns an access function that allows 'N' simultaneous entries between
474-- acquire (+M) and release (-M). For binary locks, use M==1. 498-- acquire (+M) and release (-M). For binary locks, use M==1.
475-- 499--
476function genlock( linda, key, N ) 500-- PUBLIC LANES API
501local function genlock( linda, key, N )
477 linda:limit(key,N) 502 linda:limit(key,N)
478 linda:set(key,nil) -- clears existing data 503 linda:set(key,nil) -- clears existing data
479 504
@@ -506,7 +531,8 @@ end
506-- Returns an access function that allows atomic increment/decrement of the 531-- Returns an access function that allows atomic increment/decrement of the
507-- number in 'key'. 532-- number in 'key'.
508-- 533--
509function genatomic( linda, key, initial_val ) 534-- PUBLIC LANES API
535local function genatomic( linda, key, initial_val )
510 linda:limit(key,2) -- value [,true] 536 linda:limit(key,2) -- value [,true]
511 linda:set(key,initial_val or 0.0) -- clears existing data (also queue) 537 linda:set(key,initial_val or 0.0) -- clears existing data (also queue)
512 538
@@ -522,4 +548,23 @@ end
522 548
523-- newuserdata = mm.newuserdata 549-- newuserdata = mm.newuserdata
524 550
551 -- activate full interface
552 lanes.gen = gen
553 lanes.linda = mm.linda
554 lanes.timer = timer
555 lanes.genlock = genlock
556 lanes.genatomic = genatomic
557 -- from now on, calling configure does nothing but checking that we don't call it with parameters that changed compared to the first invocation
558 lanes.configure = function( _nk, _t)
559 if _nk ~= _nb_keepers then
560 error( "mismatched configuration: " .. tostring( _nk) .. " keepers instead of " .. tostring( _nb_keepers))
561 end
562 if _t ~= _timers then
563 error( "mismatched configuration: " .. tostring( _t) .. " timer activity instead of " .. tostring( _timers))
564 end
565 end
566end -- lanes.configure
567
525--the end 568--the end
569return lanes
570
diff --git a/src/threading.c b/src/threading.c
index 00be243..0a07d47 100644
--- a/src/threading.c
+++ b/src/threading.c
@@ -74,6 +74,7 @@ THE SOFTWARE.
74#if (defined PLATFORM_WIN32) || (defined PLATFORM_POCKETPC) 74#if (defined PLATFORM_WIN32) || (defined PLATFORM_POCKETPC)
75static void FAIL( const char *funcname, int rc ) { 75static void FAIL( const char *funcname, int rc ) {
76 fprintf( stderr, "%s() failed! (%d)\n", funcname, rc ); 76 fprintf( stderr, "%s() failed! (%d)\n", funcname, rc );
77 __debugbreak(); // give a chance to the debugger!
77 abort(); 78 abort();
78} 79}
79#endif 80#endif
diff --git a/src/tools.c b/src/tools.c
index f9854db..b412e84 100644
--- a/src/tools.c
+++ b/src/tools.c
@@ -31,6 +31,7 @@ THE SOFTWARE.
31*/ 31*/
32 32
33#include "tools.h" 33#include "tools.h"
34#include "keeper.h"
34 35
35#include "lualib.h" 36#include "lualib.h"
36#include "lauxlib.h" 37#include "lauxlib.h"
@@ -66,7 +67,7 @@ void luaG_dump( lua_State* L ) {
66 // enable it for more debugging. 67 // enable it for more debugging.
67 // 68 //
68 STACK_CHECK(L) 69 STACK_CHECK(L)
69 STACK_GROW( L, 2 ) 70 STACK_GROW( L, 2);
70 71
71 lua_getglobal( L, "tostring" ); 72 lua_getglobal( L, "tostring" );
72 // 73 //
@@ -108,21 +109,302 @@ static const luaL_Reg libs[] = {
108 109
109static bool_t openlib( lua_State *L, const char *name, size_t len ) { 110static bool_t openlib( lua_State *L, const char *name, size_t len ) {
110 111
111 unsigned i; 112 unsigned i;
112 bool_t all= strncmp( name, "*", len ) == 0; 113 bool_t all= strncmp( name, "*", len ) == 0;
113 114
114 for( i=0; libs[i].name; i++ ) { 115 for( i=0; libs[i].name; i++ )
115 if (all || (strncmp(name, libs[i].name, len) ==0)) { 116 {
116 if (libs[i].func) { 117 if (all || (strncmp(name, libs[i].name, len) ==0))
117 STACK_GROW(L,2); 118 {
118 lua_pushcfunction( L, libs[i].func ); 119 if (libs[i].func)
119 lua_pushstring( L, libs[i].name ); 120 {
120 lua_call( L, 1, 0 ); 121 STACK_GROW(L,1);
121 } 122 STACK_CHECK(L)
122 if (!all) return TRUE; 123 lua_pushcfunction( L, libs[i].func);
123 } 124 // pushes the module table on the stack
124 } 125 lua_call( L, 0, 1);
125 return all; 126 populate_func_lookup_table( L, -1, libs[i].name);
127 // remove the module when we are done
128 lua_pop( L, 1);
129 STACK_END(L, 0)
130 }
131 if (!all) return TRUE;
132 }
133 }
134 return all;
135}
136
137static int dummy_writer(lua_State *L, const void* p, size_t sz, void* ud)
138{
139 return 666;
140}
141
142
143/*
144 * differentiation between C, bytecode and JIT-fast functions
145 *
146 *
147 * +----------+------------+----------+
148 * | bytecode | C function | JIT-fast |
149 * +-----------------+----------+------------+----------+
150 * | lua_topointer | | | |
151 * +-----------------+----------+------------+----------+
152 * | lua_tocfunction | NULL | | NULL |
153 * +-----------------+----------+------------+----------+
154 * | lua_dump | 666 | 1 | 1 |
155 * +-----------------+----------+------------+----------+
156 */
157
158typedef enum
159{
160 FST_Bytecode,
161 FST_Native,
162 FST_FastJIT
163} FuncSubType;
164
165FuncSubType luaG_getfuncsubtype( lua_State *L, int _i)
166{
167 if( lua_tocfunction( L, _i))
168 {
169 return FST_Native;
170 }
171 {
172 int mustpush = 0, dumpres;
173 if( STACK_ABS( L, _i) != lua_gettop( L))
174 {
175 lua_pushvalue( L, _i);
176 mustpush = 1;
177 }
178 // the provided writer fails with code 666
179 // therefore, anytime we get 666, this means that lua_dump() attempted a dump
180 // all other cases mean this is either a C or LuaJIT-fast function
181 dumpres = lua_dump( L, dummy_writer, NULL);
182 lua_pop( L, mustpush);
183 if( dumpres == 666)
184 {
185 return FST_Bytecode;
186 }
187 }
188 return FST_FastJIT;
189}
190
191static lua_CFunction luaG_tocfunction( lua_State *L, int _i, FuncSubType *_out)
192{
193 lua_CFunction p = lua_tocfunction( L, _i);
194 *_out = luaG_getfuncsubtype( L, _i);
195 return p;
196}
197
198
199#define LOOKUP_KEY "ddea37aa-50c7-4d3f-8e0b-fb7a9d62bac5"
200#define LOOKUP_KEY_CACHE "d1059270-4976-4193-a55b-c952db5ab7cd"
201
202
203// inspired from tconcat() in ltablib.c
204static char const * luaG_pushFQN(lua_State *L, int t, int last)
205{
206 int i = 1;
207 luaL_Buffer b;
208 STACK_CHECK( L)
209 luaL_buffinit(L, &b);
210 for( ; i < last; i++)
211 {
212 lua_rawgeti( L, t, i);
213 luaL_addvalue( &b);
214 luaL_addlstring(&b, ".", 1);
215 }
216 if (i == last) /* add last value (if interval was not empty) */
217 {
218 lua_rawgeti( L, t, i);
219 luaL_addvalue( &b);
220 }
221 luaL_pushresult( &b);
222 STACK_END( L, 1)
223 return lua_tostring( L, -1);
224}
225
226
227static void populate_func_lookup_table_recur( lua_State *L, int _ctx_base, int _i, int _depth)
228{
229 lua_Integer visit_count;
230 // slot 1 in the stack contains the table that receives everything we found
231 int const dest = _ctx_base;
232 // slot 2 contains a table that, when concatenated, produces the fully qualified name of scanned elements in the table provided at slot _i
233 int const fqn = _ctx_base + 1;
234 // slot 3 contains a cache that stores all already visited tables to avoid infinite recursion loops
235 int const cache = _ctx_base + 2;
236 // we need to remember subtables to process them after functions encountered at the current depth (breadth-first search)
237 int const breadth_first_cache = lua_gettop( L) + 1;
238
239 STACK_GROW( L, 6);
240 // slot _i contains a table where we search for functions
241 STACK_CHECK( L) // ... {_i}
242
243 // if table is already visited, we are done
244 lua_pushvalue( L, _i); // ... {_i} {}
245 lua_rawget( L, cache); // ... {_i} nil|n
246 visit_count = lua_tointeger( L, -1); // 0 if nil, else n
247 lua_pop( L, 1); // ... {_i}
248 STACK_MID( L, 0)
249 if( visit_count > 0)
250 {
251 return;
252 }
253
254 // remember we visited this table (1-visit count)
255 lua_pushvalue( L, _i); // ... {_i} {}
256 lua_pushinteger( L, visit_count + 1); // ... {_i} {} 1
257 lua_rawset( L, cache); // ... {_i}
258 STACK_MID( L, 0)
259
260 // this table is at breadth_first_cache index
261 lua_newtable( L); // ... {_i} {bfc}
262 ASSERT_L( lua_gettop( L) == breadth_first_cache);
263 // iterate over all entries in the processed table
264 lua_pushnil( L); // ... {_i} {bfc} nil
265 while( lua_next( L, _i) != 0) // ... {_i} {bfc} k v
266 {
267 // just for debug, not actually needed
268 //char const * key = (lua_type( L, -2) == LUA_TSTRING) ? lua_tostring( L, -2) : "not a string";
269 // subtable: process it recursively
270 if( lua_istable( L, -1)) // ... {_i} {bfc} k {}
271 {
272 // increment visit count to make sure we will actually scan it at this recursive level
273 lua_pushvalue( L, -1); // ... {_i} {bfc} k {} {}
274 lua_pushvalue( L, -1); // ... {_i} {bfc} k {} {} {}
275 lua_rawget( L, cache); // ... {_i} {bfc} k {} {} n?
276 visit_count = lua_tointeger( L, -1) + 1; // 1 if we got nil, else n+1
277 lua_pop( L, 1); // ... {_i} {bfc} k {} {}
278 lua_pushinteger( L, visit_count); // ... {_i} {bfc} k {} {} n
279 lua_rawset( L, cache); // ... {_i} {bfc} k {}
280 // store the table in the breadth-first cache
281 lua_pushvalue( L, -2); // ... {_i} {bfc} k {} k
282 lua_insert( L, -2); // ... {_i} {bfc} k k {}
283 lua_rawset( L, breadth_first_cache); // ... {_i} {bfc} k
284 STACK_MID( L, 2)
285 }
286 else if( lua_isfunction( L, -1)) // ... {_i} {bfc} k func
287 {
288 if( luaG_getfuncsubtype( L, -1) != FST_Bytecode)
289 {
290 char const *fqnString;
291 bool_t not_registered;
292 // first, skip everything if the function is already known
293 lua_pushvalue( L, -1); // ... {_i} {bfc} k func func
294 lua_rawget( L, dest); // ... {_i} {bfc} k func name?
295 not_registered = lua_isnil( L, -1);
296 lua_pop( L, 1); // ... {_i} {bfc} k func
297 if( not_registered)
298 {
299 ++ _depth;
300 // push function name in fqn stack (note that concatenation will crash if name is a not string!)
301 lua_pushvalue( L, -2); // ... {_i} {bfc} k func k
302 lua_rawseti( L, fqn, _depth); // ... {_i} {bfc} k func
303 // generate name
304 fqnString = luaG_pushFQN( L, fqn, _depth); // ... {_i} {bfc} k func "f.q.n"
305 //puts( fqnString);
306 // prepare the stack for database feed
307 lua_pushvalue( L, -1); // ... {_i} {bfc} k func "f.q.n" "f.q.n"
308 lua_pushvalue( L, -3); // ... {_i} {bfc} k func "f.q.n" "f.q.n" func
309 // t["f.q.n"] = func
310 lua_rawset( L, dest); // ... {_i} {bfc} k func "f.q.n"
311 // t[func] = "f.q.n"
312 lua_rawset( L, dest); // ... {_i} {bfc} k
313 // remove table name from fqn stack
314 lua_pushnil( L); // ... {_i} {bfc} k nil
315 lua_rawseti( L, fqn, _depth); // ... {_i} {bfc} k
316 -- _depth;
317 }
318 else
319 {
320 lua_pop( L, 1); // ... {_i} {bfc} k
321 }
322 }
323 else
324 {
325 lua_pop( L, 1); // ... {_i} {bfc} k
326 }
327 }
328 else
329 {
330 lua_pop( L, 1); // ... {_i} {bfc} k
331 }
332 STACK_MID( L, 2)
333 }
334 // now process the tables we encountered at that depth
335 ++ _depth;
336 lua_pushnil( L); // ... {_i} {bfc} nil
337 while( lua_next( L, breadth_first_cache) != 0) // ... {_i} {bfc} k {}
338 {
339 // un-visit this table in case we do need to process it
340 lua_pushvalue( L, -1); // ... {_i} {bfc} k {} {}
341 lua_rawget( L, cache); // ... {_i} {bfc} k {} n
342 ASSERT_L( lua_type( L, -1) == LUA_TNUMBER);
343 visit_count = lua_tointeger( L, -1) - 1;
344 lua_pop( L, 1); // ... {_i} {bfc} k {}
345 lua_pushvalue( L, -1); // ... {_i} {bfc} k {} {}
346 if( visit_count > 0)
347 {
348 lua_pushinteger( L, visit_count); // ... {_i} {bfc} k {} {} n
349 }
350 else
351 {
352 lua_pushnil( L); // ... {_i} {bfc} k {} {} nil
353 }
354 lua_rawset( L, cache); // ... {_i} {bfc} k {}
355 // push table name in fqn stack (note that concatenation will crash if name is a not string!)
356 lua_pushvalue( L, -2); // ... {_i} {bfc} k {} k
357 lua_rawseti( L, fqn, _depth); // ... {_i} {bfc} k {}
358 populate_func_lookup_table_recur( L, _ctx_base, lua_gettop( L), _depth); // ... {_i} {bfc} k {}
359 lua_pop( L, 1); // ... {_i} {bfc} k
360 STACK_MID( L, 2)
361 }
362 // remove table name from fqn stack
363 lua_pushnil( L); // ... {_i} {bfc} nil
364 lua_rawseti( L, fqn, _depth); // ... {_i} {bfc}
365 -- _depth;
366 // we are done with our cache
367 lua_pop( L, 1); // ... {_i}
368 STACK_END( L, 0)
369 // we are done // ... {_i} {bfc}
370}
371
372/*
373 * create a "fully.qualified.name" <-> function equivalence dabase
374 */
375void populate_func_lookup_table( lua_State *L, int _i, char const *_name)
376{
377 int const ctx_base = lua_gettop( L) + 1;
378 int const in_base = STACK_ABS( L, _i);
379 int const start_depth = _name ? 1 : 0;
380 //printf( "%p: populate_func_lookup_table('%s')\n", L, _name ? _name : "NULL");
381 STACK_GROW( L, 3);
382 STACK_CHECK( L)
383 lua_getfield( L, LUA_REGISTRYINDEX, LOOKUP_KEY); // {}?
384 if( lua_isnil( L, -1)) // nil
385 {
386 lua_pop( L, 1); //
387 lua_newtable( L); // {}
388 lua_pushvalue( L, -1); // {} {}
389 lua_setfield( L, LUA_REGISTRYINDEX, LOOKUP_KEY); // {}
390 }
391 lua_newtable( L); // {} {fqn}
392 if( _name)
393 {
394 lua_pushstring( L, _name); // {} {fqn} "name"
395 lua_rawseti( L, -2, start_depth); // {} {fqn}
396 }
397 lua_getfield( L, LUA_REGISTRYINDEX, LOOKUP_KEY_CACHE); // {} {fqn} {cache}?
398 if( lua_isnil( L, -1))
399 {
400 lua_pop( L, 1); // {} {fqn}
401 lua_newtable( L); // {} {fqn} {cache}
402 lua_pushvalue( L, -1); // {} {fqn} {cache} {cache}
403 lua_setfield( L, LUA_REGISTRYINDEX, LOOKUP_KEY_CACHE); // {} {fqn} {cache}
404 }
405 populate_func_lookup_table_recur( L, ctx_base, in_base, start_depth); // {...} {fqn} {cache}
406 lua_pop( L, 3);
407 STACK_END( L, 0)
126} 408}
127 409
128/* 410/*
@@ -139,33 +421,39 @@ static bool_t openlib( lua_State *L, const char *name, size_t len ) {
139*/ 421*/
140#define is_name_char(c) (isalpha(c) || (c)=='*') 422#define is_name_char(c) (isalpha(c) || (c)=='*')
141 423
142const char *luaG_openlibs( lua_State *L, const char *libs ) { 424const char *luaG_openlibs( lua_State *L, const char *libs)
143 const char *p; 425{
144 unsigned len; 426 const char *p;
427 unsigned len;
145 428
146 if (!libs) return NULL; // no libs, not even 'base' 429 if (!libs) return NULL; // no libs, not even 'base'
147 430
148 // 'lua.c' stops GC during initialization so perhaps its a good idea. :) 431 // 'lua.c' stops GC during initialization so perhaps its a good idea. :)
149 // 432 //
150 lua_gc(L, LUA_GCSTOP, 0); 433 lua_gc( L, LUA_GCSTOP, 0);
151 434
152 // Anything causes 'base' to be taken in 435 // Anything causes 'base' to be taken in
153 // 436 //
154 STACK_GROW(L,2); 437 STACK_GROW(L,2);
155 lua_pushcfunction( L, luaopen_base ); 438 STACK_CHECK(L)
156 lua_pushliteral( L, "" ); 439 lua_pushcfunction( L, luaopen_base);
157 lua_call( L, 1, 0 ); 440 lua_call( L, 0, 1);
158 441 // after opening base, register the functions they exported in our name<->function database
159 for( p= libs; *p; p+=len ) { 442 populate_func_lookup_table( L, LUA_GLOBALSINDEX, NULL);
160 len=0; 443 lua_pop( L, 1);
161 while (*p && !is_name_char(*p)) p++; // bypass delimiters 444 STACK_MID( L, 0);
162 while (is_name_char(p[len])) len++; // bypass name 445 for( p= libs; *p; p+=len )
163 if (len && (!openlib( L, p, len ))) 446 {
164 break; 447 len=0;
165 } 448 while (*p && !is_name_char(*p)) p++; // bypass delimiters
166 lua_gc(L, LUA_GCRESTART, 0); 449 while (is_name_char(p[len])) len++; // bypass name
450 if (len && (!openlib( L, p, len )))
451 break;
452 }
453 STACK_END(L,0)
454 lua_gc(L, LUA_GCRESTART, 0);
167 455
168 return *p ? p : NULL; 456 return *p ? p : NULL;
169} 457}
170 458
171 459
@@ -284,7 +572,7 @@ luaG_IdFunction get_idfunc( lua_State *L, int index )
284{ 572{
285 luaG_IdFunction ret; 573 luaG_IdFunction ret;
286 574
287 index= STACK_ABS(L,index); 575 index = STACK_ABS( L, index);
288 576
289 STACK_GROW(L,1); 577 STACK_GROW(L,1);
290 578
@@ -696,7 +984,7 @@ uint_t get_mt_id( lua_State *L, int i ) {
696 static uint_t last_id= 0; 984 static uint_t last_id= 0;
697 uint_t id; 985 uint_t id;
698 986
699 i= STACK_ABS(L,i); 987 i = STACK_ABS( L, i);
700 988
701 STACK_GROW(L,3); 989 STACK_GROW(L,3);
702 990
@@ -819,8 +1107,8 @@ static void inter_copy_func( lua_State *L2, uint_t L2_cache_i, lua_State *L, uin
819 1107
820static void push_cached_func( lua_State *L2, uint_t L2_cache_i, lua_State *L, uint_t i ) 1108static void push_cached_func( lua_State *L2, uint_t L2_cache_i, lua_State *L, uint_t i )
821{ 1109{
1110 void * const aspointer = (void*)lua_topointer( L, i );
822 // TBD: Merge this and same code for tables 1111 // TBD: Merge this and same code for tables
823
824 ASSERT_L( L2_cache_i != 0 ); 1112 ASSERT_L( L2_cache_i != 0 );
825 1113
826 STACK_GROW(L2,3); 1114 STACK_GROW(L2,3);
@@ -832,7 +1120,7 @@ static void push_cached_func( lua_State *L2, uint_t L2_cache_i, lua_State *L, ui
832 // We don't need to use the from state ('L') in ID since the life span 1120 // We don't need to use the from state ('L') in ID since the life span
833 // is only for the duration of a copy (both states are locked). 1121 // is only for the duration of a copy (both states are locked).
834 // 1122 //
835 lua_pushlightuserdata( L2, (void*)lua_topointer( L, i )); // push a light userdata uniquely representing the function 1123 lua_pushlightuserdata( L2, aspointer); // push a light userdata uniquely representing the function
836 1124
837 //fprintf( stderr, "<< ID: %s >>\n", lua_tostring(L2,-1) ); 1125 //fprintf( stderr, "<< ID: %s >>\n", lua_tostring(L2,-1) );
838 1126
@@ -886,9 +1174,46 @@ static void push_cached_func( lua_State *L2, uint_t L2_cache_i, lua_State *L, ui
886 // 1174 //
887 // L2 [-1]: function 1175 // L2 [-1]: function
888 1176
889 ASSERT_L( lua_isfunction(L2,-1) ); 1177 ASSERT_L( lua_isfunction(L2,-1));
890} 1178}
891 1179
1180/*
1181* Push a looked-up native/LuaJIT function.
1182*/
1183static void lookup_native_func( lua_State *L2, lua_State *L, uint_t i)
1184{
1185 char const *fqn;
1186 size_t len;
1187 _ASSERT_L( L, lua_isfunction( L, i));
1188 STACK_CHECK( L)
1189 STACK_CHECK( L2)
1190 // fetch the name from the source state's lookup table
1191 lua_getfield( L, LUA_REGISTRYINDEX, LOOKUP_KEY); // {}
1192 _ASSERT_L( L, lua_istable( L, -1));
1193 lua_pushvalue( L, i); // {} f
1194 lua_rawget( L, -2); // {} "f.q.n"
1195 fqn = lua_tolstring( L, -1, &len);
1196 if( !fqn)
1197 {
1198 luaL_error( L, "function not found in origin transfer database.");
1199 }
1200 // push the equivalent function in the destination's stack, retrieved from the lookup table
1201 lua_getfield( L2, LUA_REGISTRYINDEX, LOOKUP_KEY); // {}
1202 _ASSERT_L( L2, lua_istable( L2, -1));
1203 lua_pushlstring( L2, fqn, len); // {} "f.q.n"
1204 lua_pop( L, 2); //
1205 lua_rawget( L2, -2); // {} f
1206 if( !lua_isfunction( L2, -1))
1207 {
1208 // yarglah: luaL_error formatting doesn't support string width modifier!
1209 char message[256];
1210 sprintf( message, "function %*s not found in destination transfer database.", len, fqn);
1211 luaL_error( L, message);
1212 }
1213 lua_remove( L2, -2); // f
1214 STACK_END( L2, 1)
1215 STACK_END( L, 0)
1216}
892 1217
893#define LOG_FUNC_INFO 0 1218#define LOG_FUNC_INFO 0
894 1219
@@ -900,114 +1225,132 @@ enum e_vt {
900}; 1225};
901static bool_t inter_copy_one_( lua_State *L2, uint_t L2_cache_i, lua_State *L, uint_t i, enum e_vt value_type ); 1226static bool_t inter_copy_one_( lua_State *L2, uint_t L2_cache_i, lua_State *L, uint_t i, enum e_vt value_type );
902 1227
903static void inter_copy_func( lua_State *L2, uint_t L2_cache_i, lua_State *L, uint_t i ) { 1228static void inter_copy_func( lua_State *L2, uint_t L2_cache_i, lua_State *L, uint_t i )
904 1229{
905 lua_CFunction cfunc= lua_tocfunction( L,i ); 1230 FuncSubType funcSubType;
906 unsigned n; 1231 lua_CFunction cfunc = luaG_tocfunction( L, i, &funcSubType); // NULL for LuaJIT-fast && bytecode functions
907 1232 i = STACK_ABS( L, i);
908 ASSERT_L( L2_cache_i != 0 );
909
910 STACK_GROW(L,2);
911
912 STACK_CHECK(L)
913 if (!cfunc) { // Lua function
914 luaL_Buffer b;
915 const char *s;
916 size_t sz;
917 int tmp;
918 const char *name= NULL;
919 int linedefined = 0;
920 1233
921#if LOG_FUNC_INFO 1234 ASSERT_L( L2_cache_i != 0 );
922 // "To get information about a function you push it onto the 1235 STACK_GROW(L,2);
923 // stack and start the what string with the character '>'." 1236 STACK_CHECK(L)
924 //
925 { lua_Debug ar;
926 lua_pushvalue( L, i );
927 lua_getinfo(L, ">nS", &ar); // fills 'name' 'namewhat' and 'linedefined', pops function
928 name= ar.namewhat;
929 linedefined = ar.linedefined;
930 fprintf( stderr, "NAME: %s @ %d\n", ar.short_src, linedefined); // just gives NULL
931 }
932#endif // LOG_FUNC_INFO
933 // 'lua_dump()' needs the function at top of stack
934 //
935 if (i!=-1) lua_pushvalue( L, i );
936 1237
937 luaL_buffinit(L,&b); 1238 if( funcSubType == FST_Bytecode)
938 tmp= lua_dump(L, buf_writer, &b); 1239 {
939 ASSERT_L(tmp==0); 1240 unsigned n;
940 // 1241 luaL_Buffer b;
941 // "value returned is the error code returned by the last call 1242 // 'lua_dump()' needs the function at top of stack
942 // to the writer" (and we only return 0) 1243 // if already on top of the stack, no need to push again
1244 int needToPush = (i != lua_gettop( L));
1245 if( needToPush)
1246 lua_pushvalue( L, i);
1247
1248 luaL_buffinit( L, &b);
1249 //
1250 // "value returned is the error code returned by the last call
1251 // to the writer" (and we only return 0)
1252 // not sure this could ever fail but for memory shortage reasons
1253 if( lua_dump( L, buf_writer, &b) != 0)
1254 {
1255 luaL_error( L, "internal error: function dump failed.");
1256 }
943 1257
944 luaL_pushresult(&b); // pushes dumped string on 'L' 1258 luaL_pushresult( &b); // pushes dumped string on 'L'
945 s= lua_tolstring(L,-1,&sz);
946 ASSERT_L( s && sz );
947 1259
948 if (i!=-1) lua_remove( L, -2 ); 1260 // if not pushed, no need to pop
1261 if( needToPush)
1262 {
1263 lua_remove( L, -2);
1264 }
949 1265
950 // Note: Line numbers seem to be taken precisely from the 1266 // transfer the bytecode, then the upvalues, to create a similar closure
951 // original function. 'name' is not used since the chunk 1267 {
952 // is precompiled (it seems...). 1268 const char *name= NULL;
953 // 1269
954 // TBD: Can we get the function's original name through, as well? 1270 #if LOG_FUNC_INFO
955 // 1271 // "To get information about a function you push it onto the
956 if (luaL_loadbuffer(L2, s, sz, name) != 0) { 1272 // stack and start the what string with the character '>'."
957 // chunk is precompiled so only LUA_ERRMEM can happen 1273 //
958 // "Otherwise, it pushes an error message" 1274 {
959 // 1275 lua_Debug ar;
960 STACK_GROW( L,1 ); 1276 lua_pushvalue( L, i );
961 luaL_error( L, "%s", lua_tostring(L2,-1) ); 1277 lua_getinfo(L, ">nS", &ar); // fills 'name' 'namewhat' and 'linedefined', pops function
962 } 1278 name= ar.namewhat;
963 lua_pop(L,1); // remove the dumped string 1279 fprintf( stderr, "NAME: %s @ %d\n", ar.short_src, ar.linedefined); // just gives NULL
964 STACK_MID(L,0) 1280 }
965 } 1281 #endif // LOG_FUNC_INFO
1282 {
1283 const char *s;
1284 size_t sz;
1285 s = lua_tolstring( L, -1, &sz);
1286 ASSERT_L( s && sz);
1287
1288 // Note: Line numbers seem to be taken precisely from the
1289 // original function. 'name' is not used since the chunk
1290 // is precompiled (it seems...).
1291 //
1292 // TBD: Can we get the function's original name through, as well?
1293 //
1294 if (luaL_loadbuffer(L2, s, sz, name) != 0)
1295 {
1296 // chunk is precompiled so only LUA_ERRMEM can happen
1297 // "Otherwise, it pushes an error message"
1298 //
1299 STACK_GROW( L,1);
1300 luaL_error( L, "%s", lua_tostring(L2,-1));
1301 }
1302 lua_pop( L, 1); // remove the dumped string
1303 }
1304 STACK_MID( L, 0)
1305
1306 /* push over any upvalues; references to this function will come from
1307 * cache so we don't end up in eternal loop.
1308 */
1309 for( n=0; lua_getupvalue( L, i, 1+n ) != NULL; n++ )
1310 {
1311 if ((!cfunc) && lua_equal(L,i,-1))
1312 {
1313 /* Lua closure that has a (recursive) upvalue to itself
1314 */
1315 lua_pushvalue( L2, -((int)n)-1 );
1316 }
1317 else
1318 {
1319 if( !inter_copy_one_( L2, L2_cache_i, L, lua_gettop(L), VT_NORMAL))
1320 luaL_error( L, "Cannot copy upvalue type '%s'", luaG_typename( L, -1));
1321 }
1322 lua_pop( L, 1);
1323 }
1324 // L2: function + 'n' upvalues (>=0)
1325
1326 STACK_MID(L,0)
1327
1328 // Set upvalues (originally set to 'nil' by 'lua_load')
1329 {
1330 int func_index = lua_gettop( L2) - n;
1331 for( ; n > 0; -- n)
1332 {
1333 char const *rc = lua_setupvalue( L2, func_index, n);
1334 //
1335 // "assigns the value at the top of the stack to the upvalue and returns its name.
1336 // It also pops the value from the stack."
1337
1338 ASSERT_L(rc); // not having enough slots?
1339 }
1340 }
1341 }
1342 }
1343 else // C function OR LuaJIT fast function!!!
1344 {
966#if LOG_FUNC_INFO 1345#if LOG_FUNC_INFO
967 else 1346 fprintf( stderr, "NAME: [C] function %p \n", cfunc);
968 {
969 fprintf( stderr, "NAME: [C] function %p \n", cfunc);
970 }
971#endif // LOG_FUNC_INFO 1347#endif // LOG_FUNC_INFO
972 1348 // No need to transfer upvalues for C/JIT functions since they weren't actually copied, only looked up
973 /* push over any upvalues; references to this function will come from 1349 lookup_native_func( L2, L, i);
974 * cache so we don't end up in eternal loop. 1350 }
975 */ 1351 STACK_END(L,0)
976 for( n=0; lua_getupvalue( L, i, 1+n ) != NULL; n++ ) {
977 if ((!cfunc) && lua_equal(L,i,-1)) {
978 /* Lua closure that has a (recursive) upvalue to itself
979 */
980 lua_pushvalue( L2, -((int)n)-1 );
981 } else {
982 if (!inter_copy_one_( L2, L2_cache_i, L, lua_gettop(L), VT_NORMAL ))
983 luaL_error( L, "Cannot copy upvalue type '%s'", luaG_typename(L,-1) );
984 }
985 lua_pop(L,1);
986 }
987 // L2: function + 'n' upvalues (>=0)
988
989 STACK_MID(L,0)
990
991 if (cfunc) {
992 lua_pushcclosure( L2, cfunc, n ); // eats up upvalues
993 } else {
994 // Set upvalues (originally set to 'nil' by 'lua_load')
995 //
996 int func_index= lua_gettop(L2)-n;
997
998 for( ; n>0; n-- ) {
999 const char *rc= lua_setupvalue( L2, func_index, n );
1000 //
1001 // "assigns the value at the top of the stack to the upvalue and returns its name.
1002 // It also pops the value from the stack."
1003
1004 ASSERT_L(rc); // not having enough slots?
1005 }
1006 }
1007 STACK_END(L,0)
1008} 1352}
1009 1353
1010
1011/* 1354/*
1012* Copies a value from 'L' state (at index 'i') to 'L2' state. Does not remove 1355* Copies a value from 'L' state (at index 'i') to 'L2' state. Does not remove
1013* the original value. 1356* the original value.
@@ -1300,32 +1643,36 @@ MUTEX_T require_cs;
1300// 1643//
1301// Upvalues: [1]: original 'require' function 1644// Upvalues: [1]: original 'require' function
1302// 1645//
1303static int new_require( lua_State *L ) 1646static int new_require( lua_State *L)
1304{ 1647{
1305 int rc; 1648 int rc, i;
1306 int args= lua_gettop(L); 1649 int args = lua_gettop( L);
1650 //char const *modname = luaL_checkstring( L, 1);
1307 1651
1308 STACK_GROW(L,1); 1652 STACK_GROW( L, args + 1);
1309 STACK_CHECK(L) 1653 STACK_CHECK( L)
1654
1655 lua_pushvalue( L, lua_upvalueindex(1));
1656 for( i = 1; i <= args; ++ i)
1657 lua_pushvalue( L, i);
1310 1658
1311 // Using 'lua_pcall()' to catch errors; otherwise a failing 'require' would 1659 // Using 'lua_pcall()' to catch errors; otherwise a failing 'require' would
1312 // leave us locked, blocking any future 'require' calls from other lanes. 1660 // leave us locked, blocking any future 'require' calls from other lanes.
1313 // 1661 //
1314 MUTEX_LOCK( &require_cs); 1662 MUTEX_LOCK( &require_cs);
1315 { 1663 {
1316 lua_pushvalue( L, lua_upvalueindex(1) ); 1664 rc = lua_pcall( L, args, 1 /*retvals*/, 0 /*errfunc*/ );
1317 lua_insert( L, 1 );
1318
1319 rc= lua_pcall( L, args, 1 /*retvals*/, 0 /*errfunc*/ );
1320 // 1665 //
1321 // LUA_ERRRUN / LUA_ERRMEM 1666 // LUA_ERRRUN / LUA_ERRMEM
1322 } 1667 }
1323 MUTEX_UNLOCK( &require_cs); 1668 MUTEX_UNLOCK( &require_cs);
1324 1669
1670 // the required module (or an error message) is left on the stack as returned value by original require function
1671 STACK_END( L, 1)
1672
1325 if (rc) 1673 if (rc)
1326 lua_error(L); // error message already at [-1] 1674 lua_error(L); // error message already at [-1]
1327 1675
1328 STACK_END(L,0)
1329 return 1; 1676 return 1;
1330} 1677}
1331 1678
diff --git a/src/tools.h b/src/tools.h
index a080257..1c9b00a 100644
--- a/src/tools.h
+++ b/src/tools.h
@@ -10,10 +10,10 @@
10 10
11#include <assert.h> 11#include <assert.h>
12 12
13// Note: The < -10000 test is to leave registry/global/upvalue indices untouched 13// Note: The < LUA_REGISTRYINDEX test is to leave registry/global/upvalue indices untouched
14// 14//
15#define /*int*/ STACK_ABS(L,n) \ 15#define /*int*/ STACK_ABS(L,n) \
16 ( ((n) >= 0 || (n) <= -10000) ? (n) : lua_gettop(L) +(n) +1 ) 16 ( ((n) >= 0 || (n) <= LUA_REGISTRYINDEX) ? (n) : lua_gettop(L) +(n) +1 )
17 17
18#ifdef NDEBUG 18#ifdef NDEBUG
19 #define _ASSERT_L(lua,c) /*nothing*/ 19 #define _ASSERT_L(lua,c) /*nothing*/
@@ -24,7 +24,7 @@
24 #define DEBUG() /*nothing*/ 24 #define DEBUG() /*nothing*/
25 #define DEBUGEXEC(_code) {} /*nothing*/ 25 #define DEBUGEXEC(_code) {} /*nothing*/
26#else 26#else
27 #define _ASSERT_L(lua,c) { if (!(c)) luaL_error( lua, "ASSERT failed: %s:%d '%s'", __FILE__, __LINE__, #c ); } 27 #define _ASSERT_L(lua,c) do { if (!(c)) luaL_error( lua, "ASSERT failed: %s:%d '%s'", __FILE__, __LINE__, #c ); } while( 0)
28 // 28 //
29 #define STACK_CHECK(L) { int _oldtop_##L = lua_gettop(L); 29 #define STACK_CHECK(L) { int _oldtop_##L = lua_gettop(L);
30 #define STACK_MID(L,change) { int a= lua_gettop(L)-_oldtop_##L; int b= (change); \ 30 #define STACK_MID(L,change) { int a= lua_gettop(L)-_oldtop_##L; int b= (change); \
@@ -37,7 +37,7 @@
37#endif 37#endif
38#define ASSERT_L(c) _ASSERT_L(L,c) 38#define ASSERT_L(c) _ASSERT_L(L,c)
39 39
40#define STACK_GROW(L,n) { if (!lua_checkstack(L,n)) luaL_error( L, "Cannot grow stack!" ); } 40#define STACK_GROW(L,n) do { if (!lua_checkstack(L,n)) luaL_error( L, "Cannot grow stack!" ); } while( 0)
41 41
42#define LUAG_FUNC( func_name ) static int LG_##func_name( lua_State *L ) 42#define LUAG_FUNC( func_name ) static int LG_##func_name( lua_State *L )
43 43
@@ -72,6 +72,7 @@ int luaG_inter_move( lua_State *L, lua_State *L2, uint_t n);
72extern MUTEX_T deep_lock; 72extern MUTEX_T deep_lock;
73extern MUTEX_T mtid_lock; 73extern MUTEX_T mtid_lock;
74 74
75void populate_func_lookup_table( lua_State *L, int _i, char const *_name);
75void serialize_require( lua_State *L); 76void serialize_require( lua_State *L);
76extern MUTEX_T require_cs; 77extern MUTEX_T require_cs;
77 78