[vlc-devel] [PATCH 1/2] core: win32: Add a vlc_mta_holder

Hugo Beauzée-Luyssen hugo at beauzee.fr
Fri Jun 2 13:51:12 CEST 2017


This small helper will hold on to the MTA to ensure it won't be
destroyed between two calls to CoInitializeEx.
This will help us not leaking our TA configurations to libvlc/libvlccore
threads
---
 include/vlc_threads.h |  20 ++++++++
 src/Makefile.am       |   3 +-
 src/libvlccore.sym    |   2 +
 src/misc/mta_holder.c | 131 ++++++++++++++++++++++++++++++++++++++++++++++++++
 4 files changed, 155 insertions(+), 1 deletion(-)
 create mode 100644 src/misc/mta_holder.c

diff --git a/include/vlc_threads.h b/include/vlc_threads.h
index 9911d2eacf..44b57f1255 100644
--- a/include/vlc_threads.h
+++ b/include/vlc_threads.h
@@ -46,6 +46,8 @@
  */
 VLC_API void vlc_testcancel(void);
 
+typedef struct vlc_mta_holder vlc_mta_holder;
+
 #if defined (_WIN32)
 # include <process.h>
 # ifndef ETIMEDOUT
@@ -946,6 +948,24 @@ VLC_API unsigned vlc_timer_getoverrun(vlc_timer_t) VLC_USED;
  */
 VLC_API unsigned vlc_GetCPUCount(void);
 
