diff --git a/indra/llcommon/llstring.cpp b/indra/llcommon/llstring.cpp index 8953a1089..d5bc65a63 100644 --- a/indra/llcommon/llstring.cpp +++ b/indra/llcommon/llstring.cpp @@ -36,9 +36,6 @@ #include // for WideCharToMultiByte #endif -LLFastTimer::DeclareTimer FT_STRING_FORMAT("String Format"); - - std::string ll_safe_string(const char* in) { if(in) return std::string(in); @@ -1190,7 +1187,6 @@ bool LLStringUtil::formatDatetime(std::string& replacement, std::string token, template<> S32 LLStringUtil::format(std::string& s, const format_map_t& substitutions) { - LLFastTimer ft(FT_STRING_FORMAT); S32 res = 0; std::string output; @@ -1263,7 +1259,6 @@ S32 LLStringUtil::format(std::string& s, const format_map_t& substitutions) template<> S32 LLStringUtil::format(std::string& s, const LLSD& substitutions) { - LLFastTimer ft(FT_STRING_FORMAT); S32 res = 0; if (!substitutions.isMap()) diff --git a/indra/llui/llnotifications.cpp b/indra/llui/llnotifications.cpp index b8fab0994..400d80d64 100644 --- a/indra/llui/llnotifications.cpp +++ b/indra/llui/llnotifications.cpp @@ -41,6 +41,7 @@ #include "llnotifications.h" #include "aialert.h" +#include "aistatemachine.h" #include "../newview/hippogridmanager.h" @@ -50,6 +51,9 @@ #endif #include +// Two macros, used to make access to mItems thread-safe, to keep the diff to a minimum. +#define AILOCK_mItems mItems_wat mItems_w(mItems_sf); LLNotificationSet& mItems(*mItems_w) +#define AILOCK_const_mItems mItems_crat mItems_r(mItems_sf); LLNotificationSet const& mItems(*mItems_r) const std::string NOTIFICATION_PERSIST_VERSION = "0.93"; @@ -99,6 +103,7 @@ private: output["version"] = NOTIFICATION_PERSIST_VERSION; LLSD& data = output["data"]; + AILOCK_mItems; for (LLNotificationSet::iterator it = mItems.begin(); it != mItems.end(); ++it) { if (!LLNotificationTemplates::instance().templateExists((*it)->getName())) continue; @@ -156,6 +161,7 @@ private: void onDelete(LLNotificationPtr pNotification) { // we want to keep deleted notifications in our log + AILOCK_mItems; mItems.insert(pNotification); return; @@ -757,6 +763,7 @@ void LLNotificationChannelBase::connectChanged(const LLStandardSignal::slot_type // all of the notifications that are already in the channel // we use a special signal called "load" in case the channel wants to care // only about new notifications + AILOCK_mItems; for (LLNotificationSet::iterator it = mItems.begin(); it != mItems.end(); ++it) { slot(LLSD().with("sigtype", "load").with("id", (*it)->id())); @@ -795,8 +802,11 @@ bool LLNotificationChannelBase::updateItem(const LLSD& payload) // internal call, for use in avoiding lookup bool LLNotificationChannelBase::updateItem(const LLSD& payload, LLNotificationPtr pNotification) -{ +{ + llassert(AIThreadID::in_main_thread()); + std::string cmd = payload["sigtype"]; + AILOCK_mItems; LLNotificationSet::iterator foundItem = mItems.find(pNotification); bool wasFound = (foundItem != mItems.end()); bool passesFilter = mFilter(pNotification); @@ -943,6 +953,7 @@ void LLNotificationChannel::setComparator(LLNotificationComparator comparator) { mComparator = comparator; LLNotificationSet s2(mComparator); + AILOCK_mItems; s2.insert(mItems.begin(), mItems.end()); mItems.swap(s2); @@ -952,16 +963,19 @@ void LLNotificationChannel::setComparator(LLNotificationComparator comparator) bool LLNotificationChannel::isEmpty() const { + AILOCK_const_mItems; return mItems.empty(); } LLNotificationChannel::Iterator LLNotificationChannel::begin() { + AILOCK_const_mItems; return mItems.begin(); } LLNotificationChannel::Iterator LLNotificationChannel::end() { + AILOCK_const_mItems; return mItems.end(); } @@ -1488,40 +1502,158 @@ LLNotificationPtr LLNotifications::add(AIAlert::Error const& error, int type, un return add(LLNotification::Params((type == AIAlert::modal || error.is_modal()) ? "AIAlertModal" : "AIAlert").substitutions(substitutions)); } +//-------------------------------------------------------------------------------- +// class UpdateItem +// +// Allow LLNotifications::add, LLNotifications::cancel and LLNotifications::update +// to be called from any thread. + +struct UpdateItem +{ + char const* sigtype; + LLNotificationPtr pNotif; + UpdateItem(char const* st, LLNotificationPtr const& np) : sigtype(st), pNotif(np) { } + void doit(void) const; +}; + +void UpdateItem::doit(void) const +{ + LLNotifications::getInstance()->updateItem(LLSD().with("sigtype", sigtype).with("id", pNotif->id()), pNotif); + if (!strcmp(sigtype, "delete")) + { + pNotif->cancel(); + } +} + +class UpdateItemSM : public AIStateMachine +{ + protected: + typedef AIStateMachine direct_base_type; + + enum update_item_state_type { + UpdateItem_idle = direct_base_type::max_state, + UpdateItem_doit + }; + + public: + static state_type const max_state = UpdateItem_doit + 1; + + public: + UpdateItemSM(void) : AIStateMachine(CWD_ONLY(true)) { } + + static void add(UpdateItem const& ui); + + private: + static UpdateItemSM* sSelf; + typedef std::deque updateQueue_type; + AIThreadSafeSimpleDC mUpdateQueue; + typedef AIAccess mUpdateQueue_wat; + typedef AIAccess mUpdateQueue_rat; + typedef AIAccessConst mUpdateQueue_crat; + + protected: + /*virtual*/ ~UpdateItemSM() { } + + protected: + /*virtual*/ void initialize_impl(void) { set_state(UpdateItem_idle); } + /*virtual*/ void multiplex_impl(state_type run_state); + /*virtual*/ void abort_impl(void) { } + /*virtual*/ void finish_impl(void) { } + /*virtual*/ char const* state_str_impl(state_type run_state) const; +}; + +//static +UpdateItemSM* UpdateItemSM::sSelf; + +void UpdateItemSM::add(UpdateItem const& ui) +{ + if (!sSelf) + { + sSelf = new UpdateItemSM; + sSelf->run(NULL, 0, false, true, &gMainThreadEngine); + } + if (AIThreadID::in_main_thread()) + { + ui.doit(); + return; + } + mUpdateQueue_wat mUpdateQueue_w(sSelf->mUpdateQueue); + mUpdateQueue_w->push_back(ui); + sSelf->advance_state(UpdateItem_doit); +} + +char const* UpdateItemSM::state_str_impl(state_type run_state) const +{ + switch(run_state) + { + // A complete listing of hello_world_state_type. + AI_CASE_RETURN(UpdateItem_idle); + AI_CASE_RETURN(UpdateItem_doit); + } + llassert(false); + return "UNKNOWN STATE"; +} + +void UpdateItemSM::multiplex_impl(state_type run_state) +{ + switch(run_state) + { + case UpdateItem_idle: + idle(); + break; + case UpdateItem_doit: + { + mUpdateQueue_wat mUpdateQueue_w(sSelf->mUpdateQueue); + while (!mUpdateQueue_w->empty()) + { + UpdateItem const& ui(mUpdateQueue_w->front()); + ui.doit(); + mUpdateQueue_w->pop_front(); + } + set_state(UpdateItem_idle); + break; + } + } +} + +// end of UpdateItemSM +//-------------------------------------------------------------------------------- void LLNotifications::add(const LLNotificationPtr pNotif) { if (pNotif == NULL) return; // first see if we already have it -- if so, that's a problem + AILOCK_mItems; LLNotificationSet::iterator it=mItems.find(pNotif); if (it != mItems.end()) { llerrs << "Notification added a second time to the master notification channel." << llendl; } - updateItem(LLSD().with("sigtype", "add").with("id", pNotif->id()), pNotif); + UpdateItemSM::add(UpdateItem("add", pNotif)); } void LLNotifications::cancel(LLNotificationPtr pNotif) { if (pNotif == NULL || pNotif->isCancelled()) return; + AILOCK_mItems; LLNotificationSet::iterator it=mItems.find(pNotif); if (it == mItems.end()) { llerrs << "Attempted to delete nonexistent notification " << pNotif->getName() << llendl; } - updateItem(LLSD().with("sigtype", "delete").with("id", pNotif->id()), pNotif); - pNotif->cancel(); + UpdateItemSM::add(UpdateItem("delete", pNotif)); } void LLNotifications::update(const LLNotificationPtr pNotif) { + AILOCK_mItems; LLNotificationSet::iterator it=mItems.find(pNotif); if (it != mItems.end()) { - updateItem(LLSD().with("sigtype", "change").with("id", pNotif->id()), pNotif); + UpdateItemSM::add(UpdateItem("change", pNotif)); } } @@ -1529,6 +1661,7 @@ void LLNotifications::update(const LLNotificationPtr pNotif) LLNotificationPtr LLNotifications::find(LLUUID const& uuid) { LLNotificationPtr target = LLNotificationPtr(new LLNotification(uuid)); + AILOCK_mItems; LLNotificationSet::iterator it=mItems.find(target); if (it == mItems.end()) { @@ -1543,6 +1676,7 @@ LLNotificationPtr LLNotifications::find(LLUUID const& uuid) void LLNotifications::forEachNotification(NotificationProcess process) { + AILOCK_mItems; std::for_each(mItems.begin(), mItems.end(), process); } diff --git a/indra/llui/llnotifications.h b/indra/llui/llnotifications.h index bb769cae7..df0168ae7 100644 --- a/indra/llui/llnotifications.h +++ b/indra/llui/llnotifications.h @@ -107,6 +107,7 @@ #include "llxmlnode.h" #include "llnotificationptr.h" #include "llnotificationcontext.h" +#include "aithreadsafe.h" namespace AIAlert { class Error; } @@ -196,6 +197,7 @@ class LLNotification : { LOG_CLASS(LLNotification); friend class LLNotifications; +friend class UpdateItem; public: // parameter object used to instantiate a new notification @@ -566,9 +568,10 @@ class LLNotificationChannelBase : public boost::signals2::trackable { LOG_CLASS(LLNotificationChannelBase); + friend class UpdateItem; public: LLNotificationChannelBase(LLNotificationFilter filter, LLNotificationComparator comp) : - mFilter(filter), mItems(comp) + mFilter(filter), mItems_sf(comp) {} virtual ~LLNotificationChannelBase() {} // you can also connect to a Channel, so you can be notified of @@ -582,7 +585,9 @@ public: const LLNotificationFilter& getFilter() { return mFilter; } protected: - LLNotificationSet mItems; + AIThreadSafeSimpleDC mItems_sf; + typedef AIAccess mItems_wat; + typedef AIAccessConst mItems_crat; LLStandardSignal mChanged; LLStandardSignal mPassedFilter; LLStandardSignal mFailedFilter; diff --git a/indra/llui/lltrans.cpp b/indra/llui/lltrans.cpp index fa9550055..be15bd406 100644 --- a/indra/llui/lltrans.cpp +++ b/indra/llui/lltrans.cpp @@ -91,15 +91,20 @@ bool LLTrans::parseStrings(const std::string& xml_filename, const std::setrenderUTF8(load_string, 0, right_x, y, sSearchStatusColor, LLFontGL::LEFT, LLFontGL::BOTTOM, LLFontGL::NORMAL, LLFontGL::NO_SHADOW, S32_MAX, S32_MAX, &right_x, FALSE);