Skip to content

Commit

Permalink
reactor: move reactor_backend and its derived classes to reactor.cc
Browse files Browse the repository at this point in the history
The only users are there, so don't burden other includers of
reactor.hh.
  • Loading branch information
avikivity committed Dec 20, 2018
1 parent 4e56463 commit b3ca0d7
Show file tree
Hide file tree
Showing 2 changed files with 84 additions and 82 deletions.
84 changes: 2 additions & 82 deletions include/seastar/core/reactor.hh
Original file line number Diff line number Diff line change
Expand Up @@ -432,90 +432,8 @@ private:
void work(sstring thread_name);
};

// The "reactor_backend" interface provides a method of waiting for various
// basic events on one thread. We have one implementation based on epoll and
// file-descriptors (reactor_backend_epoll) and one implementation based on
// OSv-specific file-descriptor-less mechanisms (reactor_backend_osv).
class reactor_backend {
public:
virtual ~reactor_backend() {};
// wait_and_process() waits for some events to become available, and
// processes one or more of them. If block==false, it doesn't wait,
// and just processes events that have already happened, if any.
// After the optional wait, just before processing the events, the
// pre_process() function is called.
virtual bool wait_and_process(int timeout = -1, const sigset_t* active_sigmask = nullptr) = 0;
// Methods that allow polling on file descriptors. This will only work on
// reactor_backend_epoll. Other reactor_backend will probably abort if
// they are called (which is fine if no file descriptors are waited on):
virtual future<> readable(pollable_fd_state& fd) = 0;
virtual future<> writeable(pollable_fd_state& fd) = 0;
virtual future<> readable_or_writeable(pollable_fd_state& fd) = 0;
virtual void forget(pollable_fd_state& fd) = 0;
// Calls reactor::signal_received(signo) when relevant
virtual void handle_signal(int signo) = 0;
virtual void start_tick() = 0;
virtual void stop_tick() = 0;
virtual void arm_highres_timer(const ::itimerspec& ts) = 0;
virtual void reset_preemption_monitor() = 0;
virtual void request_preemption() = 0;
};

class reactor_backend_selector;

// reactor backend using file-descriptor & epoll, suitable for running on
// Linux. Can wait on multiple file descriptors, and converts other events
// (such as timers, signals, inter-thread notifications) into file descriptors
// using mechanisms like timerfd, signalfd and eventfd respectively.
class reactor_backend_epoll : public reactor_backend {
reactor* _r;
std::thread _task_quota_timer_thread;
timer_t _steady_clock_timer = {};
bool _timer_enabled = false;
private:
file_desc _epollfd;
future<> get_epoll_future(pollable_fd_state& fd,
promise<> pollable_fd_state::* pr, int event);
void complete_epoll_event(pollable_fd_state& fd,
promise<> pollable_fd_state::* pr, int events, int event);
static void signal_received(int signo, siginfo_t* siginfo, void* ignore);
public:
explicit reactor_backend_epoll(reactor* r);
virtual ~reactor_backend_epoll() override;
virtual bool wait_and_process(int timeout, const sigset_t* active_sigmask) override;
virtual future<> readable(pollable_fd_state& fd) override;
virtual future<> writeable(pollable_fd_state& fd) override;
virtual future<> readable_or_writeable(pollable_fd_state& fd) override;
virtual void forget(pollable_fd_state& fd) override;
virtual void handle_signal(int signo) override;
virtual void start_tick() override;
virtual void stop_tick() override;
virtual void arm_highres_timer(const ::itimerspec& ts) override;
virtual void reset_preemption_monitor() override;
virtual void request_preemption() override;
};

#ifdef HAVE_OSV
// reactor_backend using OSv-specific features, without any file descriptors.
// This implementation cannot currently wait on file descriptors, but unlike
// reactor_backend_epoll it doesn't need file descriptors for waiting on a
// timer, for example, so file descriptors are not necessary.
class reactor_backend_osv : public reactor_backend {
private:
osv::newpoll::poller _poller;
future<> get_poller_future(reactor_notifier_osv *n);
promise<> _timer_promise;
public:
reactor_backend_osv();
virtual ~reactor_backend_osv() override { }
virtual bool wait_and_process() override;
virtual future<> readable(pollable_fd_state& fd) override;
virtual future<> writeable(pollable_fd_state& fd) override;
virtual void forget(pollable_fd_state& fd) override;
void enable_timer(steady_clock_type::time_point when);
};
#endif /* HAVE_OSV */

