diff options
Diffstat (limited to 'indra/llcommon')
| -rw-r--r-- | indra/llcommon/apply.h | 115 | ||||
| -rw-r--r-- | indra/llcommon/llalignedarray.h | 10 | ||||
| -rw-r--r-- | indra/llcommon/llcoros.cpp | 37 | ||||
| -rw-r--r-- | indra/llcommon/llcoros.h | 35 | ||||
| -rw-r--r-- | indra/llcommon/llprocessor.cpp | 139 | ||||
| -rw-r--r-- | indra/llcommon/llprocessor.h | 5 | ||||
| -rw-r--r-- | indra/llcommon/llsd.h | 12 | ||||
| -rw-r--r-- | indra/llcommon/llstl.h | 81 | ||||
| -rw-r--r-- | indra/llcommon/llsys.cpp | 69 | ||||
| -rw-r--r-- | indra/llcommon/llsys.h | 12 | ||||
| -rw-r--r-- | indra/llcommon/tests/llleap_test.cpp | 14 | 
11 files changed, 454 insertions, 75 deletions
diff --git a/indra/llcommon/apply.h b/indra/llcommon/apply.h new file mode 100644 index 0000000000..7c58d63bc0 --- /dev/null +++ b/indra/llcommon/apply.h @@ -0,0 +1,115 @@ +/** + * @file   apply.h + * @author Nat Goodspeed + * @date   2022-06-18 + * @brief  C++14 version of std::apply() + *  + * $LicenseInfo:firstyear=2022&license=viewerlgpl$ + * Copyright (c) 2022, Linden Research, Inc. + * $/LicenseInfo$ + */ + +#if ! defined(LL_APPLY_H) +#define LL_APPLY_H + +#include <boost/type_traits/function_traits.hpp> +#include <tuple> + +namespace LL +{ + +/** + * USAGE NOTE: + * https://stackoverflow.com/a/40523474/5533635 + * + * If you're trying to pass apply() a variadic function, the compiler + * complains that it can't deduce the callable type, presumably because it + * doesn't know which arity to reify to pass. + * + * But it works to wrap the variadic function in a generic lambda, e.g.: + * + * @CODE + * LL::apply( + *     [](auto&&... args) + *     { + *         return variadic(std::forward<decltype(args)>(args)...); + *     }, + *     args); + * @ENDCODE + * + * Presumably this is because there's only one instance of the generic lambda + * @em type, with a variadic <tt>operator()()</tt>. + * + * It's pointless to provide a wrapper @em function that implicitly supplies + * the generic lambda. You couldn't pass your variadic function to our wrapper + * function, for the same original reason! + * + * Instead we provide a wrapper @em macro. Sorry, Dr. Stroustrup. + */ +#define VAPPLY(FUNC, ARGS)                                          \ +    LL::apply(                                                      \ +        [](auto&&... args)                                          \ +        {                                                           \ +            return (FUNC)(std::forward<decltype(args)>(args)...);   \ +        },                                                          \ +        (ARGS)) + +#if __cplusplus >= 201703L + +// C++17 implementation +using std::apply; + +#else // C++14 + +// Derived from https://stackoverflow.com/a/20441189 +// and https://en.cppreference.com/w/cpp/utility/apply +template <typename CALLABLE, typename TUPLE, std::size_t... I> +auto apply_impl(CALLABLE&& func, TUPLE&& args, std::index_sequence<I...>) +{ +    // call func(unpacked args) +    return std::forward<CALLABLE>(func)(std::move(std::get<I>(args))...); +} + +template <typename CALLABLE, typename... ARGS> +auto apply(CALLABLE&& func, const std::tuple<ARGS...>& args) +{ +    // std::index_sequence_for is the magic sauce here, generating an argument +    // pack of indexes for each entry in args. apply_impl() can then pass +    // those to std::get() to unpack args into individual arguments. +    return apply_impl(std::forward<CALLABLE>(func), +                      args, +                      std::index_sequence_for<ARGS...>{}); +} + +// per https://stackoverflow.com/a/57510428/5533635 +template <typename CALLABLE, typename T, size_t SIZE> +auto apply(CALLABLE&& func, const std::array<T, SIZE>& args) +{ +    return apply(std::forward<CALLABLE>(func), std::tuple_cat(args)); +} + +// per https://stackoverflow.com/a/28411055/5533635 +template <typename CALLABLE, typename T, std::size_t... I> +auto apply_impl(CALLABLE&& func, const std::vector<T>& args, std::index_sequence<I...>) +{ +    return apply_impl(std::forward<CALLABLE>(func), +                      std::make_tuple(std::forward<T>(args[I])...), +                      I...); +} + +// this goes beyond C++17 std::apply() +template <typename CALLABLE, typename T> +auto apply(CALLABLE&& func, const std::vector<T>& args) +{ +    constexpr auto arity = boost::function_traits<CALLABLE>::arity; +    assert(args.size() == arity); +    return apply_impl(std::forward<CALLABLE>(func), +                      args, +                      std::make_index_sequence<arity>()); +} + +#endif // C++14 + +} // namespace LL + +#endif /* ! defined(LL_APPLY_H) */ 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; diff --git a/indra/llcommon/llprocessor.cpp b/indra/llcommon/llprocessor.cpp index 818df07bb2..4a1a81f083 100644 --- a/indra/llcommon/llprocessor.cpp +++ b/indra/llcommon/llprocessor.cpp @@ -118,7 +118,11 @@ namespace  		eMONTIOR_MWAIT=33,  		eCPLDebugStore=34,  		eThermalMonitor2=35, -		eAltivec=36 +		eAltivec=36, +        eSSE3S_Features = 37, +        eSSE4_1_Features = 38, +        eSSE4_2_Features = 39, +        eSSE4a_Features = 40,  	};  	const char* cpu_feature_names[] = @@ -161,7 +165,11 @@ namespace  		"CPL Qualified Debug Store",  		"Thermal Monitor 2", -		"Altivec" +		"Altivec", +        "SSE3S Instructions", +        "SSE4.1 Instructions", +        "SSE4.2 Instructions", +        "SSE4a Instructions",  	};  	std::string intel_CPUFamilyName(int composed_family)  @@ -250,6 +258,31 @@ public:  		return hasExtension(cpu_feature_names[eSSE2_Ext]);  	} +    bool hasSSE3() const +    { +        return hasExtension(cpu_feature_names[eSSE3_Features]); +    } + +    bool hasSSE3S() const +    { +        return hasExtension(cpu_feature_names[eSSE3S_Features]); +    } + +    bool hasSSE41() const +    { +        return hasExtension(cpu_feature_names[eSSE4_1_Features]); +    } + +    bool hasSSE42() const +    { +        return hasExtension(cpu_feature_names[eSSE4_2_Features]); +    } + +    bool hasSSE4a() const +    { +        return hasExtension(cpu_feature_names[eSSE4a_Features]); +    } +  	bool hasAltivec() const   	{  		return hasExtension("Altivec");  @@ -473,6 +506,12 @@ private:  		*((int*)(cpu_vendor+4)) = cpu_info[3];  		*((int*)(cpu_vendor+8)) = cpu_info[2];  		setInfo(eVendor, cpu_vendor); +        std::string cmp_vendor(cpu_vendor); +        bool is_amd = false; +        if (cmp_vendor == "AuthenticAMD") +        { +            is_amd = true; +        }  		// Get the information associated with each valid Id  		for(unsigned int i=0; i<=ids; ++i) @@ -504,6 +543,7 @@ private:  				if(cpu_info[2] & 0x8)  				{ +                    // intel specific SSE3 suplements  					setExtension(cpu_feature_names[eMONTIOR_MWAIT]);  				} @@ -516,7 +556,22 @@ private:  				{  					setExtension(cpu_feature_names[eThermalMonitor2]);  				} -						 + +                if (cpu_info[2] & 0x200) +                { +                    setExtension(cpu_feature_names[eSSE3S_Features]); +                } + +                if (cpu_info[2] & 0x80000) +                { +                    setExtension(cpu_feature_names[eSSE4_1_Features]); +                } + +                if (cpu_info[2] & 0x100000) +                { +                    setExtension(cpu_feature_names[eSSE4_2_Features]); +                } +  				unsigned int feature_info = (unsigned int) cpu_info[3];  				for(unsigned int index = 0, bit = 1; index < eSSE3_Features; ++index, bit <<= 1)  				{ @@ -543,8 +598,17 @@ private:  			__cpuid(cpu_info, i);  			// Interpret CPU brand string and cache information. -			if  (i == 0x80000002) -				memcpy(cpu_brand_string, cpu_info, sizeof(cpu_info)); +            if (i == 0x80000001) +            { +                if (is_amd) +                { +                    setExtension(cpu_feature_names[eSSE4a_Features]); +                } +            } +            else if (i == 0x80000002) +            { +                memcpy(cpu_brand_string, cpu_info, sizeof(cpu_info)); +            }  			else if  (i == 0x80000003)  				memcpy(cpu_brand_string + 16, cpu_info, sizeof(cpu_info));  			else if  (i == 0x80000004) @@ -690,6 +754,41 @@ private:  		uint64_t ext_feature_info = getSysctlInt64("machdep.cpu.extfeature_bits");  		S32 *ext_feature_infos = (S32*)(&ext_feature_info);  		setConfig(eExtFeatureBits, ext_feature_infos[0]); + + +        char cpu_features[1024]; +        len = sizeof(cpu_features); +        memset(cpu_features, 0, len); +        sysctlbyname("machdep.cpu.features", (void*)cpu_features, &len, NULL, 0); + +        std::string cpu_features_str(cpu_features); +        cpu_features_str = " " + cpu_features_str + " "; + +        if (cpu_features_str.find(" SSE3 ") != std::string::npos) +        { +            setExtension(cpu_feature_names[eSSE3_Features]); +        } + +        if (cpu_features_str.find(" SSSE3 ") != std::string::npos) +        { +            setExtension(cpu_feature_names[eSSE3S_Features]); +        } + +        if (cpu_features_str.find(" SSE4.1 ") != std::string::npos) +        { +            setExtension(cpu_feature_names[eSSE4_1_Features]); +        } + +        if (cpu_features_str.find(" SSE4.2 ") != std::string::npos) +        { +            setExtension(cpu_feature_names[eSSE4_2_Features]); +        } + +        if (cpu_features_str.find(" SSE4A ") != std::string::npos) +        { +            // Not supposed to happen? +            setExtension(cpu_feature_names[eSSE4a_Features]); +        }  	}  }; @@ -800,6 +899,31 @@ private:  		{  			setExtension(cpu_feature_names[eSSE2_Ext]);  		} + +        if (flags.find(" pni ") != std::string::npos) +        { +            setExtension(cpu_feature_names[eSSE3_Features]); +        } + +        if (flags.find(" ssse3 ") != std::string::npos) +        { +            setExtension(cpu_feature_names[eSSE3S_Features]); +        } + +        if (flags.find(" sse4_1 ") != std::string::npos) +        { +            setExtension(cpu_feature_names[eSSE4_1_Features]); +        } + +        if (flags.find(" sse4_2 ") != std::string::npos) +        { +            setExtension(cpu_feature_names[eSSE4_2_Features]); +        } + +        if (flags.find(" sse4a ") != std::string::npos) +        { +            setExtension(cpu_feature_names[eSSE4a_Features]); +        }  # endif // LL_X86  	} @@ -860,6 +984,11 @@ LLProcessorInfo::~LLProcessorInfo() {}  F64MegahertzImplicit LLProcessorInfo::getCPUFrequency() const { return mImpl->getCPUFrequency(); }  bool LLProcessorInfo::hasSSE() const { return mImpl->hasSSE(); }  bool LLProcessorInfo::hasSSE2() const { return mImpl->hasSSE2(); } +bool LLProcessorInfo::hasSSE3() const { return mImpl->hasSSE3(); } +bool LLProcessorInfo::hasSSE3S() const { return mImpl->hasSSE3S(); } +bool LLProcessorInfo::hasSSE41() const { return mImpl->hasSSE41(); } +bool LLProcessorInfo::hasSSE42() const { return mImpl->hasSSE42(); } +bool LLProcessorInfo::hasSSE4a() const { return mImpl->hasSSE4a(); }  bool LLProcessorInfo::hasAltivec() const { return mImpl->hasAltivec(); }  std::string LLProcessorInfo::getCPUFamilyName() const { return mImpl->getCPUFamilyName(); }  std::string LLProcessorInfo::getCPUBrandName() const { return mImpl->getCPUBrandName(); } diff --git a/indra/llcommon/llprocessor.h b/indra/llcommon/llprocessor.h index b77eb22c3a..1a473ddc97 100644 --- a/indra/llcommon/llprocessor.h +++ b/indra/llcommon/llprocessor.h @@ -54,6 +54,11 @@ public:  	F64MegahertzImplicit getCPUFrequency() const;  	bool hasSSE() const;  	bool hasSSE2() const; +    bool hasSSE3() const; +    bool hasSSE3S() const; +    bool hasSSE41() const; +    bool hasSSE42() const; +    bool hasSSE4a() const;  	bool hasAltivec() const;  	std::string getCPUFamilyName() const;  	std::string getCPUBrandName() const; diff --git a/indra/llcommon/llsd.h b/indra/llcommon/llsd.h index 24cb9bbce1..3daaef44fc 100644 --- a/indra/llcommon/llsd.h +++ b/indra/llcommon/llsd.h @@ -421,42 +421,42 @@ public:  	static std::string		typeString(Type type);		// Return human-readable type as a string  }; -struct llsd_select_bool : public std::unary_function<LLSD, LLSD::Boolean> +struct llsd_select_bool  {  	LLSD::Boolean operator()(const LLSD& sd) const  	{  		return sd.asBoolean();  	}  }; -struct llsd_select_integer : public std::unary_function<LLSD, LLSD::Integer> +struct llsd_select_integer  {  	LLSD::Integer operator()(const LLSD& sd) const  	{  		return sd.asInteger();  	}  }; -struct llsd_select_real : public std::unary_function<LLSD, LLSD::Real> +struct llsd_select_real  {  	LLSD::Real operator()(const LLSD& sd) const  	{  		return sd.asReal();  	}  }; -struct llsd_select_float : public std::unary_function<LLSD, F32> +struct llsd_select_float  {  	F32 operator()(const LLSD& sd) const  	{  		return (F32)sd.asReal();  	}  }; -struct llsd_select_uuid : public std::unary_function<LLSD, LLSD::UUID> +struct llsd_select_uuid  {  	LLSD::UUID operator()(const LLSD& sd) const  	{  		return sd.asUUID();  	}  }; -struct llsd_select_string : public std::unary_function<LLSD, LLSD::String> +struct llsd_select_string  {  	LLSD::String operator()(const LLSD& sd) const  	{ diff --git a/indra/llcommon/llstl.h b/indra/llcommon/llstl.h index a90c2c7e08..25131291f9 100644 --- a/indra/llcommon/llstl.h +++ b/indra/llcommon/llstl.h @@ -142,7 +142,7 @@ struct DeletePairedPointerArray  //                     llselect2nd<map_type::value_type>()));  template<typename T> -struct DeletePointerFunctor : public std::unary_function<T*, bool> +struct DeletePointerFunctor  {  	bool operator()(T* ptr) const  	{ @@ -153,7 +153,7 @@ struct DeletePointerFunctor : public std::unary_function<T*, bool>  // See notes about DeleteArray for why you should consider avoiding this.  template<typename T> -struct DeleteArrayFunctor : public std::unary_function<T*, bool> +struct DeleteArrayFunctor  {  	bool operator()(T* ptr) const  	{ @@ -395,16 +395,17 @@ OutputIter ll_transform_n(  // select... with the stl. Look up usage on the sgi website.  template <class _Pair> -struct _LLSelect1st : public std::unary_function<_Pair, typename _Pair::first_type> { -  const typename _Pair::first_type& operator()(const _Pair& __x) const { +struct _LLSelect1st +{ +  const auto& operator()(const _Pair& __x) const {      return __x.first;    }  };  template <class _Pair> -struct _LLSelect2nd : public std::unary_function<_Pair, typename _Pair::second_type> +struct _LLSelect2nd  { -  const typename _Pair::second_type& operator()(const _Pair& __x) const { +  const auto& operator()(const _Pair& __x) const {      return __x.second;    }  }; @@ -416,9 +417,7 @@ template <class _Pair> struct llselect2nd : public _LLSelect2nd<_Pair> {};  // compose... with the stl. Look up usage on the sgi website.  template <class _Operation1, class _Operation2> -class ll_unary_compose : -	public std::unary_function<typename _Operation2::argument_type, -							   typename _Operation1::result_type> +class ll_unary_compose  {  protected:    _Operation1 __op1; @@ -426,8 +425,9 @@ protected:  public:    ll_unary_compose(const _Operation1& __x, const _Operation2& __y)      : __op1(__x), __op2(__y) {} -  typename _Operation1::result_type -  operator()(const typename _Operation2::argument_type& __x) const { +  template <typename _Op2Arg> +  auto +  operator()(const _Op2Arg& __x) const {      return __op1(__op2(__x));    }  }; @@ -441,8 +441,7 @@ llcompose1(const _Operation1& __op1, const _Operation2& __op2)  template <class _Operation1, class _Operation2, class _Operation3>  class ll_binary_compose -  : public std::unary_function<typename _Operation2::argument_type, -							   typename _Operation1::result_type> { +{  protected:    _Operation1 _M_op1;    _Operation2 _M_op2; @@ -451,8 +450,9 @@ public:    ll_binary_compose(const _Operation1& __x, const _Operation2& __y,  					const _Operation3& __z)      : _M_op1(__x), _M_op2(__y), _M_op3(__z) { } -  typename _Operation1::result_type -  operator()(const typename _Operation2::argument_type& __x) const { +  template<typename OP2ARG> +  auto +  operator()(const OP2ARG& __x) const {      return _M_op1(_M_op2(__x), _M_op3(__x));    }  }; @@ -468,54 +468,51 @@ llcompose2(const _Operation1& __op1, const _Operation2& __op2,  // helpers to deal with the fact that MSDev does not package  // bind... with the stl. Again, this is from sgi. -template <class _Operation> -class llbinder1st : -	public std::unary_function<typename _Operation::second_argument_type, -							   typename _Operation::result_type> { +template <class _Operation, typename _Arg1> +class llbinder1st +{  protected:    _Operation op; -  typename _Operation::first_argument_type value; +  _Arg1 value;  public: -  llbinder1st(const _Operation& __x, -			  const typename _Operation::first_argument_type& __y) +  llbinder1st(const _Operation& __x, const _Arg1& __y)        : op(__x), value(__y) {} -	typename _Operation::result_type -	operator()(const typename _Operation::second_argument_type& __x) const { -		return op(value, __x); -	} +    template <typename _Arg2> +    auto +    operator()(const _Arg2& __x) const { +        return op(value, __x); +    }  };  template <class _Operation, class _Tp> -inline llbinder1st<_Operation> +inline auto  llbind1st(const _Operation& __oper, const _Tp& __x)  { -  typedef typename _Operation::first_argument_type _Arg1_type; -  return llbinder1st<_Operation>(__oper, _Arg1_type(__x)); +  return llbinder1st<_Operation, _Tp>(__oper, __x);  } -template <class _Operation> +template <class _Operation, typename _Arg2>  class llbinder2nd -	: public std::unary_function<typename _Operation::first_argument_type, -								 typename _Operation::result_type> { +{  protected:  	_Operation op; -	typename _Operation::second_argument_type value; +	_Arg2 value;  public:  	llbinder2nd(const _Operation& __x, -				const typename _Operation::second_argument_type& __y) +				const _Arg2& __y)  		: op(__x), value(__y) {} -	typename _Operation::result_type -	operator()(const typename _Operation::first_argument_type& __x) const { +	template <typename _Arg1> +	auto +	operator()(const _Arg1& __x) const {  		return op(__x, value);  	}  };  template <class _Operation, class _Tp> -inline llbinder2nd<_Operation> +inline auto  llbind2nd(const _Operation& __oper, const _Tp& __x)  { -  typedef typename _Operation::second_argument_type _Arg2_type; -  return llbinder2nd<_Operation>(__oper, _Arg2_type(__x)); +  return llbinder2nd<_Operation, _Tp>(__oper, __x);  }  /** @@ -548,8 +545,7 @@ bool before(const std::type_info* lhs, const std::type_info* rhs)  namespace std  {  	template <> -	struct less<const std::type_info*>: -		public std::binary_function<const std::type_info*, const std::type_info*, bool> +	struct less<const std::type_info*>  	{  		bool operator()(const std::type_info* lhs, const std::type_info* rhs) const  		{ @@ -558,8 +554,7 @@ namespace std  	};  	template <> -	struct less<std::type_info*>: -		public std::binary_function<std::type_info*, std::type_info*, bool> +	struct less<std::type_info*>  	{  		bool operator()(std::type_info* lhs, std::type_info* rhs) const  		{ diff --git a/indra/llcommon/llsys.cpp b/indra/llcommon/llsys.cpp index 9b6bb3826c..26a0fa1b1c 100644 --- a/indra/llcommon/llsys.cpp +++ b/indra/llcommon/llsys.cpp @@ -597,6 +597,11 @@ LLCPUInfo::LLCPUInfo()  	// proc.WriteInfoTextFile("procInfo.txt");  	mHasSSE = proc.hasSSE();  	mHasSSE2 = proc.hasSSE2(); +    mHasSSE3 = proc.hasSSE3(); +    mHasSSE3S = proc.hasSSE3S(); +    mHasSSE41 = proc.hasSSE41(); +    mHasSSE42 = proc.hasSSE42(); +    mHasSSE4a = proc.hasSSE4a();  	mHasAltivec = proc.hasAltivec();  	mCPUMHz = (F64)proc.getCPUFrequency();  	mFamily = proc.getCPUFamilyName(); @@ -609,6 +614,35 @@ LLCPUInfo::LLCPUInfo()  	}  	mCPUString = out.str();  	LLStringUtil::trim(mCPUString); + +    if (mHasSSE) +    { +        mSSEVersions.append("1"); +    } +    if (mHasSSE2) +    { +        mSSEVersions.append("2"); +    } +    if (mHasSSE3) +    { +        mSSEVersions.append("3"); +    } +    if (mHasSSE3S) +    { +        mSSEVersions.append("3S"); +    } +    if (mHasSSE41) +    { +        mSSEVersions.append("4.1"); +    } +    if (mHasSSE42) +    { +        mSSEVersions.append("4.2"); +    } +    if (mHasSSE4a) +    { +        mSSEVersions.append("4a"); +    }  }  bool LLCPUInfo::hasAltivec() const @@ -626,6 +660,31 @@ bool LLCPUInfo::hasSSE2() const  	return mHasSSE2;  } +bool LLCPUInfo::hasSSE3() const +{ +    return mHasSSE3; +} + +bool LLCPUInfo::hasSSE3S() const +{ +    return mHasSSE3S; +} + +bool LLCPUInfo::hasSSE41() const +{ +    return mHasSSE41; +} + +bool LLCPUInfo::hasSSE42() const +{ +    return mHasSSE42; +} + +bool LLCPUInfo::hasSSE4a() const +{ +    return mHasSSE4a; +} +  F64 LLCPUInfo::getMHz() const  {  	return mCPUMHz; @@ -636,6 +695,11 @@ std::string LLCPUInfo::getCPUString() const  	return mCPUString;  } +const LLSD& LLCPUInfo::getSSEVersions() const +{ +    return mSSEVersions; +} +  void LLCPUInfo::stream(std::ostream& s) const  {  	// gather machine information. @@ -645,6 +709,11 @@ void LLCPUInfo::stream(std::ostream& s) const  	// CPU's attributes regardless of platform  	s << "->mHasSSE:     " << (U32)mHasSSE << std::endl;  	s << "->mHasSSE2:    " << (U32)mHasSSE2 << std::endl; +    s << "->mHasSSE3:    " << (U32)mHasSSE3 << std::endl; +    s << "->mHasSSE3S:    " << (U32)mHasSSE3S << std::endl; +    s << "->mHasSSE41:    " << (U32)mHasSSE41 << std::endl; +    s << "->mHasSSE42:    " << (U32)mHasSSE42 << std::endl; +    s << "->mHasSSE4a:    " << (U32)mHasSSE4a << std::endl;  	s << "->mHasAltivec: " << (U32)mHasAltivec << std::endl;  	s << "->mCPUMHz:     " << mCPUMHz << std::endl;  	s << "->mCPUString:  " << mCPUString << std::endl; diff --git a/indra/llcommon/llsys.h b/indra/llcommon/llsys.h index cb92cb0ac6..5ffbf5a732 100644 --- a/indra/llcommon/llsys.h +++ b/indra/llcommon/llsys.h @@ -80,10 +80,16 @@ public:  	void stream(std::ostream& s) const;  	std::string getCPUString() const; +	const LLSD& getSSEVersions() const;  	bool hasAltivec() const;  	bool hasSSE() const;  	bool hasSSE2() const; +    bool hasSSE3() const; +    bool hasSSE3S() const; +    bool hasSSE41() const; +    bool hasSSE42() const; +    bool hasSSE4a() const;  	F64 getMHz() const;  	// Family is "AMD Duron" or "Intel Pentium Pro" @@ -92,10 +98,16 @@ public:  private:  	bool mHasSSE;  	bool mHasSSE2; +    bool mHasSSE3; +    bool mHasSSE3S; +    bool mHasSSE41; +    bool mHasSSE42; +    bool mHasSSE4a;  	bool mHasAltivec;  	F64 mCPUMHz;  	std::string mFamily;  	std::string mCPUString; +    LLSD mSSEVersions;  };  //============================================================================= diff --git a/indra/llcommon/tests/llleap_test.cpp b/indra/llcommon/tests/llleap_test.cpp index 9754353ab0..7ee36a9ea6 100644 --- a/indra/llcommon/tests/llleap_test.cpp +++ b/indra/llcommon/tests/llleap_test.cpp @@ -15,10 +15,10 @@  #include "llleap.h"  // STL headers  // std headers +#include <functional>  // external library headers  #include <boost/assign/list_of.hpp>  #include <boost/phoenix/core/argument.hpp> -#include <boost/foreach.hpp>  // other Linden headers  #include "../test/lltut.h"  #include "../test/namedtempfile.h" @@ -29,7 +29,6 @@  #include "llstring.h"  #include "stringize.h"  #include "StringVec.h" -#include <functional>  using boost::assign::list_of; @@ -110,11 +109,6 @@ namespace tut                     "import os\n"                     "import sys\n"                     "\n" -                   // Don't forget that this Python script is written to some -                   // temp directory somewhere! Its __file__ is useless in -                   // finding indra/lib/python. Use our __FILE__, with -                   // raw-string syntax to deal with Windows pathnames. -                   "mydir = os.path.dirname(r'" << __FILE__ << "')\n"                     "from llbase import llsd\n"                     "\n"                     "class ProtocolError(Exception):\n" @@ -241,9 +235,9 @@ namespace tut                               "import sys\n"                               "sys.stderr.write('''Hello from Python!\n"                               "note partial line''')\n"); +        StringVec vcommand{ PYTHON, script.getName() };          CaptureLog log(LLError::LEVEL_INFO); -        waitfor(LLLeap::create(get_test_name(), -                               sv(list_of(PYTHON)(script.getName())))); +        waitfor(LLLeap::create(get_test_name(), vcommand));          log.messageWith("Hello from Python!");          log.messageWith("note partial line");      } @@ -531,7 +525,7 @@ namespace tut          result.ensure();      } -    struct TestLargeMessage: public std::binary_function<size_t, size_t, bool> +    struct TestLargeMessage      {          TestLargeMessage(const std::string& PYTHON_, const std::string& reader_module_,                           const std::string& test_name_):  | 
