Skip to content

File lock.h

File List > device > util > lock.h

Go to the documentation of this file

#pragma once

#include <atomic>
#include <optional>
#include "timeout.h"


namespace jac {


class TimeoutLock {
    Timeout _timeout;
    bool _locked = false;
    int _owner = 0;
    std::mutex _mutex;
    int _stops = 0;
    std::function<void()> _callback;
public:
    TimeoutLock(std::chrono::milliseconds duration, std::function<void()> callback):
        _timeout(duration),
        _callback(callback)
    {}

    TimeoutLock(const TimeoutLock&) = delete;
    TimeoutLock(TimeoutLock&&) = delete;
    TimeoutLock& operator=(const TimeoutLock&) = delete;
    TimeoutLock& operator=(TimeoutLock&&) = delete;

    void init() {
        _timeout.init();
    }

    bool lock(int who) {
        std::scoped_lock<std::mutex> _(_mutex);

        if (_locked && _owner == who) {
            throw std::runtime_error("Lock already locked, reset() should be used to reset the timeout");
        }

        if (!_locked) {
            _locked = true;
            _owner = who;
            _timeout.start([this]() {
                std::scoped_lock<std::mutex> __(_mutex);
                if (_callback) {
                    _callback();
                }
                _locked = false;
            });

            return true;
        }
        return false;
    }

    void resetTimeout(int who) {
        std::scoped_lock<std::mutex> _(_mutex);

        if (!_locked || _owner != who) {
            return;
        }

        _stops = _stops > 0 ? _stops - 1 : 0;

        if (_stops == 0) {
            _timeout.reset();
        }
    }

    void stopTimeout(int who) {
        std::scoped_lock<std::mutex> _(_mutex);

        if (!_locked || _owner != who) {
            return;
        }

        _timeout.stop();
        _stops++;
    }

    bool unlock(int who) {
        std::scoped_lock<std::mutex> _(_mutex);

        if (_owner != who) {
            return false;
        }

        _timeout.stop();
        _locked = false;
        return true;
    }

    void forceUnlock() {
        std::scoped_lock<std::mutex> _(_mutex);

        _timeout.stop();
        _locked = false;
    }

    bool ownedBy(int who) {
        std::scoped_lock<std::mutex> _(_mutex);
        return _locked && _owner == who;
    }

    ~TimeoutLock() {
        _timeout.stop();
    }
};


} // namespace jac