[PATCH 02/10] mfplat: Initialize system queues on startup.

Nikolay Sivov nsivov at codeweavers.com
Fri Mar 1 00:59:31 CST 2019


Signed-off-by: Nikolay Sivov <nsivov at codeweavers.com>
---
 dlls/mfplat/main.c           |  26 ++++++--
 dlls/mfplat/mfplat_private.h |  20 ++++++
 dlls/mfplat/queue.c          | 123 ++++++++++++++++++++++++++++-------
 include/mfapi.h              |   8 +++
 include/mfobjects.idl        |   1 +
 5 files changed, 150 insertions(+), 28 deletions(-)
 create mode 100644 dlls/mfplat/mfplat_private.h

diff --git a/dlls/mfplat/main.c b/dlls/mfplat/main.c
index a38c03b4d1..2d82589dfb 100644
--- a/dlls/mfplat/main.c
+++ b/dlls/mfplat/main.c
@@ -36,6 +36,8 @@
 #include "wine/debug.h"
 #include "wine/unicode.h"
 
+#include "mfplat_private.h"
+
 WINE_DEFAULT_DEBUG_CHANNEL(mfplat);
 
 static LONG platform_lock;
@@ -465,11 +467,16 @@ HRESULT WINAPI MFStartup(ULONG version, DWORD flags)
 #define MF_VERSION_XP   MAKELONG( MF_API_VERSION, 1 )
 #define MF_VERSION_WIN7 MAKELONG( MF_API_VERSION, 2 )
 
-    FIXME("(%u, %u): stub\n", version, flags);
+    TRACE("%#x, %#x.\n", version, flags);
 
-    if(version != MF_VERSION_XP && version != MF_VERSION_WIN7)
+    if (version != MF_VERSION_XP && version != MF_VERSION_WIN7)
         return MF_E_BAD_STARTUP_VERSION;
 
+    if (InterlockedIncrement(&platform_lock) == 1)
+    {
+        init_system_queues();
+    }
+
     return S_OK;
 }
 
@@ -478,7 +485,15 @@ HRESULT WINAPI MFStartup(ULONG version, DWORD flags)
  */
 HRESULT WINAPI MFShutdown(void)
 {
-    FIXME("(): stub\n");
+    TRACE("\n");
+
+    if (platform_lock <= 0)
+        return S_OK;
+
+    if (InterlockedExchangeAdd(&platform_lock, -1) == 1)
+    {
+        shutdown_system_queues();
+    }
 
     return S_OK;
 }
@@ -498,7 +513,10 @@ HRESULT WINAPI MFLockPlatform(void)
  */
 HRESULT WINAPI MFUnlockPlatform(void)
 {
-    InterlockedDecrement(&platform_lock);
+    if (InterlockedDecrement(&platform_lock) == 0)
+    {
+        shutdown_system_queues();
+    }
 
     return S_OK;
 }
