atomic_op() rewritten, atomic.h refactoring

cellSync refactoring, wait_op() rewritten, bugfixes
This commit is contained in:
Nekotekina
2015-06-26 02:26:23 +03:00
parent 39f836b495
commit c598fe7aa9
24 changed files with 725 additions and 754 deletions
+15 -25
View File
@@ -165,13 +165,6 @@ union u128
} _bit;
//operator u64() const { return _u64[0]; }
//operator u32() const { return _u32[0]; }
//operator u16() const { return _u16[0]; }
//operator u8() const { return _u8[0]; }
//operator bool() const { return _u64[0] != 0 || _u64[1] != 0; }
static u128 from64(u64 _0, u64 _1 = 0)
{
u128 ret;
@@ -443,7 +436,7 @@ static force_inline u128 sync_fetch_and_xor(volatile u128* dest, u128 value)
}
}
template<typename T, int size = sizeof(T)> struct se_t;
template<typename T, std::size_t Size = sizeof(T)> struct se_t;
template<typename T> struct se_t<T, 2>
{
@@ -501,16 +494,13 @@ template<typename T> struct se_t<T, 16>
}
};
template<typename T, T _value, size_t size = sizeof(T)> struct const_se_t;
template<u8 _value> struct const_se_t<u8, _value, 1>
{
static const u8 value = _value;
};
template<typename T, T _value, std::size_t size = sizeof(T)> struct const_se_t;
template<u16 _value> struct const_se_t<u16, _value, 2>
{
static const u16 value = ((_value >> 8) & 0xff) | ((_value << 8) & 0xff00);
static const u16 value =
((_value >> 8) & 0x00ff) |
((_value << 8) & 0xff00);
};
template<u32 _value> struct const_se_t<u32, _value, 4>
@@ -600,9 +590,9 @@ public:
using stype = be_storage_t<std::remove_cv_t<T>>;
#ifdef IS_LE_MACHINE
stype m_data;
stype m_data; // don't access directly
#else
type m_data;
type m_data; // don't access directly
#endif
static_assert(!std::is_class<type>::value, "be_t<> error: invalid type (class or structure)");
@@ -695,41 +685,41 @@ public:
be_t& operator --() { *this -= 1; return *this; }
};
template<typename T1, typename T2> inline std::enable_if_t<std::is_same<T1, T2>::value, bool> operator ==(const be_t<T1>& left, const be_t<T2>& right)
template<typename T1, typename T2> inline std::enable_if_t<std::is_same<T1, T2>::value && std::is_integral<T1>::value, bool> operator ==(const be_t<T1>& left, const be_t<T2>& right)
{
return left.data() == right.data();
}
template<typename T1, typename T2> inline std::enable_if_t<std::is_same<T1, T2>::value, bool> operator !=(const be_t<T1>& left, const be_t<T2>& right)
template<typename T1, typename T2> inline std::enable_if_t<std::is_same<T1, T2>::value && std::is_integral<T1>::value, bool> operator !=(const be_t<T1>& left, const be_t<T2>& right)
{
return left.data() != right.data();
}
template<typename T1, typename T2> inline std::enable_if_t<std::is_same<T1, T2>::value, be_t<T1>> operator &(const be_t<T1>& left, const be_t<T2>& right)
template<typename T1, typename T2> inline std::enable_if_t<std::is_same<T1, T2>::value && std::is_integral<T1>::value, be_t<T1>> operator &(const be_t<T1>& left, const be_t<T2>& right)
{
be_t<T1> result;
result.m_data = left.data() & right.data();
return result;
}
template<typename T1, typename T2> inline std::enable_if_t<std::is_same<T1, T2>::value, be_t<T1>> operator |(const be_t<T1>& left, const be_t<T2>& right)
template<typename T1, typename T2> inline std::enable_if_t<std::is_same<T1, T2>::value && std::is_integral<T1>::value, be_t<T1>> operator |(const be_t<T1>& left, const be_t<T2>& right)
{
be_t<T1> result;
result.m_data = left.data() | right.data();
return result;
}
template<typename T1, typename T2> inline std::enable_if_t<std::is_same<T1, T2>::value, be_t<T1>> operator ^(const be_t<T1>& left, const be_t<T2>& right)
template<typename T1, typename T2> inline std::enable_if_t<std::is_same<T1, T2>::value && std::is_integral<T1>::value, be_t<T1>> operator ^(const be_t<T1>& left, const be_t<T2>& right)
{
be_t<T1> result;
result.m_data = left.data() ^ right.data();
return result;
}
template<typename T1> inline std::enable_if_t<true, be_t<T1>> operator ~(const be_t<T1>& other)
template<typename T1> inline std::enable_if_t<std::is_integral<T1>::value, be_t<T1>> operator ~(const be_t<T1>& arg)
{
be_t<T1> result;
result.m_data = ~other.data();
result.m_data = ~arg.data();
return result;
}
@@ -782,7 +772,7 @@ public:
using type = std::remove_cv_t<T>;
using stype = be_storage_t<std::remove_cv_t<T>>;
type m_data;
type m_data; // don't access directly
static_assert(!std::is_class<type>::value, "le_t<> error: invalid type (class or structure)");
static_assert(!std::is_union<type>::value || std::is_same<type, u128>::value, "le_t<> error: invalid type (union)");
+9 -3
View File
@@ -749,7 +749,7 @@ size_t get_x64_access_size(x64_context* context, x64_op_t op, x64_reg_t reg, siz
if (op == X64OP_CMPXCHG)
{
// detect whether this instruction can't actually modify memory to avoid breaking reservation;
// this may theoretically cause endless loop, but it shouldn't be a problem if only read_sync() generates such instruction
// this may theoretically cause endless loop, but it shouldn't be a problem if only load_sync() generates such instruction
u64 cmp, exch;
if (!get_x64_reg_value(context, reg, d_size, i_size, cmp) || !get_x64_reg_value(context, X64R_RAX, d_size, i_size, exch))
{
@@ -1480,16 +1480,22 @@ bool thread_t::joinable() const
return m_state == TS_JOINABLE;
}
bool waiter_map_t::is_stopped(u64 signal_id)
bool waiter_map_t::is_stopped(u32 addr)
{
if (Emu.IsStopped())
{
LOG_WARNING(Log::HLE, "%s: waiter_op() aborted (signal_id=0x%llx)", name.c_str(), signal_id);
LOG_WARNING(Log::HLE, "%s: waiter_op() aborted (addr=0x%x)", name.c_str(), addr);
return true;
}
return false;
}
void waiter_map_t::notify(u32 addr)
{
// signal appropriate condition variable
cv[get_hash(addr)].notify_all();
}
const std::function<bool()> SQUEUE_ALWAYS_EXIT = [](){ return true; };
const std::function<bool()> SQUEUE_NEVER_EXIT = [](){ return false; };
+29 -26
View File
@@ -103,7 +103,7 @@ class slw_shared_mutex_t
struct waiter_map_t
{
static const size_t size = 32;
static const size_t size = 16;
std::array<std::mutex, size> mutex;
std::array<std::condition_variable, size> cv;
@@ -115,40 +115,43 @@ struct waiter_map_t
{
}
bool is_stopped(u64 signal_id);
// generate simple "hash" for mutex/cv distribution
u32 get_hash(u32 addr)
{
addr ^= addr >> 16;
addr ^= addr >> 24;
addr ^= addr >> 28;
return addr % size;
}
// check emu status
bool is_stopped(u32 addr);
// wait until waiter_func() returns true, signal_id is an arbitrary number
template<typename S, typename WT> force_inline safe_buffers void wait_op(const S& signal_id, const WT waiter_func)
template<typename F, typename... Args> safe_buffers auto wait_op(u32 addr, F pred, Args&&... args) -> decltype(static_cast<void>(pred(args...)))
{
// generate hash
const auto hash = std::hash<S>()(signal_id) % size;
const u32 hash = get_hash(addr);
// set mutex locker
std::unique_lock<std::mutex> locker(mutex[hash], std::defer_lock);
std::unique_lock<std::mutex> lock(mutex[hash], std::defer_lock);
// check the condition or if the emulator is stopped
while (!waiter_func() && !is_stopped(signal_id))
while (true)
{
// check the condition
if (pred(args...)) return;
// lock the mutex and initialize waiter (only once)
if (!locker.owns_lock())
{
locker.lock();
}
if (!lock) lock.lock();
// wait on appropriate condition variable for 1 ms or until signal arrived
cv[hash].wait_for(locker, std::chrono::milliseconds(1));
cv[hash].wait_for(lock, std::chrono::milliseconds(1));
if (is_stopped(addr)) return;
}
}
// signal all threads waiting on waiter_op() with the same signal_id (signaling only hints those threads that corresponding conditions are *probably* met)
template<typename S> force_inline void notify(const S& signal_id)
{
// generate hash
const auto hash = std::hash<S>()(signal_id) % size;
// signal appropriate condition variable
cv[hash].notify_all();
}
void notify(u32 addr);
};
extern const std::function<bool()> SQUEUE_ALWAYS_EXIT;
@@ -209,7 +212,7 @@ public:
{
u32 pos = 0;
while (u32 res = m_sync.atomic_op_sync(SQSVR_OK, [&pos](squeue_sync_var_t& sync) -> u32
while (u32 res = m_sync.atomic_op([&pos](squeue_sync_var_t& sync) -> u32
{
assert(sync.count <= sq_size);
assert(sync.position < sq_size);
@@ -272,7 +275,7 @@ public:
{
u32 pos = 0;
while (u32 res = m_sync.atomic_op_sync(SQSVR_OK, [&pos](squeue_sync_var_t& sync) -> u32
while (u32 res = m_sync.atomic_op([&pos](squeue_sync_var_t& sync) -> u32
{
assert(sync.count <= sq_size);
assert(sync.position < sq_size);
@@ -341,7 +344,7 @@ public:
assert(start_pos < sq_size);
u32 pos = 0;
while (u32 res = m_sync.atomic_op_sync(SQSVR_OK, [&pos, start_pos](squeue_sync_var_t& sync) -> u32
while (u32 res = m_sync.atomic_op([&pos, start_pos](squeue_sync_var_t& sync) -> u32
{
assert(sync.count <= sq_size);
assert(sync.position < sq_size);
@@ -425,7 +428,7 @@ public:
{
u32 pos, count;
while (m_sync.atomic_op_sync(SQSVR_OK, [&pos, &count](squeue_sync_var_t& sync) -> u32
while (m_sync.atomic_op([&pos, &count](squeue_sync_var_t& sync) -> u32
{
assert(sync.count <= sq_size);
assert(sync.position < sq_size);
@@ -463,7 +466,7 @@ public:
void clear()
{
while (m_sync.atomic_op_sync(SQSVR_OK, [](squeue_sync_var_t& sync) -> u32
while (m_sync.atomic_op([](squeue_sync_var_t& sync) -> u32
{
assert(sync.count <= sq_size);
assert(sync.position < sq_size);