msi/tests: Delete the temp .msi file in all failure cases.
[wine.git] / dlls / sapi / async.c
blob69f962d550214faa424a5d608b0b025d92ae4678
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/list.h"
28 #include "wine/debug.h"
30 #include "sapi_private.h"
32 WINE_DEFAULT_DEBUG_CHANNEL(sapi);
34 static struct async_task *async_dequeue_task(struct async_queue *queue)
36 struct async_task *task = NULL;
37 struct list *head;
39 EnterCriticalSection(&queue->cs);
40 if ((head = list_head(&queue->tasks)))
42 task = LIST_ENTRY(head, struct async_task, entry);
43 list_remove(head);
45 LeaveCriticalSection(&queue->cs);
47 return task;
50 void async_empty_queue(struct async_queue *queue)
52 struct async_task *task, *next;
54 if (!queue->init) return;
56 EnterCriticalSection(&queue->cs);
57 LIST_FOR_EACH_ENTRY_SAFE(task, next, &queue->tasks, struct async_task, entry)
59 list_remove(&task->entry);
60 free(task);
62 LeaveCriticalSection(&queue->cs);
64 SetEvent(queue->empty);
67 static void CALLBACK async_worker(TP_CALLBACK_INSTANCE *instance, void *ctx)
69 struct async_queue *queue = ctx;
70 HANDLE handles[2] = { queue->cancel, queue->wait };
71 DWORD ret;
73 CoInitializeEx(NULL, COINIT_MULTITHREADED);
74 SetEvent(queue->ready);
76 for (;;)
78 ret = WaitForMultipleObjects(2, handles, FALSE, INFINITE);
79 if (ret == WAIT_OBJECT_0)
80 goto cancel;
81 else if (ret == WAIT_OBJECT_0 + 1)
83 struct async_task *task;
85 while ((task = async_dequeue_task(queue)))
87 ResetEvent(queue->empty);
88 task->proc(task);
89 free(task);
90 if (WaitForSingleObject(queue->cancel, 0) == WAIT_OBJECT_0)
91 goto cancel;
94 SetEvent(queue->empty);
96 else
97 ERR("WaitForMultipleObjects failed: %#lx.\n", ret);
100 cancel:
101 async_empty_queue(queue);
102 CoUninitialize();
103 TRACE("cancelled.\n");
104 SetEvent(queue->ready);
107 HRESULT async_start_queue(struct async_queue *queue)
109 HRESULT hr;
111 if (queue->init)
112 return S_OK;
114 InitializeCriticalSection(&queue->cs);
115 list_init(&queue->tasks);
117 if (!(queue->wait = CreateEventW(NULL, FALSE, FALSE, NULL)) ||
118 !(queue->ready = CreateEventW(NULL, FALSE, FALSE, NULL)) ||
119 !(queue->cancel = CreateEventW(NULL, FALSE, FALSE, NULL)) ||
120 !(queue->empty = CreateEventW(NULL, TRUE, TRUE, NULL)))
121 goto fail;
123 queue->init = TRUE;
125 if (!TrySubmitThreadpoolCallback(async_worker, queue, NULL))
126 goto fail;
128 WaitForSingleObject(queue->ready, INFINITE);
129 return S_OK;
131 fail:
132 hr = HRESULT_FROM_WIN32(GetLastError());
133 DeleteCriticalSection(&queue->cs);
134 if (queue->wait) CloseHandle(queue->wait);
135 if (queue->ready) CloseHandle(queue->ready);
136 if (queue->cancel) CloseHandle(queue->cancel);
137 if (queue->empty) CloseHandle(queue->empty);
138 memset(queue, 0, sizeof(*queue));
139 return hr;
142 void async_cancel_queue(struct async_queue *queue)
144 if (!queue->init) return;
146 SetEvent(queue->cancel);
147 WaitForSingleObject(queue->ready, INFINITE);
149 DeleteCriticalSection(&queue->cs);
150 CloseHandle(queue->wait);
151 CloseHandle(queue->ready);
152 CloseHandle(queue->cancel);
153 CloseHandle(queue->empty);
155 memset(queue, 0, sizeof(*queue));
158 HRESULT async_queue_task(struct async_queue *queue, struct async_task *task)
160 HRESULT hr;
162 if (FAILED(hr = async_start_queue(queue)))
163 return hr;
165 EnterCriticalSection(&queue->cs);
166 list_add_tail(&queue->tasks, &task->entry);
167 LeaveCriticalSection(&queue->cs);
169 ResetEvent(queue->empty);
170 SetEvent(queue->wait);
172 return S_OK;
175 HRESULT async_wait_queue_empty(struct async_queue *queue, DWORD timeout)
177 if (!queue->init) return WAIT_OBJECT_0;
178 return WaitForSingleObject(queue->empty, timeout);