blob: 0c518e053b023474075bc7bdcdc87b79280468fd [file] [log] [blame]
#include <gdk/gdk.h>
#include <gtk/gtk.h>
#include <sys/epoll.h>
#include <condition_variable>
#include <mutex>
#include <thread>
#include "aos/vision/events/epoll_events.h"
namespace aos {
namespace events {
void EpollLoop::RunWithGtkMain() {
int timeout;
static constexpr size_t kNumberOfEvents = 64;
epoll_event events[kNumberOfEvents];
int number_events = 0;
std::mutex m;
std::condition_variable cv;
bool all_events_handled = false;
auto handle_cb = [&]() {
{
std::unique_lock<std::mutex> lk(m);
for (int i = 0; i < number_events; i++) {
EpollEvent *event = static_cast<EpollEvent *>(events[i].data.ptr);
if ((events[i].events & ~(EPOLLIN | EPOLLPRI)) != 0) {
LOG(FATAL, "unexpected epoll events set in %x on %d\n",
events[i].events, event->fd());
}
event->ReadEvent();
}
timeout = CalculateTimeout();
all_events_handled = true;
}
cv.notify_one();
};
handle_cb();
using HandleCBType = decltype(handle_cb);
std::thread t([&]() {
std::unique_lock<std::mutex> lk(m);
while (true) {
cv.wait(lk, [&all_events_handled] { return all_events_handled; });
// Wait for handle_cb to be done.
number_events =
PCHECK(epoll_wait(epoll_fd(), events, kNumberOfEvents, timeout));
all_events_handled = false;
// Trigger handle_cb on main_thread to avoid concurrency.
gdk_threads_add_idle(
+[](gpointer user_data) -> gboolean {
auto &handle_cb = *reinterpret_cast<HandleCBType *>(user_data);
handle_cb();
return G_SOURCE_REMOVE;
},
&handle_cb);
}
});
gtk_main();
// TODO(parker): Allow concurrent proxy onto the normal thread just like Gtk
// in order to allow event loop fusion, and make event addition thread-safe.
// Avoid stack destructors (explicitly shutting down of the thread.)
exit(EXIT_SUCCESS);
}
} // namespace events
} // namespace aos