text: /* os.h
     Mathieu Stefani, 13 August 2015
  
     Operating system specific functions
  */
  
  #pragma once
  
  #include <memory>
  #include <chrono>
  #include <vector>
  #include <bitset>
  
  #include <sched.h>
  
  #include <pistache/flags.h>
  #include <pistache/common.h>
  
  namespace Pistache {
  
  using Fd = int;
  
  uint hardware_concurrency();
  bool make_non_blocking(int fd);
  
  class CpuSet {
  public:
      static constexpr size_t Size = 1024;
  
      CpuSet();
      explicit CpuSet(std::initializer_list<size_t> cpus);
  
      void clear();
      CpuSet& set(size_t cpu);
      CpuSet& unset(size_t cpu);
  
      CpuSet& set(std::initializer_list<size_t> cpus);
      CpuSet& unset(std::initializer_list<size_t> cpus);
  
      CpuSet& setRange(size_t begin, size_t end);
      CpuSet& unsetRange(size_t begin, size_t end);
  
      bool isSet(size_t cpu) const;
      size_t count() const;
  
      cpu_set_t toPosix() const;
  
  private:
      std::bitset<Size> bits;
  };
  
  namespace Polling {
  
  enum class Mode {
      Level,
      Edge
  };
  
  enum class NotifyOn {
      None = 0,
  
      Read     = 1,
      Write    = Read << 1,
      Hangup   = Read << 2,
      Shutdown = Read << 3
  };
  
  DECLARE_FLAGS_OPERATORS(NotifyOn)
  
  struct Tag {
      friend class Epoll;
  
      explicit constexpr Tag(uint64_t value)
        : value_(value)
      { }
  
      constexpr uint64_t value() const { return value_; }
  
      friend constexpr bool operator==(Tag lhs, Tag rhs);
  
  private:
      uint64_t value_;
  };
  
  inline constexpr bool operator==(Tag lhs, Tag rhs) {
      return lhs.value_ == rhs.value_;
  }
  
  struct Event {
      explicit Event(Tag _tag)
          : flags()
          , fd(-1)
          , tag(_tag)
      { }
  
      Flags<NotifyOn> flags;
      Fd fd;
      Tag tag;
  };
  
  class Epoll {
  public:
      Epoll(size_t max = 128);
  
      void addFd(Fd fd, Flags<NotifyOn> interest, Tag tag, Mode mode = Mode::Level);
      void addFdOneShot(Fd fd, Flags<NotifyOn> interest, Tag tag, Mode mode = Mode::Level);
  
      void removeFd(Fd fd);
      void rearmFd(Fd fd, Flags<NotifyOn> interest, Tag tag, Mode mode = Mode::Level);
  
      int poll(std::vector<Event>& events,
               size_t maxEvents = Const::MaxEvents,
               std::chrono::milliseconds timeout = std::chrono::milliseconds(0)) const;
  
  private:
      static int toEpollEvents(const Flags<NotifyOn>& interest);
      static Flags<NotifyOn> toNotifyOn(int events);
      int epoll_fd;
  };
  
  } // namespace Polling
  
  class NotifyFd {
  public:
      NotifyFd()
          : event_fd(-1)
      { }
  
      Polling::Tag bind(Polling::Epoll& poller);
  
      bool isBound() const;
  
      Polling::Tag tag() const;
  
      void notify() const;
  
      void read() const;
      bool tryRead() const;
  
  private:
      int event_fd;
  };
  
  } // namespace Pistache
  