[Kernel/Threading] Fix some kernel threading issues
- broken atomic exchange on linux - spinlock release memory buffer - race in thread suspension - removed misleading volatile qualifiers
This commit is contained in:
@@ -66,6 +66,14 @@ inline bool atomic_cas(int64_t old_value, int64_t new_value,
|
|||||||
old_value) == old_value;
|
old_value) == old_value;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Atomic store with release semantics (for releasing locks)
|
||||||
|
inline void atomic_store_release(int32_t new_value, volatile int32_t* value) {
|
||||||
|
_InterlockedExchange(reinterpret_cast<volatile long*>(value), new_value);
|
||||||
|
}
|
||||||
|
inline void atomic_store_release(uint32_t new_value, volatile uint32_t* value) {
|
||||||
|
_InterlockedExchange(reinterpret_cast<volatile long*>(value), new_value);
|
||||||
|
}
|
||||||
|
|
||||||
#elif XE_PLATFORM_LINUX || XE_PLATFORM_MAC
|
#elif XE_PLATFORM_LINUX || XE_PLATFORM_MAC
|
||||||
|
|
||||||
inline int32_t atomic_inc(volatile int32_t* value) {
|
inline int32_t atomic_inc(volatile int32_t* value) {
|
||||||
@@ -85,10 +93,26 @@ inline int32_t atomic_xor(volatile int32_t* value, int32_t nv) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
inline int32_t atomic_exchange(int32_t new_value, volatile int32_t* value) {
|
inline int32_t atomic_exchange(int32_t new_value, volatile int32_t* value) {
|
||||||
return __sync_val_compare_and_swap(value, *value, new_value);
|
int32_t old_value;
|
||||||
|
do {
|
||||||
|
old_value = *value;
|
||||||
|
} while (!__sync_bool_compare_and_swap(value, old_value, new_value));
|
||||||
|
return old_value;
|
||||||
}
|
}
|
||||||
inline int64_t atomic_exchange(int64_t new_value, volatile int64_t* value) {
|
inline int64_t atomic_exchange(int64_t new_value, volatile int64_t* value) {
|
||||||
return __sync_val_compare_and_swap(value, *value, new_value);
|
int64_t old_value;
|
||||||
|
do {
|
||||||
|
old_value = *value;
|
||||||
|
} while (!__sync_bool_compare_and_swap(value, old_value, new_value));
|
||||||
|
return old_value;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Atomic store with release semantics (for releasing locks)
|
||||||
|
inline void atomic_store_release(int32_t new_value, volatile int32_t* value) {
|
||||||
|
__atomic_store_n(value, new_value, __ATOMIC_RELEASE);
|
||||||
|
}
|
||||||
|
inline void atomic_store_release(uint32_t new_value, volatile uint32_t* value) {
|
||||||
|
__atomic_store_n(value, new_value, __ATOMIC_RELEASE);
|
||||||
}
|
}
|
||||||
|
|
||||||
inline int32_t atomic_exchange_add(int32_t amount, volatile int32_t* value) {
|
inline int32_t atomic_exchange_add(int32_t amount, volatile int32_t* value) {
|
||||||
|
|||||||
@@ -83,8 +83,8 @@ class Fence {
|
|||||||
std::mutex mutex_;
|
std::mutex mutex_;
|
||||||
std::condition_variable cond_;
|
std::condition_variable cond_;
|
||||||
// Use the highest bit (sign bit) as the signal flag and the rest to count
|
// Use the highest bit (sign bit) as the signal flag and the rest to count
|
||||||
// waiting threads.
|
// waiting threads. Protected by mutex_.
|
||||||
volatile state_t_ signal_state_;
|
state_t_ signal_state_;
|
||||||
};
|
};
|
||||||
|
|
||||||
// Returns the total number of logical processors in the host system.
|
// Returns the total number of logical processors in the host system.
|
||||||
|
|||||||
@@ -546,7 +546,7 @@ class PosixCondition<Timer> final : public PosixConditionBase {
|
|||||||
}
|
}
|
||||||
std::weak_ptr<TimerQueueWaitItem> wait_item_;
|
std::weak_ptr<TimerQueueWaitItem> wait_item_;
|
||||||
std::function<void()> callback_;
|
std::function<void()> callback_;
|
||||||
volatile bool signal_;
|
bool signal_; // Protected by mutex_
|
||||||
const bool manual_reset_;
|
const bool manual_reset_;
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -820,6 +820,7 @@ class PosixCondition<Thread> final : public PosixConditionBase {
|
|||||||
bool is_current_thread = pthread_self() == thread_;
|
bool is_current_thread = pthread_self() == thread_;
|
||||||
|
|
||||||
{
|
{
|
||||||
|
std::unique_lock lock(state_mutex_);
|
||||||
if (out_previous_suspend_count) {
|
if (out_previous_suspend_count) {
|
||||||
*out_previous_suspend_count = suspend_count_;
|
*out_previous_suspend_count = suspend_count_;
|
||||||
}
|
}
|
||||||
@@ -908,8 +909,8 @@ class PosixCondition<Thread> final : public PosixConditionBase {
|
|||||||
pthread_t thread_;
|
pthread_t thread_;
|
||||||
bool signaled_;
|
bool signaled_;
|
||||||
int exit_code_;
|
int exit_code_;
|
||||||
volatile State state_;
|
State state_; // Protected by state_mutex_
|
||||||
volatile uint32_t suspend_count_;
|
uint32_t suspend_count_; // Protected by state_mutex_
|
||||||
mutable std::mutex state_mutex_;
|
mutable std::mutex state_mutex_;
|
||||||
mutable std::mutex callback_mutex_;
|
mutable std::mutex callback_mutex_;
|
||||||
mutable std::condition_variable state_signal_;
|
mutable std::condition_variable state_signal_;
|
||||||
|
|||||||
@@ -1167,8 +1167,8 @@ DECLARE_XBOXKRNL_EXPORT3(KfAcquireSpinLock, kThreading, kImplemented, kBlocking,
|
|||||||
void xeKeKfReleaseSpinLock(PPCContext* ctx, X_KSPINLOCK* lock,
|
void xeKeKfReleaseSpinLock(PPCContext* ctx, X_KSPINLOCK* lock,
|
||||||
uint32_t old_irql, bool change_irql) {
|
uint32_t old_irql, bool change_irql) {
|
||||||
assert_true(lock->prcb_of_owner == static_cast<uint32_t>(ctx->r[13]));
|
assert_true(lock->prcb_of_owner == static_cast<uint32_t>(ctx->r[13]));
|
||||||
// Unlock.
|
// Unlock with release semantics to ensure all prior writes are visible.
|
||||||
lock->prcb_of_owner.value = 0;
|
xe::atomic_store_release(0u, &lock->prcb_of_owner.value);
|
||||||
|
|
||||||
if (change_irql) {
|
if (change_irql) {
|
||||||
// Unlock.
|
// Unlock.
|
||||||
|
|||||||
Reference in New Issue
Block a user