wrflock_release.cpp 2.9 KB
#include <errno.h>
#include <limits.h>

#include "futex.h"
#include "wrflock.h"
#include <stdio.h>

int wrflock_wrelease (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|CURRSTATE_WRITE_MASK_32|RDNXTLOOP_FLAG_MASK_32));
		if (newdata32 & RDACQUIRE_VALUE_MASK_32) {
			newdata32|=CURRSTATE_READ_MASK_32;
		} else if (newdata32 & FRACQUIRE_VALUE_MASK_32) {
			newdata32|=CURRSTATE_FREE_MASK_32;
		} else {
			newdata32|=NEXTSTATE_READFREE_MASK_32;
		}
	} while (!lock->data32[WRFLOCK_STATE_OFFSET].compare_exchange_weak(data32, newdata32, std::memory_order_release, std::memory_order_relaxed));
	if ((!(newdata32&WRFLOCK_RWAITYIELD_MASK_32) && (newdata32&(CURRSTATE_READ_MASK_32|RDNXTLOOP_FLAG_MASK_32))) || (!(newdata32&WRFLOCK_FWAITYIELD_MASK_32) && newdata32&CURRSTATE_FREE_MASK_32))
		return futex_wake_bitset((int *) &lock->data32[WRFLOCK_STATE_OFFSET], INT_MAX, FUTEX_BITSET_MATCH_ANY, (data32 & WRFLOCK_PRIVATE_MASK_32)!=0);
	return 0;
}


int wrflock_rrelease (wrflock_t *lock) {
	uint64_t newdata64;
	uint64_t data64=lock->data64.load(std::memory_order_relaxed);
	do {
		if (!(data64 & RDACQUIRE_COUNTER_MASK_64)) {
			errno=(EOVERFLOW);
			return -1;
		}
		newdata64=data64 - ((uint64_t)1 << RDACQUIRE_COUNTER_SHIFT_64);
		if (!(newdata64 & RDACQUIRE_COUNTER_MASK_64)) {
			newdata64=newdata64 & (~(RDACQUIRE_VALUE_MASK_64));
			if (newdata64 & FRACQUIRE_VALUE_MASK_64)
				newdata64=(newdata64 ^ (CURRSTATE_READ_MASK_64 | CURRSTATE_FREE_MASK_64));
			else
				newdata64=(newdata64 ^ (CURRSTATE_READ_MASK_64 | NEXTSTATE_READFREE_MASK_64));
		}
	} while (!lock->data64.compare_exchange_weak(data64, newdata64, std::memory_order_release, std::memory_order_relaxed));
	if (!(newdata64&WRFLOCK_FWAITYIELD_MASK_64) && newdata64&CURRSTATE_FREE_MASK_64)
		return futex_wake_bitset((int *) &lock->data32[WRFLOCK_STATE_OFFSET], INT_MAX, FUTEX_BITSET_MATCH_ANY, (data64 & WRFLOCK_PRIVATE_MASK_64)!=0);
	return 0;
}

int wrflock_frelease (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|CURRSTATE_FREE_MASK_32));
		if (newdata32 & WRACQUIRE_VALUE_MASK_32) {
			newdata32|=CURRSTATE_WRITE_MASK_32;
		} else {
			newdata32|=NEXTSTATE_WRITE_MASK_32;
		}
	} while (!lock->data32[WRFLOCK_STATE_OFFSET].compare_exchange_weak(data32, newdata32, std::memory_order_release, std::memory_order_relaxed));
	if (!(newdata32&WRFLOCK_WWAITYIELD_MASK_32) && newdata32&CURRSTATE_WRITE_MASK_32)
		return futex_wake_bitset((int *) &lock->data32[WRFLOCK_STATE_OFFSET], INT_MAX, FUTEX_BITSET_MATCH_ANY, (data32 & WRFLOCK_PRIVATE_MASK_32)!=0);
	return 0;
}