Commit 9ee0adc8 authored by Rémi Denis-Courmont's avatar Rémi Denis-Courmont

interrupt: add support for custom callbacks

It seems impossible to handle interruptions while waiting on a
condition variable otherwise.

In particular, a single vlc_cond_wait_i11e() function would be
intrinsically prone to deadlocks:
 - It would need to acquire the interrupt context lock while the caller
   already holds the mutex corresponding to the condition variable, but
 - the interrupt callback would need to acquire the mutex while holding
   the interrupt context lock.
This would be a classic lock inversion race.

This addition should also enable hooking with other libraries, such as
Glib´s GCancellable.

Be very careful when using these two new functions. VLC does not
support stacking interrupt handlers (at least not currently). So there
MUST NOT be any call to another interruptible function between
vlc_interrupt_register() and vlc_interrupt_unregister().
parent 053c00fd
......@@ -136,6 +136,20 @@ ssize_t vlc_send_i11e(int fd, const void *buf, size_t len, int flags)
VLC_API int vlc_accept_i11e(int fd, struct sockaddr *, socklen_t *, bool);
/**
* Registers a custom interrupt handler.
*
* Registers a custom callback as interrupt handler for the calling thread.
* The callback must be unregistered with vlc_interrupt_unregister() before
* thread termination and before any further callback registration.
*
* If the calling thread has no interruption context, this function has no
* effects.
*/
VLC_API void vlc_interrupt_register(void (*cb)(void *), void *opaque);
VLC_API int vlc_interrupt_unregister(void);
/**
* @}
* @defgroup interrupt_context Interrupt context signaling and manipulation
......
......@@ -566,6 +566,8 @@ vlc_interrupt_raise
vlc_interrupt_kill
vlc_interrupt_forward_start
vlc_interrupt_forward_stop
vlc_interrupt_register
vlc_interrupt_unregister
vlc_killed
vlc_join
vlc_list_children
......
......@@ -203,6 +203,19 @@ static int vlc_interrupt_finish(vlc_interrupt_t *ctx)
return ret;
}
void vlc_interrupt_register(void (*cb)(void *), void *opaque)
{
vlc_interrupt_t *ctx = vlc_threadvar_get(vlc_interrupt_var);
if (ctx != NULL)
vlc_interrupt_prepare(ctx, cb, opaque);
}
int vlc_interrupt_unregister(void)
{
vlc_interrupt_t *ctx = vlc_threadvar_get(vlc_interrupt_var);
return (ctx != NULL) ? vlc_interrupt_finish(ctx) : 0;
}
static void vlc_interrupt_cleanup(void *opaque)
{
vlc_interrupt_finish(opaque);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment