Upgrade bundled Dasynq to 1.1.2.
[oweals/dinit.git] / src / dasynq / dasynq-basewatchers.h
1 // Dasynq: early declarations and base watchers.
2 //
3 // Here we define watcher functionality that is not dependent on the event loop type. In particular,
4 // base classes for the various watcher types. These are not part of the public API.
5 //
6 // In general access to the members of the basewatcher should be protected by a mutex. The
7 // event_dispatch lock is used for this purpose.
8
9 namespace dasynq {
10
11 namespace dprivate {
12     // POSIX says that sigprocmask has unspecified behaviour if used in a multi-threaded process. We can use
13     // pthread_sigmask instead, but that may require linking with the threads library. This function is
14     // specialised to call one or the other depending on the mutex type:
15     template <typename T_Mutex> void sigmaskf(int how, const sigset_t *set, sigset_t *oset)
16     {
17         pthread_sigmask(how, set, oset);
18     }
19
20     template <> inline void sigmaskf<null_mutex>(int how, const sigset_t *set, sigset_t *oset)
21     {
22         sigprocmask(how, set, oset);
23     }
24 }
25
26 // A template to generate suitable default loop traits for a given type of mutex:
27 template <typename T_Mutex> class default_traits
28 {
29     public:
30     using mutex_t  = T_Mutex;
31     template <typename Base> using backend_t = dasynq::loop_t<Base>;
32     using backend_traits_t = dasynq::loop_traits_t;
33
34     // Alter the current thread signal mask using the correct function
35     // (sigprocmask or pthread_sigmask):
36     static void sigmaskf(int how, const sigset_t *set, sigset_t *oset)
37     {
38         dprivate::sigmaskf<T_Mutex>(how, set, oset);
39     }
40 };
41
42 // Forward declarations:
43 template <typename T_Mutex, typename Traits = default_traits<T_Mutex>>
44 class event_loop;
45
46 inline namespace {
47     constexpr int DEFAULT_PRIORITY = 50;
48 }
49
50 namespace dprivate {
51     // (non-public API)
52
53     class base_watcher;
54     template <typename A, typename B, typename C> using dary_heap_def = dary_heap<A,B,C>;
55     using prio_queue = stable_heap<dary_heap_def, dprivate::base_watcher *, int>;
56
57     template <typename T_Loop> class fd_watcher;
58     template <typename T_Loop> class bidi_fd_watcher;
59     template <typename T_Loop> class signal_watcher;
60     template <typename T_Loop> class child_proc_watcher;
61     template <typename T_Loop> class timer;
62
63     template <typename, typename> class fd_watcher_impl;
64     template <typename, typename> class bidi_fd_watcher_impl;
65     template <typename, typename> class signal_watcher_impl;
66     template <typename, typename> class child_proc_watcher_impl;
67     template <typename, typename> class timer_impl;
68
69     enum class watch_type_t
70     {
71         SIGNAL,
72         FD,
73         CHILD,
74         SECONDARYFD,
75         TIMER
76     };
77
78     template <typename Traits, typename LoopTraits> class event_dispatch;
79
80     // For FD watchers:
81     // Use this watch flag to indicate that in and out events should be reported separately,
82     // that is, watcher should not be disabled until all watched event types are queued.
83     constexpr static int multi_watch = 4;
84
85     // Represents a queued event notification. Various event watchers derive from this type.
86     class base_watcher
87     {
88         public:
89         watch_type_t watchType;
90         int active : 1;    // currently executing handler?
91         int deleteme : 1;  // delete when handler finished?
92         int emulatefd : 1; // emulate file watch (by re-queueing)
93         int emulate_enabled : 1;   // whether an emulated watch is enabled
94         int child_termd : 1;  // child process has terminated
95
96         prio_queue::handle_t heap_handle;
97         int priority;
98
99         static void set_priority(base_watcher &p, int prio)
100         {
101             p.priority = prio;
102         }
103
104         // Perform initialisation necessary before registration with an event loop
105         void init()
106         {
107             active = false;
108             deleteme = false;
109             emulatefd = false;
110             emulate_enabled = false;
111             child_termd = false;
112             prio_queue::init_handle(heap_handle);
113             priority = DEFAULT_PRIORITY;
114         }
115
116         base_watcher(watch_type_t wt) noexcept : watchType(wt) { }
117         base_watcher(const base_watcher &) = delete;
118         base_watcher &operator=(const base_watcher &) = delete;
119
120         // The dispatch function is called to process a watcher's callback. It is the "real" callback
121         // function; it usually delegates to a user-provided callback.
122         virtual void dispatch(void *loop_ptr) noexcept { };
123
124         // Bi-directional file descriptor watches have a secondary dispatch function for the secondary
125         // watcher (i.e. the output watcher):
126         virtual void dispatch_second(void *loop_ptr) noexcept { }
127
128         virtual ~base_watcher() noexcept { }
129
130         // Called when the watcher has been removed.
131         // It is guaranteed by the caller that:
132         // - the dispatch method is not currently running
133         // - the dispatch method will not be called.
134         virtual void watch_removed() noexcept
135         {
136             // Later: the "delete" behaviour could be dependent on a flag, perhaps?
137             // delete this;
138         }
139     };
140
141     // Base signal event - not part of public API
142     template <typename T_Sigdata>
143     class base_signal_watcher : public base_watcher
144     {
145         template <typename, typename> friend class event_dispatch;
146         template <typename, typename> friend class dasynq::event_loop;
147
148         protected:
149         T_Sigdata siginfo;
150         base_signal_watcher() : base_watcher(watch_type_t::SIGNAL) { }
151
152         public:
153         using siginfo_t = T_Sigdata;
154         typedef siginfo_t &siginfo_p;
155     };
156
157     class base_fd_watcher : public base_watcher
158     {
159         template <typename, typename> friend class event_dispatch;
160         template <typename, typename> friend class dasynq::event_loop;
161
162         protected:
163         int watch_fd;
164
165         // These flags are protected by the loop's internal lock:
166         int watch_flags;  // events being watched
167         int event_flags;  // events pending (queued)
168
169         // watch_flags: for a regular fd_watcher, this specifies the events that the watcher
170         //              is watching (or was watching if disabled). For a bidi_fd_watcher, specifies
171         //              the events that the watcher is currently watching (i.e. specifies which
172         //              halves of the Bidi watcher are enabled).
173
174         base_fd_watcher() noexcept : base_watcher(watch_type_t::FD) { }
175     };
176
177     class base_bidi_fd_watcher : public base_fd_watcher
178     {
179         template <typename, typename> friend class event_dispatch;
180         template <typename, typename> friend class dasynq::event_loop;
181
182         base_bidi_fd_watcher(const base_bidi_fd_watcher &) = delete;
183
184         protected:
185         base_bidi_fd_watcher() noexcept { }
186
187         // The main instance is the "input" watcher only; we keep a secondary watcher with a secondary set
188         // of flags for the "output" watcher. Note that some of the flags in the secondary watcher aren't
189         // used; it exists mainly so that it can be queued independently of the primary watcher.
190         base_watcher out_watcher {watch_type_t::SECONDARYFD};
191
192         int read_removed : 1; // read watch removed?
193         int write_removed : 1; // write watch removed?
194     };
195
196     class base_child_watcher : public base_watcher
197     {
198         template <typename, typename> friend class event_dispatch;
199         template <typename, typename> friend class dasynq::event_loop;
200
201         protected:
202         pid_watch_handle_t watch_handle;
203         pid_t watch_pid;
204         int child_status;
205
206         base_child_watcher() : base_watcher(watch_type_t::CHILD) { }
207     };
208
209
210     class base_timer_watcher : public base_watcher
211     {
212         template <typename, typename> friend class event_dispatch;
213         template <typename, typename> friend class dasynq::event_loop;
214
215         protected:
216         timer_handle_t timer_handle;
217         int intervals;
218         clock_type clock;
219
220         base_timer_watcher() : base_watcher(watch_type_t::TIMER)
221         {
222             init_timer_handle(timer_handle);
223         }
224     };
225 } // dprivate
226 } // dasynq