Showing the changes to libraries/script-engine/src/ScriptEngine.cpp (1 of 2 files). Show all
Unified · Split
| @@ -1974,8 +1974,9 @@ void ScriptEngine::forwardHandlerCall(const EntityItemID& entityID, const QStrin · 1973 unmodified lines | ||
| 1974 | 1974 | } |
| 1975 | 1975 | |
| 1976 | 1976 | int ScriptEngine::getNumRunningEntityScripts() const { |
| 1977 | + QReadLocker locker { &_entityScriptsLock }; | |
| 1977 | 1978 | int sum = 0; |
| 1978 | − for (auto& st : _entityScripts) { | |
| 1979 | + for (const auto& st : _entityScripts) { | |
| 1979 | 1980 | if (st.status == EntityScriptStatus::RUNNING) { |
| 1980 | 1981 | ++sum; |
| 1981 | 1982 | } |
| @@ -1984,14 +1985,20 @@ int ScriptEngine::getNumRunningEntityScripts() const { · 2 unmodified lines | ||
| 1984 | 1985 | } |
| 1985 | 1986 | |
| 1986 | 1987 | void ScriptEngine::setEntityScriptDetails(const EntityItemID& entityID, const EntityScriptDetails& details) { |
| 1987 | − _entityScripts[entityID] = details; | |
| 1988 | + { | |
| 1989 | + QWriteLocker locker { &_entityScriptsLock }; | |
| 1990 | + _entityScripts[entityID] = details; | |
| 1991 | + } | |
| 1988 | 1992 | emit entityScriptDetailsUpdated(); |
| 1989 | 1993 | } |
| 1990 | 1994 | |
| 1991 | 1995 | void ScriptEngine::updateEntityScriptStatus(const EntityItemID& entityID, const EntityScriptStatus &status, const QString& errorInfo) { |
| 1992 | − EntityScriptDetails &details = _entityScripts[entityID]; | |
| 1993 | − details.status = status; | |
| 1994 | − details.errorInfo = errorInfo; | |
| 1996 | + { | |
| 1997 | + QWriteLocker locker { &_entityScriptsLock }; | |
| 1998 | + EntityScriptDetails& details = _entityScripts[entityID]; | |
| 1999 | + details.status = status; | |
| 2000 | + details.errorInfo = errorInfo; | |
| 2001 | + } | |
| 1995 | 2002 | emit entityScriptDetailsUpdated(); |
| 1996 | 2003 | } |
| 1997 | 2004 | |
| @@ -2042,6 +2049,7 @@ QFuture<QVariant> ScriptEngine::getLocalEntityScriptDetails(const EntityItemID& · 44 unmodified lines | ||
| 2042 | 2049 | } |
| 2043 | 2050 | |
| 2044 | 2051 | bool ScriptEngine::getEntityScriptDetails(const EntityItemID& entityID, EntityScriptDetails &details) const { |
| 2052 | + QReadLocker locker { &_entityScriptsLock }; | |
| 2045 | 2053 | auto it = _entityScripts.constFind(entityID); |
| 2046 | 2054 | if (it == _entityScripts.constEnd()) { |
| 2047 | 2055 | return false; |
| @@ -2050,6 +2058,11 @@ bool ScriptEngine::getEntityScriptDetails(const EntityItemID& entityID, EntitySc · 2 unmodified lines | ||
| 2050 | 2058 | return true; |
| 2051 | 2059 | } |
| 2052 | 2060 | |
| 2061 | +bool ScriptEngine::hasEntityScriptDetails(const EntityItemID& entityID) const { | |
| 2062 | + QReadLocker locker { &_entityScriptsLock }; | |
| 2063 | + return _entityScripts.contains(entityID); | |
| 2064 | +} | |
| 2065 | + | |
| 2053 | 2066 | const static EntityItemID BAD_SCRIPT_UUID_PLACEHOLDER { "{20170224-dead-face-0000-cee000021114}" }; |
| 2054 | 2067 | |
| 2055 | 2068 | void ScriptEngine::processDeferredEntityLoads(const QString& entityScript, const EntityItemID& leaderID) { |
| @@ -2064,14 +2077,15 @@ void ScriptEngine::processDeferredEntityLoads(const QString& entityScript, const · 8 unmodified lines | ||
| 2064 | 2077 | } |
| 2065 | 2078 | foreach(DeferredLoadEntity retry, retryLoads) { |
| 2066 | 2079 | // check whether entity was since been deleted |
| 2067 | − if (!_entityScripts.contains(retry.entityID)) { | |
| 2080 | + | |
| 2081 | + EntityScriptDetails details; | |
| 2082 | + if (!getEntityScriptDetails(retry.entityID, details)) { | |
| 2068 | 2083 | qCDebug(scriptengine) << "processDeferredEntityLoads -- entity details gone (entity deleted?)" |
| 2069 | 2084 | << retry.entityID; |
| 2070 | 2085 | continue; |
| 2071 | 2086 | } |
| 2072 | 2087 | |
| 2073 | 2088 | // check whether entity has since been unloaded or otherwise errored-out |
| 2074 | − auto details = _entityScripts[retry.entityID]; | |
| 2075 | 2089 | if (details.status != EntityScriptStatus::PENDING) { |
| 2076 | 2090 | qCDebug(scriptengine) << "processDeferredEntityLoads -- entity status no longer PENDING; " |
| 2077 | 2091 | << retry.entityID << details.status; |
| @@ -2079,7 +2093,11 @@ void ScriptEngine::processDeferredEntityLoads(const QString& entityScript, const · 1 unmodified line | ||
| 2079 | 2093 | } |
| 2080 | 2094 | |
| 2081 | 2095 | // propagate leader's failure reasons to the pending entity |
| 2082 | − const auto leaderDetails = _entityScripts[leaderID]; | |
| 2096 | + EntityScriptDetails leaderDetails; | |
| 2097 | + { | |
| 2098 | + QWriteLocker locker { &_entityScriptsLock }; | |
| 2099 | + leaderDetails = _entityScripts[leaderID]; | |
| 2100 | + } | |
| 2083 | 2101 | if (leaderDetails.status != EntityScriptStatus::RUNNING) { |
| 2084 | 2102 | qCDebug(scriptengine) << QString("... pending load of %1 cancelled (leader: %2 status: %3)") |
| 2085 | 2103 | .arg(retry.entityID.toString()).arg(leaderID.toString()).arg(leaderDetails.status); |
| @@ -2125,7 +2143,7 @@ void ScriptEngine::loadEntityScript(const EntityItemID& entityID, const QString& · 39 unmodified lines | ||
| 2125 | 2143 | return; |
| 2126 | 2144 | } |
| 2127 | 2145 | |
| 2128 | − if (!_entityScripts.contains(entityID)) { | |
| 2146 | + if (!hasEntityScriptDetails(entityID)) { | |
| 2129 | 2147 | // make sure EntityScriptDetails has an entry for this UUID right away |
| 2130 | 2148 | // (which allows bailing from the loading/provisioning process early if the Entity gets deleted mid-flight) |
| 2131 | 2149 | updateEntityScriptStatus(entityID, EntityScriptStatus::PENDING, "...pending..."); |
| @@ -2166,9 +2184,12 @@ void ScriptEngine::loadEntityScript(const EntityItemID& entityID, const QString& · 34 unmodified lines | ||
| 2166 | 2184 | _occupiedScriptURLs[entityScript] = entityID; |
| 2167 | 2185 | |
| 2168 | 2186 | #ifdef DEBUG_ENTITY_STATES |
| 2169 | − auto previousStatus = _entityScripts.contains(entityID) ? _entityScripts[entityID].status : EntityScriptStatus::PENDING; | |
| 2170 | − qCDebug(scriptengine) << "loadEntityScript.LOADING: " << entityScript << entityID.toString() | |
| 2171 | − << "(previous: " << previousStatus << ")"; | |
| 2187 | + { | |
| 2188 | + EntityScriptDetails details; | |
| 2189 | + bool hasEntityScript = getEntityScriptDetails(entityID, details); | |
| 2190 | + qCDebug(scriptengine) << "loadEntityScript.LOADING: " << entityScript << entityID.toString() | |
| 2191 | + << "(previous: " << (hasEntityScript ? details.status : EntityScriptStatus::PENDING) << ")"; | |
| 2192 | + } | |
| 2172 | 2193 | #endif |
| 2173 | 2194 | |
| 2174 | 2195 | EntityScriptDetails newDetails; |
| @@ -2197,7 +2218,7 @@ void ScriptEngine::loadEntityScript(const EntityItemID& entityID, const QString& · 22 unmodified lines | ||
| 2197 | 2218 | #ifdef DEBUG_ENTITY_STATES |
| 2198 | 2219 | qCDebug(scriptengine) << "loadEntityScript.contentAvailable" << status << QUrl(url).fileName() << entityID.toString(); |
| 2199 | 2220 | #endif |
| 2200 | − if (!isStopping() && _entityScripts.contains(entityID)) { | |
| 2221 | + if (!isStopping() && hasEntityScriptDetails(entityID)) { | |
| 2201 | 2222 | _contentAvailableQueue[entityID] = { entityID, url, contents, isURL, success, status }; |
| 2202 | 2223 | } else { |
| 2203 | 2224 | #ifdef DEBUG_ENTITY_STATES |
| @@ -2267,8 +2288,11 @@ void ScriptEngine::entityScriptContentAvailable(const EntityItemID& entityID, co · 63 unmodified lines | ||
| 2267 | 2288 | bool isFileUrl = isURL && scriptOrURL.startsWith("file://"); |
| 2268 | 2289 | auto fileName = isURL ? scriptOrURL : "about:EmbeddedEntityScript"; |
| 2269 | 2290 | |
| 2270 | − const EntityScriptDetails &oldDetails = _entityScripts[entityID]; | |
| 2271 | − const QString entityScript = oldDetails.scriptText; | |
| 2291 | + QString entityScript; | |
| 2292 | + { | |
| 2293 | + QWriteLocker locker { &_entityScriptsLock }; | |
| 2294 | + entityScript = _entityScripts[entityID].scriptText; | |
| 2295 | + } | |
| 2272 | 2296 | |
| 2273 | 2297 | EntityScriptDetails newDetails; |
| 2274 | 2298 | newDetails.scriptText = scriptOrURL; |
| @@ -2446,8 +2470,8 @@ void ScriptEngine::unloadEntityScript(const EntityItemID& entityID, bool shouldR · 171 unmodified lines | ||
| 2446 | 2470 | "entityID:" << entityID; |
| 2447 | 2471 | #endif |
| 2448 | 2472 | |
| 2449 | − if (_entityScripts.contains(entityID)) { | |
| 2450 | − const EntityScriptDetails &oldDetails = _entityScripts[entityID]; | |
| 2473 | + EntityScriptDetails oldDetails; | |
| 2474 | + if (getEntityScriptDetails(entityID, oldDetails)) { | |
| 2451 | 2475 | auto scriptText = oldDetails.scriptText; |
| 2452 | 2476 | |
| 2453 | 2477 | if (isEntityScriptRunning(entityID)) { |
| @@ -2460,7 +2484,10 @@ void ScriptEngine::unloadEntityScript(const EntityItemID& entityID, bool shouldR · 6 unmodified lines | ||
| 2460 | 2484 | #endif |
| 2461 | 2485 | if (shouldRemoveFromMap) { |
| 2462 | 2486 | // this was a deleted entity, we've been asked to remove it from the map |
| 2463 | − _entityScripts.remove(entityID); | |
| 2487 | + { | |
| 2488 | + QWriteLocker locker { &_entityScriptsLock }; | |
| 2489 | + _entityScripts.remove(entityID); | |
| 2490 | + } | |
| 2464 | 2491 | emit entityScriptDetailsUpdated(); |
| 2465 | 2492 | } else if (oldDetails.status != EntityScriptStatus::UNLOADED) { |
| 2466 | 2493 | EntityScriptDetails newDetails; |
| @@ -2491,10 +2518,19 @@ void ScriptEngine::unloadAllEntityScripts() { · 24 unmodified lines | ||
| 2491 | 2518 | #ifdef THREAD_DEBUGGING |
| 2492 | 2519 | qCDebug(scriptengine) << "ScriptEngine::unloadAllEntityScripts() called on correct thread [" << thread() << "]"; |
| 2493 | 2520 | #endif |
| 2494 | − foreach(const EntityItemID& entityID, _entityScripts.keys()) { | |
| 2521 | + | |
| 2522 | + QList<EntityItemID> keys; | |
| 2523 | + { | |
| 2524 | + QReadLocker locker{ &_entityScriptsLock }; | |
| 2525 | + keys = _entityScripts.keys(); | |
| 2526 | + } | |
| 2527 | + foreach(const EntityItemID& entityID, keys) { | |
| 2495 | 2528 | unloadEntityScript(entityID); |
| 2496 | 2529 | } |
| 2497 | − _entityScripts.clear(); | |
| 2530 | + { | |
| 2531 | + QWriteLocker locker{ &_entityScriptsLock }; | |
| 2532 | + _entityScripts.clear(); | |
| 2533 | + } | |
| 2498 | 2534 | emit entityScriptDetailsUpdated(); |
| 2499 | 2535 | _occupiedScriptURLs.clear(); |
| 2500 | 2536 | |
| @@ -2508,7 +2544,7 @@ void ScriptEngine::unloadAllEntityScripts() { · 7 unmodified lines | ||
| 2508 | 2544 | } |
| 2509 | 2545 | |
| 2510 | 2546 | void ScriptEngine::refreshFileScript(const EntityItemID& entityID) { |
| 2511 | − if (!HIFI_AUTOREFRESH_FILE_SCRIPTS || !_entityScripts.contains(entityID)) { | |
| 2547 | + if (!HIFI_AUTOREFRESH_FILE_SCRIPTS || !hasEntityScriptDetails(entityID)) { | |
| 2512 | 2548 | return; |
| 2513 | 2549 | } |
| 2514 | 2550 | |
| @@ -2518,7 +2554,11 @@ void ScriptEngine::refreshFileScript(const EntityItemID& entityID) { · 3 unmodified lines | ||
| 2518 | 2554 | } |
| 2519 | 2555 | recurseGuard = true; |
| 2520 | 2556 | |
| 2521 | − EntityScriptDetails details = _entityScripts[entityID]; | |
| 2557 | + EntityScriptDetails details; | |
| 2558 | + { | |
| 2559 | + QWriteLocker locker { &_entityScriptsLock }; | |
| 2560 | + details = _entityScripts[entityID]; | |
| 2561 | + } | |
| 2522 | 2562 | // Check to see if a file based script needs to be reloaded (easier debugging) |
| 2523 | 2563 | if (details.lastModified > 0) { |
| 2524 | 2564 | QString filePath = QUrl(details.scriptText).toLocalFile(); |
| @@ -2584,7 +2624,11 @@ void ScriptEngine::callEntityScriptMethod(const EntityItemID& entityID, const QS · 59 unmodified lines | ||
| 2584 | 2624 | refreshFileScript(entityID); |
| 2585 | 2625 | } |
| 2586 | 2626 | if (isEntityScriptRunning(entityID)) { |
| 2587 | − EntityScriptDetails details = _entityScripts[entityID]; | |
| 2627 | + EntityScriptDetails details; | |
| 2628 | + { | |
| 2629 | + QWriteLocker locker { &_entityScriptsLock }; | |
| 2630 | + details = _entityScripts[entityID]; | |
| 2631 | + } | |
| 2588 | 2632 | QScriptValue entityScript = details.scriptObject; // previously loaded |
| 2589 | 2633 | |
| 2590 | 2634 | // If this is a remote call, we need to check to see if the function is remotely callable |
| @@ -2646,7 +2690,11 @@ void ScriptEngine::callEntityScriptMethod(const EntityItemID& entityID, const QS · 55 unmodified lines | ||
| 2646 | 2690 | refreshFileScript(entityID); |
| 2647 | 2691 | } |
| 2648 | 2692 | if (isEntityScriptRunning(entityID)) { |
| 2649 | − EntityScriptDetails details = _entityScripts[entityID]; | |
| 2693 | + EntityScriptDetails details; | |
| 2694 | + { | |
| 2695 | + QWriteLocker locker { &_entityScriptsLock }; | |
| 2696 | + details = _entityScripts[entityID]; | |
| 2697 | + } | |
| 2650 | 2698 | QScriptValue entityScript = details.scriptObject; // previously loaded |
| 2651 | 2699 | if (entityScript.property(methodName).isFunction()) { |
| 2652 | 2700 | QScriptValueList args; |
| @@ -2680,7 +2728,11 @@ void ScriptEngine::callEntityScriptMethod(const EntityItemID& entityID, const QS · 27 unmodified lines | ||
| 2680 | 2728 | refreshFileScript(entityID); |
| 2681 | 2729 | } |
| 2682 | 2730 | if (isEntityScriptRunning(entityID)) { |
| 2683 | − EntityScriptDetails details = _entityScripts[entityID]; | |
| 2731 | + EntityScriptDetails details; | |
| 2732 | + { | |
| 2733 | + QWriteLocker locker { &_entityScriptsLock }; | |
| 2734 | + details = _entityScripts[entityID]; | |
| 2735 | + } | |
| 2684 | 2736 | QScriptValue entityScript = details.scriptObject; // previously loaded |
| 2685 | 2737 | if (entityScript.property(methodName).isFunction()) { |
| 2686 | 2738 | QScriptValueList args; |