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.