I knew about Reactor pattern since I have a copy of POSA Vol. 2. I admit that it have been years since I opened the book for the last time.

I never implement a reactor by myself but I am interested to see how it is implemented in various projects. Today I learned how eventfd and epoll can be used together to implement a simple reactor from Bluetooth library in AOSP:

struct reactor_t {
  int epoll_fd;
  int event_fd;
  pthread_mutex_t list_lock;  // protects invalidation_list.
  list_t *invalidation_list;  // reactor objects that have been unregistered.
  pthread_t run_thread;       // the pthread on which reactor_run is executing.
  bool is_running;            // indicates whether |run_thread| is valid.
  bool object_removed;
};

struct reactor_object_t {
  int fd;                              // the file descriptor to monitor for events.
  void *context;                       // a context that's passed back to the *_ready functions.
  reactor_t *reactor;                  // the reactor instance this object is registered with.
  pthread_mutex_t lock;                // protects the lifetime of this object and all variables.
  void (*read_ready)(void *context);   // function to call when the file descriptor becomes readable.
  void (*write_ready)(void *context);  // function to call when the file descriptor becomes writeable.
};

The idea is simple: while your event loop is blocked on waiting for fd events, it can also wait for events (sent through eventfd handle) such as notification to shut down the reactor.

I also learned that how to unregister existing fd with a invalidation list and some locks.