PPUThread refactoring

`CallbackManager` removed, added _gcm_intr_thread for cellGcmSys
`PPUThread` renamed to `ppu_thread`, inheritance allowed
Added lightweight command queue for `ppu_thread`
Implemented call stack dump for PPU
`get_current_thread_mutex` removed
`thread_ctrl::spawn`: minor initialization fix
`thread_ctrl::wait_for` added
`named_thread`: some methods added
`cpu_thread::run` added
Some bugs fixes, including SPU channels
This commit is contained in:
Nekotekina
2016-07-28 00:43:22 +03:00
parent 33c59fa51b
commit f8719c1230
99 changed files with 4480 additions and 4592 deletions
+27 -30
View File
@@ -143,22 +143,34 @@ struct atomic_storage
return atomic_storage<T>::sub_fetch(dest, 1);
}
static inline bool test_and_set(T& dest, T mask)
{
return (atomic_storage<T>::fetch_or(dest, mask) & mask) != 0;
}
static inline bool test_and_reset(T& dest, T mask)
{
return (atomic_storage<T>::fetch_and(dest, ~mask) & mask) != 0;
}
static inline bool test_and_complement(T& dest, T mask)
{
return (atomic_storage<T>::fetch_xor(dest, mask) & mask) != 0;
}
static inline bool bts(T& dest, uint bit)
{
const T mask = static_cast<T>(1) << bit;
return (atomic_storage<T>::fetch_or(dest, mask) & mask) != 0;
return atomic_storage<T>::test_and_set(dest, static_cast<T>(1) << bit);
}
static inline bool btr(T& dest, uint bit)
{
const T mask = static_cast<T>(1) << bit;
return (atomic_storage<T>::fetch_and(dest, ~mask) & mask) != 0;
return atomic_storage<T>::test_and_reset(dest, static_cast<T>(1) << bit);
}
static inline bool btc(T& dest, uint bit)
{
const T mask = static_cast<T>(1) << bit;
return (atomic_storage<T>::fetch_xor(dest, mask) & mask) != 0;
return atomic_storage<T>::test_and_complement(dest, static_cast<T>(1) << bit);
}
};
@@ -637,14 +649,9 @@ struct atomic_test_and_set
template<typename T1, typename T2>
struct atomic_test_and_set<T1, T2, std::enable_if_t<std::is_integral<T1>::value && std::is_convertible<T2, T1>::value>>
{
static inline bool op(T1& lhs, const T2& rhs)
{
return (atomic_storage<T1>::fetch_or(lhs, rhs) & rhs) != 0;
}
static constexpr auto fetch_op = &op;
static constexpr auto op_fetch = &op;
static constexpr auto atomic_op = &op;
static constexpr auto fetch_op = &atomic_storage<T1>::test_and_set;
static constexpr auto op_fetch = &atomic_storage<T1>::test_and_set;
static constexpr auto atomic_op = &atomic_storage<T1>::test_and_set;
};
template<typename T1, typename T2, typename>
@@ -659,14 +666,9 @@ struct atomic_test_and_reset
template<typename T1, typename T2>
struct atomic_test_and_reset<T1, T2, std::enable_if_t<std::is_integral<T1>::value && std::is_convertible<T2, T1>::value>>
{
static inline bool op(T1& lhs, const T2& rhs)
{
return (atomic_storage<T1>::fetch_and(lhs, ~rhs) & rhs) != 0;
}
static constexpr auto fetch_op = &op;
static constexpr auto op_fetch = &op;
static constexpr auto atomic_op = &op;
static constexpr auto fetch_op = &atomic_storage<T1>::test_and_reset;
static constexpr auto op_fetch = &atomic_storage<T1>::test_and_reset;
static constexpr auto atomic_op = &atomic_storage<T1>::test_and_reset;
};
template<typename T1, typename T2, typename>
@@ -681,14 +683,9 @@ struct atomic_test_and_complement
template<typename T1, typename T2>
struct atomic_test_and_complement<T1, T2, std::enable_if_t<std::is_integral<T1>::value && std::is_convertible<T2, T1>::value>>
{
static inline bool op(T1& lhs, const T2& rhs)
{
return (atomic_storage<T1>::fetch_xor(lhs, rhs) & rhs) != 0;
}
static constexpr auto fetch_op = &op;
static constexpr auto op_fetch = &op;
static constexpr auto atomic_op = &op;
static constexpr auto fetch_op = &atomic_storage<T1>::test_and_complement;
static constexpr auto op_fetch = &atomic_storage<T1>::test_and_complement;
static constexpr auto atomic_op = &atomic_storage<T1>::test_and_complement;
};
// Atomic type with lock-free and standard layout guarantees (and appropriate limitations)
+1 -1
View File
@@ -12,7 +12,7 @@ template<typename T> using sleep_queue = std::deque<T*>;
// Sleep is called in the constructor (if not null)
// Awake is called in the destructor (if not null)
// Sleep queue is actually std::deque with pointers, be careful about the lifetime
template<typename T, void(T::*Sleep)() = &T::sleep, void(T::*Awake)() = &T::awake>
template<typename T, void(T::*Sleep)() = nullptr, void(T::*Awake)() = nullptr>
class sleep_entry final
{
sleep_queue<T>& m_queue;
+1 -6
View File
@@ -1830,11 +1830,6 @@ struct thread_ctrl::internal
thread_local thread_ctrl::internal* g_tls_internal = nullptr;
extern std::mutex& get_current_thread_mutex()
{
return g_tls_internal->mutex;
}
extern std::condition_variable& get_current_thread_cv()
{
return g_tls_internal->cond;
@@ -2244,7 +2239,7 @@ void named_thread::start_thread(const std::shared_ptr<void>& _this)
ENSURES(_this.get() == this);
// Run thread
m_thread = thread_ctrl::spawn(get_name(), [this, _this]()
thread_ctrl::spawn(m_thread, get_name(), [this, _this]()
{
try
{
+70 -9
View File
@@ -233,9 +233,12 @@ public:
// Wait until pred(). Abortable, may throw. Thread must be locked.
// Timeout in microseconds (zero means infinite).
template<typename F>
static inline auto wait(u64 useconds, F&& pred)
static inline auto wait_for(u64 useconds, F&& pred)
{
g_tls_this_thread->wait_start(useconds);
if (useconds)
{
g_tls_this_thread->wait_start(useconds);
}
while (true)
{
@@ -252,6 +255,26 @@ public:
}
}
// Wait once. Abortable, may throw. Thread must be locked.
// Timeout in microseconds (zero means infinite).
static inline bool wait_for(u64 useconds = 0)
{
if (useconds)
{
g_tls_this_thread->wait_start(useconds);
}
g_tls_this_thread->test();
if (!g_tls_this_thread->wait_wait(useconds) && useconds)
{
return false;
}
g_tls_this_thread->test();
return true;
}
// Wait until pred(). Abortable, may throw. Thread must be locked.
template<typename F>
static inline auto wait(F&& pred)
@@ -269,7 +292,7 @@ public:
}
}
// Wait once. Thread must be locked.
// Wait once. Abortable, may throw. Thread must be locked.
static inline void wait()
{
g_tls_this_thread->test();
@@ -277,7 +300,7 @@ public:
g_tls_this_thread->test();
}
// Wait unconditionally until aborted. Thread must be locked.
// Wait eternally. Abortable, may throw. Thread must be locked.
[[noreturn]] static inline void eternalize()
{
while (true)
@@ -302,13 +325,20 @@ public:
// Named thread factory
template<typename N, typename F>
static inline std::shared_ptr<thread_ctrl> spawn(N&& name, F&& func)
static inline void spawn(N&& name, F&& func)
{
auto ctrl = std::make_shared<thread_ctrl>(std::forward<N>(name));
auto&& out = std::make_shared<thread_ctrl>(std::forward<N>(name));
thread_ctrl::start(ctrl, std::forward<F>(func));
thread_ctrl::start(out, std::forward<F>(func));
}
return ctrl;
// Named thread factory
template<typename N, typename F>
static inline void spawn(std::shared_ptr<thread_ctrl>& out, N&& name, F&& func)
{
out = std::make_shared<thread_ctrl>(std::forward<N>(name));
thread_ctrl::start(out, std::forward<F>(func));
}
};
@@ -356,6 +386,31 @@ public:
{
return m_thread.get();
}
void join() const
{
return m_thread->join();
}
void lock() const
{
return m_thread->lock();
}
void unlock() const
{
return m_thread->unlock();
}
void lock_notify() const
{
return m_thread->lock_notify();
}
void notify() const
{
return m_thread->notify();
}
};
// Simple thread mutex locker
@@ -429,8 +484,8 @@ class scope_thread final
public:
template<typename N, typename F>
scope_thread(N&& name, F&& func)
: m_thread(thread_ctrl::spawn(std::forward<N>(name), std::forward<F>(func)))
{
thread_ctrl::spawn(m_thread, std::forward<N>(name), std::forward<F>(func));
}
// Deleted copy/move constructors + copy/move operators
@@ -441,4 +496,10 @@ public:
{
m_thread->join();
}
// Access thread_ctrl
thread_ctrl* operator->() const
{
return m_thread.get();
}
};