--- /dev/null
+cmake_minimum_required(VERSION 2.8)
+
+project(event_loop CXX)
+set(BIN_NAME event_loop)
+
+set(CMAKE_CXX_FLAGS "-Wall -Werror -std=c++0x")
+
+set(EVENT_LOOP_SRC_DIR ${PROJECT_SRC}/daemon/cpp/events)
+include_directories(
+ .
+ ${EVENT_LOOP_SRC_DIR}
+ ${PROJECT_SRC}/src
+)
+
+set(EVENT_LOOP_SRC
+ ${EVENT_LOOP_SRC_DIR}/evloop.cpp
+ ${EVENT_LOOP_SRC_DIR}/evloop_c.cpp
+)
+
+add_executable(${BIN_NAME} main.cpp ${EVENT_LOOP_SRC})
+target_link_libraries(${BIN_NAME} pthread)
+
+add_test(event_loop ${BIN_NAME})
--- /dev/null
+#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;
+}
--- /dev/null
+#ifndef SWAP_DEBUG_H
+#define SWAP_DEBUG_H
+
+
+#include <unistd.h>
+#include <sys/syscall.h>
+
+#include <stdarg.h>
+#include <time.h>
+
+
+#define LOGI(...) do_log("INF", __func__, __LINE__, __VA_ARGS__)
+#define LOGW(...) do_log("WRN", __func__, __LINE__, __VA_ARGS__)
+#define LOGE(...) do_log("ERR", __func__, __LINE__, __VA_ARGS__)
+
+
+
+static float get_uptime(void)
+{
+ int ret;
+ struct timespec ts;
+ float uptime = 0.0;
+
+ ret = clock_gettime(CLOCK_BOOTTIME, &ts);
+ if (!ret)
+ uptime = ((float)ts.tv_sec + (ts.tv_nsec / 1000000000.0));
+
+ return uptime;
+}
+
+static inline void do_log(const char *prefix, const char *funcname, int line, ...)
+{
+ va_list ap;
+ const char *fmt;
+ fprintf(stderr, "[%s][%f] PID %u:%u (%s:%d):", prefix, get_uptime(),
+ (unsigned int)getpid(),
+ (unsigned int)syscall(SYS_gettid),
+ funcname, line);
+
+ va_start(ap, line);
+ fmt = va_arg(ap, const char *);
+ vfprintf(stderr, fmt, ap);
+ va_end(ap);
+}
+
+
+#endif // SWAP_DEBUG_H