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);
251 const bool removal =
try_remove (*id_pointer);
260 warning (
"%s: failed to remove loop source: %u", __func__,
id);
272 auto once_handler = [vfunc,once_id]() { *once_id = 0; vfunc(); };
273 EventSourceP source = TimedSource::create (once_handler, delay_ms, 0);
274 source->loop_ =
this;
275 source->id_ = alloc_id();
276 source->loop_state_ = WAITING;
277 source->priority_ = priority;
284 remove_source_Lm (source);
289 *once_id = source->id_;
292 warning (
"%s: failed to remove loop source: %u", __func__, once_id);
306EventLoop::kill_sources_Lm()
313 remove_source_Lm (source);
336 EventLoopP main_loop_guard = shared_ptr_cast<EventLoop*> (main_loop_);
338 if (
this != main_loop_)
339 main_loop_->kill_loop_Lm (*
this);
341 main_loop_->kill_loops_Lm();
349 main_loop_->wakeup_poll();
353MainLoop::MainLoop() :
355 rr_index_ (0), running_ (false), has_quit_ (false), quit_code_ (0), gcontext_ (NULL)
358 const int err = eventfd_.open();
360 fatal_error (
"MainLoop: failed to create wakeup pipe: %s", strerror (-err));
387MainLoop::wakeup_poll()
394MainLoop::add_loop_L (EventLoop &loop)
397 loops_.push_back (shared_ptr_cast<EventLoop> (&loop));
402MainLoop::kill_loop_Lm (EventLoop &loop)
405 loop.kill_sources_Lm();
408 loop.main_loop_ = NULL;
410 [&loop] (EventLoopP &lp) { return lp.get() == &loop; });
418 if (it != loops_.end())
425MainLoop::kill_loops_Lm()
427 while (loops_.size() > 1 || loops_[0].get() !=
this)
429 EventLoopP loop = loops_[0].get() !=
this ? loops_[0] : loops_[loops_.size() - 1];
430 kill_loop_Lm (*loop);
432 kill_loop_Lm (*
this);
438 EventLoopP main_loop_guard = shared_ptr_cast<EventLoop> (
this);
441 running_ = !has_quit_;
443 iterate_loops_Lm (state,
true,
true);
444 const int last_quit_code = quit_code_;
448 return last_quit_code;
462 quit_code_ = quit_code;
469MainLoop::finishable_L()
472 bool found_primary = primary_;
473 for (
size_t i = 0; !found_primary && i < loops_.size(); i++)
474 if (loops_[i]->has_primary_L())
475 found_primary =
true;
476 return !found_primary;
483 return finishable_L();
499 EventLoopP main_loop_guard = shared_ptr_cast<EventLoop> (
this);
502 const bool was_running = running_;
504 const bool sources_pending = iterate_loops_Lm (state, may_block,
true);
505 running_ = was_running && !has_quit_;
506 return sources_pending;
512 EventLoopP main_loop_guard = shared_ptr_cast<EventLoop> (
this);
515 const bool was_running = running_;
518 if (!iterate_loops_Lm (state,
false,
true))
520 running_ = was_running && !has_quit_;
528 EventLoopP main_loop_guard = shared_ptr_cast<EventLoop> (
this);
529 return iterate_loops_Lm (state,
false,
false);
537 if (glib_main_context)
541 if (!g_main_context_acquire (glib_main_context))
543 gcontext_ = g_main_context_ref (glib_main_context);
547 glib_main_context = gcontext_;
549 g_main_context_release (glib_main_context);
550 g_main_context_unref (glib_main_context);
562 GPollFD *gpfd = (GPollFD*) pfd;
563 static_assert (
sizeof (GPollFD) ==
sizeof (
PollFD),
"");
564 static_assert (
sizeof (gpfd->fd) ==
sizeof (pfd->fd),
"");
565 static_assert (
sizeof (gpfd->events) ==
sizeof (pfd->events),
"");
566 static_assert (
sizeof (gpfd->revents) ==
sizeof (pfd->revents),
"");
567 static_assert (offsetof (GPollFD, fd) == offsetof (
PollFD, fd),
"");
568 static_assert (offsetof (GPollFD, events) == offsetof (
PollFD, events),
"");
569 static_assert (offsetof (GPollFD, revents) == offsetof (
PollFD, revents),
"");
585EventLoop::unpoll_sources_U()
592EventLoop::collect_sources_Lm (LoopState &state)
603 if (
UNLIKELY (!state.seen_primary && primary_))
604 state.seen_primary =
true;
605 EventSourceP* arraymem[7];
606 QuickSourcePArray poll_candidates (
ARRAY_SIZE (arraymem), arraymem);
608 dispatch_priority_ = UNDEFINED_PRIORITY;
609 for (SourceList::iterator lit = sources_.
begin(); lit != sources_.
end(); lit++)
611 EventSource &source = **lit;
612 if (
UNLIKELY (!state.seen_primary && source.primary_))
613 state.seen_primary =
true;
614 if (source.loop_ !=
this ||
615 (source.dispatching_ && !source.may_recurse_))
617 if (source.priority_ > dispatch_priority_ &&
618 source.loop_state_ == NEEDS_DISPATCH)
619 dispatch_priority_ = source.priority_;
620 if (source.priority_ > dispatch_priority_ ||
621 (source.priority_ == dispatch_priority_ &&
622 source.loop_state_ == NEEDS_DISPATCH))
623 poll_candidates.push (&*lit);
627 for (
size_t i = 0; i < poll_candidates.size(); i++)
628 if ((*poll_candidates[i])->priority_ > dispatch_priority_ ||
629 ((*poll_candidates[i])->priority_ == dispatch_priority_ &&
630 (*poll_candidates[i])->loop_state_ == NEEDS_DISPATCH))
631 poll_sources_.
push_back (*poll_candidates[i]);
639EventLoop::prepare_sources_Lm (LoopState &state, QuickPfdArray &pfda)
643 for (
auto lit = poll_sources_.
begin(); lit != poll_sources_.
end(); lit++)
645 EventSource &source = **lit;
646 if (source.loop_ !=
this)
650 const bool need_dispatch = source.prepare (state, &timeout);
652 if (source.loop_ !=
this)
656 dispatch_priority_ =
std::max (dispatch_priority_, source.priority_);
657 source.loop_state_ = NEEDS_DISPATCH;
660 source.loop_state_ = PREPARED;
662 state.timeout_usecs =
std::min (state.timeout_usecs, timeout);
663 uint npfds = source.n_pfds();
664 for (
uint i = 0; i < npfds; i++)
665 if (source.pfds_[i].pfd->fd >= 0)
667 uint idx = pfda.size();
668 source.pfds_[i].idx = idx;
669 pfda.push (*source.pfds_[i].pfd);
670 pfda[idx].revents = 0;
673 source.pfds_[i].idx = 4294967295U;
675 return dispatch_priority_ > UNDEFINED_PRIORITY;
679EventLoop::check_sources_Lm (LoopState &state,
const QuickPfdArray &pfda)
683 for (
auto lit = poll_sources_.
begin(); lit != poll_sources_.
end(); lit++)
685 EventSource &source = **lit;
686 if (source.loop_ !=
this &&
687 source.loop_state_ != PREPARED)
689 uint npfds = source.n_pfds();
690 for (
uint i = 0; i < npfds; i++)
692 uint idx = source.pfds_[i].idx;
693 if (idx < pfda.size() &&
694 source.pfds_[i].pfd->fd == pfda[idx].fd)
695 source.pfds_[i].pfd->revents = pfda[idx].revents;
697 source.pfds_[i].idx = 4294967295U;
700 bool need_dispatch = source.check (state);
702 if (source.loop_ !=
this)
706 dispatch_priority_ =
std::max (dispatch_priority_, source.priority_);
707 source.loop_state_ = NEEDS_DISPATCH;
710 source.loop_state_ = WAITING;
712 return dispatch_priority_ > UNDEFINED_PRIORITY;
716EventLoop::dispatch_source_Lm (LoopState &state)
720 EventSourceP dispatch_source = NULL;
721 for (
auto lit = poll_sources_.
begin(); lit != poll_sources_.
end(); lit++)
723 EventSourceP &source = *lit;
724 if (source->loop_ ==
this &&
725 source->priority_ == dispatch_priority_ &&
726 source->loop_state_ == NEEDS_DISPATCH)
728 dispatch_source = source;
732 dispatch_priority_ = UNDEFINED_PRIORITY;
736 dispatch_source->loop_state_ = WAITING;
737 const bool old_was_dispatching = dispatch_source->was_dispatching_;
738 dispatch_source->was_dispatching_ = dispatch_source->dispatching_;
739 dispatch_source->dispatching_ =
true;
741 const bool keep_alive = dispatch_source->dispatch (state);
743 dispatch_source->dispatching_ = dispatch_source->was_dispatching_;
744 dispatch_source->was_dispatching_ = old_was_dispatching;
745 if (dispatch_source->loop_ ==
this && !keep_alive)
746 remove_source_Lm (dispatch_source);
751MainLoop::iterate_loops_Lm (LoopState &state,
bool may_block,
bool may_dispatch)
755 PollFD reserved_pfd_mem[7];
756 QuickPfdArray pfda (
ARRAY_SIZE (reserved_pfd_mem), reserved_pfd_mem);
759 const uint wakeup_idx = 0;
762 const size_t nrloops = loops_.size();
763 EventLoopP loops[nrloops];
764 for (
size_t i = 0; i < nrloops; i++)
765 loops[i] = loops_[i];
767 state.phase = state.COLLECT;
768 state.seen_primary =
false;
769 for (
size_t i = 0; i < nrloops; i++)
770 loops[i]->collect_sources_Lm (state);
772 bool any_dispatchable =
false;
773 state.phase = state.PREPARE;
776 bool dispatchable[nrloops + 1];
777 for (
size_t i = 0; i < nrloops; i++)
779 dispatchable[i] = loops[i]->prepare_sources_Lm (state, pfda);
780 any_dispatchable |= dispatchable[i];
783 ASE_UNUSED
const int gfirstfd = pfda.size();
788 dispatchable[nrloops] = g_main_context_prepare (gcontext_, &gpriority) != 0;
789 any_dispatchable |= dispatchable[nrloops];
791 pfda.resize (pfda.capacity());
792 int gnfds = g_main_context_query (gcontext_, gpriority, >imeout, mk_gpollfd (&pfda[gfirstfd]), pfda.size() - gfirstfd);
793 while (gnfds >= 0 &&
size_t (gnfds) != pfda.size() - gfirstfd)
795 pfda.resize (gfirstfd + gnfds);
797 gnfds = g_main_context_query (gcontext_, gpriority, >imeout, mk_gpollfd (&pfda[gfirstfd]), pfda.size() - gfirstfd);
800 state.timeout_usecs =
MIN (state.timeout_usecs, gtimeout *
int64 (1000));
804 dispatchable[nrloops] =
false;
806 int64 timeout_msecs = state.timeout_usecs / 1000;
807 if (state.timeout_usecs > 0 && timeout_msecs <= 0)
809 if (!may_block || any_dispatchable)
811 state.timeout_usecs = 0;
815 presult =
poll ((
struct pollfd*) &pfda[0], pfda.size(),
std::min (timeout_msecs,
int64 (2147483647)));
816 while (presult < 0 && errno == EAGAIN);
818 if (presult < 0 && errno != EINTR)
819 warning (
"MainLoop: poll() failed: %s",
strerror());
820 else if (pfda[wakeup_idx].revents)
823 state.phase = state.CHECK;
825 int16 max_dispatch_priority = -32768;
826 for (
size_t i = 0; i < nrloops; i++)
828 dispatchable[i] |= loops[i]->check_sources_Lm (state, pfda);
829 if (!dispatchable[i])
831 any_dispatchable =
true;
832 max_dispatch_priority =
std::max (max_dispatch_priority, loops[i]->dispatch_priority_);
834 bool priority_ascension =
false;
836 priority_ascension =
true;
841 dispatchable[nrloops] = g_main_context_check (gcontext_, gpriority, mk_gpollfd (&pfda[gfirstfd]), pfda.size() - gfirstfd);
842 any_dispatchable |= dispatchable[nrloops];
846 if (may_dispatch && any_dispatchable)
848 const size_t gloop =
ASE_UNLIKELY (gcontext_) && dispatchable[nrloops] ? 1 : 0;
849 const size_t maxloops = nrloops + gloop;
853 index = rr_index_++ % maxloops;
854 if (!dispatchable[index])
856 if (index < nrloops && loops[index]->dispatch_priority_ < max_dispatch_priority)
858 if (priority_ascension && index >= nrloops)
862 state.phase = state.DISPATCH;
863 if (index >= nrloops)
866 g_main_context_dispatch (gcontext_);
870 loops[index]->dispatch_source_Lm (state);
873 state.phase = state.NONE;
875 for (
size_t i = 0; i < nrloops; i++)
877 loops[i]->unpoll_sources_U();
881 return any_dispatchable;
900 this->add_loop_L (*sub_loop);
905EventSource::EventSource () :
909 priority_ (UNDEFINED_PRIORITY),
913 was_dispatching_ (0),
918EventSource::n_pfds ()
948 primary_ = is_primary;
954 return dispatching_ && was_dispatching_;
960 const uint idx = n_pfds();
961 uint npfds = idx + 1;
962 pfds_ = (typeof (pfds_))
realloc (pfds_,
sizeof (pfds_[0]) * (npfds + 1));
964 fatal_error (
"EventSource: out of memory");
965 pfds_[npfds].idx = 4294967295U;
966 pfds_[npfds].pfd = NULL;
967 pfds_[idx].idx = 4294967295U;
968 pfds_[idx].pfd = pfd;
974 uint idx, npfds = n_pfds();
975 for (idx = 0; idx < npfds; idx++)
976 if (pfds_[idx].pfd == pfd)
980 pfds_[idx].idx = 4294967295U;
981 pfds_[idx].pfd = pfds_[npfds - 1].pfd;
982 pfds_[idx].idx = pfds_[npfds - 1].idx;
983 pfds_[npfds - 1].idx = 4294967295U;
984 pfds_[npfds - 1].pfd = NULL;
987 warning (
"EventSource: unremovable PollFD: %p (fd=%d)", pfd, pfd->fd);
991EventSource::destroy ()
1001EventSource::~EventSource ()
1009DispatcherSource::DispatcherSource (
const DispatcherSlot &slot) :
1013DispatcherSource::~DispatcherSource ()
1021 return slot_ (state);
1027 return slot_ (state);
1033 return slot_ (state);
1037DispatcherSource::destroy()
1040 state.phase = state.DESTROY;
1045USignalSource::USignalSource (
int8 signum,
const USignalSlot &slot) :
1046 slot_ (slot), signum_ (signum)
1048 const uint s = 128 + signum_;
1053USignalSource::~USignalSource ()
1064 const uint s = 128 + signum;
1065 const uint index = s / 32;
1066 const uint shift = s % 32;
1067 usignals_notified[index] |= 1 << shift;
1073 return usignals_notified[index_] & (1 << shift_);
1079 return usignals_notified[index_] & (1 << shift_);
1085 usignals_notified[index_] &= ~(1 << shift_);
1086 return slot_ (signum_);
1090USignalSource::destroy()
1094write_uint (uint32_t i)
1097 char *c = &a.back();
1100 *c =
'0' + (i % 10);
1103 *(--c) =
'0' + (i % 10);
1107 memmove (&a[0], c, &a.back() + 1 - c);
1113USignalSource::install_sigaction (
int8 signum)
1116 action.sa_handler = [] (
int signum) {
1118 constexpr size_t N = 1024;
1119 char buf[N] = __FILE__
":";
1120 strncat (buf, &write_uint (__LINE__)[0], N);
1121 strncat (buf,
": sa_handler: signal=", N);
1122 strncat (buf, &write_uint (signum)[0], N);
1124 ::write (2, buf, strlen (buf));
1129 action.sa_flags = SA_NOMASK;
1136SigchldSource::SigchldSource (int64_t pid,
const SigchldSlot &slot) :
1137 slot_ (slot), pid_ (pid)
1141 action.sa_handler = [] (
int signum) {
1145 action.sa_flags = SA_NOMASK;
1150SigchldSource::~SigchldSource()
1156 return pid_ && sigchld_counter_ != sigchld_counter;
1162 return pid_ && sigchld_counter_ != sigchld_counter;
1169 sigchld_counter_ = sigchld_counter;
1172 const pid_t child_pid = wait4 (pid_, &status, WNOHANG,
nullptr);
1173 if (child_pid > 0) {
1174 slot_ (pid_, status);
1176 struct rusage ru {};
1177 printf (
" Child Pid %d user time: %ld.%06ld sec\n", child_pid, ru.ru_utime.tv_sec, ru.ru_utime.tv_usec);
1178 printf (
" System time: %ld.%06ld sec\n", ru.ru_stime.tv_sec, ru.ru_stime.tv_usec);
1179 printf (
" Max RSS: %ld KB\n", ru.ru_maxrss);
1180 printf (
" Page faults: %ld\n", ru.ru_minflt);
1181 printf (
" I/O operations: %ld\n", ru.ru_inblock + ru.ru_oublock);
1182 printf (
" Voluntary context switches: %ld\n", ru.ru_nvcsw);
1183 printf (
" Involuntary context switches: %ld\n", ru.ru_nivcsw);
1186 if (WIFEXITED (status) || WIFSIGNALED (status)) {
1197SigchldSource::destroy ()
1203TimedSource::TimedSource (
const VoidSlot &slot,
uint initial_interval_msecs,
uint repeat_interval_msecs) :
1205 interval_msecs_ (repeat_interval_msecs), first_interval_ (true),
1206 oneshot_ (true), void_slot_ (slot)
1209TimedSource::TimedSource (
const BoolSlot &slot,
uint initial_interval_msecs,
uint repeat_interval_msecs) :
1211 interval_msecs_ (repeat_interval_msecs), first_interval_ (true),
1212 oneshot_ (false), bool_slot_ (slot)
1220 if (!first_interval_)
1222 uint64 interval = interval_msecs_ * 1000ULL;
1227 return 0 == *timeout_usecs_p;
1239 bool repeat =
false;
1240 first_interval_ =
false;
1241 if (oneshot_ && void_slot_ != NULL)
1243 else if (!oneshot_ && bool_slot_ != NULL)
1244 repeat = bool_slot_ ();
1250TimedSource::~TimedSource ()
1253 void_slot_.~VoidSlot();
1255 bool_slot_.~BoolSlot();
1271PollFDSource::PollFDSource (
const BPfdSlot &slot,
int fd,
const String &mode) :
1272 pfd_ ((PollFD) { fd, 0, 0 }),
1273 never_close_ (strchr (mode.c_str(),
'C') != NULL),
1274 oneshot_ (
false), bool_poll_slot_ (slot)
1279PollFDSource::PollFDSource (
const VPfdSlot &slot,
int fd,
const String &mode) :
1280 pfd_ ((PollFD) { fd, 0, 0 }),
1281 never_close_ (strchr (mode.c_str(),
'C') != NULL),
1282 oneshot_ (
true), void_poll_slot_ (slot)
1288PollFDSource::construct (
const String &mode)
1297 const long lflags =
fcntl (pfd_.fd, F_GETFL, 0);
1298 long nflags = lflags;
1299 if (strchr (mode.c_str(),
'b'))
1300 nflags &= ~long (O_NONBLOCK);
1301 else if (strchr (mode.c_str(),
'B'))
1302 nflags |= O_NONBLOCK;
1303 if (nflags != lflags)
1307 err =
fcntl (pfd_.fd, F_SETFL, nflags);
1308 while (err < 0 && (errno == EINTR || errno == EAGAIN));
1323 return pfd_.fd < 0 || pfd_.revents != 0;
1329 bool keep_alive = !oneshot_;
1330 if (oneshot_ && void_poll_slot_ != NULL)
1331 void_poll_slot_ (pfd_);
1332 else if (!oneshot_ && bool_poll_slot_ != NULL)
1333 keep_alive = bool_poll_slot_ (pfd_);
1337 if (!never_close_ && pfd_.fd >= 0)
1345PollFDSource::destroy()
1348 if (!never_close_ && pfd_.fd >= 0)
1353PollFDSource::~PollFDSource ()
1356 void_poll_slot_.~VPfdSlot();
1358 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.
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