blob: 3b7d75a039c32be21e76d5c88585b710716e09a6 [file] [log] [blame]
Brian Silverman801d49c2016-03-20 15:50:22 -07001#ifndef AOS_VISION_EVENTS_EPOLL_EVENTS_H_
2#define AOS_VISION_EVENTS_EPOLL_EVENTS_H_
3
Brian Silverman801d49c2016-03-20 15:50:22 -07004#include <limits.h>
Parker Schuhb59bf5e2016-12-28 21:09:36 -08005#include <stdint.h>
Brian Silverman801d49c2016-03-20 15:50:22 -07006#include <memory>
Parker Schuhb59bf5e2016-12-28 21:09:36 -08007#include <vector>
Brian Silverman801d49c2016-03-20 15:50:22 -07008
Parker Schuhb59bf5e2016-12-28 21:09:36 -08009#include "aos/common/scoped_fd.h"
Brian Silverman801d49c2016-03-20 15:50:22 -070010#include "aos/common/time.h"
11
12namespace aos {
13namespace events {
14
15class EpollLoop;
16
17// Performs an asychronous wait using an EpollLoop.
18//
19// Note: this does not have very high resolution (sub-millisecond).
Parker Schuhd7db83d2017-02-08 20:49:15 -080020// TODO(parker): This is mostly broken.
Brian Silverman801d49c2016-03-20 15:50:22 -070021class EpollWait {
22 public:
23 virtual ~EpollWait() {}
24
25 // Called when the currently set time is reached.
26 virtual void Done() = 0;
27
28 // Sets this wait to end at new_time.
29 // A negative new_time disables this wait.
Austin Schuhf2a50ba2016-12-24 16:16:26 -080030 void SetTime(const monotonic_clock::time_point new_time) { time_ = new_time; }
Brian Silverman801d49c2016-03-20 15:50:22 -070031
32 private:
33 // Calculates how long to wait starting at now and calls Done() if
34 // appropriate.
35 // Returns the number of milliseconds from now that this event will expire in.
36 // Returns -1 if this wait is never going to expire.
37 // Returns INT_MAX if this wait expires in longer than that.
Austin Schuhf2a50ba2016-12-24 16:16:26 -080038 int Recalculate(const monotonic_clock::time_point now) {
39 if (time_ < monotonic_clock::epoch()) return -1;
Brian Silverman801d49c2016-03-20 15:50:22 -070040 if (time_ <= now) {
Austin Schuhf2a50ba2016-12-24 16:16:26 -080041 time_ = monotonic_clock::time_point(::std::chrono::seconds(-1));
Parker Schuhd7db83d2017-02-08 20:49:15 -080042 Done();
Brian Silverman801d49c2016-03-20 15:50:22 -070043 }
Parker Schuhd7db83d2017-02-08 20:49:15 -080044 // Duplicate above to allow Done to change itself.
45 if (time_ < monotonic_clock::epoch()) return -1;
46 if (time_ <= now) {
Parker Schuh309dd722017-02-25 11:31:18 -080047 return -1;
Parker Schuhd7db83d2017-02-08 20:49:15 -080048 }
49
Austin Schuhf2a50ba2016-12-24 16:16:26 -080050 if (time_ - now > ::std::chrono::milliseconds(INT_MAX)) {
Brian Silverman801d49c2016-03-20 15:50:22 -070051 return INT_MAX;
52 } else {
Austin Schuhf2a50ba2016-12-24 16:16:26 -080053 return ::std::chrono::duration_cast<::std::chrono::milliseconds>(time_ -
54 now)
55 .count();
Brian Silverman801d49c2016-03-20 15:50:22 -070056 }
57 }
58
Austin Schuhf2a50ba2016-12-24 16:16:26 -080059 ::aos::monotonic_clock::time_point time_ = ::aos::monotonic_clock::epoch();
Brian Silverman801d49c2016-03-20 15:50:22 -070060
61 friend class EpollLoop;
62};
63
64// Represents a file descriptor which signals events from an EpollLoop.
65class EpollEvent {
66 public:
67 EpollEvent(int fd) : fd_(fd) {}
68 virtual ~EpollEvent() {}
69
70 int fd() { return fd_; }
71
72 // Called when fd() is readable. This must make fd() non-readable or the event
73 // loop degrades into a busy loop.
74 virtual void ReadEvent() = 0;
75
Parker Schuhb59bf5e2016-12-28 21:09:36 -080076 EpollLoop *loop() { return loop_; }
77
Brian Silverman801d49c2016-03-20 15:50:22 -070078 private:
79 const int fd_;
Parker Schuhb59bf5e2016-12-28 21:09:36 -080080 friend class EpollLoop;
81 EpollLoop *loop_ = nullptr;
Brian Silverman801d49c2016-03-20 15:50:22 -070082};
83
Brian Silverman801d49c2016-03-20 15:50:22 -070084// A file descriptor based event loop implemented with epoll.
Brian Silverman801d49c2016-03-20 15:50:22 -070085class EpollLoop {
86 public:
87 EpollLoop();
88
89 // Ways to add various objects which interact with this event loop.
90 // None of these take ownership of the passed-in objects.
91 void AddWait(EpollWait *wait);
92 void Add(EpollEvent *event);
Brian Silverman801d49c2016-03-20 15:50:22 -070093
Parker Schuhb59bf5e2016-12-28 21:09:36 -080094 // Delete event. Note that there are caveats here as this is
95 // not idiot proof.
96 // ie:
97 // - Do not call from other threads.
98 // - Do not free while the object could still receive events.
99 // - This is safe only because the events are set as edge.
100 // TODO(parker): The thread-safety of this should be investigated and
101 // improved as well as adding support for non-edge events if this is to
102 // be used more generally.
103 void Delete(EpollEvent *event);
104
Brian Silverman801d49c2016-03-20 15:50:22 -0700105 // Loops forever, handling events.
106 void Run();
107
Parker Schuhd7db83d2017-02-08 20:49:15 -0800108 // Fuses with gtk_main().
109 // Note that the dep for this is separate: //aos/vision/events:gtk_event
110 void RunWithGtkMain();
111
Brian Silverman801d49c2016-03-20 15:50:22 -0700112 private:
Parker Schuhb59bf5e2016-12-28 21:09:36 -0800113 int epoll_fd() { return epoll_fd_.get(); }
Brian Silverman801d49c2016-03-20 15:50:22 -0700114
Parker Schuhb59bf5e2016-12-28 21:09:36 -0800115 int CalculateTimeout();
116
117 ::aos::ScopedFD epoll_fd_;
118 ::std::vector<EpollWait *> waits_;
Brian Silverman801d49c2016-03-20 15:50:22 -0700119};
120
121} // namespace events
122} // namespace aos
123
124#endif // AOS_VISION_EVENTS_EPOLL_EVENTS_H_