diff options
author | Benoit Germain <bnt.germain@gmail.com> | 2024-03-30 14:45:01 +0100 |
---|---|---|
committer | Benoit Germain <bnt.germain@gmail.com> | 2024-03-30 14:45:01 +0100 |
commit | 79d91901745e0c65443607c804533f06575b43ad (patch) | |
tree | cb8a937fa9c971c83a1e7e4138485bb5c7454313 /src/lanes.cpp | |
parent | 53d327679364093e8e1b4c17075633670bea9c83 (diff) | |
download | lanes-79d91901745e0c65443607c804533f06575b43ad.tar.gz lanes-79d91901745e0c65443607c804533f06575b43ad.tar.bz2 lanes-79d91901745e0c65443607c804533f06575b43ad.zip |
C++ migration: make sure to always create the lane handle userdata
Diffstat (limited to 'src/lanes.cpp')
-rw-r--r-- | src/lanes.cpp | 111 |
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 | ||