Skip to content

Instantly share code, notes, and snippets.

@alk
Created January 28, 2011 23:42
Show Gist options
  • Select an option

  • Save alk/801254 to your computer and use it in GitHub Desktop.

Select an option

Save alk/801254 to your computer and use it in GitHub Desktop.
#include <stdint.h>
struct KindaAtomic64 {
union data_type {
volatile uint64_t u64;
#ifndef WORDS_BIGENDIAN
struct {
volatile uint32_t low;
volatile uint32_t high;
} u32;
#else
struct {
volatile uint32_t high;
volatile uint32_t low;
} u32;
#endif
} data;
KindaAtomic64(void) {data.u64 = 0;}
KindaAtomic64(uint64_t l) {data.u64 = l << 1;};
// uint64_t read() {
// uint32_t high1, low, high2;
// again:
// high1 = data.u32.high;
// __sync_synchronize();
// low = data.u32.low;
// __sync_synchronize();
// high2 = data.u32.high;
// if (high2 != high1 || ((int32_t)high1) < 0) {
// __sync_synchronize();
// goto again;
// }
// return ((uint64_t)(high1 & 0x7FFFFFFF) << 32) | low;
// }
uint32_t lock_spin(void) {
uint32_t high;
do {
high = data.u32.high;
if (((int32_t)high) < 0) {
__sync_synchronize();
continue;
}
uint32_t locked = high | 0x80000000;
if (__sync_bool_compare_and_swap(&data.u32.high, high, locked))
return high;
} while (true);
}
uint64_t read() {
uint32_t high = lock_spin();
uint32_t low = data.u32.low;
uint64_t rv = ((uint64_t)high << 32) | low;
data.u32.high = high & 0x7ffffff;
__sync_synchronize();
return rv;
}
void add_consistent(int v) {
uint32_t high = lock_spin();
int64_t low = (int64_t)(uint64_t)data.u32.low + (int64_t)v;
data.u32.low = (uint32_t)low;
__sync_synchronize();
high += (uint32_t)(low >> 32);
data.u32.high = high;
__sync_synchronize();
}
};
uint64_t foobar(KindaAtomic64 *a)
{
extern void something(void);
a->add_consistent(-1);
something();
return a->read();
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment