File:  [Isaki's NoNo m68k/m88k emulator] / nono / lib / rwlock.h
Revision 1.1.1.2 (vendor branch): download - view: text, annotated - select for diffs
Wed Apr 29 17:05:57 2026 UTC (2 months, 3 weeks ago) by root
Branches: MAIN, Isaki
CVS tags: v027, HEAD
nono 1.7.0

/*
 * Copyright (C) 2025 Tetsuya Isaki
 *
 * Permission to use, copy, modify, and/or distribute this software for any
 * purpose with or without fee is hereby granted.
 *
 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 */

//
// rwlock (ただし書き込み優先)
//

#pragma once

#include <condition_variable>
#include <mutex>

class RWLock
{
 public:
	RWLock()
	{
	}

	void EnterRead()
	{
		std::unique_lock<std::mutex> lock(mtx);
		cv.wait(lock, [this]() {
			return rw_acquired >= 0 && writer_waiting == 0;
		});
		rw_acquired++;
	}

	void LeaveRead()
	{
		std::lock_guard<std::mutex> lock(mtx);
		assert(rw_acquired > 0);
		if (--rw_acquired == 0) {
			cv.notify_all();
		}
	}

	void EnterWrite()
	{
		std::unique_lock<std::mutex> lock(mtx);
		writer_waiting++;
		cv.wait(lock, [this]() {
			return rw_acquired == 0;
		});
		writer_waiting--;
		rw_acquired--;
	}

	void LeaveWrite()
	{
		std::lock_guard<std::mutex> lock(mtx);
		assert(rw_acquired < 0);
		rw_acquired = 0;
		cv.notify_all();
	}

 private:
	std::mutex mtx {};
	std::condition_variable cv {};

	// 正なら読み込みロックの数。
	// -1 なら書き込みがロック取得中。
	int rw_acquired {};

	int writer_waiting {};
};

class RWLockGuard_Read
{
 public:
	explicit RWLockGuard_Read(RWLock& lock_)
		: lock(lock_)
	{
		lock.EnterRead();
	}
	~RWLockGuard_Read()
	{
		lock.LeaveRead();
	}

 private:
	RWLock& lock;
};

class RWLockGuard_Write
{
 public:
	explicit RWLockGuard_Write(RWLock& lock_)
		: lock(lock_)
	{
		lock.EnterWrite();
	}
	~RWLockGuard_Write()
	{
		lock.LeaveWrite();
	}

 private:
	RWLock& lock;
};

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.