wrflock_acquire.cpp 2.59 KB
#include <errno.h>
#include <sched.h>
#include "futex.h"
#include "wrflock.h"

int wrflock_wacquire (wrflock_t *lock) {
	uint32_t newdata32;
	uint32_t data32 = lock->data32[WRFLOCK_STATE_OFFSET].load(std::memory_order_relaxed);
	do {
		if (data32 & WRACQUIRE_VALUE_MASK_32) {
			errno=(EOVERFLOW);
			return -1;
		}
		newdata32=data32 | WRACQUIRE_VALUE_MASK_32;
		if (newdata32 & FRACQUIRE_VALUE_MASK_32) { //writer reached free barier - new readers goes to next loop
			newdata32|=RDNXTLOOP_FLAG_MASK_32;
		}
		if (newdata32 & NEXTSTATE_WRITE_MASK_32) { //no barier, can take write lock
			newdata32=(newdata32 ^ (NEXTSTATE_WRITE_MASK_32 | CURRSTATE_WRITE_MASK_32));
		}
	} while (!lock->data32[WRFLOCK_STATE_OFFSET].compare_exchange_weak(data32, newdata32, std::memory_order_relaxed, std::memory_order_relaxed));
	return 0;
}

int wrflock_racquire (wrflock_t *lock) {
	uint32_t newdata32;
	uint32_t data32 = lock->data32[WRFLOCK_STATE_OFFSET].load(std::memory_order_relaxed);
	while (data32 & RDNXTLOOP_FLAG_MASK_32) {
		if (data32 & WRFLOCK_RWAITYIELD_MASK_32)
			sched_yield();
		else
			futex_wait_bitset((int*)(&lock->data32[WRFLOCK_STATE_OFFSET]), data32, NULL, FUTEX_BITSET_MATCH_ANY, (data32 & WRFLOCK_PRIVATE_MASK_32)!=0);
		data32 = lock->data32[WRFLOCK_STATE_OFFSET].load(std::memory_order_relaxed);
	}
	do {
		if ((data32 & RDACQUIRE_COUNTER_MASK_32) == RDACQUIRE_COUNTER_MASK_32) {
			errno=(EOVERFLOW);
			return -1;
		}
		newdata32 = data32 + ((uint32_t)1 << RDACQUIRE_COUNTER_SHIFT_32);
	} while (!lock->data32[WRFLOCK_COUNTERS_OFFSET].compare_exchange_weak(data32, newdata32, std::memory_order_relaxed, std::memory_order_relaxed));
	data32 = lock->data32[WRFLOCK_STATE_OFFSET].load(std::memory_order_relaxed);
	do {
		newdata32 = data32 | RDACQUIRE_VALUE_MASK_32;
		if (newdata32 & NEXTSTATE_READFREE_MASK_32) {
			newdata32 = (newdata32 ^ (NEXTSTATE_READFREE_MASK_32 | CURRSTATE_READ_MASK_32));
		}
	} while (!lock->data32[WRFLOCK_STATE_OFFSET].compare_exchange_weak(data32, newdata32, std::memory_order_relaxed, std::memory_order_relaxed));
	return 0;
}

int wrflock_facquire (wrflock_t *lock) {
	uint32_t newdata32;
	uint32_t data32 = lock->data32[WRFLOCK_STATE_OFFSET].load(std::memory_order_relaxed);
	do {
		if (data32 & FRACQUIRE_VALUE_MASK_32) {
			errno=(EOVERFLOW);
			return -1;
		}
		newdata32 = data32 | FRACQUIRE_VALUE_MASK_32;
		if (newdata32 & NEXTSTATE_READFREE_MASK_32) {
			newdata32 = (newdata32 ^ (NEXTSTATE_READFREE_MASK_32 | CURRSTATE_FREE_MASK_32));
		}
	} while (!lock->data32[WRFLOCK_STATE_OFFSET].compare_exchange_weak(data32, newdata32, std::memory_order_relaxed, std::memory_order_relaxed));
	return 0;
}