Commit 80a68d2e authored by jan.koester's avatar jan.koester
Browse files

test

parent 595a2daa
Loading
Loading
Loading
Loading
+66 −2
Original line number Diff line number Diff line
@@ -31,6 +31,9 @@

#if defined(__GLIBC__)
#include <pthread.h>
#else
#include <mutex>
#include <condition_variable>
#endif

namespace netplus {
@@ -74,8 +77,69 @@ private:
};
#else
// pthread_rwlockattr_setkind_np is a glibc extension, unavailable on
// musl/BSD/Windows builds — fall back to the portable default there.
using WriterPreferringSharedMutex = std::shared_mutex;
// musl/BSD/Windows builds (musl's pthread_rwlock has no writer-preferring
// mode at all). Same fairness fix as the glibc branch above, built instead
// from std::mutex/std::condition_variable — the classic writer-preferring
// readers-writers algorithm, portable to any platform with a C++11
// standard library. A waiting writer blocks new readers from acquiring
// (lock_shared()'s wait predicate checks _waitingWriters), so a sustained
// stream of readers can't starve it out; only readers already active when
// the writer arrives are allowed to finish.
class WriterPreferringSharedMutex {
public:
    WriterPreferringSharedMutex() = default;
    WriterPreferringSharedMutex(const WriterPreferringSharedMutex&) = delete;
    WriterPreferringSharedMutex& operator=(const WriterPreferringSharedMutex&) = delete;

    void lock() {
        std::unique_lock<std::mutex> lk(_mtx);
        ++_waitingWriters;
        _cv.wait(lk, [this] { return !_writerActive && _activeReaders == 0; });
        --_waitingWriters;
        _writerActive = true;
    }
    void unlock() {
        {
            std::lock_guard<std::mutex> lk(_mtx);
            _writerActive = false;
        }
        _cv.notify_all();
    }
    bool try_lock() {
        std::lock_guard<std::mutex> lk(_mtx);
        if (_writerActive || _activeReaders > 0) return false;
        _writerActive = true;
        return true;
    }

    void lock_shared() {
        std::unique_lock<std::mutex> lk(_mtx);
        _cv.wait(lk, [this] { return !_writerActive && _waitingWriters == 0; });
        ++_activeReaders;
    }
    void unlock_shared() {
        bool notify;
        {
            std::lock_guard<std::mutex> lk(_mtx);
            --_activeReaders;
            notify = (_activeReaders == 0);
        }
        if (notify) _cv.notify_all();
    }
    bool try_lock_shared() {
        std::lock_guard<std::mutex> lk(_mtx);
        if (_writerActive || _waitingWriters > 0) return false;
        ++_activeReaders;
        return true;
    }

private:
    std::mutex _mtx;
    std::condition_variable _cv;
    int _activeReaders = 0;
    int _waitingWriters = 0;
    bool _writerActive = false;
};
#endif

} // namespace netplus