enum class open_flags {
rw = O_RDWR,
ro = O_RDONLY,
Expand All @@ -533,6 +451,8 @@ inline open_flags operator&(open_flags a, open_flags b) {
return open_flags(std::underlying_type_t<open_flags>(a) & std::underlying_type_t<open_flags>(b));
}

class reactor_backend;

class io_queue {
private:
struct priority_class_data {
Expand Down
82 changes: 82 additions & 0 deletions src/core/reactor.cc
Original file line number Diff line number Diff line change
Expand Up @@ -302,6 +302,88 @@ inline int alarm_signal() {
return SIGRTMIN;
}

// The "reactor_backend" interface provides a method of waiting for various
// basic events on one thread. We have one implementation based on epoll and
// file-descriptors (reactor_backend_epoll) and one implementation based on
// OSv-specific file-descriptor-less mechanisms (reactor_backend_osv).
class reactor_backend {
public:
virtual ~reactor_backend() {};
// wait_and_process() waits for some events to become available, and
// processes one or more of them. If block==false, it doesn't wait,
// and just processes events that have already happened, if any.
// After the optional wait, just before processing the events, the
// pre_process() function is called.
virtual bool wait_and_process(int timeout = -1, const sigset_t* active_sigmask = nullptr) = 0;
// Methods that allow polling on file descriptors. This will only work on
// reactor_backend_epoll. Other reactor_backend will probably abort if
// they are called (which is fine if no file descriptors are waited on):
virtual future<> readable(pollable_fd_state& fd) = 0;
virtual future<> writeable(pollable_fd_state& fd) = 0;
virtual future<> readable_or_writeable(pollable_fd_state& fd) = 0;
virtual void forget(pollable_fd_state& fd) = 0;
// Calls reactor::signal_received(signo) when relevant
virtual void handle_signal(int signo) = 0;
virtual void start_tick() = 0;
virtual void stop_tick() = 0;
virtual void arm_highres_timer(const ::itimerspec& ts) = 0;
virtual void reset_preemption_monitor() = 0;
virtual void request_preemption() = 0;
};

// reactor backend using file-descriptor & epoll, suitable for running on
// Linux. Can wait on multiple file descriptors, and converts other events
// (such as timers, signals, inter-thread notifications) into file descriptors
// using mechanisms like timerfd, signalfd and eventfd respectively.
class reactor_backend_epoll : public reactor_backend {
reactor* _r;
std::thread _task_quota_timer_thread;
timer_t _steady_clock_timer = {};
bool _timer_enabled = false;
private:
file_desc _epollfd;
future<> get_epoll_future(pollable_fd_state& fd,
promise<> pollable_fd_state::* pr, int event);
void complete_epoll_event(pollable_fd_state& fd,
promise<> pollable_fd_state::* pr, int events, int event);
static void signal_received(int signo, siginfo_t* siginfo, void* ignore);
public:
explicit reactor_backend_epoll(reactor* r);
virtual ~reactor_backend_epoll() override;
virtual bool wait_and_process(int timeout, const sigset_t* active_sigmask) override;
virtual future<> readable(pollable_fd_state& fd) override;
virtual future<> writeable(pollable_fd_state& fd) override;
virtual future<> readable_or_writeable(pollable_fd_state& fd) override;
virtual void forget(pollable_fd_state& fd) override;
virtual void handle_signal(int signo) override;
virtual void start_tick() override;
virtual void stop_tick() override;
virtual void arm_highres_timer(const ::itimerspec& ts) override;
virtual void reset_preemption_monitor() override;
virtual void request_preemption() override;
};

#ifdef HAVE_OSV
// reactor_backend using OSv-specific features, without any file descriptors.
// This implementation cannot currently wait on file descriptors, but unlike
// reactor_backend_epoll it doesn't need file descriptors for waiting on a
// timer, for example, so file descriptors are not necessary.
class reactor_backend_osv : public reactor_backend {
private:
osv::newpoll::poller _poller;
future<> get_poller_future(reactor_notifier_osv *n);
promise<> _timer_promise;
public:
reactor_backend_osv();
virtual ~reactor_backend_osv() override { }
virtual bool wait_and_process() override;
virtual future<> readable(pollable_fd_state& fd) override;
virtual future<> writeable(pollable_fd_state& fd) override;
virtual void forget(pollable_fd_state& fd) override;
void enable_timer(steady_clock_type::time_point when);
};
#endif /* HAVE_OSV */

class reactor_backend_aio : public reactor_backend {
static constexpr size_t max_polls = 10000;
reactor* _r;
Expand Down

0 comments on commit b3ca0d7

Please sign in to comment.