+/**
+ * Ensure an MTA context will be available until vlc_mta_release gets called.
+ *
+ * In the background, this will create a thread that does nothing but to keep the MTA
+ * refcount greater than 0.
+ *
+ * This is usefull in order not to commit a thread to a specific concurrency model.
+ * This function is win32 specific.
+ */
+VLC_API vlc_mta_holder* vlc_mta_acquire( vlc_object_t* p_obj );
+
+/**
+ * Releases a reference to the MTA holder.
+ *
+ * When its refcount reaches 0, the thread created by
+ */
+VLC_API void vlc_mta_release( vlc_mta_holder* p_mta );
+
 enum
 {
     VLC_CLEANUP_PUSH,
diff --git a/src/Makefile.am b/src/Makefile.am
index 5f3726c3e6..7c9f08a3b3 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -345,6 +345,7 @@ libvlccore_la_SOURCES = \
 	misc/filter_chain.c \
 	misc/httpcookies.c \
 	misc/fingerprinter.c \
+	misc/mta_holder.c \
 	misc/text_style.c \
 	misc/subpicture.c \
 	misc/subpicture.h
@@ -467,7 +468,7 @@ libvlccore_la_LDFLAGS = \
 libvlccore_la_DEPENDENCIES = libvlccore.sym
 if HAVE_WIN32
 libvlccore_la_DEPENDENCIES += libvlc_win32_rc.$(OBJEXT)
-libvlccore_la_LDFLAGS += -Wl,libvlc_win32_rc.$(OBJEXT) -avoid-version -Wc,-static
+libvlccore_la_LDFLAGS += -Wl,libvlc_win32_rc.$(OBJEXT) -avoid-version -Wc,-static $(LIBCOM)
 endif
 if HAVE_OS2
 libvlccore_la_LDFLAGS += -avoid-version
diff --git a/src/libvlccore.sym b/src/libvlccore.sym
index aa957ff26d..04d40a4e32 100644
--- a/src/libvlccore.sym
+++ b/src/libvlccore.sym
@@ -754,3 +754,5 @@ vlc_rd_get_names
 vlc_rd_new
 vlc_rd_release
 vlc_rd_probe_add
+vlc_mta_acquire
+vlc_mta_release
diff --git a/src/misc/mta_holder.c b/src/misc/mta_holder.c
new file mode 100644
index 0000000000..4b4da5e95d
--- /dev/null
+++ b/src/misc/mta_holder.c
@@ -0,0 +1,131 @@
+/*****************************************************************************
+ * mta_holder.c: Hold a MTA from another thread
+ *****************************************************************************
+ * Copyright (C) 2002-2017 the VideoLAN and AUTHORS
+ *
+ * Author: Hugo Beauzée-Luyssen <hugo at beauzee.fr>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
+ *****************************************************************************/
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include <vlc_common.h>
+
+#ifdef _WIN32
+
+#include "libvlc.h"
+
+#include <assert.h>
+#include <windows.h>
+#include <objbase.h>
+
+typedef struct vlc_mta_holder
+{
+    VLC_COMMON_MEMBERS
+
+    vlc_thread_t thread;
+    vlc_cond_t   cond;
+    vlc_mutex_t  lock;
+    bool         b_done;
+} vlc_mta_holder;
+
+static vlc_mta_holder* sp_mta = NULL;
+static vlc_mutex_t s_mutex = VLC_STATIC_MUTEX;
+
+static void* MtaMainLoop( void* opaque )
+{
+    vlc_mta_holder* p_mta = (vlc_mta_holder*)opaque;
+    msg_Dbg( p_mta, "Acquiring MTA from a background thread" );
+    CoInitializeEx( NULL, COINIT_MULTITHREADED );
+    vlc_mutex_lock( &p_mta->lock );
+    while( p_mta->b_done == false )
+    {
+        vlc_cond_wait( &p_mta->cond, &p_mta->lock );
+    }
+    vlc_mutex_unlock( &p_mta->lock );
+    msg_Dbg( p_mta, "Releasing background MTA" );
+    CoUninitialize();
+    return NULL;
+}
+
+static void MtaDestructor( vlc_object_t* p_obj )
+{
+    vlc_mutex_lock( &s_mutex );
+    sp_mta = NULL;
+    vlc_mutex_unlock( &s_mutex );
+
+    vlc_mta_holder* p_mta = (vlc_mta_holder*)p_obj;
+
+    vlc_mutex_lock( &p_mta->lock );
+    p_mta->b_done = true;
+    vlc_cond_signal( &p_mta->cond );
+    vlc_mutex_unlock( &p_mta->lock );
+
+    vlc_join( p_mta->thread, NULL );
+}
+
+vlc_mta_holder* vlc_mta_acquire( vlc_object_t* p_obj )
+{
+    assert( p_obj != NULL );
+    vlc_mutex_lock( &s_mutex );
+    if ( sp_mta == NULL )
+    {
+        sp_mta = vlc_object_create( p_obj->obj.libvlc, sizeof( *sp_mta ) );
+        if ( unlikely( sp_mta == NULL ) )
+        {
+            vlc_mutex_unlock( &s_mutex );
+            return NULL;
+        }
+        vlc_cond_init( &sp_mta->cond );
+        vlc_mutex_init( &sp_mta->lock );
+        vlc_object_set_destructor( sp_mta, MtaDestructor );
+        sp_mta->b_done = false;
+        if ( vlc_clone( &sp_mta->thread, MtaMainLoop, sp_mta, VLC_THREAD_PRIORITY_LOW ) )
+        {
+            vlc_mutex_destroy( &sp_mta->lock );
+            vlc_cond_destroy( &sp_mta->cond );
+            vlc_object_release( sp_mta );
+            sp_mta = NULL;
+        }
+    }
+    else
+        vlc_object_hold( sp_mta );
+    vlc_mutex_unlock( &s_mutex );
+    return sp_mta;
+}
+
+void vlc_mta_release( vlc_mta_holder* p_mta )
+{
+    assert( p_mta != NULL );
+    vlc_object_release( VLC_OBJECT( p_mta ) );
+}
+
+#else
+
+vlc_mta_holder* vlc_mta_acquire( vlc_object_t* p_obj )
+{
+    (void)p_obj;
+    return NULL;
+}
+
+void vlc_mta_release( vlc_mta_holder* p_mta )
+{
+    (void)p_mta;
+}
+
+#endif
-- 
2.11.0



More information about the vlc-devel mailing list