History

Add lock around _entityScripts

Clement committed 8 years ago

Commit e6b4cce1 parent d5456ed2 files · +82 −26Browse files

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

Unified · Split

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