summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorChris Robinson <[email protected]>2014-05-27 15:48:15 -0700
committerChris Robinson <[email protected]>2014-05-27 15:48:15 -0700
commit73614f228eda86e9dc074540989a11a4fd7fb9e9 (patch)
treef06a99caeba3556be3275ad69f4abcd2e4f1d2ff
parentfd62868c17ce1b7c0a68c6615c0392b09c3661cd (diff)
Add methods to exchange and compare-exchange RefCount values
-rw-r--r--common/atomic.c2
-rw-r--r--include/atomic.h38
2 files changed, 40 insertions, 0 deletions
diff --git a/common/atomic.c b/common/atomic.c
index 95b8f835..634587e4 100644
--- a/common/atomic.c
+++ b/common/atomic.c
@@ -8,6 +8,8 @@ extern inline void InitRef(volatile RefCount *ptr, uint value);
extern inline uint ReadRef(volatile RefCount *ptr);
extern inline uint IncrementRef(volatile RefCount *ptr);
extern inline uint DecrementRef(volatile RefCount *ptr);
+extern inline uint ExchangeRef(volatile RefCount *ptr, uint newval);
+extern inline uint CompExchangeRef(volatile RefCount *ptr, uint oldval, uint newval);
extern inline int ExchangeInt(volatile int *ptr, int newval);
extern inline void *ExchangePtr(XchgPtr *ptr, void *newval);
extern inline int CompExchangeInt(volatile int *ptr, int oldval, int newval);
diff --git a/include/atomic.h b/include/atomic.h
index e8a9d3f4..87a02f7b 100644
--- a/include/atomic.h
+++ b/include/atomic.h
@@ -23,6 +23,10 @@ inline uint IncrementRef(volatile RefCount *ptr)
{ return __sync_add_and_fetch(&ptr->value, 1); }
inline uint DecrementRef(volatile RefCount *ptr)
{ return __sync_sub_and_fetch(&ptr->value, 1); }
+inline uint ExchangeRef(volatile RefCount *ptr, uint newval)
+{ return __sync_lock_test_and_set(&ptr->value, newval); }
+inline uint CompExchangeRef(volatile RefCount *ptr, uint oldval, uint newval)
+{ return __sync_val_compare_and_swap(&ptr->value, oldval, newval); }
inline int ExchangeInt(volatile int *ptr, int newval)
{ return __sync_lock_test_and_set(ptr, newval); }
@@ -53,6 +57,24 @@ inline uint IncrementRef(volatile RefCount *ptr)
{ return xaddl(&ptr->value, 1)+1; }
inline uint DecrementRef(volatile RefCount *ptr)
{ return xaddl(&ptr->value, -1)-1; }
+inline uint ExchangeRef(volatile RefCount *ptr, uint newval)
+{
+ int ret;
+ __asm__ __volatile__("lock; xchgl %0,(%1)"
+ : "=r" (ret)
+ : "r" (&ptr->value), "0" (newval)
+ : "memory");
+ return ret;
+}
+inline uint CompExchangeRef(volatile RefCount *ptr, uint oldval, uint newval)
+{
+ int ret;
+ __asm__ __volatile__("lock; cmpxchgl %2,(%1)"
+ : "=a" (ret)
+ : "r" (&ptr->value), "r" (newval), "0" (oldval)
+ : "memory");
+ return ret;
+}
inline int ExchangeInt(volatile int *dest, int newval)
{
@@ -130,6 +152,22 @@ inline uint DecrementRef(volatile RefCount *ptr)
} u = { &ptr->value };
return InterlockedDecrement(u.l);
}
+inline uint ExchangeRef(volatile RefCount *ptr, uint newval)
+{
+ union {
+ volatile uint *i;
+ volatile LONG *l;
+ } u = { &ptr->value };
+ return InterlockedExchange(u.l, newval);
+}
+inline uint CompExchangeRef(volatile RefCount *ptr, uint oldval, uint newval)
+{
+ union {
+ volatile uint *i;
+ volatile LONG *l;
+ } u = { &ptr->value };
+ return InterlockedCompareExchange(u.l, newval, oldval);
+}
inline int ExchangeInt(volatile int *ptr, int newval)
{