[vlc-commits] interrupt: add support for custom callbacks

Rémi Denis-Courmont git at videolan.org
Sun Dec 13 17:20:30 CET 2015


vlc | branch: master | Rémi Denis-Courmont <remi at remlab.net> | Sun Dec 13 16:35:31 2015 +0200| [9ee0adc8e44916eb69eedb3620e9d836db643144] | committer: 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().

> http://git.videolan.org/gitweb.cgi/vlc.git/?a=commit;h=9ee0adc8e44916eb69eedb3620e9d836db643144
---

 include/vlc_interrupt.h |   14 ++++++++++++++
 src/libvlccore.sym      |    2 ++
 src/misc/interrupt.c    |   13 +++++++++++++
 3 files changed, 29 insertions(+)

diff --git a/include/vlc_interrupt.h b/include/vlc_interrupt.h
index 84e4585..f45e048 100644
--- a/include/vlc_interrupt.h
+++ b/include/vlc_interrupt.h
@@ -137,6 +137,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
  * @{
diff --git a/src/libvlccore.sym b/src/libvlccore.sym
index 95152e8..d7971d8 100644
--- a/src/libvlccore.sym
+++ b/src/libvlccore.sym
@@ -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
diff --git a/src/misc/interrupt.c b/src/misc/interrupt.c
index 68c0364..6560ba1 100644
--- a/src/misc/interrupt.c
+++ b/src/misc/interrupt.c
@@ -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);



More information about the vlc-commits mailing list