Rest of 2016 vision code.
Vision2016Debug:
- Added live debug (debug_reciever);
- Added file replay (blob_stream_replay).
- Add gtk event code.
- Updated code and fixed compile errors after rebase.
- Added useful tools for reference. As per Austins directions.
Change-Id: I7c5e7df01eb09057178bcb99dd3e302ca274ac76
diff --git a/aos/vision/events/BUILD b/aos/vision/events/BUILD
index e003dc9..2b5b9e7 100644
--- a/aos/vision/events/BUILD
+++ b/aos/vision/events/BUILD
@@ -1,3 +1,4 @@
+load('/tools/build_rules/gtk_dependent', 'gtk_dependent_cc_binary', 'gtk_dependent_cc_library')
package(default_visibility = ["//visibility:public"])
cc_library(
@@ -56,3 +57,12 @@
'//aos/testing:googletest',
],
)
+
+gtk_dependent_cc_library(
+ name = "gtk_event",
+ srcs = ["gtk_event.cc"],
+ deps = [
+ ":epoll_events",
+ '@usr_repo//:gtk+-3.0',
+ ],
+)
diff --git a/aos/vision/events/epoll_events.cc b/aos/vision/events/epoll_events.cc
index f191259..e4f789f 100644
--- a/aos/vision/events/epoll_events.cc
+++ b/aos/vision/events/epoll_events.cc
@@ -42,17 +42,10 @@
}
event->ReadEvent();
}
-
- for (EpollWatcher *watcher : watchers_) {
- watcher->Wake();
- }
}
}
void EpollLoop::AddWait(EpollWait *wait) { waits_.push_back(wait); }
-void EpollLoop::AddWatcher(EpollWatcher *watcher) {
- watchers_.push_back(watcher);
-}
// Calculates the new timeout value to pass to epoll_wait.
int EpollLoop::CalculateTimeout() {
diff --git a/aos/vision/events/epoll_events.h b/aos/vision/events/epoll_events.h
index d7574f9..ee288c4 100644
--- a/aos/vision/events/epoll_events.h
+++ b/aos/vision/events/epoll_events.h
@@ -17,6 +17,7 @@
// Performs an asychronous wait using an EpollLoop.
//
// Note: this does not have very high resolution (sub-millisecond).
+// TODO(parker): This is mostly broken.
class EpollWait {
public:
virtual ~EpollWait() {}
@@ -37,10 +38,15 @@
int Recalculate(const monotonic_clock::time_point now) {
if (time_ < monotonic_clock::epoch()) return -1;
if (time_ <= now) {
- Done();
time_ = monotonic_clock::time_point(::std::chrono::seconds(-1));
- return -1;
+ Done();
}
+ // Duplicate above to allow Done to change itself.
+ if (time_ < monotonic_clock::epoch()) return -1;
+ if (time_ <= now) {
+ return -1;// Recalculate(now);
+ }
+
if (time_ - now > ::std::chrono::milliseconds(INT_MAX)) {
return INT_MAX;
} else {
@@ -75,17 +81,6 @@
EpollLoop *loop_ = nullptr;
};
-// Provides a way for code to be notified every time after events are handled by
-// an EpollLoop. This is mainly a hack for the GTK integration and testing;
-// think very carefully before using it anywhere else.
-class EpollWatcher {
- public:
- virtual ~EpollWatcher() {}
-
- // Called after events have been processed each time the event loop wakes up.
- virtual void Wake() = 0;
-};
-
// A file descriptor based event loop implemented with epoll.
class EpollLoop {
public:
@@ -95,7 +90,6 @@
// None of these take ownership of the passed-in objects.
void AddWait(EpollWait *wait);
void Add(EpollEvent *event);
- void AddWatcher(EpollWatcher *watcher);
// Delete event. Note that there are caveats here as this is
// not idiot proof.
@@ -111,6 +105,10 @@
// Loops forever, handling events.
void Run();
+ // Fuses with gtk_main().
+ // Note that the dep for this is separate: //aos/vision/events:gtk_event
+ void RunWithGtkMain();
+
private:
int epoll_fd() { return epoll_fd_.get(); }
@@ -118,7 +116,6 @@
::aos::ScopedFD epoll_fd_;
::std::vector<EpollWait *> waits_;
- ::std::vector<EpollWatcher *> watchers_;
};
} // namespace events
diff --git a/aos/vision/events/gtk_event.cc b/aos/vision/events/gtk_event.cc
new file mode 100644
index 0000000..e8b43aa
--- /dev/null
+++ b/aos/vision/events/gtk_event.cc
@@ -0,0 +1,68 @@
+#include <gtk/gtk.h>
+#include <gdk/gdk.h>
+#include <thread>
+#include <sys/epoll.h>
+#include <mutex>
+#include <condition_variable>
+
+#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
diff --git a/aos/vision/events/tcp_client.h b/aos/vision/events/tcp_client.h
index e7b80a6..7ce01f7 100644
--- a/aos/vision/events/tcp_client.h
+++ b/aos/vision/events/tcp_client.h
@@ -1,5 +1,5 @@
-#ifndef _AOS_VISION_DEBUG_TCP_SERVER_H_
-#define _AOS_VISION_DEBUG_TCP_SERVER_H_
+#ifndef _AOS_VISION_DEBUG_TCP_CLIENT_H_
+#define _AOS_VISION_DEBUG_TCP_CLIENT_H_
#include "aos/vision/events/epoll_events.h"
@@ -19,4 +19,4 @@
} // namespace events
} // namespace aos
-#endif // _AOS_VISION_DEBUG_TCP_SERVER_H_
+#endif // _AOS_VISION_DEBUG_TCP_CLIENT_H_