+#include <thread>
+#include <cassert>
+#include <unistd.h>
+#include <chrono>
+#include "evloop_c.h"
+#include <sys/eventfd.h>
+
+
+class EvHandler {
+public:
+ using CallBack = void (*)(const struct evloop_handler *handler, void *data);
+ EvHandler(CallBack callback, void *data) :
+ data_(data), callback_(callback)
+ {
+ fd_ = ::eventfd(0, EFD_NONBLOCK | EFD_CLOEXEC);
+ }
+
+ ~EvHandler()
+ {
+ ::close(fd_);
+ }
+
+ int fd()
+ {
+ return fd_;
+ }
+
+ void touch()
+ {
+ eventfd_t ev_val = 1;
+ ::eventfd_write(fd_, ev_val);
+ }
+
+ static void callback(const struct evloop_handler *handler, void *data)
+ {
+ EvHandler *self = static_cast<EvHandler *>(data);
+ assert(self->fd_ >= 0 && self->fd_ < 100); // 100 - small value
+
+ eventfd_t ev_val;
+ ::eventfd_read(self->fd_, &ev_val);
+
+ self->callback_(handler, self->data_);
+ }
+
+private:
+ int fd_;
+
+ void *data_;
+ CallBack callback_;
+};
+
+
+static void handler(const struct evloop_handler *handler, void *data)
+{
+ int *val = static_cast<int *>(data);
+
+ *val += 1;
+}
+
+static void do_run()
+{
+ int val0 = 0;
+ int val1 = 0;
+ int val2 = 0;
+
+ EvHandler eh0(handler, &val0);
+ EvHandler eh1(handler, &val1);
+ EvHandler eh2(handler, &val2);
+
+ evloop *loop = evloop_create();
+ std::thread worker(evloop_run, loop);
+ auto ev0 = evloop_handler_add(loop, eh0.fd(), &eh0, eh0.callback);
+
+ // case 1:
+ eh0.touch();
+ eh1.touch();
+ std::this_thread::sleep_for(std::chrono::milliseconds(100));
+ assert(val0 == 1 && val1 == 0 && val2 == 0);
+
+ // case 2:
+ auto ev1 = evloop_handler_add(loop, eh1.fd(), &eh1, eh1.callback);
+ eh1.touch();
+ std::this_thread::sleep_for(std::chrono::milliseconds(100));
+ eh1.touch();
+ std::this_thread::sleep_for(std::chrono::milliseconds(100));
+ assert(val0 == 1 && val1 == 2 && val2 == 0);
+
+ // case 3:
+ evloop_handler_del(loop, ev0);
+ auto ev2 = evloop_handler_add(loop, eh2.fd(), &eh2, eh2.callback);
+ eh0.touch();
+ eh2.touch();
+ std::this_thread::sleep_for(std::chrono::milliseconds(100));
+ assert(val0 == 1 && val1 == 2 && val2 == 1);
+
+ // case 4:
+ evloop_stop(loop);
+ std::this_thread::sleep_for(std::chrono::milliseconds(100));
+ eh0.touch();
+ eh1.touch();
+ eh2.touch();
+ assert(val0 == 1 && val1 == 2 && val2 == 1);
+
+ // case 5:
+ eh0.touch();
+ eh1.touch();
+ eh2.touch();
+ evloop_handler_del(loop, ev1);
+ worker.join();
+ evloop_handler_del(loop, ev2);
+ evloop_destroy(loop);
+ assert(val0 == 1 && val1 == 2 && val2 == 1);
+}
+
+int main()
+{
+ do_run();
+
+ return 0;
+}