Migrating atomic ops to std::atomic where possible and poly.

This commit is contained in:
Ben Vanik 2014-07-12 17:48:54 -07:00
parent bf882714d0
commit 9b78dd977b
18 changed files with 174 additions and 139 deletions

View File

@ -4020,16 +4020,16 @@ int Translate_UNPACK(TranslationContext& ctx, Instr* i) {
}
uint32_t IntCode_ATOMIC_EXCHANGE_I32(IntCodeState& ics, const IntCode* i) {
auto address = (uint8_t*)ics.rf[i->src1_reg].u64;
auto address = (uint32_t*)ics.rf[i->src1_reg].u64;
auto new_value = ics.rf[i->src2_reg].u32;
auto old_value = xe_atomic_exchange_32(new_value, address);
auto old_value = poly::atomic_exchange(new_value, address);
ics.rf[i->dest_reg].u32 = old_value;
return IA_NEXT;
}
uint32_t IntCode_ATOMIC_EXCHANGE_I64(IntCodeState& ics, const IntCode* i) {
auto address = (uint8_t*)ics.rf[i->src1_reg].u64;
auto address = (uint64_t*)ics.rf[i->src1_reg].u64;
auto new_value = ics.rf[i->src2_reg].u64;
auto old_value = xe_atomic_exchange_64(new_value, address);
auto old_value = poly::atomic_exchange(new_value, address);
ics.rf[i->dest_reg].u64 = old_value;
return IA_NEXT;
}

View File

@ -11,7 +11,6 @@
#define ALLOY_CORE_H_
// TODO(benvanik): move the common stuff into here?
#include <xenia/atomic.h>
#include <xenia/byte_order.h>
#include <xenia/config.h>
#include <xenia/logging.h>

View File

