28static constexpr int16_t WILLQUIT = 0x8000;
29static constexpr int16_t HASQUIT = 0x4000;
30static constexpr int16_t UNDEFINED_PRIORITY = -32768;
44static_assert (
sizeof (PollFD) ==
sizeof (
struct pollfd));
45static_assert (offsetof (PollFD, fd) == offsetof (
struct pollfd, fd));
46static_assert (
sizeof (((PollFD*) 0)->fd) ==
sizeof (((
struct pollfd*) 0)->fd));
47static_assert (offsetof (PollFD, events) == offsetof (
struct pollfd, events));
48static_assert (
sizeof (((PollFD*) 0)->events) ==
sizeof (((
struct pollfd*) 0)->events));
49static_assert (offsetof (PollFD, revents) == offsetof (
struct pollfd, revents));
50static_assert (
sizeof (((PollFD*) 0)->revents) ==
sizeof (((
struct pollfd*) 0)->revents));
89 int16 dispatch_priority_ = 0;
91 GlibGMainContext *gcontext_;
96 void quit (
int quit_code)
override;
98 bool iterate (
bool may_block)
override;
103 bool iterate_loops_Lm (
LoopState&,
bool b,
bool d);
107 bool has_primary_L (
void);
109 void kill_sources_Lm (
void);
110 void unpoll_sources_U ();
115 void process_atomic_stacks ();
117 void cancel (LoopID
id)
override;
118 void cancel (LoopID *idp)
override;
128LoopImpl::find_first_L()
131 return sources_.
empty() ? null_source : sources_[0];
135LoopImpl::find_source_L (LoopID
id)
137 for (SourceList::iterator lit = sources_.
begin(); lit != sources_.
end(); lit++)
138 if (
id == (*lit)->id_)
145LoopImpl::has_primary_L()
147 for (SourceList::iterator lit = sources_.
begin(); lit != sources_.
end(); lit++)
148 if ((*lit)->primary())
154LoopImpl::process_atomic_stacks ()
157 while (pending_add_stack_.pop (source))
160 while (pending_cancel_stack_.
pop (cancel_id))
162 LoopSourceP &src = find_source_L (cancel_id);
164 remove_source_Lm (src);
171 return has_primary_L();
187 static_assert (UNDEFINED_PRIORITY < 1,
"");
188 assert_return (
static_cast<uint16_t> (priority) >= 1 && priority <= PRIORITY_CEILING, LoopID::INVALID);
191 source->loop_ =
this;
192 const auto source_id = source->id_ = alloc_id();
193 source->loop_state_ = WAITING;
194 source->priority_ =
static_cast<uint16_t> (priority);
195 if (pending_add_stack_.push (source))
204 source->loop_ = NULL;
205 source->loop_state_ = WAITING;
206 auto pos = find (sources_.
begin(), sources_.
end(), source);
208 sources_.
erase (pos);
209 release_id (source->id_);
210 source->id_ = LoopID::INVALID;
225 if (pending_cancel_stack_.
push (
id))
240 if (*idp != LoopID::INVALID)
242 *idp = LoopID::INVALID;
255 auto once_handler = [vfunc,once_id]() { *once_id = LoopID::INVALID; vfunc(); };
256 LoopSourceP source = TimedSource::create (once_handler, delay_ms, 0);
257 source->loop_ =
this;
258 source->id_ = alloc_id();
259 source->loop_state_ = WAITING;
260 source->priority_ =
static_cast<uint16_t> (priority);
261 LoopID warn_id = LoopID::INVALID;
263 if (*once_id != LoopID::INVALID) {
266 remove_source_Lm (source);
271 *once_id = source->id_;
273 if (warn_id != LoopID::INVALID)
274 warning (
"%s: failed to remove loop source: %lu", __func__,
static_cast<uint64_t> (warn_id));
282 return add_source (SigchldSource::create (pid, slot), priority);
286LoopImpl::kill_sources_Lm()
293 remove_source_Lm (source);
308 static thread_local LoopP thread_loop = LoopImpl::make_shared();
317 auto promise = this->make_promise<uint64_t> ([&] (
auto resolve)
319 this->add ([resolve, start]()
322 const uint64_t elapsed = std::chrono::duration_cast<std::chrono::milliseconds> (end - start).count();
331LoopImpl::LoopImpl() :
334 cached_pollfd_vector_.reserve (1);
335 cached_poll_candidates_.reserve (1);
336 const int err = eventfd_.open();
338 fatal_error (
"LoopImpl: failed to create wakeup pipe: %s", strerror (-err));
362 LoopP main_loop_guard = shared_ptr_cast<Loop*> (
this);
363 process_atomic_stacks();
387 LoopP main_loop_guard = shared_ptr_cast<Loop> (
this);
389 quit_code_ &= ~HASQUIT;
391 while (
ISLIKELY (!(WILLQUIT & quit_code_)))
392 iterate_loops_Lm (state,
true,
true);
394 if (quit_code_ & WILLQUIT)
395 quit_code_ = HASQUIT | (quit_code_ & ~WILLQUIT);
408 return HASQUIT & quit_code_;
422 if (!(WILLQUIT & quit_code_)) {
423 quit_code_ = quit_code | WILLQUIT;
429LoopImpl::finishable_L()
432 return !has_primary_L();
438 return finishable_L();
454 LoopP main_loop_guard = shared_ptr_cast<Loop> (
this);
457 const bool sources_pending = iterate_loops_Lm (state, may_block,
true);
459 return sources_pending;
471 LoopP main_loop_guard = shared_ptr_cast<Loop> (
this);
473 const uint16_t saved_quit_code_ = quit_code_;
475 while (
ISLIKELY (!(WILLQUIT & quit_code_)))
476 if (!iterate_loops_Lm (state,
false,
true))
479 if (saved_quit_code_ & HASQUIT)
480 quit_code_ = saved_quit_code_ & ~WILLQUIT;
481 else if (quit_code_ & WILLQUIT)
482 quit_code_ = HASQUIT | (quit_code_ & ~WILLQUIT);
489 LoopP main_loop_guard = shared_ptr_cast<Loop> (
this);
491 const bool more = iterate_loops_Lm (state,
false,
false);
500 if (glib_main_context)
504 if (!g_main_context_acquire (glib_main_context))
506 gcontext_ = g_main_context_ref (glib_main_context);
510 glib_main_context = gcontext_;
512 g_main_context_release (glib_main_context);
513 g_main_context_unref (glib_main_context);
525 GPollFD *gpfd = (GPollFD*) pfd;
526 static_assert (
sizeof (GPollFD) ==
sizeof (
PollFD),
"");
527 static_assert (
sizeof (gpfd->fd) ==
sizeof (pfd->fd),
"");
528 static_assert (
sizeof (gpfd->events) ==
sizeof (pfd->events),
"");
529 static_assert (
sizeof (gpfd->revents) ==
sizeof (pfd->revents),
"");
530 static_assert (offsetof (GPollFD, fd) == offsetof (
PollFD, fd),
"");
531 static_assert (offsetof (GPollFD, events) == offsetof (
PollFD, events),
"");
532 static_assert (offsetof (GPollFD, revents) == offsetof (
PollFD, revents),
"");
548LoopImpl::unpoll_sources_U()
555LoopImpl::collect_sources_Lm (LoopState &state)
564 state.seen_primary =
true;
567 poll_candidates.resize (0);
569 dispatch_priority_ = UNDEFINED_PRIORITY;
570 for (SourceList::iterator lit = sources_.
begin(); lit != sources_.
end(); lit++)
572 LoopSource &source = **lit;
573 if (
UNLIKELY (!state.seen_primary && source.primary_))
574 state.seen_primary =
true;
575 if (source.loop_ !=
this ||
576 (source.dispatching_ && !source.may_recurse_))
578 if (source.priority_ > dispatch_priority_ &&
579 source.loop_state_ == NEEDS_DISPATCH)
580 dispatch_priority_ = source.priority_;
581 if (source.priority_ > dispatch_priority_ ||
582 (source.priority_ == dispatch_priority_ &&
583 source.loop_state_ == NEEDS_DISPATCH))
584 poll_candidates.push_back (&*lit);
588 for (
size_t i = 0; i < poll_candidates.size(); i++)
589 if ((*poll_candidates[i])->priority_ > dispatch_priority_ ||
590 ((*poll_candidates[i])->priority_ == dispatch_priority_ &&
591 (*poll_candidates[i])->loop_state_ == NEEDS_DISPATCH))
592 poll_sources_.
push_back (*poll_candidates[i]);
603 for (
auto lit = poll_sources_.
begin(); lit != poll_sources_.
end(); lit++)
605 LoopSource &source = **lit;
606 if (source.loop_ !=
this)
609 const bool need_dispatch = source.prepare (state, &timeout);
610 if (source.loop_ !=
this)
614 dispatch_priority_ =
std::max (dispatch_priority_, source.priority_);
615 source.loop_state_ = NEEDS_DISPATCH;
618 source.loop_state_ = PREPARED;
620 state.timeout_usecs =
std::min (state.timeout_usecs, timeout);
621 uint npfds = source.n_pfds();
622 for (
uint i = 0; i < npfds; i++)
623 if (source.pfds_[i].pfd->fd >= 0)
625 uint idx = pfda.size();
626 source.pfds_[i].idx = idx;
627 pfda.push_back (*source.pfds_[i].pfd);
628 pfda[idx].revents = 0;
631 source.pfds_[i].idx = 4294967295U;
633 return dispatch_priority_ > UNDEFINED_PRIORITY;
640 for (
auto lit = poll_sources_.
begin(); lit != poll_sources_.
end(); lit++)
642 LoopSource &source = **lit;
643 if (source.loop_ !=
this &&
644 source.loop_state_ != PREPARED)
646 uint npfds = source.n_pfds();
647 for (
uint i = 0; i < npfds; i++)
649 uint idx = source.pfds_[i].idx;
650 if (idx < pfda.size() &&
651 source.pfds_[i].pfd->fd == pfda[idx].fd)
652 source.pfds_[i].pfd->revents = pfda[idx].revents;
654 source.pfds_[i].idx = 4294967295U;
656 bool need_dispatch = source.check (state);
657 if (source.loop_ !=
this)
661 dispatch_priority_ =
std::max (dispatch_priority_, source.priority_);
662 source.loop_state_ = NEEDS_DISPATCH;
665 source.loop_state_ = WAITING;
667 return dispatch_priority_ > UNDEFINED_PRIORITY;
671LoopImpl::dispatch_source_Lm (LoopState &state)
674 LoopSourceP dispatch_source = NULL;
675 for (
auto lit = poll_sources_.
begin(); lit != poll_sources_.
end(); lit++)
677 LoopSourceP &source = *lit;
678 if (source->loop_ ==
this &&
679 source->priority_ == dispatch_priority_ &&
680 source->loop_state_ == NEEDS_DISPATCH)
682 dispatch_source = source;
686 dispatch_priority_ = UNDEFINED_PRIORITY;
690 dispatch_source->loop_state_ = WAITING;
691 const bool old_was_dispatching = dispatch_source->was_dispatching_;
692 dispatch_source->was_dispatching_ = dispatch_source->dispatching_;
693 dispatch_source->dispatching_ =
true;
694 const bool keep_alive = dispatch_source->dispatch (state);
695 dispatch_source->dispatching_ = dispatch_source->was_dispatching_;
696 dispatch_source->was_dispatching_ = old_was_dispatching;
697 if (dispatch_source->loop_ ==
this && !keep_alive)
698 remove_source_Lm (dispatch_source);
703LoopImpl::iterate_loops_Lm (LoopState &state,
bool may_block,
bool may_dispatch)
706 process_atomic_stacks ();
711 const uint wakeup_idx = 0;
714 state.phase = state.COLLECT;
715 state.seen_primary =
false;
716 collect_sources_Lm (state);
718 bool any_dispatchable =
false;
719 state.phase = state.PREPARE;
722 bool adispatchable =
false;
723 bool gdispatchable =
false;
724 adispatchable = prepare_sources_Lm (state, pfda);
725 any_dispatchable |= adispatchable;
727 ASE_UNUSED
const int gfirstfd = pfda.size();
732 gdispatchable = g_main_context_prepare (gcontext_, &gpriority) != 0;
733 any_dispatchable |= gdispatchable;
735 int gnfds = g_main_context_query (gcontext_, gpriority, >imeout, mk_gpollfd (&pfda[gfirstfd]), pfda.size() - gfirstfd);
736 while (gnfds >= 0 &&
size_t (gnfds) != pfda.size() - gfirstfd)
738 pfda.resize (gfirstfd + gnfds);
740 gnfds = g_main_context_query (gcontext_, gpriority, >imeout, mk_gpollfd (&pfda[gfirstfd]), pfda.size() - gfirstfd);
743 state.timeout_usecs =
MIN (state.timeout_usecs, gtimeout *
int64 (1000));
747 int64 timeout_msecs = state.timeout_usecs / 1000;
748 if (state.timeout_usecs > 0 && timeout_msecs <= 0)
750 if (!may_block || any_dispatchable)
752 state.timeout_usecs = 0;
755 presult =
poll ((
struct pollfd*) &pfda[0], pfda.size(),
std::min (timeout_msecs,
int64 (2147483647)));
756 while (presult < 0 && errno == EAGAIN);
757 if (presult < 0 && errno != EINTR)
758 warning (
"LoopImpl: poll() failed: %s",
strerror());
759 else if (pfda[wakeup_idx].revents)
762 state.phase = state.CHECK;
764 int16 max_dispatch_priority = -32768;
765 adispatchable |= check_sources_Lm (state, pfda);
768 any_dispatchable =
true;
769 max_dispatch_priority =
std::max (max_dispatch_priority, dispatch_priority_);
775 gdispatchable = g_main_context_check (gcontext_, gpriority, mk_gpollfd (&pfda[gfirstfd]), pfda.size() - gfirstfd);
776 any_dispatchable |= gdispatchable;
780 if (may_dispatch && any_dispatchable)
782 state.phase = state.DISPATCH;
783 if (gdispatchable && (!adispatchable || (rr_index_++ & 1)))
786 g_main_context_dispatch (gcontext_);
789 else if (adispatchable)
790 dispatch_source_Lm (state);
793 state.phase = state.NONE;
795 return any_dispatchable;
799LoopSource::LoopSource () :
802 id_ (LoopID::INVALID),
803 priority_ (UNDEFINED_PRIORITY),
807 was_dispatching_ (0),
842 primary_ = is_primary;
848 return dispatching_ && was_dispatching_;
854 const uint idx = n_pfds();
855 uint npfds = idx + 1;
856 pfds_ = (typeof (pfds_))
realloc (pfds_,
sizeof (pfds_[0]) * (npfds + 1));
858 fatal_error (
"LoopSource: out of memory");
859 pfds_[npfds].idx = 4294967295U;
860 pfds_[npfds].pfd = NULL;
861 pfds_[idx].idx = 4294967295U;
862 pfds_[idx].pfd = pfd;
868 uint idx, npfds = n_pfds();
869 for (idx = 0; idx < npfds; idx++)
870 if (pfds_[idx].pfd == pfd)
874 pfds_[idx].idx = 4294967295U;
875 pfds_[idx].pfd = pfds_[npfds - 1].pfd;
876 pfds_[idx].idx = pfds_[npfds - 1].idx;
877 pfds_[npfds - 1].idx = 4294967295U;
878 pfds_[npfds - 1].pfd = NULL;
881 warning (
"LoopSource: unremovable PollFD: %p (fd=%d)", pfd, pfd->fd);
885LoopSource::destroy ()
892 loop_->
cancel (source_id());
895LoopSource::~LoopSource ()
903DispatcherSource::DispatcherSource (
const DispatcherSlot &slot) :
907DispatcherSource::~DispatcherSource ()
915 return slot_ (state);
921 return slot_ (state);
927 return slot_ (state);
931DispatcherSource::destroy()
934 state.phase = state.DESTROY;
939USignalSource::USignalSource (
int8 signum,
const USignalSlot &slot) :
940 slot_ (slot), signum_ (signum)
942 const uint s = 128 + signum_;
947USignalSource::~USignalSource ()
958 const uint s = 128 + signum;
959 const uint index = s / 32;
960 const uint shift = s % 32;
961 usignals_notified[index] |= 1 << shift;
967 return usignals_notified[index_] & (1 << shift_);
973 return usignals_notified[index_] & (1 << shift_);
979 usignals_notified[index_] &= ~(1 << shift_);
980 return slot_ (signum_);
984USignalSource::destroy()
988write_uint (uint32_t i)
997 *(--c) =
'0' + (i % 10);
1001 memmove (&a[0], c, &a.back() + 1 - c);
1007USignalSource::install_sigaction (
int8 signum)
1010 action.sa_handler = [] (
int signum) {
1012 constexpr size_t N = 1024;
1013 char buf[N] = __FILE__
":";
1014 strncat (buf, &write_uint (__LINE__)[0], N);
1015 strncat (buf,
": sa_handler: signal=", N);
1016 strncat (buf, &write_uint (signum)[0], N);
1018 ::write (2, buf, strlen (buf));
1023 action.sa_flags = SA_NOMASK;
1030SigchldSource::SigchldSource (int64_t pid,
const SigchldSlot &slot) :
1031 slot_ (slot), pid_ (pid)
1035 action.sa_handler = [] (
int signum) {
1039 action.sa_flags = SA_NOMASK;
1044SigchldSource::~SigchldSource()
1050 return pid_ && sigchld_counter_ != sigchld_counter;
1056 return pid_ && sigchld_counter_ != sigchld_counter;
1063 sigchld_counter_ = sigchld_counter;
1066 const pid_t child_pid = wait4 (pid_, &status, WNOHANG,
nullptr);
1067 if (child_pid > 0) {
1068 slot_ (pid_, status);
1070 struct rusage ru {};
1071 printf (
" Child Pid %d user time: %ld.%06ld sec\n", child_pid, ru.ru_utime.tv_sec, ru.ru_utime.tv_usec);
1072 printf (
" System time: %ld.%06ld sec\n", ru.ru_stime.tv_sec, ru.ru_stime.tv_usec);
1073 printf (
" Max RSS: %ld KB\n", ru.ru_maxrss);
1074 printf (
" Page faults: %ld\n", ru.ru_minflt);
1075 printf (
" I/O operations: %ld\n", ru.ru_inblock + ru.ru_oublock);
1076 printf (
" Voluntary context switches: %ld\n", ru.ru_nvcsw);
1077 printf (
" Involuntary context switches: %ld\n", ru.ru_nivcsw);
1080 if (WIFEXITED (status) || WIFSIGNALED (status)) {
1091SigchldSource::destroy ()
1097TimedSource::TimedSource (
const VoidSlot &slot,
uint initial_interval_msecs,
uint repeat_interval_msecs) :
1099 interval_msecs_ (repeat_interval_msecs), first_interval_ (true),
1100 oneshot_ (true), void_slot_ (slot)
1103TimedSource::TimedSource (
const BoolSlot &slot,
uint initial_interval_msecs,
uint repeat_interval_msecs) :
1105 interval_msecs_ (repeat_interval_msecs), first_interval_ (true),
1106 oneshot_ (false), bool_slot_ (slot)
1114 if (!first_interval_)
1116 uint64 interval = interval_msecs_ * 1000ULL;
1121 return 0 == *timeout_usecs_p;
1133 bool repeat =
false;
1134 first_interval_ =
false;
1135 if (oneshot_ && void_slot_ != NULL)
1137 else if (!oneshot_ && bool_slot_ != NULL)
1138 repeat = bool_slot_ ();
1144TimedSource::~TimedSource ()
1147 void_slot_.~VoidSlot();
1149 bool_slot_.~BoolSlot();
1165PollFDSource::PollFDSource (
const BPfdSlot &slot,
int fd,
const String &mode) :
1166 pfd_ ((PollFD) { fd, 0, 0 }),
1167 never_close_ (strchr (mode.c_str(),
'C') != NULL),
1168 oneshot_ (
false), bool_poll_slot_ (slot)
1173PollFDSource::PollFDSource (
const VPfdSlot &slot,
int fd,
const String &mode) :
1174 pfd_ ((PollFD) { fd, 0, 0 }),
1175 never_close_ (strchr (mode.c_str(),
'C') != NULL),
1176 oneshot_ (
true), void_poll_slot_ (slot)
1182PollFDSource::construct (
const String &mode)
1191 const long lflags =
fcntl (pfd_.fd, F_GETFL, 0);
1192 long nflags = lflags;
1193 if (strchr (mode.c_str(),
'b'))
1194 nflags &= ~long (O_NONBLOCK);
1195 else if (strchr (mode.c_str(),
'B'))
1196 nflags |= O_NONBLOCK;
1197 if (nflags != lflags)
1201 err =
fcntl (pfd_.fd, F_SETFL, nflags);
1202 while (err < 0 && (errno == EINTR || errno == EAGAIN));
1217 return pfd_.fd < 0 || pfd_.revents != 0;
1223 bool keep_alive = !oneshot_;
1224 if (oneshot_ && void_poll_slot_ != NULL)
1225 void_poll_slot_ (pfd_);
1226 else if (!oneshot_ && bool_poll_slot_ != NULL)
1227 keep_alive = bool_poll_slot_ (pfd_);
1231 if (!never_close_ && pfd_.fd >= 0)
1239PollFDSource::destroy()
1242 if (!never_close_ && pfd_.fd >= 0)
1247PollFDSource::~PollFDSource ()
1250 void_poll_slot_.~VPfdSlot();
1252 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.
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