9#include <sys/resource.h>
29static constexpr int16_t WILLQUIT = 0x8000;
30static constexpr int16_t HASQUIT = 0x4000;
31static constexpr int16_t UNDEFINED_PRIORITY = -32768;
45static_assert (
sizeof (PollFD) ==
sizeof (
struct pollfd));
46static_assert (offsetof (PollFD, fd) == offsetof (
struct pollfd, fd));
47static_assert (
sizeof (((PollFD*) 0)->fd) ==
sizeof (((
struct pollfd*) 0)->fd));
48static_assert (offsetof (PollFD, events) == offsetof (
struct pollfd, events));
49static_assert (
sizeof (((PollFD*) 0)->events) ==
sizeof (((
struct pollfd*) 0)->events));
50static_assert (offsetof (PollFD, revents) == offsetof (
struct pollfd, revents));
51static_assert (
sizeof (((PollFD*) 0)->revents) ==
sizeof (((
struct pollfd*) 0)->revents));
90 int16 dispatch_priority_ = 0;
92 GlibGMainContext *gcontext_;
97 void quit (
int quit_code)
override;
99 bool iterate (
bool may_block)
override;
104 bool iterate_loops_Lm (
LoopState&,
bool b,
bool d);
108 bool has_primary_L (
void);
110 void kill_sources_Lm (
void);
111 void unpoll_sources_U ();
116 void process_atomic_stacks ();
118 void cancel (LoopID
id)
override;
119 void cancel (LoopID *idp)
override;
129LoopImpl::find_first_L()
132 return sources_.
empty() ? null_source : sources_[0];
136LoopImpl::find_source_L (LoopID
id)
138 for (SourceList::iterator lit = sources_.
begin(); lit != sources_.
end(); lit++)
139 if (
id == (*lit)->id_)
146LoopImpl::has_primary_L()
148 for (SourceList::iterator lit = sources_.
begin(); lit != sources_.
end(); lit++)
149 if ((*lit)->primary())
155LoopImpl::process_atomic_stacks ()
158 while (pending_add_stack_.pop (source))
161 while (pending_cancel_stack_.
pop (cancel_id))
163 LoopSourceP &src = find_source_L (cancel_id);
165 remove_source_Lm (src);
172 return has_primary_L();
188 static_assert (UNDEFINED_PRIORITY < 1,
"");
189 assert_return (
static_cast<uint16_t> (priority) >= 1 && priority <= PRIORITY_CEILING, LoopID::INVALID);
192 source->loop_ =
this;
193 const auto source_id = source->id_ = alloc_id();
194 source->loop_state_ = WAITING;
195 source->priority_ =
static_cast<uint16_t> (priority);
196 if (pending_add_stack_.push (source))
205 source->loop_ = NULL;
206 source->loop_state_ = WAITING;
207 auto pos = find (sources_.
begin(), sources_.
end(), source);
209 sources_.
erase (pos);
210 release_id (source->id_);
211 source->id_ = LoopID::INVALID;
226 if (pending_cancel_stack_.
push (
id))
241 if (*idp != LoopID::INVALID)
243 *idp = LoopID::INVALID;
256 auto once_handler = [vfunc,once_id]() { *once_id = LoopID::INVALID; vfunc(); };
257 LoopSourceP source = TimedSource::create (once_handler, delay_ms, 0);
258 source->loop_ =
this;
259 source->id_ = alloc_id();
260 source->loop_state_ = WAITING;
261 source->priority_ =
static_cast<uint16_t> (priority);
262 LoopID warn_id = LoopID::INVALID;
264 if (*once_id != LoopID::INVALID) {
267 remove_source_Lm (source);
272 *once_id = source->id_;
274 if (warn_id != LoopID::INVALID)
275 warning (
"%s: failed to remove loop source: %lu", __func__,
static_cast<uint64_t> (warn_id));
283 return add_source (SigchldSource::create (pid, slot), priority);
287LoopImpl::kill_sources_Lm()
294 remove_source_Lm (source);
309 static thread_local LoopP thread_loop = LoopImpl::make_shared();
318 auto promise = this->make_promise<uint64_t> ([&] (
auto resolve)
320 this->add ([resolve, start]()
323 const uint64_t elapsed = std::chrono::duration_cast<std::chrono::milliseconds> (end - start).count();
332LoopImpl::LoopImpl() :
335 cached_pollfd_vector_.reserve (1);
336 cached_poll_candidates_.reserve (1);
337 const int err = eventfd_.open();
339 fatal_error (
"LoopImpl: failed to create wakeup pipe: %s", strerror (-err));
363 LoopP main_loop_guard = shared_ptr_cast<Loop*> (
this);
364 process_atomic_stacks();
388 LoopP main_loop_guard = shared_ptr_cast<Loop> (
this);
390 quit_code_ &= ~HASQUIT;
392 while (
ISLIKELY (!(WILLQUIT & quit_code_)))
393 iterate_loops_Lm (state,
true,
true);
395 if (quit_code_ & WILLQUIT)
396 quit_code_ = HASQUIT | (quit_code_ & ~WILLQUIT);
397 return quit_code_ & ~HASQUIT;
409 return HASQUIT & quit_code_;
423 if (!(WILLQUIT & quit_code_)) {
424 quit_code_ = quit_code | WILLQUIT;
430LoopImpl::finishable_L()
433 return !has_primary_L();
439 return finishable_L();
455 LoopP main_loop_guard = shared_ptr_cast<Loop> (
this);
458 const bool sources_pending = iterate_loops_Lm (state, may_block,
true);
460 return sources_pending;
472 LoopP main_loop_guard = shared_ptr_cast<Loop> (
this);
474 const uint16_t saved_quit_code_ = quit_code_;
476 while (
ISLIKELY (!(WILLQUIT & quit_code_)))
477 if (!iterate_loops_Lm (state,
false,
true))
480 if (saved_quit_code_ & HASQUIT)
481 quit_code_ = saved_quit_code_ & ~WILLQUIT;
482 else if (quit_code_ & WILLQUIT)
483 quit_code_ = HASQUIT | (quit_code_ & ~WILLQUIT);
490 LoopP main_loop_guard = shared_ptr_cast<Loop> (
this);
492 const bool more = iterate_loops_Lm (state,
false,
false);
501 if (glib_main_context)
505 if (!g_main_context_acquire (glib_main_context))
507 gcontext_ = g_main_context_ref (glib_main_context);
511 glib_main_context = gcontext_;
513 g_main_context_release (glib_main_context);
514 g_main_context_unref (glib_main_context);
526 GPollFD *gpfd = (GPollFD*) pfd;
527 static_assert (
sizeof (GPollFD) ==
sizeof (
PollFD),
"");
528 static_assert (
sizeof (gpfd->fd) ==
sizeof (pfd->fd),
"");
529 static_assert (
sizeof (gpfd->events) ==
sizeof (pfd->events),
"");
530 static_assert (
sizeof (gpfd->revents) ==
sizeof (pfd->revents),
"");
531 static_assert (offsetof (GPollFD, fd) == offsetof (
PollFD, fd),
"");
532 static_assert (offsetof (GPollFD, events) == offsetof (
PollFD, events),
"");
533 static_assert (offsetof (GPollFD, revents) == offsetof (
PollFD, revents),
"");
549LoopImpl::unpoll_sources_U()
556LoopImpl::collect_sources_Lm (LoopState &state)
565 state.seen_primary =
true;
568 poll_candidates.resize (0);
570 dispatch_priority_ = UNDEFINED_PRIORITY;
571 for (SourceList::iterator lit = sources_.
begin(); lit != sources_.
end(); lit++)
573 LoopSource &source = **lit;
574 if (
UNLIKELY (!state.seen_primary && source.primary_))
575 state.seen_primary =
true;
576 if (source.loop_ !=
this ||
577 (source.dispatching_ && !source.may_recurse_))
579 if (source.priority_ > dispatch_priority_ &&
580 source.loop_state_ == NEEDS_DISPATCH)
581 dispatch_priority_ = source.priority_;
582 if (source.priority_ > dispatch_priority_ ||
583 (source.priority_ == dispatch_priority_ &&
584 source.loop_state_ == NEEDS_DISPATCH))
585 poll_candidates.push_back (&*lit);
589 for (
size_t i = 0; i < poll_candidates.size(); i++)
590 if ((*poll_candidates[i])->priority_ > dispatch_priority_ ||
591 ((*poll_candidates[i])->priority_ == dispatch_priority_ &&
592 (*poll_candidates[i])->loop_state_ == NEEDS_DISPATCH))
593 poll_sources_.
push_back (*poll_candidates[i]);
604 for (
auto lit = poll_sources_.
begin(); lit != poll_sources_.
end(); lit++)
606 LoopSource &source = **lit;
607 if (source.loop_ !=
this)
610 const bool need_dispatch = source.prepare (state, &timeout);
611 if (source.loop_ !=
this)
615 dispatch_priority_ =
std::max (dispatch_priority_, source.priority_);
616 source.loop_state_ = NEEDS_DISPATCH;
619 source.loop_state_ = PREPARED;
621 state.timeout_usecs =
std::min (state.timeout_usecs, timeout);
622 uint npfds = source.n_pfds();
623 for (
uint i = 0; i < npfds; i++)
624 if (source.pfds_[i].pfd->fd >= 0)
626 uint idx = pfda.size();
627 source.pfds_[i].idx = idx;
628 pfda.push_back (*source.pfds_[i].pfd);
629 pfda[idx].revents = 0;
632 source.pfds_[i].idx = 4294967295U;
634 return dispatch_priority_ > UNDEFINED_PRIORITY;
641 for (
auto lit = poll_sources_.
begin(); lit != poll_sources_.
end(); lit++)
643 LoopSource &source = **lit;
644 if (source.loop_ !=
this &&
645 source.loop_state_ != PREPARED)
647 uint npfds = source.n_pfds();
648 for (
uint i = 0; i < npfds; i++)
650 uint idx = source.pfds_[i].idx;
651 if (idx < pfda.size() &&
652 source.pfds_[i].pfd->fd == pfda[idx].fd)
653 source.pfds_[i].pfd->revents = pfda[idx].revents;
655 source.pfds_[i].idx = 4294967295U;
657 bool need_dispatch = source.check (state);
658 if (source.loop_ !=
this)
662 dispatch_priority_ =
std::max (dispatch_priority_, source.priority_);
663 source.loop_state_ = NEEDS_DISPATCH;
666 source.loop_state_ = WAITING;
668 return dispatch_priority_ > UNDEFINED_PRIORITY;
672LoopImpl::dispatch_source_Lm (LoopState &state)
675 LoopSourceP dispatch_source = NULL;
676 for (
auto lit = poll_sources_.
begin(); lit != poll_sources_.
end(); lit++)
678 LoopSourceP &source = *lit;
679 if (source->loop_ ==
this &&
680 source->priority_ == dispatch_priority_ &&
681 source->loop_state_ == NEEDS_DISPATCH)
683 dispatch_source = source;
687 dispatch_priority_ = UNDEFINED_PRIORITY;
691 dispatch_source->loop_state_ = WAITING;
692 const bool old_was_dispatching = dispatch_source->was_dispatching_;
693 dispatch_source->was_dispatching_ = dispatch_source->dispatching_;
694 dispatch_source->dispatching_ =
true;
695 const bool keep_alive = dispatch_source->dispatch (state);
696 dispatch_source->dispatching_ = dispatch_source->was_dispatching_;
697 dispatch_source->was_dispatching_ = old_was_dispatching;
698 if (dispatch_source->loop_ ==
this && !keep_alive)
699 remove_source_Lm (dispatch_source);
704LoopImpl::iterate_loops_Lm (LoopState &state,
bool may_block,
bool may_dispatch)
707 process_atomic_stacks ();
712 const uint wakeup_idx = 0;
715 state.phase = state.COLLECT;
716 state.seen_primary =
false;
717 collect_sources_Lm (state);
719 bool any_dispatchable =
false;
720 state.phase = state.PREPARE;
723 bool adispatchable =
false;
724 bool gdispatchable =
false;
725 adispatchable = prepare_sources_Lm (state, pfda);
726 any_dispatchable |= adispatchable;
728 ASE_UNUSED
const int gfirstfd = pfda.size();
733 gdispatchable = g_main_context_prepare (gcontext_, &gpriority) != 0;
734 any_dispatchable |= gdispatchable;
736 int gnfds = g_main_context_query (gcontext_, gpriority, >imeout, mk_gpollfd (&pfda[gfirstfd]), pfda.size() - gfirstfd);
737 while (gnfds >= 0 &&
size_t (gnfds) != pfda.size() - gfirstfd)
739 pfda.resize (gfirstfd + gnfds);
741 gnfds = g_main_context_query (gcontext_, gpriority, >imeout, mk_gpollfd (&pfda[gfirstfd]), pfda.size() - gfirstfd);
744 state.timeout_usecs =
MIN (state.timeout_usecs, gtimeout *
int64 (1000));
748 int64 timeout_msecs = state.timeout_usecs / 1000;
749 if (state.timeout_usecs > 0 && timeout_msecs <= 0)
751 if (!may_block || any_dispatchable)
753 state.timeout_usecs = 0;
756 presult =
poll ((
struct pollfd*) &pfda[0], pfda.size(),
std::min (timeout_msecs,
int64 (2147483647)));
757 while (presult < 0 && errno == EAGAIN);
758 if (presult < 0 && errno != EINTR)
759 warning (
"LoopImpl: poll() failed: %s",
strerror());
760 else if (pfda[wakeup_idx].revents)
763 state.phase = state.CHECK;
765 int16 max_dispatch_priority = -32768;
766 adispatchable |= check_sources_Lm (state, pfda);
769 any_dispatchable =
true;
770 max_dispatch_priority =
std::max (max_dispatch_priority, dispatch_priority_);
776 gdispatchable = g_main_context_check (gcontext_, gpriority, mk_gpollfd (&pfda[gfirstfd]), pfda.size() - gfirstfd);
777 any_dispatchable |= gdispatchable;
781 if (may_dispatch && any_dispatchable)
783 state.phase = state.DISPATCH;
784 if (gdispatchable && (!adispatchable || (rr_index_++ & 1)))
787 g_main_context_dispatch (gcontext_);
790 else if (adispatchable)
791 dispatch_source_Lm (state);
794 state.phase = state.NONE;
796 return any_dispatchable;
800LoopSource::LoopSource () :
803 id_ (LoopID::INVALID),
804 priority_ (UNDEFINED_PRIORITY),
808 was_dispatching_ (0),
843 primary_ = is_primary;
849 return dispatching_ && was_dispatching_;
855 const uint idx = n_pfds();
856 uint npfds = idx + 1;
857 pfds_ = (typeof (pfds_))
realloc (pfds_,
sizeof (pfds_[0]) * (npfds + 1));
859 fatal_error (
"LoopSource: out of memory");
860 pfds_[npfds].idx = 4294967295U;
861 pfds_[npfds].pfd = NULL;
862 pfds_[idx].idx = 4294967295U;
863 pfds_[idx].pfd = pfd;
869 uint idx, npfds = n_pfds();
870 for (idx = 0; idx < npfds; idx++)
871 if (pfds_[idx].pfd == pfd)
875 pfds_[idx].idx = 4294967295U;
876 pfds_[idx].pfd = pfds_[npfds - 1].pfd;
877 pfds_[idx].idx = pfds_[npfds - 1].idx;
878 pfds_[npfds - 1].idx = 4294967295U;
879 pfds_[npfds - 1].pfd = NULL;
882 warning (
"LoopSource: unremovable PollFD: %p (fd=%d)", pfd, pfd->fd);
886LoopSource::destroy ()
893 loop_->
cancel (source_id());
896LoopSource::~LoopSource ()
904DispatcherSource::DispatcherSource (
const DispatcherSlot &slot) :
908DispatcherSource::~DispatcherSource ()
916 return slot_ (state);
922 return slot_ (state);
928 return slot_ (state);
932DispatcherSource::destroy()
935 state.phase = state.DESTROY;
940USignalSource::USignalSource (
int8 signum,
const USignalSlot &slot) :
941 slot_ (slot), signum_ (signum)
943 const uint s = 128 + signum_;
948USignalSource::~USignalSource ()
959 const uint s = 128 + signum;
960 const uint index = s / 32;
961 const uint shift = s % 32;
962 usignals_notified[index] |= 1 << shift;
968 return usignals_notified[index_] & (1 << shift_);
974 return usignals_notified[index_] & (1 << shift_);
980 usignals_notified[index_] &= ~(1 << shift_);
981 return slot_ (signum_);
985USignalSource::destroy()
989write_uint (uint32_t i)
998 *(--c) =
'0' + (i % 10);
1002 memmove (&a[0], c, &a.back() + 1 - c);
1008USignalSource::install_sigaction (
int8 signum)
1011 action.sa_handler = [] (
int signum) {
1013 constexpr size_t N = 1024;
1014 char buf[N] = __FILE__
":";
1015 strncat (buf, &write_uint (__LINE__)[0], N);
1016 strncat (buf,
": sa_handler: signal=", N);
1017 strncat (buf, &write_uint (signum)[0], N);
1019 ::write (2, buf, strlen (buf));
1024 action.sa_flags = SA_NOMASK;
1031SigchldSource::SigchldSource (int64_t pid,
const SigchldSlot &slot) :
1032 slot_ (slot), pid_ (pid)
1036 action.sa_handler = [] (
int signum) {
1040 action.sa_flags = SA_NOMASK;
1045SigchldSource::~SigchldSource()
1051 return pid_ && sigchld_counter_ != sigchld_counter;
1057 return pid_ && sigchld_counter_ != sigchld_counter;
1064 sigchld_counter_ = sigchld_counter;
1067 struct rusage ru {};
1068 const pid_t child_pid = wait4 (pid_, &status, WNOHANG, &ru);
1069 if (child_pid > 0) {
1070 slot_ (pid_, status);
1072 printerr (
" Child Pid %d user time: %ld.%06ld sec\n", child_pid, ru.ru_utime.tv_sec, ru.ru_utime.tv_usec);
1073 printerr (
" System time: %ld.%06ld sec\n", ru.ru_stime.tv_sec, ru.ru_stime.tv_usec);
1074 printerr (
" Max RSS: %ld KB\n", ru.ru_maxrss);
1075 printerr (
" Page faults: %ld\n", ru.ru_minflt);
1076 printerr (
" I/O operations: %ld\n", ru.ru_inblock + ru.ru_oublock);
1077 printerr (
" Voluntary context switches: %ld\n", ru.ru_nvcsw);
1078 printerr (
" Involuntary context switches: %ld\n", ru.ru_nivcsw);
1081 if (WIFEXITED (status) || WIFSIGNALED (status)) {
1092SigchldSource::destroy ()
1098TimedSource::TimedSource (
const VoidSlot &slot,
uint initial_interval_msecs,
uint repeat_interval_msecs) :
1100 interval_msecs_ (repeat_interval_msecs), first_interval_ (true),
1101 oneshot_ (true), void_slot_ (slot)
1104TimedSource::TimedSource (
const BoolSlot &slot,
uint initial_interval_msecs,
uint repeat_interval_msecs) :
1106 interval_msecs_ (repeat_interval_msecs), first_interval_ (true),
1107 oneshot_ (false), bool_slot_ (slot)
1115 if (!first_interval_)
1117 uint64 interval = interval_msecs_ * 1000ULL;
1122 return 0 == *timeout_usecs_p;
1134 bool repeat =
false;
1135 first_interval_ =
false;
1136 if (oneshot_ && void_slot_ != NULL)
1138 else if (!oneshot_ && bool_slot_ != NULL)
1139 repeat = bool_slot_ ();
1145TimedSource::~TimedSource ()
1148 void_slot_.~VoidSlot();
1150 bool_slot_.~BoolSlot();
1166PollFDSource::PollFDSource (
const BPfdSlot &slot,
int fd,
const String &mode) :
1167 pfd_ ((PollFD) { fd, 0, 0 }),
1168 never_close_ (strchr (mode.c_str(),
'C') != NULL),
1169 oneshot_ (
false), bool_poll_slot_ (slot)
1174PollFDSource::PollFDSource (
const VPfdSlot &slot,
int fd,
const String &mode) :
1175 pfd_ ((PollFD) { fd, 0, 0 }),
1176 never_close_ (strchr (mode.c_str(),
'C') != NULL),
1177 oneshot_ (
true), void_poll_slot_ (slot)
1183PollFDSource::construct (
const String &mode)
1192 const long lflags =
fcntl (pfd_.fd, F_GETFL, 0);
1193 long nflags = lflags;
1194 if (strchr (mode.c_str(),
'b'))
1195 nflags &= ~long (O_NONBLOCK);
1196 else if (strchr (mode.c_str(),
'B'))
1197 nflags |= O_NONBLOCK;
1198 if (nflags != lflags)
1202 err =
fcntl (pfd_.fd, F_SETFL, nflags);
1203 while (err < 0 && (errno == EINTR || errno == EAGAIN));
1218 return pfd_.fd < 0 || pfd_.revents != 0;
1224 bool keep_alive = !oneshot_;
1225 if (oneshot_ && void_poll_slot_ != NULL)
1226 void_poll_slot_ (pfd_);
1227 else if (!oneshot_ && bool_poll_slot_ != NULL)
1228 keep_alive = bool_poll_slot_ (pfd_);
1232 if (!never_close_ && pfd_.fd >= 0)
1240PollFDSource::destroy()
1243 if (!never_close_ && pfd_.fd >= 0)
1248PollFDSource::~PollFDSource ()
1251 void_poll_slot_.~VPfdSlot();
1253 bool_poll_slot_.~BPfdSlot();
virtual bool dispatch(const LoopState &state)
Dispatch source, returns if it should be kept alive.
virtual bool prepare(const LoopState &state, int64 *timeout_usecs_p)
Prepare the source for dispatching (true return) or polling (false).
virtual bool check(const LoopState &state)
Check the source and its PollFD descriptors for dispatching (true return).
bool opened()
Indicates whether eventfd has been opened.
void flush()
Clear pending wakeups.
int inputfd()
Returns the file descriptor for POLLIN.
void wakeup()
Wakeup polling end.
Loop implementation with internal state.
void quit(int quit_code) override
Stop the event loop.
bool has_quit() override
Check if quit() has been called.
void wakeup() override
Wake up the event loop.
void cancel(LoopID id) override
Cancel an event source.
int run() override
Run the event loop.
bool pending() override
Check if iterate() needs to be called for dispatching.
LoopID exec_sigchld(int64_t pid, const SigchldSlot &vfunc, LoopPriority priority) override
Execute a signal callback for prepare, check, dispatch.
bool set_g_main_context(GlibGMainContext *glib_main_context) override
Set context to integrate with a GLib GMainContext loop.
void iterate_pending() override
Iterate pending sources.
LoopID add_source(LoopSourceP loop_source, LoopPriority priority) override
Add an event source to the loop.
bool exec_once(uint delay_ms, LoopID *once_id, const VoidSlot &vfunc, LoopPriority priority) override
Execute a callback once on SIGCHLD for pid.
bool has_primary() override
Indicates whether loop contains primary sources.
bool finishable() override
Indicates wether this loop has no primary sources left to process.
bool running() override
Indicates if quit() has been called already.
void destroy_loop() override
Remove all sources from a loop and prevent any further execution.
bool iterate(bool may_block) override
Iterate the main loop once.
bool recursion() const
Indicates wether the source is currently in recursion.
void add_poll(PollFD *const pfd)
Add a PollFD descriptors for poll(2) and check().
bool primary() const
Indicate whether this source is primary.
bool may_recurse() const
Indicates if this source may recurse.
void loop_remove()
Remove this source from its event loop if any.
void remove_poll(PollFD *const pfd)
Remove a previously added PollFD.
Loop object, polling for events and executing callbacks in accordance.
std::shared_ptr< Promise< uint64_t > > delay(std::chrono::milliseconds ms)
Create a promise that resolves after ms milliseconds and returns the elapsed delay.
virtual void cancel(LoopID id)=0
Cancel a source and remove it from the loop.
static LoopP current()
Return the thread-local singleton loop, created on first call.
virtual bool dispatch(const LoopState &state)
Dispatch source, returns if it should be kept alive.
virtual bool prepare(const LoopState &state, int64 *timeout_usecs_p)
Prepare the source for dispatching (true return) or polling (false).
virtual bool check(const LoopState &state)
Check the source and its PollFD descriptors for dispatching (true return).
virtual bool dispatch(const LoopState &state)
Dispatch source, returns if it should be kept alive.
virtual bool prepare(const LoopState &state, int64 *timeout_usecs_p)
Prepare the source for dispatching (true return) or polling (false).
virtual bool check(const LoopState &state)
Check the source and its PollFD descriptors for dispatching (true return).
virtual bool check(const LoopState &state)
Check the source and its PollFD descriptors for dispatching (true return).
virtual bool prepare(const LoopState &state, int64 *timeout_usecs_p)
Prepare the source for dispatching (true return) or polling (false).
virtual bool dispatch(const LoopState &state)
Dispatch source, returns if it should be kept alive.
virtual bool dispatch(const LoopState &state)
Dispatch source, returns if it should be kept alive.
virtual bool prepare(const LoopState &state, int64 *timeout_usecs_p)
Prepare the source for dispatching (true return) or polling (false).
static void raise(int8 signum)
Flag a unix signal being raised, this function may be called from any thread at any time.
virtual bool check(const LoopState &state)
Check the source and its PollFD descriptors for dispatching (true return).
T compare_exchange_strong(T... args)
#define ASE_ASSERT(expr)
Issue an assertion warning if expr evaluates to false.
#define ASE_DEFINE_MAKE_SHARED(CLASS)
Define a member function static shared_ptr<CLASS> make_shared(ctorargs...);.
#define ASE_UNLIKELY(expr)
Compiler hint to optimize for expr evaluating to false.
#define ASE_CLASS_NON_COPYABLE(ClassName)
Delete copy ctor and assignment operator.
#define assert_return(expr,...)
Return from the current function if expr is unmet and issue an assertion warning.
#define MIN(a, b)
Yield minimum of a and b.
#define return_unless(cond,...)
Return silently if cond does not evaluate to true with return value ...
#define UNLIKELY(cond)
Hint to the compiler to optimize for cond == FALSE.
#define ISLIKELY(cond)
Hint to the compiler to optimize for cond == TRUE.
The Anklang C++ API namespace.
uint64_t uint64
A 64-bit unsigned integer, use PRI*64 in format strings.
int16_t int16
A 16-bit signed integer.
int8_t int8
An 8-bit signed integer.
int64_t int64
A 64-bit unsigned integer, use PRI*64 in format strings.
@ SYSALLOC
Internal maintenance, don't use.
std::string String
Convenience alias for std::string.
bool debug_key_enabled(const char *conditional) noexcept
Check if conditional is enabled by $ASE_DEBUG.
uint32_t uint
Provide 'uint' as convenience type.
uint64 timestamp_realtime()
Return the current time as uint64 in µseconds.
Thread-safe, lock-free stack based on MpmcStack and an Allocator with allows_read_after_free.
bool pop(Value &value)
Pop value from top of the stack, returns if value was reassigned (true), otherwise the stack was empt...
bool push(Value &&value)
Add value to top of the stack, returns if the stack was empty (true).
uint64 current_time_usecs
Equals timestamp_realtime() as of prepare() and check().
Mirrors struct pollfd for poll(3posix)
@ RDNORM
reading data will not block
@ HUP
file descriptor closed
@ WRNORM
writing data will not block
@ PRI
urgent data available
@ RDBAND
reading priority data will not block
@ OUT
writing data will not block
@ WRBAND
writing priority data will not block