blob: d7574f9fa21ff4de0b995126387e3387a6d0ec3c [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).
20class EpollWait {
21 public:
22 virtual ~EpollWait() {}
23
24 // Called when the currently set time is reached.
25 virtual void Done() = 0;
26
27 // Sets this wait to end at new_time.
28 // A negative new_time disables this wait.
Austin Schuhf2a50ba2016-12-24 16:16:26 -080029 void SetTime(const monotonic_clock::time_point new_time) { time_ = new_time; }
Brian Silverman801d49c2016-03-20 15:50:22 -070030
31 private:
32 // Calculates how long to wait starting at now and calls Done() if
33 // appropriate.
34 // Returns the number of milliseconds from now that this event will expire in.
35 // Returns -1 if this wait is never going to expire.
36 // Returns INT_MAX if this wait expires in longer than that.
Austin Schuhf2a50ba2016-12-24 16:16:26 -080037 int Recalculate(const monotonic_clock::time_point now) {
38 if (time_ < monotonic_clock::epoch()) return -1;
Brian Silverman801d49c2016-03-20 15:50:22 -070039 if (time_ <= now) {
40 Done();
Austin Schuhf2a50ba2016-12-24 16:16:26 -080041 time_ = monotonic_clock::time_point(::std::chrono::seconds(-1));
Brian Silverman801d49c2016-03-20 15:50:22 -070042 return -1;
43 }
Austin Schuhf2a50ba2016-12-24 16:16:26 -080044 if (time_ - now > ::std::chrono::milliseconds(INT_MAX)) {
Brian Silverman801d49c2016-03-20 15:50:22 -070045 return INT_MAX;
46 } else {
Austin Schuhf2a50ba2016-12-24 16:16:26 -080047 return ::std::chrono::duration_cast<::std::chrono::milliseconds>(time_ -
48 now)
49 .count();
Brian Silverman801d49c2016-03-20 15:50:22 -070050 }
51 }
52
Austin Schuhf2a50ba2016-12-24 16:16:26 -080053 ::aos::monotonic_clock::time_point time_ = ::aos::monotonic_clock::epoch();
Brian Silverman801d49c2016-03-20 15:50:22 -070054
55 friend class EpollLoop;
56};
57
58// Represents a file descriptor which signals events from an EpollLoop.
59class EpollEvent {
60 public:
61 EpollEvent(int fd) : fd_(fd) {}
62 virtual ~EpollEvent() {}
63
64 int fd() { return fd_; }
65
66 // Called when fd() is readable. This must make fd() non-readable or the event
67 // loop degrades into a busy loop.
68 virtual void ReadEvent() = 0;
69
Parker Schuhb59bf5e2016-12-28 21:09:36 -080070 EpollLoop *loop() { return loop_; }
71
Brian Silverman801d49c2016-03-20 15:50:22 -070072 private:
73 const int fd_;
Parker Schuhb59bf5e2016-12-28 21:09:36 -080074 friend class EpollLoop;
75 EpollLoop *loop_ = nullptr;
Brian Silverman801d49c2016-03-20 15:50:22 -070076};
77
78// Provides a way for code to be notified every time after events are handled by
79// an EpollLoop. This is mainly a hack for the GTK integration and testing;
80// think very carefully before using it anywhere else.
81class EpollWatcher {
82 public:
83 virtual ~EpollWatcher() {}
84
85 // Called after events have been processed each time the event loop wakes up.
86 virtual void Wake() = 0;
87};
88
89// A file descriptor based event loop implemented with epoll.
Brian Silverman801d49c2016-03-20 15:50:22 -070090class EpollLoop {
91 public:
92 EpollLoop();
93
94 // Ways to add various objects which interact with this event loop.
95 // None of these take ownership of the passed-in objects.
96 void AddWait(EpollWait *wait);
97 void Add(EpollEvent *event);
98 void AddWatcher(EpollWatcher *watcher);
99
Parker Schuhb59bf5e2016-12-28 21:09:36 -0800100 // Delete event. Note that there are caveats here as this is
101 // not idiot proof.
102 // ie:
103 // - Do not call from other threads.
104 // - Do not free while the object could still receive events.
105 // - This is safe only because the events are set as edge.
106 // TODO(parker): The thread-safety of this should be investigated and
107 // improved as well as adding support for non-edge events if this is to
108 // be used more generally.
109 void Delete(EpollEvent *event);
110
Brian Silverman801d49c2016-03-20 15:50:22 -0700111 // Loops forever, handling events.
112 void Run();
113
114 private:
Parker Schuhb59bf5e2016-12-28 21:09:36 -0800115 int epoll_fd() { return epoll_fd_.get(); }
Brian Silverman801d49c2016-03-20 15:50:22 -0700116
Parker Schuhb59bf5e2016-12-28 21:09:36 -0800117 int CalculateTimeout();
118
119 ::aos::ScopedFD epoll_fd_;
120 ::std::vector<EpollWait *> waits_;
121 ::std::vector<EpollWatcher *> watchers_;
Brian Silverman801d49c2016-03-20 15:50:22 -0700122};
123
124} // namespace events
125} // namespace aos
126
127#endif // AOS_VISION_EVENTS_EPOLL_EVENTS_H_