blob: e8b43aabfd6121d52d398dc467a21fcef93f9468 [file] [log] [blame]
Parker Schuhd7db83d2017-02-08 20:49:15 -08001#include <gtk/gtk.h>
2#include <gdk/gdk.h>
3#include <thread>
4#include <sys/epoll.h>
5#include <mutex>
6#include <condition_variable>
7
8#include "aos/vision/events/epoll_events.h"
9
10namespace aos {
11namespace events {
12
13void EpollLoop::RunWithGtkMain() {
14 int timeout;
15 static constexpr size_t kNumberOfEvents = 64;
16 epoll_event events[kNumberOfEvents];
17 int number_events = 0;
18
19 std::mutex m;
20 std::condition_variable cv;
21 bool all_events_handled = false;
22 auto handle_cb = [&]() {
23 {
24 std::unique_lock<std::mutex> lk(m);
25
26 for (int i = 0; i < number_events; i++) {
27 EpollEvent *event = static_cast<EpollEvent *>(events[i].data.ptr);
28 if ((events[i].events & ~(EPOLLIN | EPOLLPRI)) != 0) {
29 LOG(FATAL, "unexpected epoll events set in %x on %d\n",
30 events[i].events, event->fd());
31 }
32 event->ReadEvent();
33 }
34 timeout = CalculateTimeout();
35
36 all_events_handled = true;
37 }
38 cv.notify_one();
39 };
40 handle_cb();
41 using HandleCBType = decltype(handle_cb);
42
43 std::thread t([&]() {
44 std::unique_lock<std::mutex> lk(m);
45 while (true) {
46 cv.wait(lk, [&all_events_handled]{return all_events_handled;});
47 // Wait for handle_cb to be done.
48 number_events = PCHECK(epoll_wait(epoll_fd(), events, kNumberOfEvents, timeout));
49 all_events_handled = false;
50 // Trigger handle_cb on main_thread to avoid concurrency.
51 gdk_threads_add_idle(+[](gpointer user_data) -> gboolean {
52 auto& handle_cb = *reinterpret_cast<HandleCBType*>(user_data);
53 handle_cb();
54 return G_SOURCE_REMOVE;
55 }, &handle_cb);
56 }
57 });
58 gtk_main();
59
60 // TODO(parker): Allow concurrent proxy onto the normal thread just like Gtk
61 // in order to allow event loop fusion, and make event addition thread-safe.
62
63 // Avoid stack destructors (explicitly shutting down of the thread.)
64 exit(EXIT_SUCCESS);
65}
66
67} // namespace events
68} // namespace aos