aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/lanes.cpp111
1 files changed, 69 insertions, 42 deletions
diff --git a/src/lanes.cpp b/src/lanes.cpp
index 8890b06..472b501 100644
--- a/src/lanes.cpp
+++ b/src/lanes.cpp
@@ -1094,15 +1094,28 @@ LUAG_FUNC(lane_new)
1094 return luaL_error(L, "could not create lane: out of memory"); 1094 return luaL_error(L, "could not create lane: out of memory");
1095 } 1095 }
1096 1096
1097 // would prefer std::experimental::scope, but it's not universally available 1097 class OnExit
1098 struct OnExit
1099 { 1098 {
1099 private:
1100
1101 lua_State* const m_L;
1100 Lane* m_lane{ nullptr }; 1102 Lane* m_lane{ nullptr };
1101 OnExit(Lane* lane_) : m_lane{ lane_ } {} 1103 int const m_gc_cb_idx;
1104
1105 public:
1106
1107 OnExit(lua_State* L_, Lane* lane_, int gc_cb_idx_)
1108 : m_L{ L_ }
1109 , m_lane{ lane_ }
1110 , m_gc_cb_idx{ gc_cb_idx_ }
1111 {}
1112
1102 ~OnExit() 1113 ~OnExit()
1103 { 1114 {
1104 if (m_lane) 1115 if (m_lane)
1105 { 1116 {
1117 // we still need a full userdata so that garbage collection can do its thing
1118 prepareUserData();
1106 // leave a single cancel_error on the stack for the caller 1119 // leave a single cancel_error on the stack for the caller
1107 lua_settop(m_lane->L, 0); 1120 lua_settop(m_lane->L, 0);
1108 CANCEL_ERROR.pushKey(m_lane->L); 1121 CANCEL_ERROR.pushKey(m_lane->L);
@@ -1117,7 +1130,47 @@ LUAG_FUNC(lane_new)
1117 m_lane->m_ready.count_down(); 1130 m_lane->m_ready.count_down();
1118 } 1131 }
1119 } 1132 }
1120 } onExit{ lane }; 1133
1134 private:
1135
1136 void prepareUserData()
1137 {
1138 DEBUGSPEW_CODE(fprintf(stderr, INDENT_BEGIN "lane_new: preparing lane userdata\n" INDENT_END));
1139 STACK_CHECK_START_REL(m_L, 0);
1140 // a Lane full userdata needs a single uservalue
1141 Lane** const ud{ lua_newuserdatauv<Lane*>(m_L, 1) }; // ... lane
1142 *ud = m_lane; // don't forget to store the pointer in the userdata!
1143
1144 // Set metatable for the userdata
1145 //
1146 lua_pushvalue(m_L, lua_upvalueindex(1)); // ... lane mt
1147 lua_setmetatable(m_L, -2); // ... lane
1148 STACK_CHECK(m_L, 1);
1149
1150 // Create uservalue for the userdata
1151 // (this is where lane body return values will be stored when the handle is indexed by a numeric key)
1152 lua_newtable(m_L); // ... lane uv
1153
1154 // Store the gc_cb callback in the uservalue
1155 if (m_gc_cb_idx > 0)
1156 {
1157 GCCB_KEY.pushKey(m_L); // ... lane uv k
1158 lua_pushvalue(m_L, m_gc_cb_idx); // ... lane uv k gc_cb
1159 lua_rawset(m_L, -3); // ... lane uv
1160 }
1161
1162 lua_setiuservalue(m_L, -2, 1); // ... lane
1163 STACK_CHECK(m_L, 1);
1164 }
1165
1166 public:
1167
1168 void success()
1169 {
1170 prepareUserData();
1171 m_lane = nullptr;
1172 }
1173 } onExit{ L, lane, gc_cb_idx };
1121 // launch the thread early, it will sync with a std::latch to parallelize OS thread warmup and L2 preparation 1174 // launch the thread early, it will sync with a std::latch to parallelize OS thread warmup and L2 preparation
1122 DEBUGSPEW_CODE(fprintf(stderr, INDENT_BEGIN "lane_new: launching thread\n" INDENT_END)); 1175 DEBUGSPEW_CODE(fprintf(stderr, INDENT_BEGIN "lane_new: launching thread\n" INDENT_END));
1123 THREAD_CREATE(&lane->thread, lane_main, lane, priority); 1176 THREAD_CREATE(&lane->thread, lane_main, lane, priority);
@@ -1133,16 +1186,15 @@ LUAG_FUNC(lane_new)
1133 lua_setglobal( L2, "decoda_name"); // 1186 lua_setglobal( L2, "decoda_name"); //
1134 ASSERT_L( lua_gettop( L2) == 0); 1187 ASSERT_L( lua_gettop( L2) == 0);
1135 1188
1136 DEBUGSPEW_CODE( fprintf( stderr, INDENT_BEGIN "lane_new: update 'package'\n" INDENT_END));
1137 // package 1189 // package
1138 if (package_idx != 0) 1190 if (package_idx != 0)
1139 { 1191 {
1192 DEBUGSPEW_CODE(fprintf(stderr, INDENT_BEGIN "lane_new: update 'package'\n" INDENT_END));
1140 // when copying with mode LookupMode::LaneBody, should raise an error in case of problem, not leave it one the stack 1193 // when copying with mode LookupMode::LaneBody, should raise an error in case of problem, not leave it one the stack
1141 (void) luaG_inter_copy_package(U, L, L2, package_idx, LookupMode::LaneBody); 1194 (void) luaG_inter_copy_package(U, L, L2, package_idx, LookupMode::LaneBody);
1142 } 1195 }
1143 1196
1144 // modules to require in the target lane *before* the function is transfered! 1197 // modules to require in the target lane *before* the function is transfered!
1145
1146 if (required_idx != 0) 1198 if (required_idx != 0)
1147 { 1199 {
1148 int nbRequired = 1; 1200 int nbRequired = 1;
@@ -1224,16 +1276,15 @@ LUAG_FUNC(lane_new)
1224 DEBUGSPEW_CODE( -- U->debugspew_indent_depth); 1276 DEBUGSPEW_CODE( -- U->debugspew_indent_depth);
1225 } 1277 }
1226 STACK_CHECK(L, 0); 1278 STACK_CHECK(L, 0);
1227 STACK_CHECK( L2, 0); 1279 STACK_CHECK(L2, 0);
1228 1280
1229 // Lane main function 1281 // Lane main function
1230 if (lua_type(L, 1) == LUA_TFUNCTION) 1282 if (lua_type(L, 1) == LUA_TFUNCTION)
1231 { 1283 {
1232 int res;
1233 DEBUGSPEW_CODE( fprintf( stderr, INDENT_BEGIN "lane_new: transfer lane body\n" INDENT_END)); 1284 DEBUGSPEW_CODE( fprintf( stderr, INDENT_BEGIN "lane_new: transfer lane body\n" INDENT_END));
1234 DEBUGSPEW_CODE( ++ U->debugspew_indent_depth); 1285 DEBUGSPEW_CODE( ++ U->debugspew_indent_depth);
1235 lua_pushvalue(L, 1); // func libs priority globals package required gc_cb [... args ...] func 1286 lua_pushvalue(L, 1); // func libs priority globals package required gc_cb [... args ...] func
1236 res = luaG_inter_move(U, L, L2, 1, LookupMode::LaneBody); // func libs priority globals package required gc_cb [... args ...] // func 1287 int const res{ luaG_inter_move(U, L, L2, 1, LookupMode::LaneBody) };// func libs priority globals package required gc_cb [... args ...] // func
1237 DEBUGSPEW_CODE( -- U->debugspew_indent_depth); 1288 DEBUGSPEW_CODE( -- U->debugspew_indent_depth);
1238 if (res != 0) 1289 if (res != 0)
1239 { 1290 {
@@ -1242,6 +1293,7 @@ LUAG_FUNC(lane_new)
1242 } 1293 }
1243 else if (lua_type(L, 1) == LUA_TSTRING) 1294 else if (lua_type(L, 1) == LUA_TSTRING)
1244 { 1295 {
1296 DEBUGSPEW_CODE(fprintf(stderr, INDENT_BEGIN "lane_new: compile lane body\n" INDENT_END));
1245 // compile the string 1297 // compile the string
1246 if (luaL_loadstring(L2, lua_tostring(L, 1)) != 0) // func 1298 if (luaL_loadstring(L2, lua_tostring(L, 1)) != 0) // func
1247 { 1299 {
@@ -1249,8 +1301,8 @@ LUAG_FUNC(lane_new)
1249 } 1301 }
1250 } 1302 }
1251 STACK_CHECK(L, 0); 1303 STACK_CHECK(L, 0);
1252 STACK_CHECK( L2, 1); 1304 STACK_CHECK(L2, 1);
1253 ASSERT_L( lua_isfunction( L2, 1)); 1305 ASSERT_L(lua_isfunction(L2, 1));
1254 1306
1255 // revive arguments 1307 // revive arguments
1256 if (nargs > 0) 1308 if (nargs > 0)
@@ -1266,44 +1318,19 @@ LUAG_FUNC(lane_new)
1266 } 1318 }
1267 } 1319 }
1268 STACK_CHECK(L, -nargs); 1320 STACK_CHECK(L, -nargs);
1269 ASSERT_L( lua_gettop( L) == FIXED_ARGS); 1321 ASSERT_L(lua_gettop( L) == FIXED_ARGS);
1270 STACK_CHECK_RESET_REL(L, 0);
1271 STACK_CHECK( L2, 1 + nargs);
1272
1273 // a Lane full userdata needs a single uservalue
1274 Lane** const ud{ lua_newuserdatauv<Lane*>(L, 1) }; // func libs priority globals package required gc_cb lane
1275 *ud = lane; // don't forget to store the pointer in the userdata!
1276
1277 // Set metatable for the userdata
1278 //
1279 lua_pushvalue(L, lua_upvalueindex( 1)); // func libs priority globals package required gc_cb lane mt
1280 lua_setmetatable(L, -2); // func libs priority globals package required gc_cb lane
1281 STACK_CHECK(L, 1);
1282
1283 // Create uservalue for the userdata
1284 // (this is where lane body return values will be stored when the handle is indexed by a numeric key)
1285 lua_newtable(L); // func libs cancelstep priority globals package required gc_cb lane uv
1286
1287 // Store the gc_cb callback in the uservalue
1288 if (gc_cb_idx > 0)
1289 {
1290 GCCB_KEY.pushKey(L); // func libs priority globals package required gc_cb lane uv k
1291 lua_pushvalue(L, gc_cb_idx); // func libs priority globals package required gc_cb lane uv k gc_cb
1292 lua_rawset(L, -3); // func libs priority globals package required gc_cb lane uv
1293 }
1294
1295 lua_setiuservalue(L, -2, 1); // func libs priority globals package required gc_cb lane
1296 1322
1297 // Store 'lane' in the lane's registry, for 'cancel_test()' (we do cancel tests at pending send/receive). 1323 // Store 'lane' in the lane's registry, for 'cancel_test()' (we do cancel tests at pending send/receive).
1298 LANE_POINTER_REGKEY.setValue(L2, [lane](lua_State* L) { lua_pushlightuserdata(L, lane); }); // func [... args ...] 1324 LANE_POINTER_REGKEY.setValue(L2, [lane](lua_State* L) { lua_pushlightuserdata(L, lane); }); // func [... args ...]
1299
1300 STACK_CHECK(L, 1);
1301 STACK_CHECK(L2, 1 + nargs); 1325 STACK_CHECK(L2, 1 + nargs);
1302 DEBUGSPEW_CODE(--U->debugspew_indent_depth);
1303 1326
1327 STACK_CHECK_RESET_REL(L, 0);
1304 // all went well, the lane's thread can start working 1328 // all went well, the lane's thread can start working
1305 onExit.m_lane = nullptr; 1329 onExit.success();
1330 // we should have the lane userdata on top of the stack
1331 STACK_CHECK(L, 1);
1306 lane->m_ready.count_down(); 1332 lane->m_ready.count_down();
1333 DEBUGSPEW_CODE(--U->debugspew_indent_depth);
1307 return 1; 1334 return 1;
1308} 1335}
1309 1336