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
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
;
40 EnterCriticalSection(&queue
->cs
);
41 if ((head
= list_head(&queue
->tasks
)))
43 task
= LIST_ENTRY(head
, struct async_task
, entry
);
46 LeaveCriticalSection(&queue
->cs
);
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
);
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
};
72 SetEvent(queue
->ready
);
76 ret
= WaitForMultipleObjects(2, handles
, FALSE
, INFINITE
);
77 if (ret
== WAIT_OBJECT_0
)
79 else if (ret
== WAIT_OBJECT_0
+ 1)
81 struct async_task
*task
;
83 while ((task
= async_dequeue_task(queue
)))
85 ResetEvent(queue
->empty
);
88 if (WaitForSingleObject(queue
->cancel
, 0) == WAIT_OBJECT_0
)
92 SetEvent(queue
->empty
);
95 ERR("WaitForMultipleObjects failed: %#lx.\n", ret
);
99 async_empty_queue(queue
);
100 TRACE("cancelled.\n");
101 SetEvent(queue
->ready
);
104 HRESULT
async_start_queue(struct async_queue
*queue
)
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
)))
122 if (!TrySubmitThreadpoolCallback(async_worker
, queue
, NULL
))
125 WaitForSingleObject(queue
->ready
, INFINITE
);
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
));
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
)
159 if (FAILED(hr
= async_start_queue(queue
)))
162 EnterCriticalSection(&queue
->cs
);
163 list_add_tail(&queue
->tasks
, &task
->entry
);
164 LeaveCriticalSection(&queue
->cs
);
166 SetEvent(queue
->wait
);
171 void async_wait_queue_empty(struct async_queue
*queue
, DWORD timeout
)
173 if (!queue
->init
) return;
174 WaitForSingleObject(queue
->empty
, timeout
);