summaryrefslogtreecommitdiff
path: root/src/guard.cc
blob: 98f8a06d9fd06ec4ab90aee07d46111804927ad7 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
#include <stdint.h>
#include <pthread.h>

static int32_t *low_32_bits(int64_t *ptr)
{
	int32_t *low= (int32_t*)ptr;
	// Test if the machine is big endian - constant propagation at compile time
	// should eliminate this completely.
	int one = 1;
	if (*(char*)&one != 1)
	{
		low++;
	}
	return low;
}

extern "C" int __cxa_guard_acquire(int64_t *guard_object)
{
	char first_byte = (*guard_object) >> 56;
	if (1 == first_byte) { return 0; }
	int32_t *lock = low_32_bits(guard_object);
	while (!__sync_bool_compare_and_swap_4(lock, 0, 1))
	{
		// TODO: Use some of the remaining 24 bits to define a mutex to sleep
		// on.  Whether this is actually worth bothering with depends on
		// whether there is likely to be any contention.
		sched_yield();
	}
	return 1;
}

extern "C" void __cxa_guard_abort(int64_t *guard_object)
{
	int32_t *lock = low_32_bits(guard_object);
	*lock = 0;
}
extern "C" void __cxa_guard_release(int64_t *guard_object)
{
	// Set the first byte to 1
	*guard_object |= ((int64_t)1) << 57;
	__cxa_guard_abort(guard_object);
}