[vlc-devel] commit: Support for cancellation cleanup functions ( Rémi Denis-Courmont )
git version control
git at videolan.org
Wed Aug 27 22:57:31 CEST 2008
vlc | branch: master | Rémi Denis-Courmont <rdenis at simphalempin.com> | Sun Aug 10 21:06:11 2008 +0300| [aa6b5c552d671fc1fce4ca38e5aff41ae259c28e] | committer: Rémi Denis-Courmont
Support for cancellation cleanup functions
> http://git.videolan.org/gitweb.cgi/vlc.git/?a=commit;h=aa6b5c552d671fc1fce4ca38e5aff41ae259c28e
---
include/vlc_threads.h | 56 +++++++++++++++++++++++++++++++++++++++++++++++++
src/misc/threads.c | 27 +++++++++++++++++------
2 files changed, 76 insertions(+), 7 deletions(-)
diff --git a/include/vlc_threads.h b/include/vlc_threads.h
index 24d85c0..e044e56 100644
--- a/include/vlc_threads.h
+++ b/include/vlc_threads.h
@@ -187,6 +187,8 @@ enum {
VLC_RESTORE_CANCEL,
VLC_TEST_CANCEL,
VLC_DO_CANCEL,
+ VLC_CLEANUP_PUSH,
+ VLC_CLEANUP_POP,
};
#endif
@@ -317,6 +319,60 @@ static inline void vlc_testcancel (void)
#endif
}
+#if defined (LIBVLC_USE_PTHREAD)
+/**
+ * Registers a new procedure to run if the thread is cancelled (or otherwise
+ * exits prematurely). Any call to vlc_cleanup_push() <b>must</b> paired with a
+ * call to either vlc_cleanup_pop() or vlc_cleanup_run(). Branching into or out
+ * of the block between these two function calls is not allowed (read: it will
+ * likely crash the whole process). If multiple procedures are registered,
+ * they are handled in last-in first-out order.
+ *
+ * @param routine procedure to call if the thread ends
+ * @param arg argument for the procedure
+ */
+# define vlc_cleanup_push( routine, arg ) pthread_cleanup_push (routine, arg)
+
+/**
+ * Removes a cleanup procedure that was previously registered with
+ * vlc_cleanup_push().
+ */
+# define vlc_cleanup_pop( ) pthread_cleanup_pop (0)
+
+/**
+ * Removes a cleanup procedure that was previously registered with
+ * vlc_cleanup_push(), and executes it.
+ */
+# define vlc_cleanup_run( ) pthread_cleanup_pop (1)
+#else
+typedef struct vlc_cleanup_t vlc_cleanup_t;
+
+struct vlc_cleanup_t
+{
+ vlc_cleanup_t *next;
+ void (*proc) (void *);
+ void *data;
+};
+
+/* This macros opens a code block on purpose. This is needed for multiple
+ * calls within a single function. This also prevent Win32 developpers from
+ * writing code that would break on POSIX (POSIX opens a block as well). */
+# define vlc_cleanup_push( routine, arg ) \
+ do { \
+ vlc_cleanup_t vlc_cleanup_data = { NULL, routine, arg, }; \
+ vlc_control_cancel (VLC_CLEANUP_PUSH, &vlc_cleanup_data)
+
+# define vlc_cleanup_pop( ) \
+ vlc_control_cancel (VLC_CLEANUP_POP); \
+ } while (0)
+
+# define vlc_cleanup_run( ) \
+ vlc_control_cancel (VLC_CLEANUP_POP); \
+ vlc_cleanup_data.proc (vlc_cleanup_data.data); \
+ } while (0)
+
+#endif /* LIBVLC_USE_PTHREAD */
+
/*****************************************************************************
* vlc_cond_init: initialize a condition
*****************************************************************************/
diff --git a/src/misc/threads.c b/src/misc/threads.c
index 69b9fd4..33a76e4 100644
--- a/src/misc/threads.c
+++ b/src/misc/threads.c
@@ -864,22 +864,19 @@ void vlc_thread_cancel (vlc_object_t *obj)
vlc_cancel (priv->thread_id);
}
-typedef struct vlc_cleanup_t
-{
- struct vlc_cleanup_t *next;
- void (*proc) (void *);
- void *data;
-} vlc_cleanup_t;
-
+#ifndef LIBVLC_USE_PTHREAD
typedef struct vlc_cancel_t
{
vlc_cleanup_t *cleaners;
bool killable;
bool killed;
} vlc_cancel_t;
+#endif
void vlc_control_cancel (int cmd, ...)
{
+ /* NOTE: This function only modifies thread-specific data, so there is no
+ * need to lock anything. */
#ifdef LIBVLC_USE_PTHREAD
(void) cmd;
assert (0);
@@ -935,6 +932,22 @@ void vlc_control_cancel (int cmd, ...)
case VLC_DO_CANCEL:
nfo->killed = true;
break;
+
+ case VLC_CLEANUP_PUSH:
+ {
+ /* cleaner is a pointer to the caller stack, no need to allocate
+ * and copy anything. As a nice side effect, this cannot fail. */
+ vlc_cleanup_t *cleaner = va_arg (ap, vlc_cleanup_t *);
+ cleaner->next = nfo->cleaners;
+ nfo->cleaners = cleaner;
+ break;
+ }
+
+ case VLC_CLEANUP_POP:
+ {
+ nfo->cleaners = nfo->cleaners->next;
+ break;
+ }
}
va_end (ap);
#endif
More information about the vlc-devel
mailing list