History

Use int handles for script timers instead of QTimer*

Ada committed 8 months ago

Commit 461e32f1 parent db38db73 files · +72 −83Browse files

Showing the changes to libraries/script-engine/src/ScriptManager.cpp (1 of 3 files). Show all

Unified · Split

libraries/script-engine/src/ScriptManager.cpp+53−41
@@ -1171,32 +1171,37 @@ void ScriptManager::run() { · 1170 unmodified lines
1171// NOTE: This is private because it must be called on the same thread that created the timers, which is why1171// NOTE: This is private because it must be called on the same thread that created the timers, which is why
1172// we want to only call it in our own run "shutdown" processing.1172// we want to only call it in our own run "shutdown" processing.
1173void ScriptManager::stopAllTimers() {1173void ScriptManager::stopAllTimers() {
1174 QMutableHashIterator<QTimer*, CallbackData> i(_timerFunctionMap);1174 for (const auto& [handle, value] : _timerFunctionMap) {
1175 int j {0};1175 QTimer* timer = std::get<0>(value);
1176 while (i.hasNext()) {1176
1177 i.next();1177 timer->stop();
1178 QTimer* timer = i.key();1178 delete timer;
1179 qCDebug(scriptengine) << getFilename() << "stopAllTimers[" << j++ << "]";
1180 stopTimer(timer);
1181 }1179 }
1180
1181 _timerFunctionMap.clear();
1182 _timerHandleCounter = 1;
1182}1183}
1183 1184
1184void ScriptManager::stopAllTimersForEntityScript(const EntityItemID& entityID) {1185void ScriptManager::stopAllTimersForEntityScript(const EntityItemID& entityID) {
1185 // We could maintain a separate map of entityID => QTimer, but someone will have to prove to me that it's worth the complexity. -HRS1186 std::vector<int> toDelete;
1186 QVector<QTimer*> toDelete;1187
1187 QMutableHashIterator<QTimer*, CallbackData> i(_timerFunctionMap);1188 for (const auto& [handle, value] : _timerFunctionMap) {
1188 while (i.hasNext()) {1189 const auto& [timer, callbackData] = value;
1189 i.next();1190
1190 if (i.value().definingEntityIdentifier != entityID) {1191 if (callbackData.definingEntityIdentifier != entityID) { continue; }
1191 continue;1192
1192 }1193 timer->stop();
1193 QTimer* timer = i.key();1194 delete timer;
1194 toDelete << timer; // don't delete while we're iterating. save it.1195
1196 toDelete.push_back(handle);
1195 }1197 }
1196 for (auto timer:toDelete) { // now reap 'em1198
1197 stopTimer(timer);1199 for (auto handle : toDelete) {
1200 _timerFunctionMap.erase(handle);
1198 }1201 }
1199 1202
1203 // the timer map is potentially shared across multiple entity scripts,
1204 // so don't clear it or reset the handle counter
1200}1205}
1201 1206
1202void ScriptManager::stop(bool marshal) {1207void ScriptManager::stop(bool marshal) {
@@ -1220,7 +1225,7 @@ void ScriptManager::updateMemoryCost(const qint64& deltaSize) { · 17 unmodified lines
1220 _engine->updateMemoryCost(deltaSize);1225 _engine->updateMemoryCost(deltaSize);
1221}1226}
1222 1227
1223void ScriptManager::timerFired() {1228void ScriptManager::timerFired(int handle) {
1224 if (isStopped()) {1229 if (isStopped()) {
1225 scriptWarningMessage("Script.timerFired() while shutting down is ignored... parent script:" + getFilename(), getFilename(), -1);1230 scriptWarningMessage("Script.timerFired() while shutting down is ignored... parent script:" + getFilename(), getFilename(), -1);
1226 return; // bail early1231 return; // bail early
@@ -1242,25 +1247,29 @@ void ScriptManager::timerFired() { · 15 unmodified lines
1242 callTimer.start();1247 callTimer.start();
1243#endif1248#endif
1244 1249
1245 QTimer* callingTimer = reinterpret_cast<QTimer*>(sender());1250 if (!_timerFunctionMap.contains(handle)) {
1246 CallbackData timerData = _timerFunctionMap.value(callingTimer);1251 qCWarning(scriptengine) << "timerFired -- not in _timerFunctionMap" << handle;
1252 return;
1253 }
1247 1254
1248 if (!callingTimer->isActive()) {1255 auto [timer, data] = _timerFunctionMap.at(handle);
1256
1257 if (!timer->isActive()) {
1249 // this timer is done, we can kill it1258 // this timer is done, we can kill it
1250 _timerFunctionMap.remove(callingTimer);1259 _timerFunctionMap.erase(handle);
1251 delete callingTimer;1260 delete timer;
1252 }1261 }
1253 1262
1254 // call the associated JS function, if it exists1263 // call the associated JS function, if it exists
1255 if (timerData.function.isValid()) {1264 if (data.function.isValid()) {
1256 PROFILE_RANGE(script, __FUNCTION__);1265 PROFILE_RANGE(script, __FUNCTION__);
1257 auto preTimer = p_high_resolution_clock::now();1266 auto preTimer = p_high_resolution_clock::now();
1258 callWithEnvironment(timerData.definingEntityIdentifier, timerData.definingSandboxURL, timerData.function, timerData.function, ScriptValueList());1267 callWithEnvironment(data.definingEntityIdentifier, data.definingSandboxURL, data.function, data.function, ScriptValueList());
1259 auto postTimer = p_high_resolution_clock::now();1268 auto postTimer = p_high_resolution_clock::now();
1260 auto elapsed = (postTimer - preTimer);1269 auto elapsed = (postTimer - preTimer);
1261 _totalTimerExecution += std::chrono::duration_cast<std::chrono::microseconds>(elapsed);1270 _totalTimerExecution += std::chrono::duration_cast<std::chrono::microseconds>(elapsed);
1262 } else {1271 } else {
1263 qCWarning(scriptengine) << "timerFired -- invalid function" << timerData.function.toVariant().toString();1272 qCWarning(scriptengine) << "timerFired -- invalid function" << data.function.toVariant().toString();
1264 }1273 }
1265 1274
1266#ifdef SCRIPT_TIMER_PERFORMANCE_STATISTICS1275#ifdef SCRIPT_TIMER_PERFORMANCE_STATISTICS
@@ -1268,7 +1277,10 @@ void ScriptManager::timerFired() { · 1 unmodified line
1268#endif1277#endif
1269}1278}
1270 1279
1271QTimer* ScriptManager::setupTimerWithInterval(const ScriptValue& function, int intervalMS, bool isSingleShot) {1280int ScriptManager::setupTimerWithInterval(const ScriptValue& function, int intervalMS, bool isSingleShot) {
1281 int handle = _timerHandleCounter;
1282 _timerHandleCounter += 1;
1283
1272 // create the timer, add it to the map, and start it1284 // create the timer, add it to the map, and start it
1273 QTimer* newTimer = new QTimer(this);1285 QTimer* newTimer = new QTimer(this);
1274 newTimer->setSingleShot(isSingleShot);1286 newTimer->setSingleShot(isSingleShot);
@@ -1279,14 +1291,13 @@ QTimer* ScriptManager::setupTimerWithInterval(const ScriptValue& function, int i · 4 unmodified lines
1279 newTimer->setTimerType(Qt::PreciseTimer);1291 newTimer->setTimerType(Qt::PreciseTimer);
1280 }1292 }
1281 1293
1282 connect(newTimer, &QTimer::timeout, this, &ScriptManager::timerFired);1294 connect(newTimer, &QTimer::timeout, [this, handle]() { timerFired(handle); });
1283 1295
1284 // make sure the timer stops when the script does1296 // make sure the timer stops when the script does
1285 connect(this, &ScriptManager::scriptEnding, newTimer, &QTimer::stop);1297 connect(this, &ScriptManager::scriptEnding, newTimer, &QTimer::stop);
1286 1298
1287
1288 CallbackData timerData = { function, currentEntityIdentifier, currentSandboxURL };1299 CallbackData timerData = { function, currentEntityIdentifier, currentSandboxURL };
1289 _timerFunctionMap.insert(newTimer, timerData);1300 _timerFunctionMap.insert({ handle, { newTimer, timerData } });
1290 1301
1291 if (intervalMS < 0) {1302 if (intervalMS < 0) {
1292 int lineNumber = -1;1303 int lineNumber = -1;
@@ -1302,10 +1313,10 @@ QTimer* ScriptManager::setupTimerWithInterval(const ScriptValue& function, int i · 9 unmodified lines
1302 newTimer->start(intervalMS);1313 newTimer->start(intervalMS);
1303 }1314 }
1304 1315
1305 return newTimer;1316 return handle;
1306}1317}
1307 1318
1308QTimer* ScriptManager::setInterval(const ScriptValue& function, int intervalMS) {1319int ScriptManager::setInterval(const ScriptValue& function, int intervalMS) {
1309 if (isStopped()) {1320 if (isStopped()) {
1310 int lineNumber = -1;1321 int lineNumber = -1;
1311 QString fileName = getFilename();1322 QString fileName = getFilename();
@@ -1315,13 +1326,13 @@ QTimer* ScriptManager::setInterval(const ScriptValue& function, int intervalMS) · 3 unmodified lines
1315 fileName = context->currentFileName();1326 fileName = context->currentFileName();
1316 }1327 }
1317 scriptWarningMessage("Script.setInterval() while shutting down is ignored... parent script:" + getFilename(), fileName, lineNumber);1328 scriptWarningMessage("Script.setInterval() while shutting down is ignored... parent script:" + getFilename(), fileName, lineNumber);
1318 return NULL; // bail early1329 return 0; // bail early
1319 }1330 }
1320 1331
1321 return setupTimerWithInterval(function, intervalMS, false);1332 return setupTimerWithInterval(function, intervalMS, false);
1322}1333}
1323 1334
1324QTimer* ScriptManager::setTimeout(const ScriptValue& function, int timeoutMS) {1335int ScriptManager::setTimeout(const ScriptValue& function, int timeoutMS) {
1325 if (isStopped()) {1336 if (isStopped()) {
1326 int lineNumber = -1;1337 int lineNumber = -1;
1327 QString fileName = getFilename();1338 QString fileName = getFilename();
@@ -1331,19 +1342,20 @@ QTimer* ScriptManager::setTimeout(const ScriptValue& function, int timeoutMS) { · 3 unmodified lines
1331 fileName = context->currentFileName();1342 fileName = context->currentFileName();
1332 }1343 }
1333 scriptWarningMessage("Script.setTimeout() while shutting down is ignored... parent script:" + getFilename(), fileName, lineNumber);1344 scriptWarningMessage("Script.setTimeout() while shutting down is ignored... parent script:" + getFilename(), fileName, lineNumber);
1334 return NULL; // bail early1345 return 0; // bail early
1335 }1346 }
1336 1347
1337 return setupTimerWithInterval(function, timeoutMS, true);1348 return setupTimerWithInterval(function, timeoutMS, true);
1338}1349}
1339 1350
1340void ScriptManager::stopTimer(QTimer *timer) {1351void ScriptManager::stopTimer(int handle) {
1341 if (_timerFunctionMap.contains(timer)) {1352 if (_timerFunctionMap.contains(handle)) {
1353 auto [timer, callbackData] = _timerFunctionMap.at(handle);
1342 timer->stop();1354 timer->stop();
1343 _timerFunctionMap.remove(timer);1355 _timerFunctionMap.erase(handle);
1344 delete timer;1356 delete timer;
1345 } else {1357 } else {
1346 qCDebug(scriptengine) << "stopTimer -- not in _timerFunctionMap" << timer;1358 qCDebug(scriptengine) << "stopTimer -- not in _timerFunctionMap" << handle;
1347 }1359 }
1348}1360}
1349 1361