diff options
Diffstat (limited to 'indra/llcommon')
| -rw-r--r-- | indra/llcommon/llalignedarray.h | 10 | ||||
| -rw-r--r-- | indra/llcommon/llcoros.cpp | 37 | ||||
| -rw-r--r-- | indra/llcommon/llcoros.h | 35 | 
3 files changed, 71 insertions, 11 deletions
diff --git a/indra/llcommon/llalignedarray.h b/indra/llcommon/llalignedarray.h index b68e9e0f82..da9d98c16c 100644 --- a/indra/llcommon/llalignedarray.h +++ b/indra/llcommon/llalignedarray.h @@ -116,14 +116,20 @@ void LLAlignedArray<T, alignment>::resize(U32 size)  template <class T, U32 alignment>  T& LLAlignedArray<T, alignment>::operator[](int idx)  { -	llassert(idx < mElementCount); +	if(idx >= mElementCount || idx < 0) +    { +        LL_ERRS() << "Out of bounds LLAlignedArray, requested: " << (S32)idx << " size: " << mElementCount << LL_ENDL; +    }  	return mArray[idx];  }  template <class T, U32 alignment>  const T& LLAlignedArray<T, alignment>::operator[](int idx) const  { -	llassert(idx < mElementCount); +    if (idx >= mElementCount || idx < 0) +    { +        LL_ERRS() << "Out of bounds LLAlignedArray, requested: " << (S32)idx << " size: " << mElementCount << LL_ENDL; +    }  	return mArray[idx];  } diff --git a/indra/llcommon/llcoros.cpp b/indra/llcommon/llcoros.cpp index c2d353b0fc..14bfb98629 100644 --- a/indra/llcommon/llcoros.cpp +++ b/indra/llcommon/llcoros.cpp @@ -35,6 +35,7 @@  // STL headers  // std headers  #include <atomic> +#include <stdexcept>  // external library headers  #include <boost/bind.hpp>  #include <boost/fiber/fiber.hpp> @@ -214,6 +215,22 @@ std::string LLCoros::logname()      return data.mName.empty()? data.getKey() : data.mName;  } +void LLCoros::saveException(const std::string& name, std::exception_ptr exc) +{ +    mExceptionQueue.emplace(name, exc); +} + +void LLCoros::rethrow() +{ +    if (! mExceptionQueue.empty()) +    { +        ExceptionData front = mExceptionQueue.front(); +        mExceptionQueue.pop(); +        LL_WARNS("LLCoros") << "Rethrowing exception from coroutine " << front.name << LL_ENDL; +        std::rethrow_exception(front.exception); +    } +} +  void LLCoros::setStackSize(S32 stacksize)  {      LL_DEBUGS("LLCoros") << "Setting coroutine stack size to " << stacksize << LL_ENDL; @@ -302,11 +319,11 @@ U32 cpp_exception_filter(U32 code, struct _EXCEPTION_POINTERS *exception_infop,      }  } -void LLCoros::winlevel(const std::string& name, const callable_t& callable) +void LLCoros::sehHandle(const std::string& name, const LLCoros::callable_t& callable)  {      __try      { -        toplevelTryWrapper(name, callable); +        LLCoros::toplevelTryWrapper(name, callable);      }      __except (cpp_exception_filter(GetExceptionCode(), GetExceptionInformation(), name))      { @@ -321,7 +338,6 @@ void LLCoros::winlevel(const std::string& name, const callable_t& callable)          throw std::exception(integer_string);      }  } -  #endif  void LLCoros::toplevelTryWrapper(const std::string& name, const callable_t& callable) @@ -350,11 +366,19 @@ void LLCoros::toplevelTryWrapper(const std::string& name, const callable_t& call      }      catch (...)      { +#if LL_WINDOWS          // Any OTHER kind of uncaught exception will cause the viewer to -        // crash, hopefully informatively. +        // crash, SEH handling should catch it and report to bugsplat.          LOG_UNHANDLED_EXCEPTION(STRINGIZE("coroutine " << name));          // to not modify callstack          throw; +#else +        // Stash any OTHER kind of uncaught exception in the rethrow() queue +        // to be rethrown by the main fiber. +        LL_WARNS("LLCoros") << "Capturing uncaught exception in coroutine " +                            << name << LL_ENDL; +        LLCoros::instance().saveException(name, std::current_exception()); +#endif      }  } @@ -364,8 +388,9 @@ void LLCoros::toplevelTryWrapper(const std::string& name, const callable_t& call  void LLCoros::toplevel(std::string name, callable_t callable)  {  #if LL_WINDOWS -    // Can not use __try in functions that require unwinding, so use one more wrapper -    winlevel(name, callable); +    // Because SEH can's have unwinding, need to call a wrapper +    // 'try' is inside SEH handling to not catch LLContinue +    sehHandle(name, callable);  #else      toplevelTryWrapper(name, callable);  #endif diff --git a/indra/llcommon/llcoros.h b/indra/llcommon/llcoros.h index a94cfca19f..dbff921f16 100644 --- a/indra/llcommon/llcoros.h +++ b/indra/llcommon/llcoros.h @@ -38,6 +38,8 @@  #include "llinstancetracker.h"  #include <boost/function.hpp>  #include <string> +#include <exception> +#include <queue>  // e.g. #include LLCOROS_MUTEX_HEADER  #define LLCOROS_MUTEX_HEADER   <boost/fiber/mutex.hpp> @@ -156,6 +158,19 @@ public:       * LLCoros::launch()).       */      static std::string getName(); +     +    /** +     * rethrow() is called by the thread's main fiber to propagate an +     * exception from any coroutine into the main fiber, where it can engage +     * the normal unhandled-exception machinery, up to and including crash +     * reporting. +     * +     * LLCoros maintains a queue of otherwise-uncaught exceptions from +     * terminated coroutines. Each call to rethrow() pops the first of those +     * and rethrows it. When the queue is empty (normal case), rethrow() is a +     * no-op. +     */ +    void rethrow();      /**       * This variation returns a name suitable for log messages: the explicit @@ -292,13 +307,27 @@ public:  private:      std::string generateDistinctName(const std::string& prefix) const; +    void toplevelTryWrapper(const std::string& name, const callable_t& callable);  #if LL_WINDOWS -    void winlevel(const std::string& name, const callable_t& callable); +    void sehHandle(const std::string& name, const callable_t& callable); // calls toplevelTryWrapper  #endif -    void toplevelTryWrapper(const std::string& name, const callable_t& callable); -    void toplevel(std::string name, callable_t callable); +    void toplevel(std::string name, callable_t callable); // calls sehHandle or toplevelTryWrapper      struct CoroData;      static CoroData& get_CoroData(const std::string& caller); +    void saveException(const std::string& name, std::exception_ptr exc); + +    struct ExceptionData +    { +        ExceptionData(const std::string& nm, std::exception_ptr exc): +            name(nm), +            exception(exc) +        {} +        // name of coroutine that originally threw this exception +        std::string name; +        // the thrown exception +        std::exception_ptr exception; +    }; +    std::queue<ExceptionData> mExceptionQueue;      S32 mStackSize;  | 
