blob: 234d949977b149c92f3980f3bcdd8687f84d25d2 [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>
Parker Schuhc1975fc2018-04-07 15:27:07 -07008#include <sys/epoll.h>
Brian Silverman801d49c2016-03-20 15:50:22 -07009
Parker Schuhb59bf5e2016-12-28 21:09:36 -080010#include "aos/common/scoped_fd.h"
Brian Silverman801d49c2016-03-20 15:50:22 -070011#include "aos/common/time.h"
12
13namespace aos {
14namespace events {
15
16class EpollLoop;
17
18// Performs an asychronous wait using an EpollLoop.
19//
20// Note: this does not have very high resolution (sub-millisecond).
Parker Schuhd7db83d2017-02-08 20:49:15 -080021// TODO(parker): This is mostly broken.
Brian Silverman801d49c2016-03-20 15:50:22 -070022class EpollWait {
23 public:
24 virtual ~EpollWait() {}
25
26 // Called when the currently set time is reached.
27 virtual void Done() = 0;
28
29 // Sets this wait to end at new_time.
30 // A negative new_time disables this wait.
Austin Schuhf2a50ba2016-12-24 16:16:26 -080031 void SetTime(const monotonic_clock::time_point new_time) { time_ = new_time; }
Brian Silverman801d49c2016-03-20 15:50:22 -070032
33 private:
34 // Calculates how long to wait starting at now and calls Done() if
35 // appropriate.
36 // Returns the number of milliseconds from now that this event will expire in.
37 // Returns -1 if this wait is never going to expire.
38 // Returns INT_MAX if this wait expires in longer than that.
Austin Schuhf2a50ba2016-12-24 16:16:26 -080039 int Recalculate(const monotonic_clock::time_point now) {
40 if (time_ < monotonic_clock::epoch()) return -1;
Brian Silverman801d49c2016-03-20 15:50:22 -070041 if (time_ <= now) {
Austin Schuhf2a50ba2016-12-24 16:16:26 -080042 time_ = monotonic_clock::time_point(::std::chrono::seconds(-1));
Parker Schuhd7db83d2017-02-08 20:49:15 -080043 Done();
Brian Silverman801d49c2016-03-20 15:50:22 -070044 }
Parker Schuhd7db83d2017-02-08 20:49:15 -080045 // Duplicate above to allow Done to change itself.
46 if (time_ < monotonic_clock::epoch()) return -1;
47 if (time_ <= now) {
Parker Schuh309dd722017-02-25 11:31:18 -080048 return -1;
Parker Schuhd7db83d2017-02-08 20:49:15 -080049 }
50
Austin Schuhf2a50ba2016-12-24 16:16:26 -080051 if (time_ - now > ::std::chrono::milliseconds(INT_MAX)) {
Brian Silverman801d49c2016-03-20 15:50:22 -070052 return INT_MAX;
53 } else {
Austin Schuhf2a50ba2016-12-24 16:16:26 -080054 return ::std::chrono::duration_cast<::std::chrono::milliseconds>(time_ -
55 now)
56 .count();
Brian Silverman801d49c2016-03-20 15:50:22 -070057 }
58 }
59
Austin Schuhf2a50ba2016-12-24 16:16:26 -080060 ::aos::monotonic_clock::time_point time_ = ::aos::monotonic_clock::epoch();
Brian Silverman801d49c2016-03-20 15:50:22 -070061
62 friend class EpollLoop;
63};
64
65// Represents a file descriptor which signals events from an EpollLoop.
66class EpollEvent {
67 public:
68 EpollEvent(int fd) : fd_(fd) {}
69 virtual ~EpollEvent() {}
70
71 int fd() { return fd_; }
72
73 // Called when fd() is readable. This must make fd() non-readable or the event
74 // loop degrades into a busy loop.
75 virtual void ReadEvent() = 0;
76
Parker Schuhc1975fc2018-04-07 15:27:07 -070077 // Handle Events directly from epoll.
78 virtual void DirectEvent(uint32_t events) {
79 if ((events & ~(EPOLLIN | EPOLLPRI | EPOLLERR)) != 0) {
80 LOG(FATAL, "unexpected epoll events set in %x on %d\n",
81 events, fd());
82 }
83 ReadEvent();
84 }
85
Parker Schuhb59bf5e2016-12-28 21:09:36 -080086 EpollLoop *loop() { return loop_; }
87
Parker Schuhc1975fc2018-04-07 15:27:07 -070088 void SetEvents(uint32_t events) {
89 events_ |= events;
90 CHECK(!loop_);
91 }
92
93 uint32_t events() const { return events_; }
94
Brian Silverman801d49c2016-03-20 15:50:22 -070095 private:
96 const int fd_;
Parker Schuhc1975fc2018-04-07 15:27:07 -070097 uint32_t events_ = EPOLLIN;
Parker Schuhb59bf5e2016-12-28 21:09:36 -080098 friend class EpollLoop;
99 EpollLoop *loop_ = nullptr;
Brian Silverman801d49c2016-03-20 15:50:22 -0700100};
101
Brian Silverman801d49c2016-03-20 15:50:22 -0700102// A file descriptor based event loop implemented with epoll.
Brian Silverman801d49c2016-03-20 15:50:22 -0700103class EpollLoop {
104 public:
105 EpollLoop();
106
107 // Ways to add various objects which interact with this event loop.
108 // None of these take ownership of the passed-in objects.
109 void AddWait(EpollWait *wait);
110 void Add(EpollEvent *event);
Brian Silverman801d49c2016-03-20 15:50:22 -0700111
Parker Schuhb59bf5e2016-12-28 21:09:36 -0800112 // Delete event. Note that there are caveats here as this is
113 // not idiot proof.
114 // ie:
115 // - Do not call from other threads.
116 // - Do not free while the object could still receive events.
117 // - This is safe only because the events are set as edge.
118 // TODO(parker): The thread-safety of this should be investigated and
119 // improved as well as adding support for non-edge events if this is to
120 // be used more generally.
121 void Delete(EpollEvent *event);
122
Brian Silverman801d49c2016-03-20 15:50:22 -0700123 // Loops forever, handling events.
124 void Run();
125
Parker Schuhd7db83d2017-02-08 20:49:15 -0800126 // Fuses with gtk_main().
127 // Note that the dep for this is separate: //aos/vision/events:gtk_event
128 void RunWithGtkMain();
129
Brian Silverman801d49c2016-03-20 15:50:22 -0700130 private:
Parker Schuhb59bf5e2016-12-28 21:09:36 -0800131 int epoll_fd() { return epoll_fd_.get(); }
Brian Silverman801d49c2016-03-20 15:50:22 -0700132
Parker Schuhb59bf5e2016-12-28 21:09:36 -0800133 int CalculateTimeout();
Parker Schuhc1975fc2018-04-07 15:27:07 -0700134 friend class EpollEvent;
Parker Schuhb59bf5e2016-12-28 21:09:36 -0800135
136 ::aos::ScopedFD epoll_fd_;
137 ::std::vector<EpollWait *> waits_;
Brian Silverman801d49c2016-03-20 15:50:22 -0700138};
139
140} // namespace events
141} // namespace aos
142
143#endif // AOS_VISION_EVENTS_EPOLL_EVENTS_H_