wrflock_wait.cpp 3.83 KB
#include <sched.h>
#include <errno.h>
#include "futex.h"
#include "wrflock.h"
#include <stdio.h>


int wrflock_wtimewait (struct wrflock_t *lock, const struct timespec *abstime)
{
	uint32_t data32;
	int err;
	if (abstime && (abstime->tv_nsec < 0 || abstime->tv_nsec >= 1000000000)) {
		errno=(EINVAL);
		return -1;
	}
	while (1) {
		data32 = lock->data32[WRFLOCK_STATE_OFFSET].load(std::memory_order_relaxed);
		if (data32 & CURRSTATE_WRITE_MASK_32) {
			std::atomic_thread_fence(std::memory_order_acquire);
			return 0;
		}
		if (!(data32&WRFLOCK_WWAITYIELD_MASK_32)){
			err=futex_wait_bitset((int*)(&lock->data32[WRFLOCK_STATE_OFFSET]), data32, abstime, FUTEX_BITSET_MATCH_ANY, (data32 & WRFLOCK_PRIVATE_MASK_32)!=0);
			if (err<0 && (errno == ETIMEDOUT || errno == EINTR))
				return err;
		} else {
			if (abstime){
				timespec  time;
				clock_gettime(CLOCK_REALTIME, &time);
				if ((time.tv_sec>abstime->tv_sec) || (time.tv_sec==abstime->tv_sec && time.tv_nsec>=abstime->tv_nsec)) {
					errno=ETIMEDOUT;
					return -1;
				}
			}
			sched_yield();
		}
	}
}

int wrflock_rtimewait (struct wrflock_t *lock, const struct timespec *abstime)
{
	uint32_t data32;
	int err;
	if (abstime && (abstime->tv_nsec < 0 || abstime->tv_nsec >= 1000000000)) {
		errno=(EINVAL);
		return -1;
	}
	while (1) {
		data32 = lock->data32[WRFLOCK_STATE_OFFSET].load(std::memory_order_relaxed);
		if (data32 & CURRSTATE_READ_MASK_32){
			std::atomic_thread_fence(std::memory_order_acquire);
			return 0;
		}
		if (!(data32&WRFLOCK_RWAITYIELD_MASK_32)){
			err=futex_wait_bitset((int*)(&lock->data32[WRFLOCK_STATE_OFFSET]), data32, abstime, FUTEX_BITSET_MATCH_ANY, (data32 & WRFLOCK_PRIVATE_MASK_32)!=0);
			if (err<0 && (errno == ETIMEDOUT || errno == EINTR))
				return err;
		} else {
			if (abstime){
				timespec  time;
				clock_gettime(CLOCK_REALTIME, &time);
				if ((time.tv_sec>abstime->tv_sec) || (time.tv_sec==abstime->tv_sec && time.tv_nsec>=abstime->tv_nsec)){
					errno=ETIMEDOUT;
					return -1;
				}
			}
			sched_yield();
		}
	}
}

int wrflock_ftimewait (struct wrflock_t *lock, const struct timespec *abstime)
{
	uint32_t data32;
	int err=0;
	if (abstime && (abstime->tv_nsec < 0 || abstime->tv_nsec >= 1000000000)) {
		errno=(EINVAL);
		return -1;
	}
	while (1) {
		data32 = lock->data32[WRFLOCK_STATE_OFFSET].load(std::memory_order_relaxed);
		if (data32 & CURRSTATE_FREE_MASK_32) {
			std::atomic_thread_fence(std::memory_order_acquire);
			return 0;
		}
		if (!(data32&WRFLOCK_FWAITYIELD_MASK_32)) {
			err=futex_wait_bitset((int*)(&lock->data32[WRFLOCK_STATE_OFFSET]), data32, abstime, FUTEX_BITSET_MATCH_ANY, (data32 & WRFLOCK_PRIVATE_MASK_32)!=0);
			if (err<0 && (errno == ETIMEDOUT || errno == EINTR))
				return err;
		} else {
			if (abstime){
				timespec  time;
				clock_gettime(CLOCK_REALTIME, &time);
				if ((time.tv_sec>abstime->tv_sec) || (time.tv_sec==abstime->tv_sec && time.tv_nsec>=abstime->tv_nsec)) {
					errno=ETIMEDOUT;
					return -1;
				}
			}
			sched_yield();
		}
	}
}

int wrflock_wwait (wrflock_t *lock){
	return wrflock_wtimewait (lock, NULL);
}

int wrflock_rwait (wrflock_t *lock){
	return wrflock_rtimewait (lock, NULL);
}

int wrflock_fwait (wrflock_t *lock){
	return wrflock_ftimewait (lock, NULL);
}

int wrflock_wtrywait (wrflock_t *lock){
	const uint32_t data32 = lock->data32[WRFLOCK_STATE_OFFSET].load(std::memory_order_acquire);
	if  (!(data32 & CURRSTATE_WRITE_MASK_32)){
		errno=(EAGAIN);
		return -1;
	}
	return 0;
}

int wrflock_rtrywait (wrflock_t *lock){
	const uint32_t data32 = lock->data32[WRFLOCK_STATE_OFFSET].load(std::memory_order_acquire);
	if  (!(data32 & CURRSTATE_READ_MASK_32)){
		errno=(EAGAIN);
		return -1;
	}
	return 0;
}

int wrflock_ftrywait (wrflock_t *lock){
	const uint32_t data32 = lock->data32[WRFLOCK_STATE_OFFSET].load(std::memory_order_acquire);
	if  (!(data32 & CURRSTATE_FREE_MASK_32)){
		errno=(EAGAIN);
		return -1;
	}
	return 0;
}