mirror of
https://gitlab.freedesktop.org/pipewire/pipewire.git
synced 2026-03-13 05:33:55 -04:00
loop: improve cancellation handling
Now that the loop_leave function will assert when the unlock fails we need to be extra careful with the cancellable loop. If it cancels inside the poll or one of the before/after callbacks we need to make sure that we lock the loop correctly again or we will create an assert later on. Do this by pushing the cleanup earlier and then record all the things we managed to do before we get canceled. If we ever get canceled and the lock was unlocked but not locked again, fix this up. Fix fixes issues when using the JACK API causing assertions when the data loop is stopped/cancelled.
This commit is contained in:
parent
7ecd51dc80
commit
5f4b422ab1
1 changed files with 13 additions and 4 deletions
|
|
@ -727,13 +727,20 @@ static int loop_accept(void *object)
|
|||
}
|
||||
|
||||
struct cancellation_handler_data {
|
||||
struct impl *impl;
|
||||
struct spa_poll_event *ep;
|
||||
int ep_count;
|
||||
int unlocked;
|
||||
int locked;
|
||||
};
|
||||
|
||||
static void cancellation_handler(void *closure)
|
||||
{
|
||||
const struct cancellation_handler_data *data = closure;
|
||||
struct impl *impl = data->impl;
|
||||
|
||||
if (data->unlocked && !data->locked)
|
||||
spa_assert_se(pthread_mutex_lock(&impl->lock) == 0);
|
||||
|
||||
for (int i = 0; i < data->ep_count; i++) {
|
||||
struct spa_source *s = data->ep[i].data;
|
||||
|
|
@ -750,22 +757,24 @@ static int loop_iterate_cancel(void *object, int timeout)
|
|||
struct spa_poll_event ep[MAX_EP], *e;
|
||||
int i, nfds;
|
||||
uint32_t remove_count;
|
||||
struct cancellation_handler_data cdata = { impl, ep, 0, 0, 0 };
|
||||
|
||||
spa_return_val_if_fail(impl->enter_count > 0, -EPERM);
|
||||
|
||||
pthread_cleanup_push(cancellation_handler, &cdata);
|
||||
|
||||
remove_count = impl->remove_count;
|
||||
spa_loop_control_hook_before(&impl->hooks_list);
|
||||
spa_assert_se(pthread_mutex_unlock(&impl->lock) == 0);
|
||||
spa_assert_se((cdata.unlocked = (pthread_mutex_unlock(&impl->lock) == 0)));
|
||||
|
||||
nfds = spa_system_pollfd_wait(impl->system, impl->poll_fd, ep, SPA_N_ELEMENTS(ep), timeout);
|
||||
|
||||
spa_assert_se(pthread_mutex_lock(&impl->lock) == 0);
|
||||
spa_assert_se((cdata.locked = (pthread_mutex_lock(&impl->lock) == 0)));
|
||||
spa_loop_control_hook_after(&impl->hooks_list);
|
||||
if (remove_count != impl->remove_count)
|
||||
nfds = 0;
|
||||
|
||||
struct cancellation_handler_data cdata = { ep, nfds };
|
||||
pthread_cleanup_push(cancellation_handler, &cdata);
|
||||
cdata.ep_count = nfds;
|
||||
|
||||
/* 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
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue