summaryrefslogtreecommitdiff
path: root/indra/llcommon
diff options
context:
space:
mode:
Diffstat (limited to 'indra/llcommon')
-rw-r--r--indra/llcommon/apply.h115
-rw-r--r--indra/llcommon/llalignedarray.h10
-rw-r--r--indra/llcommon/llcoros.cpp37
-rw-r--r--indra/llcommon/llcoros.h35
-rw-r--r--indra/llcommon/llprocessor.cpp139
-rw-r--r--indra/llcommon/llprocessor.h5
-rw-r--r--indra/llcommon/llsd.h12
-rw-r--r--indra/llcommon/llstl.h81
-rw-r--r--indra/llcommon/llsys.cpp69
-rw-r--r--indra/llcommon/llsys.h12
-rw-r--r--indra/llcommon/tests/llleap_test.cpp14
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_):