aboutsummaryrefslogtreecommitdiffstats
path: root/src/lib/utils/cpuid/cpuid.h
diff options
context:
space:
mode:
authorJack Lloyd <[email protected]>2019-01-28 15:13:59 -0500
committerJack Lloyd <[email protected]>2019-01-30 19:28:39 -0500
commitd9a5ffe01f33d509afac68563dbb26a9dc8b9ef6 (patch)
treeaf3605c57ef457a2987b842908f702966082ec97 /src/lib/utils/cpuid/cpuid.h
parent8c835b3b1238083c4b4bb4a90e4d9e9b38dffb11 (diff)
Refactor CPUID to make it thread safe
Needed for #1819 and unfortunately Windows does not allow thread local data to be stored as a member of a DLL exported class. So hide it behind an accessor function instead. This slows down CPUID test somewhat and I would like to address that but it seems hard without breaking the CPUID API, which is for better or worse public.
Diffstat (limited to 'src/lib/utils/cpuid/cpuid.h')
-rw-r--r--src/lib/utils/cpuid/cpuid.h72
1 files changed, 40 insertions, 32 deletions
diff --git a/src/lib/utils/cpuid/cpuid.h b/src/lib/utils/cpuid/cpuid.h
index 95f6d687b..46eef2095 100644
--- a/src/lib/utils/cpuid/cpuid.h
+++ b/src/lib/utils/cpuid/cpuid.h
@@ -65,21 +65,17 @@ class BOTAN_PUBLIC_API(2,1) CPUID final
*/
static size_t cache_line_size()
{
- if(g_processor_features == 0)
- {
- initialize();
- }
- return g_cache_line_size;
+ return state().cache_line_size();
}
static bool is_little_endian()
{
- return endian_status() == ENDIAN_LITTLE;
+ return state().endian_status() == Endian_Status::Little;
}
static bool is_big_endian()
{
- return endian_status() == ENDIAN_BIG;
+ return state().endian_status() == Endian_Status::Big;
}
enum CPUID_bits : uint64_t {
@@ -309,8 +305,7 @@ class BOTAN_PUBLIC_API(2,1) CPUID final
*/
static void clear_cpuid_bit(CPUID_bits bit)
{
- const uint64_t mask = ~(static_cast<uint64_t>(bit));
- g_processor_features &= mask;
+ state().clear_cpuid_bit(static_cast<uint64_t>(bit));
}
/*
@@ -319,43 +314,56 @@ class BOTAN_PUBLIC_API(2,1) CPUID final
*/
static bool has_cpuid_bit(CPUID_bits elem)
{
- if(g_processor_features == 0)
- initialize();
-
const uint64_t elem64 = static_cast<uint64_t>(elem);
- return ((g_processor_features & elem64) == elem64);
+ return state().has_bit(elem64);
}
static std::vector<CPUID::CPUID_bits> bit_from_string(const std::string& tok);
private:
- enum Endian_status : uint32_t {
- ENDIAN_UNKNOWN = 0x00000000,
- ENDIAN_BIG = 0x01234567,
- ENDIAN_LITTLE = 0x67452301,
+ enum class Endian_Status : uint32_t {
+ Unknown = 0x00000000,
+ Big = 0x01234567,
+ Little = 0x67452301,
};
+ struct CPUID_Data
+ {
+ public:
+ CPUID_Data();
+
+ CPUID_Data(const CPUID_Data& other) = default;
+ CPUID_Data& operator=(const CPUID_Data& other) = default;
+
+ void clear_cpuid_bit(uint64_t bit)
+ {
+ m_processor_features &= ~bit;
+ }
+
+ bool has_bit(uint64_t bit) const
+ {
+ return (m_processor_features & bit) == bit;
+ }
+
+ uint64_t processor_features() const { return m_processor_features; }
+ Endian_Status endian_status() const { return m_endian_status; }
+ size_t cache_line_size() const { return m_cache_line_size; }
+
+ private:
+ static Endian_Status runtime_check_endian();
+
#if defined(BOTAN_TARGET_CPU_IS_PPC_FAMILY) || \
defined(BOTAN_TARGET_CPU_IS_ARM_FAMILY) || \
defined(BOTAN_TARGET_CPU_IS_X86_FAMILY)
- static uint64_t detect_cpu_features(size_t* cache_line_size);
+ static uint64_t detect_cpu_features(size_t* cache_line_size);
#endif
+ uint64_t m_processor_features;
+ size_t m_cache_line_size;
+ Endian_Status m_endian_status;
+ };
- static Endian_status runtime_check_endian();
-
- static Endian_status endian_status()
- {
- if(g_endian_status == ENDIAN_UNKNOWN)
- {
- g_endian_status = runtime_check_endian();
- }
- return g_endian_status;
- }
-
- static uint64_t g_processor_features;
- static size_t g_cache_line_size;
- static Endian_status g_endian_status;
+ static CPUID_Data& state();
};
}