diff --git a/dlls/mfplat/mfplat_private.h b/dlls/mfplat/mfplat_private.h
new file mode 100644
index 0000000000..2d9e7d5906
--- /dev/null
+++ b/dlls/mfplat/mfplat_private.h
@@ -0,0 +1,20 @@
+/*
+ * Copyright 2019 Nikolay Sivov for CodeWeavers
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+extern void init_system_queues(void) DECLSPEC_HIDDEN;
+extern void shutdown_system_queues(void) DECLSPEC_HIDDEN;
diff --git a/dlls/mfplat/queue.c b/dlls/mfplat/queue.c
index 7c8790b52c..9a3922fce2 100644
--- a/dlls/mfplat/queue.c
+++ b/dlls/mfplat/queue.c
@@ -26,33 +26,40 @@
 #include "wine/debug.h"
 #include "wine/heap.h"
 
+#include "mfplat_private.h"
+
 WINE_DEFAULT_DEBUG_CHANNEL(mfplat);
 
 #define FIRST_USER_QUEUE_HANDLE 5
 #define MAX_USER_QUEUE_HANDLES 124
 
 struct queue
+{
+    TP_POOL *pool;
+};
+
+struct queue_handle
 {
     void *obj;
     LONG refcount;
     WORD generation;
 };
 
-static struct queue user_queues[MAX_USER_QUEUE_HANDLES];
-static struct queue *next_free_user_queue;
-static struct queue *next_unused_user_queue = user_queues;
+static struct queue_handle user_queues[MAX_USER_QUEUE_HANDLES];
+static struct queue_handle *next_free_user_queue;
+static struct queue_handle *next_unused_user_queue = user_queues;
 static WORD queue_generation;
 
-static CRITICAL_SECTION user_queues_section;
-static CRITICAL_SECTION_DEBUG user_queues_critsect_debug =
+static CRITICAL_SECTION queues_section;
+static CRITICAL_SECTION_DEBUG queues_critsect_debug =
 {
-    0, 0, &user_queues_section,
-    { &user_queues_critsect_debug.ProcessLocksList, &user_queues_critsect_debug.ProcessLocksList },
-      0, 0, { (DWORD_PTR)(__FILE__ ": user_queues_section") }
+    0, 0, &queues_section,
+    { &queues_critsect_debug.ProcessLocksList, &queues_critsect_debug.ProcessLocksList },
+      0, 0, { (DWORD_PTR)(__FILE__ ": queues_section") }
 };
-static CRITICAL_SECTION user_queues_section = { &user_queues_critsect_debug, -1, 0, 0, 0, 0 };
+static CRITICAL_SECTION queues_section = { &queues_critsect_debug, -1, 0, 0, 0, 0 };
 
-static struct queue *get_queue_obj(DWORD handle)
+static struct queue_handle *get_queue_obj(DWORD handle)
 {
     unsigned int idx = HIWORD(handle) - FIRST_USER_QUEUE_HANDLE;
 
@@ -65,12 +72,79 @@ static struct queue *get_queue_obj(DWORD handle)
     return NULL;
 }
 
-static HRESULT alloc_user_queue(DWORD *queue)
+enum system_queue_index
+{
+    SYS_QUEUE_STANDARD = 0,
+    SYS_QUEUE_RT,
+    SYS_QUEUE_IO,
+    SYS_QUEUE_TIMER,
+    SYS_QUEUE_MULTITHREADED,
+    SYS_QUEUE_DO_NOT_USE,
+    SYS_QUEUE_LONG_FUNCTION,
+    SYS_QUEUE_COUNT,
+};
+
+static struct queue system_queues[SYS_QUEUE_COUNT];
+
+static void init_work_queue(MFASYNC_WORKQUEUE_TYPE queue_type, struct queue *queue)
+{
+    queue->pool = CreateThreadpool(NULL);
+}
+
+void init_system_queues(void)
+{
+    /* Always initialize standard queue, keep the rest lazy. */
+
+    EnterCriticalSection(&queues_section);
+
+    if (system_queues[SYS_QUEUE_STANDARD].pool)
+    {
+        LeaveCriticalSection(&queues_section);
+        return;
+    }
+
+    init_work_queue(MF_STANDARD_WORKQUEUE, &system_queues[SYS_QUEUE_STANDARD]);
+
+    LeaveCriticalSection(&queues_section);
+}
+
+static void shutdown_queue(struct queue *queue)
+{
+    if (!queue->pool)
+        return;
+
+    CloseThreadpool(queue->pool);
+    queue->pool = NULL;
+}
+
+void shutdown_system_queues(void)
+{
+    unsigned int i;
+
+    EnterCriticalSection(&queues_section);
+
+    for (i = 0; i < ARRAY_SIZE(system_queues); ++i)
+    {
+        shutdown_queue(&system_queues[i]);
+    }
+
+    LeaveCriticalSection(&queues_section);
+}
+
+static HRESULT alloc_user_queue(MFASYNC_WORKQUEUE_TYPE queue_type, DWORD *queue_id)
 {
-    struct queue *entry;
+    struct queue_handle *entry;
+    struct queue *queue;
     unsigned int idx;
 
-    EnterCriticalSection(&user_queues_section);
+    *queue_id = MFASYNC_CALLBACK_QUEUE_UNDEFINED;
+
+    queue = heap_alloc_zero(sizeof(*queue));
+    if (!queue)
+        return E_OUTOFMEMORY;
+    init_work_queue(queue_type, queue);
+
+    EnterCriticalSection(&queues_section);
 
     entry = next_free_user_queue;
     if (entry)
@@ -79,17 +153,18 @@ static HRESULT alloc_user_queue(DWORD *queue)
         entry = next_unused_user_queue++;
     else
     {
-        LeaveCriticalSection(&user_queues_section);
+        LeaveCriticalSection(&queues_section);
         return E_OUTOFMEMORY;
     }
 
     entry->refcount = 1;
-    entry->obj = NULL;
+    entry->obj = queue;
     if (++queue_generation == 0xffff) queue_generation = 1;
     entry->generation = queue_generation;
     idx = entry - user_queues + FIRST_USER_QUEUE_HANDLE;
-    *queue = (idx << 16) | entry->generation;
-    LeaveCriticalSection(&user_queues_section);
+    *queue_id = (idx << 16) | entry->generation;
+
+    LeaveCriticalSection(&queues_section);
 
     return S_OK;
 }