@ -9,15 +9,17 @@
#include <alloy/tracing/tracer.h>
#include <atomic>
#include <alloy/tracing/channel.h>
namespace alloy {
namespace tracing {
volatile int next_thread_id_ = 0x10000000;
std::atomic<int> next_thread_id_(0x10000000);
Tracer::Tracer(Channel* channel) : channel_(channel) {
thread_id_ = xe_atomic_inc_32(&next_thread_id_);
thread_id_ = ++next_thread_id_;
}
Tracer::~Tracer() {}

127
src/poly/atomic.h Normal file
View File

@ -0,0 +1,127 @@
/**
******************************************************************************
* Xenia : Xbox 360 Emulator Research Project *
******************************************************************************
* Copyright 2014 Ben Vanik. All rights reserved. *
* Released under the BSD license - see LICENSE in the root for more details. *
******************************************************************************
*/
#ifndef POLY_ATOMIC_H_
#define POLY_ATOMIC_H_
#include <cstdint>
#include <poly/config.h>
#include <poly/platform.h>
namespace poly {
// These functions are modeled off of the Apple OSAtomic routines
// http://developer.apple.com/library/mac/#documentation/DriversKernelHardware/Reference/libkern_ref/OSAtomic_h/
#if XE_LIKE_OSX
#include <libkern/OSAtomic.h>
inline int32_t atomic_inc(volatile int32_t* value) {
return OSAtomicIncrement32Barrier(reinterpret_cast<volatile LONG*>(value));
}
inline int32_t atomic_dec(volatile int32_t* value) {
return OSAtomicDecrement32Barrier(reinterpret_cast<volatile LONG*>(value));
}
inline int32_t atomic_exchange(int32_t new_value, volatile int32_t* value) {
//
}
inline int64_t atomic_exchange(int64_t new_value, volatile int64_t* value) {
//
}
inline int32_t atomic_cas(int32_t old_value, int32_t new_value,
volatile int32_t* value) {
return OSAtomicCompareAndSwap32Barrier(
old_value, new_value, reinterpret_cast<volatile LONG*>(value));
}
#elif XE_LIKE_WIN32
inline int32_t atomic_inc(volatile int32_t* value) {
return InterlockedIncrement(reinterpret_cast<volatile LONG*>(value));
}
inline int32_t atomic_dec(volatile int32_t* value) {
return InterlockedDecrement(reinterpret_cast<volatile LONG*>(value));
}
inline int32_t atomic_exchange(int32_t new_value, volatile int32_t* value) {
return InterlockedExchange(reinterpret_cast<volatile LONG*>(value),
new_value);
}
inline int64_t atomic_exchange(int64_t new_value, volatile int64_t* value) {
return InterlockedExchange64(reinterpret_cast<volatile LONGLONG*>(value),
new_value);
}
inline int32_t atomic_cas(int32_t old_value, int32_t new_value,
volatile int32_t* value) {
return InterlockedCompareExchange(reinterpret_cast<volatile LONG*>(value),
new_value, old_value) == old_value;
}
#elif XE_LIKE_POSIX
inline int32_t atomic_inc(volatile int32_t* value) {
return __sync_add_and_fetch(value, 1);
}
inline int32_t atomic_dec(volatile int32_t* value) {
return __sync_sub_and_fetch(value, 1);
}
inline int32_t atomic_exchange(int32_t new_value, volatile int32_t* value) {
//
}
inline int64_t atomic_exchange(int64_t new_value, volatile int64_t* value) {
//
}
inline int32_t atomic_cas(int32_t old_value, int32_t new_value,
volatile int32_t* value) {
return __sync_bool_compare_and_swap(reinterpret_cast<volatile LONG*>(value),
old_value, new_value);
}
#else
#error No atomic primitives defined for this platform/cpu combination.
#endif // OSX
inline uint32_t atomic_inc(volatile uint32_t* value) {
return static_cast<uint32_t>(
atomic_inc(reinterpret_cast<volatile int32_t*>(value)));
}
inline uint32_t atomic_dec(volatile uint32_t* value) {
return static_cast<uint32_t>(
atomic_dec(reinterpret_cast<volatile int32_t*>(value)));
}
inline uint32_t atomic_exchange(uint32_t new_value, volatile uint32_t* value) {
return static_cast<uint32_t>(
atomic_exchange(static_cast<int32_t>(new_value),
reinterpret_cast<volatile int32_t*>(value)));
}
inline uint64_t atomic_exchange(uint64_t new_value, volatile uint64_t* value) {
return static_cast<uint64_t>(
atomic_exchange(static_cast<int64_t>(new_value),
reinterpret_cast<volatile int64_t*>(value)));
}
inline uint32_t atomic_cas(uint32_t old_value, uint32_t new_value,
volatile uint32_t* value) {
return static_cast<uint32_t>(atomic_cas(
static_cast<int32_t>(old_value), static_cast<int32_t>(new_value),
reinterpret_cast<volatile int32_t*>(value)));
}
} // namespace poly
#endif // POLY_ATOMIC_H_

View File

@ -11,6 +11,7 @@
#define POLY_POLY_H_
#include <poly/assert.h>
#include <poly/atomic.h>
#include <poly/config.h>
#include <poly/cxx_compat.h>
#include <poly/math.h>

View File

@ -2,6 +2,7 @@
{
'sources': [
'assert.h',
'atomic.h',
'config.h',
'cxx_compat.h',
'math.h',

View File

@ -1,100 +0,0 @@
/**
******************************************************************************
* Xenia : Xbox 360 Emulator Research Project *
******************************************************************************
* Copyright 2013 Ben Vanik. All rights reserved. *
* Released under the BSD license - see LICENSE in the root for more details. *
******************************************************************************
*/
#ifndef XENIA_ATOMIC_H_
#define XENIA_ATOMIC_H_
#include <cstdint>
#include <xenia/platform.h>
#include <xenia/types.h>
// These functions are modeled off of the Apple OSAtomic routines
// http://developer.apple.com/library/mac/#documentation/DriversKernelHardware/Reference/libkern_ref/OSAtomic_h/
#if XE_LIKE_OSX
#include <libkern/OSAtomic.h>
#define xe_atomic_inc_32(value) \
OSAtomicIncrement32Barrier(value)
#define xe_atomic_dec_32(value) \
OSAtomicDecrement32Barrier(value)
#define xe_atomic_add_32(amount, value) \
((void)OSAtomicAdd32Barrier(amount, value))
#define xe_atomic_sub_32(amount, value) \
((void)OSAtomicAdd32Barrier(-amount, value))
#define xe_atomic_exchange_32(newValue, value) \
TODOTODO
#define xe_atomic_cas_32(oldValue, newValue, value) \
OSAtomicCompareAndSwap32Barrier(oldValue, newValue, value)
typedef OSQueueHead xe_atomic_stack_t;
#define xe_atomic_stack_init(stack) \
*(stack) = (OSQueueHead)OS_ATOMIC_QUEUE_INIT
#define xe_atomic_stack_enqueue(stack, item, offset) \
OSAtomicEnqueue((OSQueueHead*)stack, item, offset)
#define xe_atomic_stack_dequeue(stack, offset) \
OSAtomicDequeue((OSQueueHead*)stack, offset)
#elif XE_LIKE_WIN32
#define xe_atomic_inc_32(value) \
InterlockedIncrement((volatile LONG*)value)
#define xe_atomic_dec_32(value) \
InterlockedDecrement((volatile LONG*)value)
#define xe_atomic_add_32(amount, value) \
((void)InterlockedExchangeAdd((volatile LONG*)value, amount))
#define xe_atomic_sub_32(amount, value) \
((void)InterlockedExchangeSubtract((volatile unsigned*)value, amount))
#define xe_atomic_exchange_32(newValue, value) \
InterlockedExchange((volatile LONG*)value, newValue)
#define xe_atomic_exchange_64(newValue, value) \
InterlockedExchange64((volatile LONGLONG*)value, newValue)
#define xe_atomic_cas_32(oldValue, newValue, value) \
(InterlockedCompareExchange((volatile LONG*)value, newValue, oldValue) == oldValue)
typedef SLIST_HEADER xe_atomic_stack_t;
#define xe_atomic_stack_init(stack) \
InitializeSListHead((PSLIST_HEADER)stack)
#define xe_atomic_stack_enqueue(stack, item, offset) \
XEIGNORE(InterlockedPushEntrySList((PSLIST_HEADER)stack, (PSLIST_ENTRY)((byte*)item + offset)))
XEFORCEINLINE void* xe_atomic_stack_dequeue(xe_atomic_stack_t* stack,
const size_t offset) {
void* ptr = (void*)InterlockedPopEntrySList((PSLIST_HEADER)stack);
if (ptr) {
return (void*)(((uint8_t*)ptr) - offset);
} else {
return NULL;
}
}
#elif XE_LIKE_POSIX
#define xe_atomic_inc_32(value) \
__sync_add_and_fetch(value, 1)
#define xe_atomic_dec_32(value) \
__sync_sub_and_fetch(value, 1)
#define xe_atomic_add_32(amount, value) \
__sync_fetch_and_add(value, amount)
#define xe_atomic_sub_32(amount, value) \
__sync_fetch_and_sub(value, amount)
#define xe_atomic_exchange_32(newValue, value) \
TODOTODO
#define xe_atomic_cas_32(oldValue, newValue, value) \
__sync_bool_compare_and_swap(value, oldValue, newValue)
#else
#error No atomic primitives defined for this platform/cpu combination.
#endif // OSX
#endif // XENIA_ATOMIC_H_

View File

@ -11,8 +11,8 @@
#define XENIA_COMMON_H_
#include <poly/assert.h>
#include <poly/atomic.h>
#include <xenia/atomic.h>
#include <xenia/byte_order.h>
#include <xenia/config.h>
#include <xenia/logging.h>

View File

@ -15,14 +15,14 @@ void xe_ref_init(xe_ref_t* ref) {
}
void xe_ref_retain(xe_ref_t* ref) {
xe_atomic_inc_32(&ref->count);
poly::atomic_inc(&ref->count);
}
void xe_ref_release(xe_ref_t* ref, xe_ref_dealloc_t dealloc) {
if (!ref) {
return;
}
if (!xe_atomic_dec_32(&ref->count)) {
if (!poly::atomic_dec(&ref->count)) {
if (dealloc) {
dealloc(ref);
}

View File

@ -76,7 +76,7 @@ volatile int* XenonThreadState::suspend_flag_address() const {
int XenonThreadState::Suspend(uint32_t timeout_ms) {
// Set suspend flag.
// One of the checks should call in to OnSuspend() at some point.
xe_atomic_inc_32(&context_->suspend_flag);
poly::atomic_inc(&context_->suspend_flag);
return 0;
}
@ -86,7 +86,7 @@ int XenonThreadState::Resume(bool force) {
context_->suspend_flag = 0;
SetEvent(debug_break_);
} else {
if (!xe_atomic_dec_32(&context_->suspend_flag)) {
if (!poly::atomic_dec(&context_->suspend_flag)) {
SetEvent(debug_break_);
}
}

View File

@ -406,7 +406,7 @@ void XThread::LeaveCriticalRegion() {
}
uint32_t XThread::RaiseIrql(uint32_t new_irql) {
return xe_atomic_exchange_32(new_irql, &irql_);
return irql_.exchange(new_irql);
}
void XThread::LowerIrql(uint32_t new_irql) {

View File

@ -10,6 +10,8 @@
#ifndef XENIA_KERNEL_XBOXKRNL_XTHREAD_H_
#define XENIA_KERNEL_XBOXKRNL_XTHREAD_H_
#include <atomic>
#include <xenia/kernel/xobject.h>
#include <xenia/xbox.h>
@ -94,7 +96,7 @@ private:
char* name_;
uint32_t irql_;
std::atomic<uint32_t> irql_;
xe_mutex_t* apc_lock_;
NativeList* apc_list_;

View File

@ -606,13 +606,13 @@ void xeRtlEnterCriticalSection(uint32_t cs_ptr, uint32_t thread_id) {
uint32_t spin_wait_remaining = cs->spin_count_div_256 * 256;
spin:
if (xe_atomic_inc_32(&cs->lock_count) != 0) {
if (poly::atomic_inc(&cs->lock_count) != 0) {
// If this thread already owns the CS increment the recursion count.
if (cs->owning_thread_id == thread_id) {
cs->recursion_count++;
return;
}
xe_atomic_dec_32(&cs->lock_count);
poly::atomic_dec(&cs->lock_count);
// Thread was locked - spin wait.
if (spin_wait_remaining) {
@ -658,13 +658,13 @@ uint32_t xeRtlTryEnterCriticalSection(uint32_t cs_ptr, uint32_t thread_id) {
X_RTL_CRITICAL_SECTION* cs = (X_RTL_CRITICAL_SECTION*)IMPL_MEM_ADDR(cs_ptr);
if (xe_atomic_cas_32(-1, 0, &cs->lock_count)) {
if (poly::atomic_cas(-1, 0, &cs->lock_count)) {
// Able to steal the lock right away.
cs->owning_thread_id = thread_id;
cs->recursion_count = 1;
return 1;
} else if (cs->owning_thread_id == thread_id) {
xe_atomic_inc_32(&cs->lock_count);
poly::atomic_inc(&cs->lock_count);
++cs->recursion_count;
return 1;
}
@ -699,13 +699,13 @@ void xeRtlLeaveCriticalSection(uint32_t cs_ptr) {
// Drop recursion count - if we are still not zero'ed return.
uint32_t recursion_count = --cs->recursion_count;
if (recursion_count) {
xe_atomic_dec_32(&cs->lock_count);
poly::atomic_dec(&cs->lock_count);
return;
}
// Unlock!
cs->owning_thread_id = 0;
if (xe_atomic_dec_32(&cs->lock_count) != -1) {
if (poly::atomic_dec(&cs->lock_count) != -1) {
// There were waiters - wake one of them.
// TODO(benvanik): wake a waiter.
XELOGE("RtlLeaveCriticalSection would have woken a waiter");

View File

@ -1258,9 +1258,9 @@ SHIM_CALL NtSignalAndWaitForSingleObjectEx_shim(
}
uint32_t xeKfAcquireSpinLock(void* lock_ptr) {
uint32_t xeKfAcquireSpinLock(uint32_t* lock_ptr) {
// Lock.
while (!xe_atomic_cas_32(0, 1, lock_ptr)) {
while (!poly::atomic_cas(0, 1, lock_ptr)) {
// Spin!
// TODO(benvanik): error on deadlock?
}
@ -1279,19 +1279,20 @@ SHIM_CALL KfAcquireSpinLock_shim(
"KfAcquireSpinLock(%.8X)",
lock_ptr);
uint32_t old_irql = xeKfAcquireSpinLock(SHIM_MEM_ADDR(lock_ptr));
auto lock = reinterpret_cast<uint32_t*>(SHIM_MEM_ADDR(lock_ptr));
uint32_t old_irql = xeKfAcquireSpinLock(lock);
SHIM_SET_RETURN_64(old_irql);
}
void xeKfReleaseSpinLock(void* lock_ptr, uint32_t old_irql) {
void xeKfReleaseSpinLock(uint32_t* lock_ptr, uint32_t old_irql) {
// Restore IRQL.
XThread* thread = XThread::GetCurrentThread();
thread->LowerIrql(old_irql);
// Unlock.
xe_atomic_dec_32(lock_ptr);
poly::atomic_dec(lock_ptr);
}
@ -1305,7 +1306,8 @@ SHIM_CALL KfReleaseSpinLock_shim(
lock_ptr,
old_irql);
xeKfReleaseSpinLock(SHIM_MEM_ADDR(lock_ptr), old_irql);
xeKfReleaseSpinLock(reinterpret_cast<uint32_t*>(SHIM_MEM_ADDR(lock_ptr)),
old_irql);
}
@ -1318,8 +1320,8 @@ SHIM_CALL KeAcquireSpinLockAtRaisedIrql_shim(
lock_ptr);
// Lock.
void* lock = SHIM_MEM_ADDR(lock_ptr);
while (!xe_atomic_cas_32(0, 1, lock)) {
auto lock = reinterpret_cast<uint32_t*>(SHIM_MEM_ADDR(lock_ptr));
while (!poly::atomic_cas(0, 1, lock)) {
// Spin!
// TODO(benvanik): error on deadlock?
}
@ -1335,8 +1337,8 @@ SHIM_CALL KeReleaseSpinLockFromRaisedIrql_shim(
lock_ptr);
// Unlock.
void* lock = SHIM_MEM_ADDR(lock_ptr);
xe_atomic_dec_32(lock);
auto lock = reinterpret_cast<uint32_t*>(SHIM_MEM_ADDR(lock_ptr));
poly::atomic_dec(lock);
}

View File

@ -52,8 +52,8 @@ X_STATUS xeKeWaitForSingleObject(
void* object_ptr, uint32_t wait_reason, uint32_t processor_mode,
uint32_t alertable, uint64_t* opt_timeout);
uint32_t xeKfAcquireSpinLock(void* lock_ptr);
void xeKfReleaseSpinLock(void* lock_ptr, uint32_t old_irql);
uint32_t xeKfAcquireSpinLock(uint32_t* lock_ptr);
void xeKfReleaseSpinLock(uint32_t* lock_ptr, uint32_t old_irql);
void xeKeEnterCriticalRegion();
void xeKeLeaveCriticalRegion();

View File

@ -46,22 +46,22 @@ X_HANDLE XObject::handle() const {
}
void XObject::RetainHandle() {
xe_atomic_inc_32(&handle_ref_count_);
++handle_ref_count_;
}
bool XObject::ReleaseHandle() {
if (!xe_atomic_dec_32(&handle_ref_count_)) {
if (--handle_ref_count_ == 0) {
return true;
}
return false;
}
void XObject::Retain() {
xe_atomic_inc_32(&pointer_ref_count_);
++pointer_ref_count_;
}
void XObject::Release() {
if (!xe_atomic_dec_32(&pointer_ref_count_)) {
if (--pointer_ref_count_ == 0) {
assert_true(pointer_ref_count_ >= handle_ref_count_);
delete this;
}

View File

@ -10,6 +10,8 @@
#ifndef XENIA_KERNEL_XBOXKRNL_XOBJECT_H_
#define XENIA_KERNEL_XBOXKRNL_XOBJECT_H_
#include <atomic>
#include <xenia/kernel/kernel_state.h>
#include <xenia/xbox.h>
@ -87,8 +89,8 @@ protected:
KernelState* kernel_state_;
private:
volatile int32_t handle_ref_count_;
volatile int32_t pointer_ref_count_;
std::atomic<int32_t> handle_ref_count_;
std::atomic<int32_t> pointer_ref_count_;
Type type_;
X_HANDLE handle_;

View File

@ -1,7 +1,6 @@
# Copyright 2013 Ben Vanik. All Rights Reserved.
{
'sources': [
'atomic.h',
'byte_order.h',
'common.h',
'config.h',