summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRider Linden <rider@lindenlab.com>2016-09-16 14:43:35 -0700
committerRider Linden <rider@lindenlab.com>2016-09-16 14:43:35 -0700
commit884b03e8770a64aee22281518a5f3e2a7c0420ab (patch)
tree70c723e32dcb5d857ea7f3c4684d586047a15a30
parent921cfa355cfc5130a55d77690e2ff80e1f370dcb (diff)
parent68b8d2658a741617ae9844824090efe922da1edd (diff)
Merge
-rw-r--r--indra/llcommon/llhandle.h81
-rw-r--r--indra/newview/llappviewer.cpp1
-rw-r--r--indra/newview/llcompilequeue.cpp323
3 files changed, 222 insertions, 183 deletions
diff --git a/indra/llcommon/llhandle.h b/indra/llcommon/llhandle.h
index 401e4d759a..feb5f41848 100644
--- a/indra/llcommon/llhandle.h
+++ b/indra/llcommon/llhandle.h
@@ -28,8 +28,11 @@
#define LLHANDLE_H
#include "llpointer.h"
+#include "llexception.h"
+#include <stdexcept>
#include <boost/type_traits/is_convertible.hpp>
#include <boost/utility/enable_if.hpp>
+#include <boost/throw_exception.hpp>
/**
* Helper object for LLHandle. Don't instantiate these directly, used
@@ -213,4 +216,82 @@ private:
mutable LLRootHandle<T> mHandle;
};
+
+
+class LLCheckedHandleBase
+{
+public:
+ class Stale : public LLException
+ {
+ public:
+ Stale() :
+ LLException("Attempt to access stale handle.")
+ {}
+ };
+
+protected:
+ LLCheckedHandleBase() { }
+
+};
+
+/**
+ * This is a simple wrapper for Handles, allowing direct calls to the underlying
+ * pointer. The checked handle will throw a Stale if an attempt
+ * is made to access the object referenced by the handle and that object has
+ * been destroyed.
+ **/
+template <typename T>
+class LLCheckedHandle: public LLCheckedHandleBase
+{
+public:
+
+ LLCheckedHandle(LLHandle<T> handle):
+ mHandle(handle)
+ { }
+
+ /**
+ * Test the underlying handle. If it is no longer valid, throw a Stale exception.
+ */
+ void check() const
+ {
+ T* ptr = mHandle.get();
+ if (!ptr)
+ BOOST_THROW_EXCEPTION(Stale());
+ }
+
+ /**
+ * Cast back to an appropriate handle
+ */
+ operator LLHandle<T>() const
+ {
+ return mHandle;
+ }
+
+ /**
+ * Converts the LLCheckedHandle to a bool. Allows for if (chkdHandle) {}
+ * Does not throw.
+ */
+ /*explicit*/ operator bool() const // explicit conversion operator not available with Linux compiler
+ {
+ return (mHandle.get() != NULL);
+ }
+
+ /**
+ * Attempt to call a method or access a member in the structure referenced
+ * by the handle. If the handle no longer points to a valid structure
+ * throw a Stale.
+ */
+ T* operator ->() const
+ {
+ T* ptr = mHandle.get();
+ if (!ptr)
+ BOOST_THROW_EXCEPTION(Stale());
+ return ptr;
+ }
+
+private:
+
+ LLHandle<T> mHandle;
+};
+
#endif
diff --git a/indra/newview/llappviewer.cpp b/indra/newview/llappviewer.cpp
index 3023944f6e..d31008f1c4 100644
--- a/indra/newview/llappviewer.cpp
+++ b/indra/newview/llappviewer.cpp
@@ -135,6 +135,7 @@
#include <boost/foreach.hpp>
#include <boost/algorithm/string.hpp>
#include <boost/regex.hpp>
+#include <boost/throw_exception.hpp>
#if LL_WINDOWS
# include <share.h> // For _SH_DENYWR in processMarkerFiles
diff --git a/indra/newview/llcompilequeue.cpp b/indra/newview/llcompilequeue.cpp
index 7721e67290..76e16f5a1f 100644
--- a/indra/newview/llcompilequeue.cpp
+++ b/indra/newview/llcompilequeue.cpp
@@ -67,7 +67,9 @@ namespace
const std::string QUEUE_EVENTPUMP_NAME("ScriptActionQueue");
-
+ // ObjectIventoryFetcher is an adapter between the LLVOInventoryListener::inventoryChanged
+ // callback mechanism and the LLEventPump coroutine architecture allowing the
+ // coroutine to wait for the inventory event.
class ObjectInventoryFetcher: public LLVOInventoryListener
{
public:
@@ -144,7 +146,7 @@ public:
queue->getChild<LLScrollListCtrl>("queue output")->addSimpleElement(message, ADD_BOTTOM);
}
- return LLSD().with("success", LLSD::Boolean(true));
+ return LLSDMap("success", LLSD::Boolean(true));
}
@@ -254,7 +256,6 @@ LLFloaterCompileQueue::LLFloaterCompileQueue(const LLSD& key)
setTitle(LLTrans::getString("CompileQueueTitle"));
setStartString(LLTrans::getString("CompileQueueStart"));
-// mUploadQueue = new LLAssetUploadQueue(new LLCompileFloaterUploadQueueSupplier(key.asUUID()));
}
LLFloaterCompileQueue::~LLFloaterCompileQueue()
@@ -267,7 +268,6 @@ void LLFloaterCompileQueue::experienceIdsReceived( const LLSD& content )
{
mExperienceIds.insert(it->asUUID());
}
-// nextObject();
}
BOOL LLFloaterCompileQueue::hasExperience( const LLUUID& id ) const
@@ -277,11 +277,6 @@ BOOL LLFloaterCompileQueue::hasExperience( const LLUUID& id ) const
// //Attempt to record this asset ID. If it can not be inserted into the set
// //then it has already been processed so return false.
-// bool LLFloaterCompileQueue::checkAssetId(const LLUUID &assetId)
-// {
-// std::pair<uuid_list_t::iterator, bool> result = mAssetIds.insert(assetId);
-// return result.second;
-// }
void LLFloaterCompileQueue::handleHTTPResponse(std::string pumpName, const LLSD &expresult)
{
@@ -331,8 +326,10 @@ void LLFloaterCompileQueue::processExperienceIdResults(LLSD result, LLUUID paren
queue->experienceIdsReceived(result["experience_ids"]);
+ // getDerived handle gets a handle that can be resolved to a parent class of the derived object.
LLHandle<LLFloaterScriptQueue> hFloater(queue->getDerivedHandle<LLFloaterScriptQueue>());
+ // note subtle difference here: getDerivedHandle in this case is for an LLFloaterCompileQueue
fnQueueAction_t fn = boost::bind(LLFloaterCompileQueue::processScript,
queue->getDerivedHandle<LLFloaterCompileQueue>(), _1, _2, _3);
@@ -345,37 +342,35 @@ void LLFloaterCompileQueue::processExperienceIdResults(LLSD result, LLUUID paren
}
+/// This is a utility function to be bound and called from objectScriptProcessingQueueCoro.
+/// Do not call directly. It may throw a LLCheckedHandle<>::Stale exception.
bool LLFloaterCompileQueue::processScript(LLHandle<LLFloaterCompileQueue> hfloater,
const LLPointer<LLViewerObject> &object, LLInventoryObject* inventory, LLEventPump &pump)
{
LLSD result;
- LLFloaterCompileQueue *that = hfloater.get();
- bool monocompile = that->mMono;
+ LLCheckedHandle<LLFloaterCompileQueue> floater(hfloater);
+ // Dereferencing floater may fail. If they do they throw LLExeceptionStaleHandle.
+ // which is caught in objectScriptProcessingQueueCoro
+ bool monocompile = floater->mMono;
F32 fetch_timeout = gSavedSettings.getF32("QueueInventoryFetchTimeout");
- if (!that)
- return false;
// Initial test to see if we can (or should) attempt to compile the script.
LLInventoryItem *item = dynamic_cast<LLInventoryItem *>(inventory);
- {
- if (!item->getPermissions().allowModifyBy(gAgent.getID(), gAgent.getGroupID()) ||
- !item->getPermissions().allowCopyBy(gAgent.getID(), gAgent.getGroupID()))
- {
- std::string buffer = "Skipping: " + item->getName() + "(Permissions)";
- that->addStringMessage(buffer);
- return true;
- }
+ if (!item)
+ {
+ LL_WARNS("SCRIPTQ") << "item retrieved is not an LLInventoryItem." << LL_ENDL;
+ return true;
+ }
-// if (!that->checkAssetId(item->getAssetUUID()))
-// {
-// std::string buffer = "Skipping: " + item->getName() + "(Repeat)";
-// that->addStringMessage(buffer);
-// return true;
-// }
+ if (!item->getPermissions().allowModifyBy(gAgent.getID(), gAgent.getGroupID()) ||
+ !item->getPermissions().allowCopyBy(gAgent.getID(), gAgent.getGroupID()))
+ {
+ std::string buffer = "Skipping: " + item->getName() + "(Permissions)";
+ floater->addStringMessage(buffer);
+ return true;
}
- that = NULL;
// Attempt to retrieve the experience
LLUUID experienceId;
@@ -384,37 +379,30 @@ bool LLFloaterCompileQueue::processScript(LLHandle<LLFloaterCompileQueue> hfloat
boost::bind(&LLFloaterCompileQueue::handleHTTPResponse, pump.getName(), _1));
result = llcoro::suspendUntilEventOnWithTimeout(pump, fetch_timeout,
- LLSD().with("timeout", LLSD::Boolean(true)));
+ LLSDMap("timeout", LLSD::Boolean(true)));
- that = hfloater.get();
- if (!that)
- {
- return false;
- }
-
- if (result.has("timeout") && result["timeout"].asBoolean())
- {
+ if (result.has("timeout"))
+ { // A timeout filed in the result will always be true if present.
LLStringUtil::format_map_t args;
args["[OBJECT_NAME]"] = inventory->getName();
- std::string buffer = that->getString("Timeout", args);
- that->addStringMessage(buffer);
+ std::string buffer = floater->getString("Timeout", args);
+ floater->addStringMessage(buffer);
return true;
}
if (result.has(LLExperienceCache::EXPERIENCE_ID))
{
experienceId = result[LLExperienceCache::EXPERIENCE_ID].asUUID();
- if (!that->hasExperience(experienceId))
+ if (!floater->hasExperience(experienceId))
{
- that->addProcessingMessage("CompileNoExperiencePerm", LLSD()
- .with("SCRIPT", inventory->getName())
- .with("EXPERIENCE", result[LLExperienceCache::NAME].asString()));
+ floater->addProcessingMessage("CompileNoExperiencePerm",
+ LLSDMap("SCRIPT", inventory->getName())
+ ("EXPERIENCE", result[LLExperienceCache::NAME].asString()));
return true;
}
}
}
- that = NULL;
{
HandleScriptUserData userData(pump.getName());
@@ -433,32 +421,23 @@ bool LLFloaterCompileQueue::processScript(LLHandle<LLFloaterCompileQueue> hfloat
&userData);
result = llcoro::suspendUntilEventOnWithTimeout(pump, fetch_timeout,
- LLSD().with("timeout", LLSD::Boolean(true)));
- }
-
- that = hfloater.get();
- if (!that)
- {
- return false;
+ LLSDMap("timeout", LLSD::Boolean(true)));
}
if (result.has("timeout"))
- {
- if (result.has("timeout") && result["timeout"].asBoolean())
- {
- LLStringUtil::format_map_t args;
- args["[OBJECT_NAME]"] = inventory->getName();
- std::string buffer = that->getString("Timeout", args);
- that->addStringMessage(buffer);
- return true;
- }
+ { // A timeout filed in the result will always be true if present.
+ LLStringUtil::format_map_t args;
+ args["[OBJECT_NAME]"] = inventory->getName();
+ std::string buffer = floater->getString("Timeout", args);
+ floater->addStringMessage(buffer);
+ return true;
}
if (result.has("error"))
{
LL_WARNS("SCRIPTQ") << "Inventory fetch returned with error. Code: " << result["error"].asString() << LL_ENDL;
std::string buffer = result["message"].asString() + " " + inventory->getName();
- that->addStringMessage(buffer);
+ floater->addStringMessage(buffer);
if (result.has("alert"))
{
@@ -470,12 +449,9 @@ bool LLFloaterCompileQueue::processScript(LLHandle<LLFloaterCompileQueue> hfloat
}
LLUUID assetId = result["asset_id"];
- that = NULL;
-
std::string url = object->getRegion()->getCapability("UpdateScriptTask");
-
{
LLResourceUploadInfo::ptr_t uploadInfo(new LLQueuedScriptAssetUpload(object->getID(),
inventory->getUUID(),
@@ -490,24 +466,15 @@ bool LLFloaterCompileQueue::processScript(LLHandle<LLFloaterCompileQueue> hfloat
LLViewerAssetUpload::EnqueueInventoryUpload(url, uploadInfo);
}
- result = llcoro::suspendUntilEventOnWithTimeout(pump, fetch_timeout, LLSD().with("timeout", LLSD::Boolean(true)));
-
- that = hfloater.get();
- if (!that)
- {
- return false;
- }
+ result = llcoro::suspendUntilEventOnWithTimeout(pump, fetch_timeout, LLSDMap("timeout", LLSD::Boolean(true)));
if (result.has("timeout"))
- {
- if (result.has("timeout") && result["timeout"].asBoolean())
- {
- LLStringUtil::format_map_t args;
- args["[OBJECT_NAME]"] = inventory->getName();
- std::string buffer = that->getString("Timeout", args);
- that->addStringMessage(buffer);
- return true;
- }
+ { // A timeout filed in the result will always be true if present.
+ LLStringUtil::format_map_t args;
+ args["[OBJECT_NAME]"] = inventory->getName();
+ std::string buffer = floater->getString("Timeout", args);
+ floater->addStringMessage(buffer);
+ return true;
}
// Bytecode save completed
@@ -515,21 +482,21 @@ bool LLFloaterCompileQueue::processScript(LLHandle<LLFloaterCompileQueue> hfloat
{
std::string buffer = std::string("Compilation of \"") + inventory->getName() + std::string("\" succeeded");
- that->addStringMessage(buffer);
+ floater->addStringMessage(buffer);
LL_INFOS() << buffer << LL_ENDL;
}
else
{
LLSD compile_errors = result["errors"];
std::string buffer = std::string("Compilation of \"") + inventory->getName() + std::string("\" failed:");
- that->addStringMessage(buffer);
+ floater->addStringMessage(buffer);
for (LLSD::array_const_iterator line = compile_errors.beginArray();
line < compile_errors.endArray(); line++)
{
std::string str = line->asString();
str.erase(std::remove(str.begin(), str.end(), '\n'), str.end());
- that->addStringMessage(str);
+ floater->addStringMessage(str);
}
LL_INFOS() << result["errors"] << LL_ENDL;
}
@@ -576,16 +543,18 @@ LLFloaterResetQueue::~LLFloaterResetQueue()
{
}
-bool LLFloaterResetQueue::resetObjectScripts(LLHandle<LLFloaterScriptQueue> hfloater,
+/// This is a utility function to be bound and called from objectScriptProcessingQueueCoro.
+/// Do not call directly. It may throw a LLCheckedHandle<>::Stale exception.
+bool LLFloaterResetQueue::resetObjectScripts(LLHandle<LLFloaterScriptQueue> hfloater,
const LLPointer<LLViewerObject> &object, LLInventoryObject* inventory, LLEventPump &pump)
{
- LLFloaterScriptQueue *that = hfloater.get();
- if (that)
- {
- std::string buffer;
- buffer = that->getString("Resetting") + (": ") + inventory->getName();
- that->addStringMessage(buffer);
- }
+ LLCheckedHandle<LLFloaterScriptQueue> floater(hfloater);
+ // Dereferencing floater may fail. If they do they throw LLExeceptionStaleHandle.
+ // which is caught in objectScriptProcessingQueueCoro
+
+ std::string buffer;
+ buffer = floater->getString("Resetting") + (": ") + inventory->getName();
+ floater->addStringMessage(buffer);
LLMessageSystem* msg = gMessageSystem;
msg->newMessageFast(_PREHASH_ScriptReset);
@@ -602,6 +571,8 @@ bool LLFloaterResetQueue::resetObjectScripts(LLHandle<LLFloaterScriptQueue> hflo
bool LLFloaterResetQueue::startQueue()
{
+ // Bind the resetObjectScripts method into a QueueAction function and pass it
+ // into the object queue processing coroutine.
fnQueueAction_t fn = boost::bind(LLFloaterResetQueue::resetObjectScripts,
getDerivedHandle<LLFloaterScriptQueue>(), _1, _2, _3);
@@ -629,16 +600,18 @@ LLFloaterRunQueue::~LLFloaterRunQueue()
{
}
-bool LLFloaterRunQueue::runObjectScripts(LLHandle<LLFloaterScriptQueue> hfloater,
+/// This is a utility function to be bound and called from objectScriptProcessingQueueCoro.
+/// Do not call directly. It may throw a LLCheckedHandle<>::Stale exception.
+bool LLFloaterRunQueue::runObjectScripts(LLHandle<LLFloaterScriptQueue> hfloater,
const LLPointer<LLViewerObject> &object, LLInventoryObject* inventory, LLEventPump &pump)
{
- LLFloaterScriptQueue *that = hfloater.get();
- if (that)
- {
- std::string buffer;
- buffer = that->getString("Running") + (": ") + inventory->getName();
- that->addStringMessage(buffer);
- }
+ LLCheckedHandle<LLFloaterScriptQueue> floater(hfloater);
+ // Dereferencing floater may fail. If they do they throw LLExeceptionStaleHandle.
+ // which is caught in objectScriptProcessingQueueCoro
+
+ std::string buffer;
+ buffer = floater->getString("Running") + (": ") + inventory->getName();
+ floater->addStringMessage(buffer);
LLMessageSystem* msg = gMessageSystem;
msg->newMessageFast(_PREHASH_SetScriptRunning);
@@ -684,16 +657,18 @@ LLFloaterNotRunQueue::~LLFloaterNotRunQueue()
{
}
+/// This is a utility function to be bound and called from objectScriptProcessingQueueCoro.
+/// Do not call directly. It may throw a LLCheckedHandle<>::Stale exception.
bool LLFloaterNotRunQueue::stopObjectScripts(LLHandle<LLFloaterScriptQueue> hfloater,
const LLPointer<LLViewerObject> &object, LLInventoryObject* inventory, LLEventPump &pump)
{
- LLFloaterScriptQueue *that = hfloater.get();
- if (that)
- {
- std::string buffer;
- buffer = that->getString("NotRunning") + (": ") + inventory->getName();
- that->addStringMessage(buffer);
- }
+ LLCheckedHandle<LLFloaterScriptQueue> floater(hfloater);
+ // Dereferencing floater may fail. If they do they throw LLExeceptionStaleHandle.
+ // which is caught in objectScriptProcessingQueueCoro
+
+ std::string buffer;
+ buffer = floater->getString("NotRunning") + (": ") + inventory->getName();
+ floater->addStringMessage(buffer);
LLMessageSystem* msg = gMessageSystem;
msg->newMessageFast(_PREHASH_SetScriptRunning);
@@ -732,7 +707,7 @@ void ObjectInventoryFetcher::inventoryChanged(LLViewerObject* object,
mInventoryList.clear();
mInventoryList.assign(inventory->begin(), inventory->end());
- mPump.post(LLSD().with("changed", LLSD::Boolean(true)));
+ mPump.post(LLSDMap("changed", LLSD::Boolean(true)));
}
@@ -740,115 +715,97 @@ void LLFloaterScriptQueue::objectScriptProcessingQueueCoro(std::string action, L
object_data_list_t objectList, fnQueueAction_t func)
{
LLCoros::set_consuming(true);
- LLFloaterScriptQueue * floater(NULL);
+ LLCheckedHandle<LLFloaterScriptQueue> floater(hfloater);
+ // Dereferencing floater may fail. If they do they throw LLExeceptionStaleHandle.
+ // This is expected if the dialog closes.
LLEventMailDrop maildrop(QUEUE_EVENTPUMP_NAME, true);
F32 fetch_timeout = gSavedSettings.getF32("QueueInventoryFetchTimeout");
-// floater = hfloater.get();
-// floater->addProcessingMessage("Starting",
-// LLSD()
-// .with("[START]", action)
-// .with("[COUNT]", LLSD::Integer(objectList.size())));
-// floater = NULL;
- for (object_data_list_t::iterator itObj(objectList.begin()); (itObj != objectList.end()); ++itObj)
+ try
{
- bool firstForObject = true;
- LLUUID object_id = (*itObj).mObjectId;
- LL_INFOS("SCRIPTQ") << "Next object in queue with ID=" << object_id.asString() << LL_ENDL;
-
- LLPointer<LLViewerObject> obj = gObjectList.findObject(object_id);
- LLInventoryObject::object_list_t inventory;
- if (obj)
+ for (object_data_list_t::iterator itObj(objectList.begin()); (itObj != objectList.end()); ++itObj)
{
- ObjectInventoryFetcher::ptr_t fetcher(new ObjectInventoryFetcher(maildrop, obj, NULL));
+ bool firstForObject = true;
+ LLUUID object_id = (*itObj).mObjectId;
+ LL_INFOS("SCRIPTQ") << "Next object in queue with ID=" << object_id.asString() << LL_ENDL;
- fetcher->fetchInventory();
-
- floater = hfloater.get();
- if (floater)
+ LLPointer<LLViewerObject> obj = gObjectList.findObject(object_id);
+ LLInventoryObject::object_list_t inventory;
+ if (obj)
{
+ ObjectInventoryFetcher::ptr_t fetcher(new ObjectInventoryFetcher(maildrop, obj, NULL));
+
+ fetcher->fetchInventory();
+
LLStringUtil::format_map_t args;
args["[OBJECT_NAME]"] = (*itObj).mObjectName;
floater->addStringMessage(floater->getString("LoadingObjInv", args));
- }
- LLSD result = llcoro::suspendUntilEventOnWithTimeout(maildrop, fetch_timeout,
- LLSD().with("timeout", LLSD::Boolean(true)));
+ LLSD result = llcoro::suspendUntilEventOnWithTimeout(maildrop, fetch_timeout,
+ LLSDMap("timeout", LLSD::Boolean(true)));
- if (result.has("timeout") && result["timeout"].asBoolean())
- {
- LL_WARNS("SCRIPTQ") << "Unable to retrieve inventory for object " << object_id.asString() <<
- ". Skipping to next object." << LL_ENDL;
+ if (result.has("timeout"))
+ { // A timeout filed in the result will always be true if present.
+ LL_WARNS("SCRIPTQ") << "Unable to retrieve inventory for object " << object_id.asString() <<
+ ". Skipping to next object." << LL_ENDL;
- // floater could have been closed
- floater = hfloater.get();
- if (floater)
- {
LLStringUtil::format_map_t args;
args["[OBJECT_NAME]"] = (*itObj).mObjectName;
floater->addStringMessage(floater->getString("Timeout", args));
+
+ continue;
}
+ inventory.assign(fetcher->getInventoryList().begin(), fetcher->getInventoryList().end());
+ }
+ else
+ {
+ LL_WARNS("SCRIPTQ") << "Unable to retrieve object with ID of " << object_id <<
+ ". Skipping to next." << LL_ENDL;
continue;
}
- inventory.assign(fetcher->getInventoryList().begin(), fetcher->getInventoryList().end());
- }
- else
- {
- LL_WARNS("SCRIPTQ") << "Unable to retrieve object with ID of " << object_id <<
- ". Skipping to next." << LL_ENDL;
- continue;
- }
+ // TODO: Get the name of the object we are looking at here so that we can display it below.
+ //std::string objName = (dynamic_cast<LLInventoryObject *>(obj.get()))->getName();
+ LL_DEBUGS("SCRIPTQ") << "Object has " << inventory.size() << " items." << LL_ENDL;
- // TODO: Get the name of the object we are looking at here so that we can display it below.
- //std::string objName = (dynamic_cast<LLInventoryObject *>(obj.get()))->getName();
- LL_DEBUGS("SCRIPTQ") << "Object has " << inventory.size() << " items." << LL_ENDL;
-
- for (LLInventoryObject::object_list_t::iterator itInv = inventory.begin();
- itInv != inventory.end(); ++itInv)
- {
- floater = hfloater.get();
- if (!floater)
+ for (LLInventoryObject::object_list_t::iterator itInv = inventory.begin();
+ itInv != inventory.end(); ++itInv)
{
- LL_WARNS("SCRIPTQ") << "Script Queue floater closed! Canceling remaining ops" << LL_ENDL;
- break;
- }
+ floater.check();
- // note, we have a smart pointer to the obj above... but if we didn't we'd check that
- // it still exists here.
+ // note, we have a smart pointer to the obj above... but if we didn't we'd check that
+ // it still exists here.
- if (((*itInv)->getType() == LLAssetType::AT_LSL_TEXT))
- {
- LL_DEBUGS("SCRIPTQ") << "Inventory item " << (*itInv)->getUUID().asString() << "\"" << (*itInv)->getName() << "\"" << LL_ENDL;
- if (firstForObject)
+ if (((*itInv)->getType() == LLAssetType::AT_LSL_TEXT))
{
- //floater->addStringMessage(objName + ":");
- firstForObject = false;
+ LL_DEBUGS("SCRIPTQ") << "Inventory item " << (*itInv)->getUUID().asString() << "\"" << (*itInv)->getName() << "\"" << LL_ENDL;
+ if (firstForObject)
+ {
+ //floater->addStringMessage(objName + ":");
+ firstForObject = false;
+ }
+
+ if (!func(obj, (*itInv), maildrop))
+ {
+ continue;
+ }
}
- if (!func(obj, (*itInv), maildrop))
- {
- continue;
- }
+ // no other explicit suspension point in this loop. func(...) MIGHT suspend
+ // but offers no guarantee of doing so.
+ llcoro::suspend();
}
-
- llcoro::suspend();
- }
- // Just test to be sure the floater is still present before calling the func
- if (!hfloater.get())
- {
- LL_WARNS("SCRIPTQ") << "Script Queue floater dismissed." << LL_ENDL;
- break;
}
- }
-
- floater = hfloater.get();
- if (floater)
- {
floater->addStringMessage("Done");
floater->getChildView("close")->setEnabled(TRUE);
}
+ catch (LLCheckedHandleBase::Stale &)
+ {
+ // This is expected. It means that floater has been closed before
+ // processing was completed.
+ LL_DEBUGS("SCRIPTQ") << "LLExeceptionStaleHandle caught! Floater has most likely been closed." << LL_ENDL;
+ }
}