/* timer_pool.h
   Mathieu Stefani, 09 février 2016
   
   A pool of timer fd to avoid creating fds everytime we need a timer and
   thus reduce the total number of system calls.

   Most operations are lock-free except resize operations needed when the
   pool is empty, in which case it's blocking but we expect it to be rare.
*/

#pragma once

#include <pistache/config.h>
#include <pistache/os.h>
#include <pistache/reactor.h>

#include <memory>
#include <vector>
#include <atomic>

#include <cassert>
#include <unistd.h>


namespace Pistache {

class TimerPool {
public:
    explicit TimerPool(size_t initialSize = Const::DefaultTimerPoolSize);

    struct Entry {

        friend class TimerPool;

        Entry();
        ~Entry();

        Fd fd() const;

        void initialize();

        template<typename Duration>
        void arm(Duration duration)
        {
            assert(fd_ != -1 && "Entry is not initialized");

            armMs(std::chrono::duration_cast<std::chrono::milliseconds>(duration));
        }

        void disarm();

        void registerReactor(const Aio::Reactor::Key& key, Aio::Reactor* reactor);

    private:
        void armMs(std::chrono::milliseconds value);
        enum class State : uint32_t { Idle, Used };
        std::atomic<uint32_t> state;
        Fd fd_;
        bool registered;
    };

    std::shared_ptr<Entry> pickTimer();
    static void releaseTimer(const std::shared_ptr<Entry>& timer);

private:
    std::vector<std::shared_ptr<Entry>> timers;
};

} // namespace Pistache
