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/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
;
39 EnterCriticalSection(&queue
->cs
);
40 if ((head
= list_head(&queue
->tasks
)))
42 task
= LIST_ENTRY(head
, struct async_task
, entry
);
45 LeaveCriticalSection(&queue
->cs
);
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
);
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
};
73 CoInitializeEx(NULL
, COINIT_MULTITHREADED
);
74 SetEvent(queue
->ready
);
78 ret
= WaitForMultipleObjects(2, handles
, FALSE
, INFINITE
);
79 if (ret
== WAIT_OBJECT_0
)
81 else if (ret
== WAIT_OBJECT_0
+ 1)
83 struct async_task
*task
;
85 while ((task
= async_dequeue_task(queue
)))
87 ResetEvent(queue
->empty
);
90 if (WaitForSingleObject(queue
->cancel
, 0) == WAIT_OBJECT_0
)
94 SetEvent(queue
->empty
);
97 ERR("WaitForMultipleObjects failed: %#lx.\n", ret
);
101 async_empty_queue(queue
);
103 TRACE("cancelled.\n");
104 SetEvent(queue
->ready
);
107 HRESULT
async_start_queue(struct async_queue
*queue
)
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
)))
125 if (!TrySubmitThreadpoolCallback(async_worker
, queue
, NULL
))
128 WaitForSingleObject(queue
->ready
, INFINITE
);
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
));
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
)
162 if (FAILED(hr
= async_start_queue(queue
)))
165 EnterCriticalSection(&queue
->cs
);
166 list_add_tail(&queue
->tasks
, &task
->entry
);
167 LeaveCriticalSection(&queue
->cs
);
169 ResetEvent(queue
->empty
);
170 SetEvent(queue
->wait
);
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
);