[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