explorerframe: Remove DECLSPEC_HIDDEN usage.
[wine.git] / dlls / sapi / async.c
blob57ae89ad723dcf0eaeeb8442c88044bba1282fc3
1 /*
2 * Speech API (SAPI) async helper implementation.
4 * Copyright 2023 Shaun Ren for CodeWeavers
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
21 #include <stdarg.h>
23 #include "windef.h"
24 #include "winbase.h"
25 #include "objbase.h"
27 #include "wine/heap.h"
28 #include "wine/list.h"
29 #include "wine/debug.h"
31 #include "sapi_private.h"
33 WINE_DEFAULT_DEBUG_CHANNEL(sapi);
35 static struct async_task *async_dequeue_task(struct async_queue *queue)
37 struct async_task *task = NULL;
38 struct list *head;
40 EnterCriticalSection(&queue->cs);
41 if ((head = list_head(&queue->tasks)))
43 task = LIST_ENTRY(head, struct async_task, entry);
44 list_remove(head);
46 LeaveCriticalSection(&queue->cs);
48 return task;
51 void async_empty_queue(struct async_queue *queue)
53 struct async_task *task, *next;
55 EnterCriticalSection(&queue->cs);
56 LIST_FOR_EACH_ENTRY_SAFE(task, next, &queue->tasks, struct async_task, entry)
58 list_remove(&task->entry);
59 heap_free(task);
61 LeaveCriticalSection(&queue->cs);
63 SetEvent(queue->empty);
66 static void CALLBACK async_worker(TP_CALLBACK_INSTANCE *instance, void *ctx)
68 struct async_queue *queue = ctx;
69 HANDLE handles[2] = { queue->cancel, queue->wait };
70 DWORD ret;
72 SetEvent(queue->ready);
74 for (;;)
76 ret = WaitForMultipleObjects(2, handles, FALSE, INFINITE);
77 if (ret == WAIT_OBJECT_0)
78 goto cancel;
79 else if (ret == WAIT_OBJECT_0 + 1)
81 struct async_task *task;
83 while ((task = async_dequeue_task(queue)))
85 ResetEvent(queue->empty);
86 task->proc(task);
87 heap_free(task);
88 if (WaitForSingleObject(queue->cancel, 0) == WAIT_OBJECT_0)
89 goto cancel;
92 SetEvent(queue->empty);
94 else
95 ERR("WaitForMultipleObjects failed: %#lx.\n", ret);
98 cancel:
99 async_empty_queue(queue);
100 TRACE("cancelled.\n");
101 SetEvent(queue->ready);
104 HRESULT async_start_queue(struct async_queue *queue)
106 HRESULT hr;
108 if (queue->init)
109 return S_OK;
111 InitializeCriticalSection(&queue->cs);
112 list_init(&queue->tasks);
114 if (!(queue->wait = CreateEventW(NULL, FALSE, FALSE, NULL)) ||
115 !(queue->ready = CreateEventW(NULL, FALSE, FALSE, NULL)) ||
116 !(queue->cancel = CreateEventW(NULL, FALSE, FALSE, NULL)) ||
117 !(queue->empty = CreateEventW(NULL, TRUE, TRUE, NULL)))
118 goto fail;
120 queue->init = TRUE;
122 if (!TrySubmitThreadpoolCallback(async_worker, queue, NULL))
123 goto fail;
125 WaitForSingleObject(queue->ready, INFINITE);
126 return S_OK;
128 fail:
129 hr = HRESULT_FROM_WIN32(GetLastError());
130 DeleteCriticalSection(&queue->cs);
131 if (queue->wait) CloseHandle(queue->wait);
132 if (queue->ready) CloseHandle(queue->ready);
133 if (queue->cancel) CloseHandle(queue->cancel);
134 if (queue->empty) CloseHandle(queue->empty);
135 memset(queue, 0, sizeof(*queue));
136 return hr;
139 void async_cancel_queue(struct async_queue *queue)
141 if (!queue->init) return;
143 SetEvent(queue->cancel);
144 WaitForSingleObject(queue->ready, INFINITE);
146 DeleteCriticalSection(&queue->cs);
147 CloseHandle(queue->wait);
148 CloseHandle(queue->ready);
149 CloseHandle(queue->cancel);
150 CloseHandle(queue->empty);
152 memset(queue, 0, sizeof(*queue));
155 HRESULT async_queue_task(struct async_queue *queue, struct async_task *task)
157 HRESULT hr;
159 if (FAILED(hr = async_start_queue(queue)))
160 return hr;
162 EnterCriticalSection(&queue->cs);
163 list_add_tail(&queue->tasks, &task->entry);
164 LeaveCriticalSection(&queue->cs);
166 SetEvent(queue->wait);
168 return S_OK;
171 void async_wait_queue_empty(struct async_queue *queue, DWORD timeout)
173 if (!queue->init) return;
174 WaitForSingleObject(queue->empty, timeout);