1 // Dasynq: early declarations and base watchers.
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.
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.
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)
17 pthread_sigmask(how, set, oset);
20 template <> inline void sigmaskf<null_mutex>(int how, const sigset_t *set, sigset_t *oset)
22 sigprocmask(how, set, oset);
26 // A template to generate suitable default loop traits for a given type of mutex:
27 template <typename T_Mutex> class default_traits
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;
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)
38 dprivate::sigmaskf<T_Mutex>(how, set, oset);
42 // Forward declarations:
43 template <typename T_Mutex, typename Traits = default_traits<T_Mutex>>
47 constexpr int DEFAULT_PRIORITY = 50;
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>;
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;
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;
69 enum class watch_type_t
78 template <typename Traits, typename LoopTraits> class event_dispatch;
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;
85 // Represents a queued event notification. Various event watchers derive from this type.
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
96 prio_queue::handle_t heap_handle;
99 static void set_priority(base_watcher &p, int prio)
104 // Perform initialisation necessary before registration with an event loop
110 emulate_enabled = false;
112 prio_queue::init_handle(heap_handle);
113 priority = DEFAULT_PRIORITY;
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;
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 { };
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 { }
128 virtual ~base_watcher() noexcept { }
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
136 // Later: the "delete" behaviour could be dependent on a flag, perhaps?
141 // Base signal event - not part of public API
142 template <typename T_Sigdata>
143 class base_signal_watcher : public base_watcher
145 template <typename, typename> friend class event_dispatch;
146 template <typename, typename> friend class dasynq::event_loop;
150 base_signal_watcher() : base_watcher(watch_type_t::SIGNAL) { }
153 using siginfo_t = T_Sigdata;
154 typedef siginfo_t &siginfo_p;
157 class base_fd_watcher : public base_watcher
159 template <typename, typename> friend class event_dispatch;
160 template <typename, typename> friend class dasynq::event_loop;
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)
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).
174 base_fd_watcher() noexcept : base_watcher(watch_type_t::FD) { }
177 class base_bidi_fd_watcher : public base_fd_watcher
179 template <typename, typename> friend class event_dispatch;
180 template <typename, typename> friend class dasynq::event_loop;
182 base_bidi_fd_watcher(const base_bidi_fd_watcher &) = delete;
185 base_bidi_fd_watcher() noexcept { }
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};
192 int read_removed : 1; // read watch removed?
193 int write_removed : 1; // write watch removed?
196 class base_child_watcher : public base_watcher
198 template <typename, typename> friend class event_dispatch;
199 template <typename, typename> friend class dasynq::event_loop;
202 pid_watch_handle_t watch_handle;
206 base_child_watcher() : base_watcher(watch_type_t::CHILD) { }
210 class base_timer_watcher : public base_watcher
212 template <typename, typename> friend class event_dispatch;
213 template <typename, typename> friend class dasynq::event_loop;
216 timer_handle_t timer_handle;
220 base_timer_watcher() : base_watcher(watch_type_t::TIMER)
222 init_timer_handle(timer_handle);