loop: add optimized non-cancellable iterate

Only use the more heavy cancellable loop when the loop.cancel property
was set. Makes pipewire go from 5% to 3% in high frequency wakeups.
This commit is contained in:
Wim Taymans 2023-05-05 17:41:37 +02:00
parent 67c38490a5
commit fbf17cf980

View file

@ -397,7 +397,7 @@ static void cancellation_handler(void *closure)
}
}
static int loop_iterate(void *object, int timeout)
static int loop_iterate_cancel(void *object, int timeout)
{
struct impl *impl = object;
struct spa_poll_event ep[MAX_EP], *e;
@ -444,6 +444,49 @@ static int loop_iterate(void *object, int timeout)
return nfds;
}
static int loop_iterate(void *object, int timeout)
{
struct impl *impl = object;
struct spa_poll_event ep[MAX_EP], *e;
int i, nfds;
impl->polling = true;
spa_loop_control_hook_before(&impl->hooks_list);
nfds = spa_system_pollfd_wait(impl->system, impl->poll_fd, ep, SPA_N_ELEMENTS(ep), timeout);
spa_loop_control_hook_after(&impl->hooks_list);
impl->polling = false;
/* first we set all the rmasks, then call the callbacks. The reason is that
* some callback might also want to look at other sources it manages and
* can then reset the rmask to suppress the callback */
for (i = 0; i < nfds; i++) {
struct spa_source *s = ep[i].data;
s->rmask = ep[i].events;
/* already active in another iteration of the loop,
* remove it from that iteration */
if (SPA_UNLIKELY(e = s->priv))
e->data = NULL;
s->priv = &ep[i];
}
if (SPA_UNLIKELY(!spa_list_is_empty(&impl->destroy_list)))
process_destroy(impl);
for (i = 0; i < nfds; i++) {
struct spa_source *s = ep[i].data;
if (SPA_LIKELY(s)) {
if (SPA_LIKELY(s->rmask))
s->func(s);
s->rmask = 0;
s->priv = NULL;
}
}
return nfds;
}
static void source_io_func(struct spa_source *source)
{
struct source_impl *s = SPA_CONTAINER_OF(source, struct source_impl, source);
@ -826,6 +869,16 @@ static const struct spa_loop_methods impl_loop = {
.invoke = loop_invoke,
};
static const struct spa_loop_control_methods impl_loop_control_cancel = {
SPA_VERSION_LOOP_CONTROL_METHODS,
.get_fd = loop_get_fd,
.add_hook = loop_add_hook,
.enter = loop_enter,
.leave = loop_leave,
.iterate = loop_iterate_cancel,
.check = loop_check,
};
static const struct spa_loop_control_methods impl_loop_control = {
SPA_VERSION_LOOP_CONTROL_METHODS,
.get_fd = loop_get_fd,
@ -908,6 +961,7 @@ impl_init(const struct spa_handle_factory *factory,
uint32_t n_support)
{
struct impl *impl;
const char *str;
int res;
spa_return_val_if_fail(factory != NULL, -EINVAL);
@ -930,6 +984,12 @@ impl_init(const struct spa_handle_factory *factory,
SPA_VERSION_LOOP_UTILS,
&impl_loop_utils, impl);
if (info) {
if ((str = spa_dict_lookup(info, "loop.cancel")) != NULL &&
spa_atob(str))
impl->control.iface.cb.funcs = &impl_loop_control_cancel;
}
impl->log = spa_support_find(support, n_support, SPA_TYPE_INTERFACE_Log);
spa_log_topic_init(impl->log, &log_topic);
impl->system = spa_support_find(support, n_support, SPA_TYPE_INTERFACE_System);