blob: c7aa1c68d42152a1d7cc41b5334e1f8bb3e160b3 [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
John Park33858a32018-09-28 23:05:48 -070010#include "aos/scoped/scoped_fd.h"
11#include "aos/time/time.h"
Brian Silverman801d49c2016-03-20 15:50:22 -070012
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.
Brian Silverman58899fd2019-03-24 11:03:11 -070078 virtual void DirectEvent(uint32_t events);
Parker Schuhc1975fc2018-04-07 15:27:07 -070079
Parker Schuhb59bf5e2016-12-28 21:09:36 -080080 EpollLoop *loop() { return loop_; }
81
Brian Silverman58899fd2019-03-24 11:03:11 -070082 void SetEvents(uint32_t events);
Parker Schuhc1975fc2018-04-07 15:27:07 -070083
84 uint32_t events() const { return events_; }
85
Brian Silverman801d49c2016-03-20 15:50:22 -070086 private:
87 const int fd_;
Parker Schuhc1975fc2018-04-07 15:27:07 -070088 uint32_t events_ = EPOLLIN;
Parker Schuhb59bf5e2016-12-28 21:09:36 -080089 friend class EpollLoop;
90 EpollLoop *loop_ = nullptr;
Brian Silverman801d49c2016-03-20 15:50:22 -070091};
92
Brian Silverman801d49c2016-03-20 15:50:22 -070093// A file descriptor based event loop implemented with epoll.
Brian Silverman801d49c2016-03-20 15:50:22 -070094class EpollLoop {
95 public:
96 EpollLoop();
97
98 // Ways to add various objects which interact with this event loop.
99 // None of these take ownership of the passed-in objects.
100 void AddWait(EpollWait *wait);
101 void Add(EpollEvent *event);
Brian Silverman801d49c2016-03-20 15:50:22 -0700102
Parker Schuhb59bf5e2016-12-28 21:09:36 -0800103 // Delete event. Note that there are caveats here as this is
104 // not idiot proof.
105 // ie:
106 // - Do not call from other threads.
107 // - Do not free while the object could still receive events.
108 // - This is safe only because the events are set as edge.
109 // TODO(parker): The thread-safety of this should be investigated and
110 // improved as well as adding support for non-edge events if this is to
111 // be used more generally.
112 void Delete(EpollEvent *event);
113
Brian Silverman801d49c2016-03-20 15:50:22 -0700114 // Loops forever, handling events.
115 void Run();
116
Parker Schuhd7db83d2017-02-08 20:49:15 -0800117 // Fuses with gtk_main().
118 // Note that the dep for this is separate: //aos/vision/events:gtk_event
119 void RunWithGtkMain();
120
Brian Silverman801d49c2016-03-20 15:50:22 -0700121 private:
Parker Schuhb59bf5e2016-12-28 21:09:36 -0800122 int epoll_fd() { return epoll_fd_.get(); }
Brian Silverman801d49c2016-03-20 15:50:22 -0700123
Parker Schuhb59bf5e2016-12-28 21:09:36 -0800124 int CalculateTimeout();
Parker Schuhc1975fc2018-04-07 15:27:07 -0700125 friend class EpollEvent;
Parker Schuhb59bf5e2016-12-28 21:09:36 -0800126
127 ::aos::ScopedFD epoll_fd_;
128 ::std::vector<EpollWait *> waits_;
Brian Silverman801d49c2016-03-20 15:50:22 -0700129};
130
131} // namespace events
132} // namespace aos
133
134#endif // AOS_VISION_EVENTS_EPOLL_EVENTS_H_