38static_assert (
sizeof (PollFD) ==
sizeof (
struct pollfd));
39static_assert (offsetof (PollFD, fd) == offsetof (
struct pollfd, fd));
40static_assert (
sizeof (((PollFD*) 0)->fd) ==
sizeof (((
struct pollfd*) 0)->fd));
41static_assert (offsetof (PollFD, events) == offsetof (
struct pollfd, events));
42static_assert (
sizeof (((PollFD*) 0)->events) ==
sizeof (((
struct pollfd*) 0)->events));
43static_assert (offsetof (PollFD, revents) == offsetof (
struct pollfd, revents));
44static_assert (
sizeof (((PollFD*) 0)->revents) ==
sizeof (((
struct pollfd*) 0)->revents));
47static volatile int global_id_counter = 65536;
51 uint id = __sync_fetch_and_add (&global_id_counter, +1);
53 fatal_error (
"EventLoop: id counter overflow, please report");
71 template<
class D>
void swap (D &a, D &b) { D t = a; a = b; b = t; }
73 typedef Data* iterator;
74 QuickArray (
uint n_reserved, Data *reserved) : data_ (reserved), n_elements_ (0), n_reserved_ (n_reserved), reserved_ (reserved) {}
76 uint size ()
const {
return n_elements_; }
77 uint capacity ()
const {
return std::max (n_elements_, n_reserved_); }
78 bool empty ()
const {
return n_elements_ == 0; }
79 Data* data ()
const {
return data_; }
80 Data& operator[] (
uint n) {
return data_[n]; }
81 const Data& operator[] (
uint n)
const {
return data_[n]; }
82 iterator begin () {
return &data_[0]; }
83 iterator end () {
return &data_[n_elements_]; }
84 void shrink (
uint n) { n_elements_ =
std::min (n_elements_, n); }
87 swap (data_, o.data_);
88 swap (n_elements_, o.n_elements_);
89 swap (n_reserved_, o.n_reserved_);
90 swap (reserved_, o.reserved_);
92 void push (
const Data &d)
94 const uint idx = n_elements_;
106 const size_t sz = n *
sizeof (Data);
107 const bool migrate_reserved =
UNLIKELY (data_ == reserved_);
108 Data *mem = (Data*) (migrate_reserved ?
malloc (sz) :
realloc (data_, sz));
111 if (migrate_reserved)
113 memcpy (mem, data_, n_elements_ *
sizeof (Data));
129EventLoop::EventLoop (
MainLoop &main) :
130 main_loop_ (&main), dispatch_priority_ (0), primary_ (false)
132 poll_sources_.reserve (7);
137EventLoop::~EventLoop ()
144EventLoop::find_first_L()
146 static EventSourceP null_source;
147 return sources_.
empty() ? null_source : sources_[0];
151EventLoop::find_source_L (
uint id)
153 for (SourceList::iterator lit = sources_.
begin(); lit != sources_.
end(); lit++)
154 if (
id == (*lit)->id_)
156 static EventSourceP null_source;
161EventLoop::has_primary_L()
165 for (SourceList::iterator lit = sources_.
begin(); lit != sources_.
end(); lit++)
166 if ((*lit)->primary())
175 return has_primary_L();
179EventLoop::flag_primary (
bool on)
182 const bool was_primary = primary_;
184 if (primary_ != was_primary)
195static const int16 UNDEFINED_PRIORITY = -32768;
200 static_assert (UNDEFINED_PRIORITY < 1,
"");
204 source->loop_ =
this;
205 source->id_ = alloc_id();
206 source->loop_state_ = WAITING;
207 source->priority_ = priority;
221 source->loop_ = NULL;
222 source->loop_state_ = WAITING;
223 auto pos = find (sources_.
begin(), sources_.
end(), source);
225 sources_.
erase (pos);
226 release_id (source->id_);
241 remove_source_Lm (source);
261 const bool removal =
try_remove (*id_pointer);
270 warning (
"%s: failed to remove loop source: %u", __func__,
id);
282 auto once_handler = [vfunc,once_id]() { *once_id = 0; vfunc(); };
283 EventSourceP source = TimedSource::create (once_handler, delay_ms, 0);
284 source->loop_ =
this;
285 source->id_ = alloc_id();
286 source->loop_state_ = WAITING;
287 source->priority_ = priority;
294 remove_source_Lm (source);
299 *once_id = source->id_;
302 warning (
"%s: failed to remove loop source: %u", __func__, once_id);
316EventLoop::kill_sources_Lm()
323 remove_source_Lm (source);
346 EventLoopP main_loop_guard = shared_ptr_cast<EventLoop*> (main_loop_);
348 if (
this != main_loop_)
349 main_loop_->kill_loop_Lm (*
this);
351 main_loop_->kill_loops_Lm();
359 main_loop_->wakeup_poll();
363MainLoop::MainLoop() :
365 rr_index_ (0), running_ (false), has_quit_ (false), quit_code_ (0), gcontext_ (NULL)
368 const int err = eventfd_.open();
370 fatal_error (
"MainLoop: failed to create wakeup pipe: %s", strerror (-err));
397MainLoop::wakeup_poll()
404MainLoop::add_loop_L (EventLoop &loop)
407 loops_.push_back (shared_ptr_cast<EventLoop> (&loop));
412MainLoop::kill_loop_Lm (EventLoop &loop)
415 loop.kill_sources_Lm();
418 loop.main_loop_ = NULL;
420 [&loop] (EventLoopP &lp) { return lp.get() == &loop; });
428 if (it != loops_.end())
435MainLoop::kill_loops_Lm()
437 while (loops_.size() > 1 || loops_[0].get() !=
this)
439 EventLoopP loop = loops_[0].get() !=
this ? loops_[0] : loops_[loops_.size() - 1];
440 kill_loop_Lm (*loop);
442 kill_loop_Lm (*
this);
448 EventLoopP main_loop_guard = shared_ptr_cast<EventLoop> (
this);
451 running_ = !has_quit_;
453 iterate_loops_Lm (state,
true,
true);
454 const int last_quit_code = quit_code_;
458 return last_quit_code;
472 quit_code_ = quit_code;
479MainLoop::finishable_L()
482 bool found_primary = primary_;
483 for (
size_t i = 0; !found_primary && i < loops_.size(); i++)
484 if (loops_[i]->has_primary_L())
485 found_primary =
true;
486 return !found_primary;
493 return finishable_L();
509 EventLoopP main_loop_guard = shared_ptr_cast<EventLoop> (
this);
512 const bool was_running = running_;
514 const bool sources_pending = iterate_loops_Lm (state, may_block,
true);
515 running_ = was_running && !has_quit_;
516 return sources_pending;
522 EventLoopP main_loop_guard = shared_ptr_cast<EventLoop> (
this);
525 const bool was_running = running_;
528 if (!iterate_loops_Lm (state,
false,
true))
530 running_ = was_running && !has_quit_;
538 EventLoopP main_loop_guard = shared_ptr_cast<EventLoop> (
this);
539 return iterate_loops_Lm (state,
false,
false);
547 if (glib_main_context)
551 if (!g_main_context_acquire (glib_main_context))
553 gcontext_ = g_main_context_ref (glib_main_context);
557 glib_main_context = gcontext_;
559 g_main_context_release (glib_main_context);
560 g_main_context_unref (glib_main_context);
572 GPollFD *gpfd = (GPollFD*) pfd;
573 static_assert (
sizeof (GPollFD) ==
sizeof (
PollFD),
"");
574 static_assert (
sizeof (gpfd->fd) ==
sizeof (pfd->fd),
"");
575 static_assert (
sizeof (gpfd->events) ==
sizeof (pfd->events),
"");
576 static_assert (
sizeof (gpfd->revents) ==
sizeof (pfd->revents),
"");
577 static_assert (offsetof (GPollFD, fd) == offsetof (
PollFD, fd),
"");
578 static_assert (offsetof (GPollFD, events) == offsetof (
PollFD, events),
"");
579 static_assert (offsetof (GPollFD, revents) == offsetof (
PollFD, revents),
"");
595EventLoop::unpoll_sources_U()
602EventLoop::collect_sources_Lm (LoopState &state)
613 if (
UNLIKELY (!state.seen_primary && primary_))
614 state.seen_primary =
true;
615 EventSourceP* arraymem[7];
616 QuickSourcePArray poll_candidates (
ARRAY_SIZE (arraymem), arraymem);
618 dispatch_priority_ = UNDEFINED_PRIORITY;
619 for (SourceList::iterator lit = sources_.
begin(); lit != sources_.
end(); lit++)
621 EventSource &source = **lit;
622 if (
UNLIKELY (!state.seen_primary && source.primary_))
623 state.seen_primary =
true;
624 if (source.loop_ !=
this ||
625 (source.dispatching_ && !source.may_recurse_))
627 if (source.priority_ > dispatch_priority_ &&
628 source.loop_state_ == NEEDS_DISPATCH)
629 dispatch_priority_ = source.priority_;
630 if (source.priority_ > dispatch_priority_ ||
631 (source.priority_ == dispatch_priority_ &&
632 source.loop_state_ == NEEDS_DISPATCH))
633 poll_candidates.push (&*lit);
637 for (
size_t i = 0; i < poll_candidates.size(); i++)
638 if ((*poll_candidates[i])->priority_ > dispatch_priority_ ||
639 ((*poll_candidates[i])->priority_ == dispatch_priority_ &&
640 (*poll_candidates[i])->loop_state_ == NEEDS_DISPATCH))
641 poll_sources_.
push_back (*poll_candidates[i]);
649EventLoop::prepare_sources_Lm (LoopState &state, QuickPfdArray &pfda)
653 for (
auto lit = poll_sources_.
begin(); lit != poll_sources_.
end(); lit++)
655 EventSource &source = **lit;
656 if (source.loop_ !=
this)
660 const bool need_dispatch = source.prepare (state, &timeout);
662 if (source.loop_ !=
this)
666 dispatch_priority_ =
std::max (dispatch_priority_, source.priority_);
667 source.loop_state_ = NEEDS_DISPATCH;
670 source.loop_state_ = PREPARED;
672 state.timeout_usecs =
std::min (state.timeout_usecs, timeout);
673 uint npfds = source.n_pfds();
674 for (
uint i = 0; i < npfds; i++)
675 if (source.pfds_[i].pfd->fd >= 0)
677 uint idx = pfda.size();
678 source.pfds_[i].idx = idx;
679 pfda.push (*source.pfds_[i].pfd);
680 pfda[idx].revents = 0;
683 source.pfds_[i].idx = 4294967295U;
685 return dispatch_priority_ > UNDEFINED_PRIORITY;
689EventLoop::check_sources_Lm (LoopState &state,
const QuickPfdArray &pfda)
693 for (
auto lit = poll_sources_.
begin(); lit != poll_sources_.
end(); lit++)
695 EventSource &source = **lit;
696 if (source.loop_ !=
this &&
697 source.loop_state_ != PREPARED)
699 uint npfds = source.n_pfds();
700 for (
uint i = 0; i < npfds; i++)
702 uint idx = source.pfds_[i].idx;
703 if (idx < pfda.size() &&
704 source.pfds_[i].pfd->fd == pfda[idx].fd)
705 source.pfds_[i].pfd->revents = pfda[idx].revents;
707 source.pfds_[i].idx = 4294967295U;
710 bool need_dispatch = source.check (state);
712 if (source.loop_ !=
this)
716 dispatch_priority_ =
std::max (dispatch_priority_, source.priority_);
717 source.loop_state_ = NEEDS_DISPATCH;
720 source.loop_state_ = WAITING;
722 return dispatch_priority_ > UNDEFINED_PRIORITY;
726EventLoop::dispatch_source_Lm (LoopState &state)
730 EventSourceP dispatch_source = NULL;
731 for (
auto lit = poll_sources_.
begin(); lit != poll_sources_.
end(); lit++)
733 EventSourceP &source = *lit;
734 if (source->loop_ ==
this &&
735 source->priority_ == dispatch_priority_ &&
736 source->loop_state_ == NEEDS_DISPATCH)
738 dispatch_source = source;
742 dispatch_priority_ = UNDEFINED_PRIORITY;
746 dispatch_source->loop_state_ = WAITING;
747 const bool old_was_dispatching = dispatch_source->was_dispatching_;
748 dispatch_source->was_dispatching_ = dispatch_source->dispatching_;
749 dispatch_source->dispatching_ =
true;
751 const bool keep_alive = dispatch_source->dispatch (state);
753 dispatch_source->dispatching_ = dispatch_source->was_dispatching_;
754 dispatch_source->was_dispatching_ = old_was_dispatching;
755 if (dispatch_source->loop_ ==
this && !keep_alive)
756 remove_source_Lm (dispatch_source);
761MainLoop::iterate_loops_Lm (LoopState &state,
bool may_block,
bool may_dispatch)
765 PollFD reserved_pfd_mem[7];
766 QuickPfdArray pfda (
ARRAY_SIZE (reserved_pfd_mem), reserved_pfd_mem);
769 const uint wakeup_idx = 0;
772 const size_t nrloops = loops_.size();
773 EventLoopP loops[nrloops];
774 for (
size_t i = 0; i < nrloops; i++)
775 loops[i] = loops_[i];
777 state.phase = state.COLLECT;
778 state.seen_primary =
false;
779 for (
size_t i = 0; i < nrloops; i++)
780 loops[i]->collect_sources_Lm (state);
782 bool any_dispatchable =
false;
783 state.phase = state.PREPARE;
786 bool dispatchable[nrloops + 1];
787 for (
size_t i = 0; i < nrloops; i++)
789 dispatchable[i] = loops[i]->prepare_sources_Lm (state, pfda);
790 any_dispatchable |= dispatchable[i];
793 ASE_UNUSED
const int gfirstfd = pfda.size();
798 dispatchable[nrloops] = g_main_context_prepare (gcontext_, &gpriority) != 0;
799 any_dispatchable |= dispatchable[nrloops];
801 pfda.resize (pfda.capacity());
802 int gnfds = g_main_context_query (gcontext_, gpriority, >imeout, mk_gpollfd (&pfda[gfirstfd]), pfda.size() - gfirstfd);
803 while (gnfds >= 0 &&
size_t (gnfds) != pfda.size() - gfirstfd)
805 pfda.resize (gfirstfd + gnfds);
807 gnfds = g_main_context_query (gcontext_, gpriority, >imeout, mk_gpollfd (&pfda[gfirstfd]), pfda.size() - gfirstfd);
810 state.timeout_usecs =
MIN (state.timeout_usecs, gtimeout *
int64 (1000));
814 dispatchable[nrloops] =
false;
816 int64 timeout_msecs = state.timeout_usecs / 1000;
817 if (state.timeout_usecs > 0 && timeout_msecs <= 0)
819 if (!may_block || any_dispatchable)
821 state.timeout_usecs = 0;
825 presult =
poll ((
struct pollfd*) &pfda[0], pfda.size(),
std::min (timeout_msecs,
int64 (2147483647)));
826 while (presult < 0 && errno == EAGAIN);
828 if (presult < 0 && errno != EINTR)
829 warning (
"MainLoop: poll() failed: %s",
strerror());
830 else if (pfda[wakeup_idx].revents)
833 state.phase = state.CHECK;
835 int16 max_dispatch_priority = -32768;
836 for (
size_t i = 0; i < nrloops; i++)
838 dispatchable[i] |= loops[i]->check_sources_Lm (state, pfda);
839 if (!dispatchable[i])
841 any_dispatchable =
true;
842 max_dispatch_priority =
std::max (max_dispatch_priority, loops[i]->dispatch_priority_);
844 bool priority_ascension =
false;
846 priority_ascension =
true;
851 dispatchable[nrloops] = g_main_context_check (gcontext_, gpriority, mk_gpollfd (&pfda[gfirstfd]), pfda.size() - gfirstfd);
852 any_dispatchable |= dispatchable[nrloops];
856 if (may_dispatch && any_dispatchable)
858 const size_t gloop =
ASE_UNLIKELY (gcontext_) && dispatchable[nrloops] ? 1 : 0;
859 const size_t maxloops = nrloops + gloop;
863 index = rr_index_++ % maxloops;
864 if (!dispatchable[index])
866 if (index < nrloops && loops[index]->dispatch_priority_ < max_dispatch_priority)
868 if (priority_ascension && index >= nrloops)
872 state.phase = state.DISPATCH;
873 if (index >= nrloops)
876 g_main_context_dispatch (gcontext_);
880 loops[index]->dispatch_source_Lm (state);
883 state.phase = state.NONE;
885 for (
size_t i = 0; i < nrloops; i++)
887 loops[i]->unpoll_sources_U();
891 return any_dispatchable;
910 this->add_loop_L (*sub_loop);
915EventSource::EventSource () :
919 priority_ (UNDEFINED_PRIORITY),
923 was_dispatching_ (0),
928EventSource::n_pfds ()
958 primary_ = is_primary;
964 return dispatching_ && was_dispatching_;
970 const uint idx = n_pfds();
971 uint npfds = idx + 1;
972 pfds_ = (typeof (pfds_))
realloc (pfds_,
sizeof (pfds_[0]) * (npfds + 1));
974 fatal_error (
"EventSource: out of memory");
975 pfds_[npfds].idx = 4294967295U;
976 pfds_[npfds].pfd = NULL;
977 pfds_[idx].idx = 4294967295U;
978 pfds_[idx].pfd = pfd;
984 uint idx, npfds = n_pfds();
985 for (idx = 0; idx < npfds; idx++)
986 if (pfds_[idx].pfd == pfd)
990 pfds_[idx].idx = 4294967295U;
991 pfds_[idx].pfd = pfds_[npfds - 1].pfd;
992 pfds_[idx].idx = pfds_[npfds - 1].idx;
993 pfds_[npfds - 1].idx = 4294967295U;
994 pfds_[npfds - 1].pfd = NULL;
997 warning (
"EventSource: unremovable PollFD: %p (fd=%d)", pfd, pfd->fd);
1001EventSource::destroy ()
1011EventSource::~EventSource ()
1019DispatcherSource::DispatcherSource (
const DispatcherSlot &slot) :
1023DispatcherSource::~DispatcherSource ()
1031 return slot_ (state);
1037 return slot_ (state);
1043 return slot_ (state);
1047DispatcherSource::destroy()
1050 state.phase = state.DESTROY;
1055USignalSource::USignalSource (
int8 signum,
const USignalSlot &slot) :
1056 slot_ (slot), signum_ (signum)
1058 const uint s = 128 + signum_;
1063USignalSource::~USignalSource ()
1074 const uint s = 128 + signum;
1075 const uint index = s / 32;
1076 const uint shift = s % 32;
1077 usignals_notified[index] |= 1 << shift;
1083 return usignals_notified[index_] & (1 << shift_);
1089 return usignals_notified[index_] & (1 << shift_);
1095 usignals_notified[index_] &= ~(1 << shift_);
1096 return slot_ (signum_);
1100USignalSource::destroy()
1104write_uint (uint32_t i)
1107 char *c = &a.back();
1110 *c =
'0' + (i % 10);
1113 *(--c) =
'0' + (i % 10);
1117 memmove (&a[0], c, &a.back() + 1 - c);
1123USignalSource::install_sigaction (
int8 signum)
1126 action.sa_handler = [] (
int signum) {
1128 constexpr size_t N = 1024;
1129 char buf[N] = __FILE__
":";
1130 strncat (buf, &write_uint (__LINE__)[0], N);
1131 strncat (buf,
": sa_handler: signal=", N);
1132 strncat (buf, &write_uint (signum)[0], N);
1134 ::write (2, buf, strlen (buf));
1139 action.sa_flags = SA_NOMASK;
1146SigchldSource::SigchldSource (int64_t pid,
const SigchldSlot &slot) :
1147 slot_ (slot), pid_ (pid)
1151 action.sa_handler = [] (
int signum) {
1155 action.sa_flags = SA_NOMASK;
1160SigchldSource::~SigchldSource()
1166 return pid_ && sigchld_counter_ != sigchld_counter;
1172 return pid_ && sigchld_counter_ != sigchld_counter;
1179 sigchld_counter_ = sigchld_counter;
1182 const pid_t child_pid = wait4 (pid_, &status, WNOHANG,
nullptr);
1183 if (child_pid > 0) {
1184 slot_ (pid_, status);
1186 struct rusage ru {};
1187 printf (
" Child Pid %d user time: %ld.%06ld sec\n", child_pid, ru.ru_utime.tv_sec, ru.ru_utime.tv_usec);
1188 printf (
" System time: %ld.%06ld sec\n", ru.ru_stime.tv_sec, ru.ru_stime.tv_usec);
1189 printf (
" Max RSS: %ld KB\n", ru.ru_maxrss);
1190 printf (
" Page faults: %ld\n", ru.ru_minflt);
1191 printf (
" I/O operations: %ld\n", ru.ru_inblock + ru.ru_oublock);
1192 printf (
" Voluntary context switches: %ld\n", ru.ru_nvcsw);
1193 printf (
" Involuntary context switches: %ld\n", ru.ru_nivcsw);
1196 if (WIFEXITED (status) || WIFSIGNALED (status)) {
1207SigchldSource::destroy ()
1213TimedSource::TimedSource (
const VoidSlot &slot,
uint initial_interval_msecs,
uint repeat_interval_msecs) :
1215 interval_msecs_ (repeat_interval_msecs), first_interval_ (true),
1216 oneshot_ (true), void_slot_ (slot)
1219TimedSource::TimedSource (
const BoolSlot &slot,
uint initial_interval_msecs,
uint repeat_interval_msecs) :
1221 interval_msecs_ (repeat_interval_msecs), first_interval_ (true),
1222 oneshot_ (false), bool_slot_ (slot)
1230 if (!first_interval_)
1232 uint64 interval = interval_msecs_ * 1000ULL;
1237 return 0 == *timeout_usecs_p;
1249 bool repeat =
false;
1250 first_interval_ =
false;
1251 if (oneshot_ && void_slot_ != NULL)
1253 else if (!oneshot_ && bool_slot_ != NULL)
1254 repeat = bool_slot_ ();
1260TimedSource::~TimedSource ()
1263 void_slot_.~VoidSlot();
1265 bool_slot_.~BoolSlot();
1281PollFDSource::PollFDSource (
const BPfdSlot &slot,
int fd,
const String &mode) :
1282 pfd_ ((PollFD) { fd, 0, 0 }),
1283 never_close_ (strchr (mode.c_str(),
'C') != NULL),
1284 oneshot_ (
false), bool_poll_slot_ (slot)
1289PollFDSource::PollFDSource (
const VPfdSlot &slot,
int fd,
const String &mode) :
1290 pfd_ ((PollFD) { fd, 0, 0 }),
1291 never_close_ (strchr (mode.c_str(),
'C') != NULL),
1292 oneshot_ (
true), void_poll_slot_ (slot)
1298PollFDSource::construct (
const String &mode)
1307 const long lflags =
fcntl (pfd_.fd, F_GETFL, 0);
1308 long nflags = lflags;
1309 if (strchr (mode.c_str(),
'b'))
1310 nflags &= ~long (O_NONBLOCK);
1311 else if (strchr (mode.c_str(),
'B'))
1312 nflags |= O_NONBLOCK;
1313 if (nflags != lflags)
1317 err =
fcntl (pfd_.fd, F_SETFL, nflags);
1318 while (err < 0 && (errno == EINTR || errno == EAGAIN));
1333 return pfd_.fd < 0 || pfd_.revents != 0;
1339 bool keep_alive = !oneshot_;
1340 if (oneshot_ && void_poll_slot_ != NULL)
1341 void_poll_slot_ (pfd_);
1342 else if (!oneshot_ && bool_poll_slot_ != NULL)
1343 keep_alive = bool_poll_slot_ (pfd_);
1347 if (!never_close_ && pfd_.fd >= 0)
1355PollFDSource::destroy()
1358 if (!never_close_ && pfd_.fd >= 0)
1363PollFDSource::~PollFDSource ()
1366 void_poll_slot_.~VPfdSlot();
1368 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 object, polling for events and executing callbacks in accordance.
bool has_primary(void)
Indicates whether loop contains primary sources.
void wakeup()
Wakeup loop from polling.
void destroy_loop(void)
Remove all sources from a loop and prevent any further execution.
bool clear_source(uint *id_pointer)
Remove source if id_pointer and *id_pointer are valid.
void remove(uint id)
Removes a source from loop, the source must be present.
static const int16 PRIORITY_CEILING
Internal upper limit, don't use.
bool exec_once(uint delay_ms, uint *once_id, const VoidSlot &vfunc, int priority=PRIORITY_NORMAL)
Execute a callback once on SIGCHLD for pid.
MainLoop * main_loop() const
Get the main loop for this loop.
static const int16 PRIORITY_ASCENT
Threshold for priorization across different loops.
bool try_remove(uint id)
Tries to remove a source, returns if successfull.
uint add(EventSourceP loop_source, int priority=PRIORITY_NORMAL)
Adds a new source to the loop with custom priority.
bool primary() const
Indicate whether this source is primary.
void add_poll(PollFD *const pfd)
Add a PollFD descriptors for poll(2) and check().
void loop_remove()
Remove this source from its event loop if any.
void remove_poll(PollFD *const pfd)
Remove a previously added PollFD.
bool recursion() const
Indicates wether the source is currently in recursion.
bool may_recurse() const
Indicates if this source may recurse.
An EventLoop implementation that offers public API for running the loop.
EventLoopP create_sub_loop()
Creates a new event loop that is run as part of this main loop.
void quit(int quit_code=0)
Cause run() to return with quit_code.
static MainLoopP create()
Create a MainLoop shared pointer handle.
bool pending()
Check if iterate() needs to be called for dispatching.
int run()
Run loop iterations until a call to quit() or finishable becomes true.
bool set_g_main_context(GlibGMainContext *glib_main_context)
Set context to integrate with a GLib GMainContext loop.
void iterate_pending()
Call iterate() until no immediate dispatching is needed.
bool running()
Indicates if quit() has been called already.
bool finishable()
Indicates wether this loop has no primary sources left to process.
std::mutex & mutex()
Provide access to the mutex associated with this main loop.
bool iterate(bool block)
Perform one loop iteration and return whether more iterations are needed.
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_UNLIKELY(expr)
Compiler hint to optimize for expr evaluating to false.
#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 ARRAY_SIZE(array)
Yield the number of C array elements.
#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.
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.
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