Zth (libzth)
waiter.h
Go to the documentation of this file.
1 #ifndef ZTH_WAITER_H
2 #define ZTH_WAITER_H
3 /*
4  * Zth (libzth), a cooperative userspace multitasking library.
5  * Copyright (C) 2019-2022 Jochem Rutgers
6  *
7  * This Source Code Form is subject to the terms of the Mozilla Public
8  * License, v. 2.0. If a copy of the MPL was not distributed with this
9  * file, You can obtain one at https://mozilla.org/MPL/2.0/.
10  */
11 
12 #ifdef __cplusplus
13 
14 # include <libzth/allocator.h>
15 # include <libzth/fiber.h>
16 # include <libzth/list.h>
17 # include <libzth/time.h>
18 # include <libzth/util.h>
19 
20 # if __cplusplus >= 201103L
21 # include <type_traits>
22 # endif
23 
24 namespace zth {
25 class Worker;
26 
27 class Waitable {
29 public:
30  Waitable() noexcept
31  : m_fiber()
32  {}
33 
35 
36  Fiber& fiber() const noexcept
37  {
39  return *m_fiber;
40  }
41 
42  virtual bool poll(Timestamp const& now = Timestamp::now()) noexcept = 0;
43 
44  virtual string str() const
45  {
46  return format("Waitable for %s", fiber().str().c_str());
47  }
48 
49  void setFiber(Fiber& fiber) noexcept
50  {
51  m_fiber = &fiber;
52  }
53 
54  void resetFiber() noexcept
55  {
56  m_fiber = nullptr;
57  }
58 
59  bool hasFiber() const noexcept
60  {
61  return m_fiber;
62  }
63 
64 private:
65  Fiber* m_fiber;
66 };
67 
69  : public Waitable
70  , public Listable<TimedWaitable> {
72 public:
73  explicit TimedWaitable(Timestamp const& timeout = Timestamp()) noexcept
74  : m_timeout(timeout)
75  {}
76 
77  virtual ~TimedWaitable() override is_default
78 
79  Timestamp const& timeout() const noexcept
80  {
81  return m_timeout;
82  }
83 
84  virtual bool poll(Timestamp const& now = Timestamp::now()) noexcept override
85  {
86  return timeout() <= now;
87  }
88 
89  bool operator<(TimedWaitable const& rhs) const noexcept
90  {
91  return timeout() < rhs.timeout();
92  }
93 
94  virtual string str() const override
95  {
96  if(hasFiber())
97  return format(
98  "Waitable with %s timeout for %s",
99  (timeout() - Timestamp::now()).str().c_str(),
100  fiber().str().c_str());
101  else
102  return format(
103  "Waitable with %s timeout",
104  (timeout() - Timestamp::now()).str().c_str());
105  }
106 
107 protected:
108  void setTimeout(Timestamp const& t) noexcept
109  {
110  m_timeout = t;
111  }
112 
113 private:
114  Timestamp m_timeout;
115 };
116 
117 template <typename F>
118 class PolledWaiting : public TimedWaitable {
120 public:
121  explicit PolledWaiting(F const& f, TimeInterval const& interval = TimeInterval())
123  , m_f(f)
124  {
126  }
127 
128  virtual ~PolledWaiting() override is_default
129 
130  virtual bool poll(Timestamp const& now = Timestamp::now()) noexcept override
131  {
132  if(m_f())
133  return true;
134 
135  Timestamp next = timeout() + interval();
136  if(unlikely(next < now))
137  next = now + interval();
138 
139  setTimeout(next);
140  return false;
141  }
142 
143  TimeInterval const& interval() const noexcept
144  {
145  return m_interval;
146  }
147 
148  void
149  setInterval(TimeInterval const& interval, Timestamp const& now = Timestamp::now()) noexcept
150  {
151  m_interval = interval;
152  setTimeout(now + interval);
153  }
154 
155 private:
156  F m_f;
157  TimeInterval m_interval;
158 };
159 
160 template <typename C>
162  constexpr PolledMemberWaitingHelper(C& that, bool (C::*f)()) noexcept
163  : that(that)
164  , f(f)
165  {}
166 
167  bool operator()() const
168  {
169  zth_assert(f != nullptr);
170  // cppcheck-suppress nullPointerRedundantCheck
171  return (that.*f)();
172  }
173 
174  C& that;
175  bool (C::*f)();
176 };
177 
178 template <typename C>
179 class PolledMemberWaiting : public PolledWaiting<PolledMemberWaitingHelper<C> > {
181 public:
183 
185  C& that, bool (C::*f)(), TimeInterval const& interval = TimeInterval()) noexcept
186  : base(PolledMemberWaitingHelper<C>(that, f), interval)
187  {}
188 
189  virtual ~PolledMemberWaiting() override is_default
190 };
191 
192 class PollerServerBase;
193 
197 class Waiter : public Runnable {
199 public:
200  explicit Waiter(Worker& worker);
201  virtual ~Waiter() override;
202 
203  void wait(TimedWaitable& w);
204  void scheduleTask(TimedWaitable& w);
205  void unscheduleTask(TimedWaitable& w);
206  void wakeup(TimedWaitable& w);
207 
208  PollerServerBase& poller();
209  void setPoller(PollerServerBase* p = nullptr);
210  void wakeup();
211 
212 protected:
213  bool polling() const;
214 
215  virtual int fiberHook(Fiber& f) override
216  {
217  f.setName("zth::Waiter");
218  f.suspend();
219  return Runnable::fiberHook(f);
220  }
221 
222  virtual void entry() override;
223 
224 private:
225  Worker& m_worker;
226  SortedList<TimedWaitable> m_waiting;
227  PollerServerBase* m_poller;
228  PollerServerBase* m_defaultPoller;
229 };
230 
235 ZTH_EXPORT void waitUntil(TimedWaitable& w);
236 
241 # if __cplusplus >= 201103L
242 template <
243  typename F,
244  typename std::enable_if<!std::is_base_of<TimedWaitable, F>::value, int>::type = 0>
245 void waitUntil(F f, TimeInterval const& pollInterval = TimeInterval())
246 {
247  PolledWaiting<F> w(f, pollInterval);
248  waitUntil(w);
249 }
250 # else
251 ZTH_EXPORT inline void waitUntil(bool (*f)(), TimeInterval const& pollInterval = TimeInterval())
252 {
253  PolledWaiting<bool (*)()> w(f, pollInterval);
254  waitUntil(w);
255 }
256 # endif
257 
262 template <typename C>
263 void waitUntil(C& that, bool (C::*f)(), TimeInterval const& pollInterval = TimeInterval())
264 {
265  PolledMemberWaiting<C> w(that, f, pollInterval);
266  waitUntil(w);
267 }
268 
269 void scheduleTask(TimedWaitable& w);
271 void wakeup(TimedWaitable& w);
272 
277 ZTH_EXPORT inline void nap(Timestamp const& sleepUntil)
278 {
279  TimedWaitable w(sleepUntil);
280  waitUntil(w);
281 }
282 
287 ZTH_EXPORT inline void nap(TimeInterval const& sleepFor)
288 {
289  if(!sleepFor.hasPassed())
290  nap(Timestamp::now() + sleepFor);
291 }
292 
297 ZTH_EXPORT inline void mnap(long sleepFor_ms)
298 {
299  nap(TimeInterval((time_t)(sleepFor_ms / 1000L), sleepFor_ms % 1000L * 1000000L));
300 }
301 
306 ZTH_EXPORT inline void unap(long sleepFor_us)
307 {
308  nap(TimeInterval((time_t)(sleepFor_us / 1000000L), sleepFor_us % 1000000L * 1000L));
309 }
310 
363 public:
365  : m_interval(interval)
366  , m_t(Timestamp::now())
367  {}
368 
369  Timestamp const& t() const noexcept
370  {
371  return m_t;
372  }
373 
374  TimeInterval const& interval() const noexcept
375  {
376  return m_interval;
377  }
378 
379  void setInterval(TimeInterval const& interval) noexcept
380  {
381  m_interval = interval;
382  }
383 
385  {
387  return *this;
388  }
389 
390  bool nap()
391  {
392  return nap(t());
393  }
394 
395  bool nap(Timestamp const& reference, Timestamp const& now = Timestamp::now());
396 
397  void operator()()
398  {
399  nap();
400  }
401 
402 private:
403  TimeInterval m_interval;
404  Timestamp m_t;
405 };
406 
407 } // namespace zth
408 
414 EXTERN_C ZTH_EXPORT ZTH_INLINE void zth_nap(struct timespec const* ts)
415 {
416  if(likely(ts))
418 }
419 
425 EXTERN_C ZTH_EXPORT ZTH_INLINE void zth_mnap(long sleepFor_ms)
426 {
427  zth::mnap(sleepFor_ms);
428 }
429 
435 EXTERN_C ZTH_EXPORT ZTH_INLINE void zth_unap(long sleepFor_us)
436 {
437  zth::unap(sleepFor_us);
438 }
439 
440 #else // !__cplusplus
441 
442 # include <libzth/macros.h>
443 
444 # include <time.h>
445 
446 ZTH_EXPORT void zth_nap(struct timespec const* ts);
447 ZTH_EXPORT void zth_mnap(long sleepFor_ms);
448 ZTH_EXPORT void zth_unap(long sleepFor_us);
449 
450 #endif // __cplusplus
451 #endif // ZTH_WAITER_H
The fiber.
Definition: fiber.h:52
void suspend() noexcept
Definition: fiber.h:328
TimedWaitable type
Definition: list.h:31
Periodic wakeup after fixed interval.
Definition: waiter.h:361
PeriodicWakeUp(TimeInterval const &interval)
Definition: waiter.h:364
void operator()()
Definition: waiter.h:397
TimeInterval const & interval() const noexcept
Definition: waiter.h:374
PeriodicWakeUp & operator=(TimeInterval const &interval) noexcept
Definition: waiter.h:384
Timestamp const & t() const noexcept
Definition: waiter.h:369
void setInterval(TimeInterval const &interval) noexcept
Definition: waiter.h:379
PolledWaiting< PolledMemberWaitingHelper< C > > base
Definition: waiter.h:182
virtual ~PolledMemberWaiting() override=default
constexpr PolledMemberWaiting(C &that, bool(C::*f)(), TimeInterval const &interval=TimeInterval()) noexcept
Definition: waiter.h:184
virtual bool poll(Timestamp const &now=Timestamp::now()) noexcept override
Definition: waiter.h:130
void setInterval(TimeInterval const &interval, Timestamp const &now=Timestamp::now()) noexcept
Definition: waiter.h:149
TimeInterval const & interval() const noexcept
Definition: waiter.h:143
PolledWaiting(F const &f, TimeInterval const &interval=TimeInterval())
Definition: waiter.h:121
virtual ~PolledWaiting() override=default
Abstract base class of a Poller server.
Definition: poller.h:273
An abstract class, that can be started as a fiber.
Definition: fiber.h:466
virtual int fiberHook(Fiber &f)
Definition: fiber.h:496
Convenient wrapper around struct timespec that contains a time interval.
Definition: time.h:52
constexpr bool hasPassed() const noexcept
Definition: time.h:239
virtual bool poll(Timestamp const &now=Timestamp::now()) noexcept override
Definition: waiter.h:84
bool operator<(TimedWaitable const &rhs) const noexcept
Definition: waiter.h:89
void setTimeout(Timestamp const &t) noexcept
Definition: waiter.h:108
Timestamp const & timeout() const noexcept
Definition: waiter.h:79
TimedWaitable(Timestamp const &timeout=Timestamp()) noexcept
Definition: waiter.h:73
virtual string str() const override
Definition: waiter.h:94
virtual ~TimedWaitable() override=default
Convenient wrapper around struct timespec that contains an absolute timestamp.
Definition: time.h:527
static Timestamp now()
Definition: time.h:554
void setName(string const &name)
Definition: util.h:730
void setFiber(Fiber &fiber) noexcept
Definition: waiter.h:49
virtual ~Waitable()=default
Waitable() noexcept
Definition: waiter.h:30
virtual string str() const
Definition: waiter.h:44
Fiber & fiber() const noexcept
Definition: waiter.h:36
void resetFiber() noexcept
Definition: waiter.h:54
bool hasFiber() const noexcept
Definition: waiter.h:59
virtual bool poll(Timestamp const &now=Timestamp::now()) noexcept=0
A single fiber per Worker that manages sleeping and blocked fibers.
Definition: waiter.h:197
virtual int fiberHook(Fiber &f) override
Definition: waiter.h:215
The class that manages the fibers within this thread.
Definition: worker.h:38
void zth_mnap(long sleepFor_ms)
Sleep for the given amount of milliseconds.
Definition: waiter.h:425
void zth_unap(long sleepFor_us)
Sleep for the given amount of microseconds.
Definition: waiter.h:435
void zth_nap(struct timespec const *ts)
Sleep for the given time interval.
Definition: waiter.h:414
void nap(Timestamp const &sleepUntil)
Sleep until the given time stamp.
Definition: waiter.h:277
void mnap(long sleepFor_ms)
Sleep for the given amount of milliseconds.
Definition: waiter.h:297
void waitUntil(TimedWaitable &w)
Wait until the given Waitable has passed.
Definition: waiter.cpp:28
void unap(long sleepFor_us)
Sleep for the given amount of microseconds.
Definition: waiter.h:306
constexpr auto entry
Guard that is only enabled upon entry of a state.
Definition: fsm14.h:2008
#define ZTH_CLASS_NEW_DELETE(T)
Define new/delete operators for a class, which are allocator-aware.
Definition: allocator.h:114
#define is_default
Definition: macros.h:205
#define ZTH_INLINE
Definition: macros.h:130
Definition: allocator.h:23
void unscheduleTask(TimedWaitable &w)
Definition: waiter.cpp:69
void scheduleTask(TimedWaitable &w)
Definition: waiter.cpp:57
string format(char const *fmt,...)
Format like sprintf(), but save the result in an zth::string.
Definition: util.h:503
void wakeup(TimedWaitable &w)
Definition: waiter.cpp:80
constexpr PolledMemberWaitingHelper(C &that, bool(C::*f)()) noexcept
Definition: waiter.h:162
#define zth_assert(expr)
assert(), but better integrated in Zth.
Definition: util.h:236
#define likely(expr)
Marks the given expression to likely be evaluated to true.
Definition: util.h:42
#define unlikely(expr)
Marks the given expression to likely be evaluated to true.
Definition: util.h:56