@@ -97,31 +172,31 @@ static HRESULT alloc_user_queue(DWORD *queue)
 static HRESULT lock_user_queue(DWORD queue)
 {
     HRESULT hr = MF_E_INVALID_WORKQUEUE;
-    struct queue *entry;
+    struct queue_handle *entry;
 
     if (!(queue & MFASYNC_CALLBACK_QUEUE_PRIVATE_MASK))
         return S_OK;
 
-    EnterCriticalSection(&user_queues_section);
+    EnterCriticalSection(&queues_section);
     entry = get_queue_obj(queue);
     if (entry && entry->refcount)
     {
         entry->refcount++;
         hr = S_OK;
     }
-    LeaveCriticalSection(&user_queues_section);
+    LeaveCriticalSection(&queues_section);
     return hr;
 }
 
 static HRESULT unlock_user_queue(DWORD queue)
 {
     HRESULT hr = MF_E_INVALID_WORKQUEUE;
-    struct queue *entry;
+    struct queue_handle *entry;
 
     if (!(queue & MFASYNC_CALLBACK_QUEUE_PRIVATE_MASK))
         return S_OK;
 
-    EnterCriticalSection(&user_queues_section);
+    EnterCriticalSection(&queues_section);
     entry = get_queue_obj(queue);
     if (entry && entry->refcount)
     {
@@ -132,7 +207,7 @@ static HRESULT unlock_user_queue(DWORD queue)
         }
         hr = S_OK;
     }
-    LeaveCriticalSection(&user_queues_section);
+    LeaveCriticalSection(&queues_section);
     return hr;
 }
 
@@ -309,7 +384,7 @@ HRESULT WINAPI MFAllocateWorkQueue(DWORD *queue)
 {
     TRACE("%p.\n", queue);
 
-    return alloc_user_queue(queue);
+    return alloc_user_queue(MF_STANDARD_WORKQUEUE, queue);
 }
 
 /***********************************************************************
diff --git a/include/mfapi.h b/include/mfapi.h
index 4b7d758488..ee5cf4c069 100644
--- a/include/mfapi.h
+++ b/include/mfapi.h
@@ -88,7 +88,15 @@ DEFINE_GUID(MFMediaType_Video,         0x73646976, 0x0000, 0x0010, 0x80, 0x00, 0
 
 typedef unsigned __int64 MFWORKITEM_KEY;
 
+typedef enum
+{
+    MF_STANDARD_WORKQUEUE,
+    MF_WINDOW_WORKQUEUE,
+    MF_MULTITHREADED_WORKQUEUE,
+} MFASYNC_WORKQUEUE_TYPE;
+
 HRESULT WINAPI MFAllocateWorkQueue(DWORD *queue);
+HRESULT WINAPI MFAllocateWorkQueueEx(MFASYNC_WORKQUEUE_TYPE queue_type, DWORD *queue);
 HRESULT WINAPI MFCancelWorkItem(MFWORKITEM_KEY key);
 HRESULT WINAPI MFCopyImage(BYTE *dest, LONG deststride, const BYTE *src, LONG srcstride, DWORD width, DWORD lines);
 HRESULT WINAPI MFCreateAttributes(IMFAttributes **attributes, UINT32 size);
diff --git a/include/mfobjects.idl b/include/mfobjects.idl
index 5ea26b2c67..3245d84d1b 100644
--- a/include/mfobjects.idl
+++ b/include/mfobjects.idl
@@ -431,6 +431,7 @@ cpp_quote("#define MFASYNC_CALLBACK_QUEUE_STANDARD       0x00000001")
 cpp_quote("#define MFASYNC_CALLBACK_QUEUE_RT             0x00000002")
 cpp_quote("#define MFASYNC_CALLBACK_QUEUE_IO             0x00000003")
 cpp_quote("#define MFASYNC_CALLBACK_QUEUE_TIMER          0x00000004")
+cpp_quote("#define MFASYNC_CALLBACK_QUEUE_MULTITHREADED  0x00000005")
 cpp_quote("#define MFASYNC_CALLBACK_QUEUE_LONG_FUNCTION  0x00000007")
 cpp_quote("#define MFASYNC_CALLBACK_QUEUE_PRIVATE_MASK   0xffff0000")
 cpp_quote("#define MFASYNC_CALLBACK_QUEUE_ALL            0xffffffff")
-- 
2.20.1




More information about the wine-devel mailing list