[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