2 * Copyright 2022 Nikolay Sivov for CodeWeavers
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Lesser General Public
6 * License as published by the Free Software Foundation; either
7 * version 2.1 of the License, or (at your option) any later version.
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Lesser General Public License for more details.
14 * You should have received a copy of the GNU Lesser General Public
15 * License along with this library; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
25 #include "winstring.h"
26 #include "wine/debug.h"
30 #include "activation.h"
32 #define WIDL_using_Windows_Foundation
33 #define WIDL_using_Windows_Foundation_Collections
34 #include "windows.foundation.h"
35 #define WIDL_using_Windows_System_Threading
36 #include "windows.system.threading.h"
38 WINE_DEFAULT_DEBUG_CHANNEL(threadpool
);
40 static const char *debugstr_hstring(HSTRING hstr
)
44 if (hstr
&& !((ULONG_PTR
)hstr
>> 16)) return "(invalid)";
45 str
= WindowsGetStringRawBuffer(hstr
, &len
);
46 return wine_dbgstr_wn(str
, len
);
49 struct threadpool_factory
51 IActivationFactory IActivationFactory_iface
;
52 IThreadPoolStatics IThreadPoolStatics_iface
;
58 IAsyncAction IAsyncAction_iface
;
59 IAsyncInfo IAsyncInfo_iface
;
63 static inline struct threadpool_factory
*impl_from_IActivationFactory(IActivationFactory
*iface
)
65 return CONTAINING_RECORD(iface
, struct threadpool_factory
, IActivationFactory_iface
);
68 static inline struct threadpool_factory
*impl_from_IThreadPoolStatics(IThreadPoolStatics
*iface
)
70 return CONTAINING_RECORD(iface
, struct threadpool_factory
, IThreadPoolStatics_iface
);
73 static inline struct async_action
*impl_from_IAsyncAction(IAsyncAction
*iface
)
75 return CONTAINING_RECORD(iface
, struct async_action
, IAsyncAction_iface
);
78 static inline struct async_action
*impl_from_IAsyncInfo(IAsyncInfo
*iface
)
80 return CONTAINING_RECORD(iface
, struct async_action
, IAsyncInfo_iface
);
83 static HRESULT STDMETHODCALLTYPE
async_action_QueryInterface(IAsyncAction
*iface
, REFIID iid
, void **out
)
85 struct async_action
*action
= impl_from_IAsyncAction(iface
);
87 TRACE("iface %p, iid %s, out %p.\n", iface
, debugstr_guid(iid
), out
);
89 if (IsEqualIID(iid
, &IID_IAsyncAction
)
90 || IsEqualIID(iid
, &IID_IInspectable
)
91 || IsEqualIID(iid
, &IID_IUnknown
))
95 else if (IsEqualIID(iid
, &IID_IAsyncInfo
))
97 *out
= &action
->IAsyncInfo_iface
;
102 WARN("Unsupported interface %s.\n", debugstr_guid(iid
));
105 IUnknown_AddRef((IUnknown
*)*out
);
109 static ULONG STDMETHODCALLTYPE
async_action_AddRef(IAsyncAction
*iface
)
111 struct async_action
*action
= impl_from_IAsyncAction(iface
);
112 ULONG refcount
= InterlockedIncrement(&action
->refcount
);
114 TRACE("iface %p, refcount %lu.\n", iface
, refcount
);
119 static ULONG STDMETHODCALLTYPE
async_action_Release(IAsyncAction
*iface
)
121 struct async_action
*action
= impl_from_IAsyncAction(iface
);
122 ULONG refcount
= InterlockedDecrement(&action
->refcount
);
124 TRACE("iface %p, refcount %lu.\n", iface
, refcount
);
132 static HRESULT STDMETHODCALLTYPE
async_action_GetIids(
133 IAsyncAction
*iface
, ULONG
*iid_count
, IID
**iids
)
135 FIXME("iface %p, iid_count %p, iids %p stub!\n", iface
, iid_count
, iids
);
140 static HRESULT STDMETHODCALLTYPE
async_action_GetRuntimeClassName(
141 IAsyncAction
*iface
, HSTRING
*class_name
)
143 FIXME("iface %p, class_name %p stub!\n", iface
, class_name
);
148 static HRESULT STDMETHODCALLTYPE
async_action_GetTrustLevel(
149 IAsyncAction
*iface
, TrustLevel
*trust_level
)
151 FIXME("iface %p, trust_level %p stub!\n", iface
, trust_level
);
156 static HRESULT STDMETHODCALLTYPE
async_action_put_Completed(IAsyncAction
*iface
, IAsyncActionCompletedHandler
*handler
)
158 FIXME("iface %p, handler %p stub!\n", iface
, handler
);
163 static HRESULT STDMETHODCALLTYPE
async_action_get_Completed(IAsyncAction
*iface
, IAsyncActionCompletedHandler
**handler
)
165 FIXME("iface %p, handler %p stub!\n", iface
, handler
);
170 static HRESULT STDMETHODCALLTYPE
async_action_GetResults(IAsyncAction
*iface
)
172 FIXME("iface %p stub!\n", iface
);
177 static const IAsyncActionVtbl async_action_vtbl
=
179 async_action_QueryInterface
,
181 async_action_Release
,
182 async_action_GetIids
,
183 async_action_GetRuntimeClassName
,
184 async_action_GetTrustLevel
,
185 async_action_put_Completed
,
186 async_action_get_Completed
,
187 async_action_GetResults
,
190 static HRESULT STDMETHODCALLTYPE
async_info_QueryInterface(IAsyncInfo
*iface
, REFIID iid
, void **out
)
192 struct async_action
*action
= impl_from_IAsyncInfo(iface
);
193 return IAsyncAction_QueryInterface(&action
->IAsyncAction_iface
, iid
, out
);
196 static ULONG STDMETHODCALLTYPE
async_info_AddRef(IAsyncInfo
*iface
)
198 struct async_action
*action
= impl_from_IAsyncInfo(iface
);
199 return IAsyncAction_AddRef(&action
->IAsyncAction_iface
);
202 static ULONG STDMETHODCALLTYPE
async_info_Release(IAsyncInfo
*iface
)
204 struct async_action
*action
= impl_from_IAsyncInfo(iface
);
205 return IAsyncAction_Release(&action
->IAsyncAction_iface
);
208 static HRESULT STDMETHODCALLTYPE
async_info_GetIids(IAsyncInfo
*iface
, ULONG
*iid_count
, IID
**iids
)
210 struct async_action
*action
= impl_from_IAsyncInfo(iface
);
211 return IAsyncAction_GetIids(&action
->IAsyncAction_iface
, iid_count
, iids
);
214 static HRESULT STDMETHODCALLTYPE
async_info_GetRuntimeClassName(IAsyncInfo
*iface
, HSTRING
*class_name
)
216 struct async_action
*action
= impl_from_IAsyncInfo(iface
);
217 return IAsyncAction_GetRuntimeClassName(&action
->IAsyncAction_iface
, class_name
);
220 static HRESULT STDMETHODCALLTYPE
async_info_GetTrustLevel(IAsyncInfo
*iface
, TrustLevel
*trust_level
)
222 struct async_action
*action
= impl_from_IAsyncInfo(iface
);
223 return IAsyncAction_GetTrustLevel(&action
->IAsyncAction_iface
, trust_level
);
226 static HRESULT STDMETHODCALLTYPE
async_info_get_Id(IAsyncInfo
*iface
, UINT32
*id
)
228 FIXME("iface %p, id %p stub!\n", iface
, id
);
233 static HRESULT STDMETHODCALLTYPE
async_info_get_Status(IAsyncInfo
*iface
, AsyncStatus
*status
)
235 FIXME("iface %p, status %p stub!\n", iface
, status
);
240 static HRESULT STDMETHODCALLTYPE
async_info_get_ErrorCode(IAsyncInfo
*iface
, HRESULT
*error_code
)
242 FIXME("iface %p, error_code %p stub!\n", iface
, error_code
);
247 static HRESULT STDMETHODCALLTYPE
async_info_Cancel(IAsyncInfo
*iface
)
249 FIXME("iface %p stub!\n", iface
);
254 static HRESULT STDMETHODCALLTYPE
async_info_Close(IAsyncInfo
*iface
)
256 FIXME("iface %p stub!\n", iface
);
261 static const IAsyncInfoVtbl async_info_vtbl
=
263 async_info_QueryInterface
,
267 async_info_GetRuntimeClassName
,
268 async_info_GetTrustLevel
,
270 async_info_get_Status
,
271 async_info_get_ErrorCode
,
276 static HRESULT
async_action_create(IAsyncAction
**ret
)
278 struct async_action
*object
;
282 if (!(object
= calloc(1, sizeof(*object
))))
283 return E_OUTOFMEMORY
;
285 object
->IAsyncAction_iface
.lpVtbl
= &async_action_vtbl
;
286 object
->IAsyncInfo_iface
.lpVtbl
= &async_info_vtbl
;
287 object
->refcount
= 1;
289 *ret
= &object
->IAsyncAction_iface
;
296 IWorkItemHandler
*handler
;
297 IAsyncAction
*action
;
300 static void release_work_item(struct work_item
*item
)
302 IWorkItemHandler_Release(item
->handler
);
303 IAsyncAction_Release(item
->action
);
307 static HRESULT
alloc_work_item(IWorkItemHandler
*handler
, struct work_item
**ret
)
309 struct work_item
*object
;
314 if (!(object
= calloc(1, sizeof(*object
))))
315 return E_OUTOFMEMORY
;
317 if (FAILED(hr
= async_action_create(&object
->action
)))
323 IWorkItemHandler_AddRef((object
->handler
= handler
));
330 static void work_item_invoke_release(struct work_item
*item
)
332 IWorkItemHandler_Invoke(item
->handler
, item
->action
);
333 release_work_item(item
);
336 static DWORD WINAPI
sliced_thread_proc(void *arg
)
338 struct work_item
*item
= arg
;
339 work_item_invoke_release(item
);
349 static struct thread_pool pools
[3];
351 static BOOL CALLBACK
pool_init_once(INIT_ONCE
*init_once
, void *param
, void **context
)
353 struct thread_pool
*pool
= param
;
355 if (!(pool
->pool
= CreateThreadpool(NULL
))) return FALSE
;
357 SetThreadpoolThreadMaximum(pool
->pool
, 10);
362 static void CALLBACK
pool_work_callback(TP_CALLBACK_INSTANCE
*instance
, void *context
, TP_WORK
*work
)
364 struct work_item
*item
= context
;
365 work_item_invoke_release(item
);
368 static HRESULT
submit_threadpool_work(struct work_item
*item
, WorkItemPriority priority
, IAsyncAction
**action
)
370 struct thread_pool
*pool
;
373 assert(priority
== WorkItemPriority_Low
374 || priority
== WorkItemPriority_Normal
375 || priority
== WorkItemPriority_High
);
377 pool
= &pools
[priority
+ 1];
379 if (!InitOnceExecuteOnce(&pool
->init_once
, pool_init_once
, pool
, NULL
))
382 if (!(work
= CreateThreadpoolWork(pool_work_callback
, item
, NULL
)))
385 IAsyncAction_AddRef((*action
= item
->action
));
386 SubmitThreadpoolWork(work
);
391 static HRESULT
submit_standalone_thread_work(struct work_item
*item
, WorkItemPriority priority
, IAsyncAction
**action
)
395 if (!(thread
= CreateThread(NULL
, 0, sliced_thread_proc
, item
, priority
== WorkItemPriority_Normal
?
396 0 : CREATE_SUSPENDED
, NULL
)))
398 WARN("Failed to create a thread, error %ld.\n", GetLastError());
399 return HRESULT_FROM_WIN32(GetLastError());
402 IAsyncAction_AddRef((*action
= item
->action
));
403 if (priority
!= WorkItemPriority_Normal
)
405 SetThreadPriority(thread
, priority
== WorkItemPriority_High
? THREAD_PRIORITY_HIGHEST
: THREAD_PRIORITY_LOWEST
);
406 ResumeThread(thread
);
413 static HRESULT
run_async(IWorkItemHandler
*handler
, WorkItemPriority priority
, WorkItemOptions options
,
414 IAsyncAction
**action
)
416 struct work_item
*item
;
424 if (priority
< WorkItemPriority_Low
|| priority
> WorkItemPriority_High
)
427 if (FAILED(hr
= alloc_work_item(handler
, &item
)))
430 if (options
== WorkItemOptions_TimeSliced
)
431 hr
= submit_standalone_thread_work(item
, priority
, action
);
433 hr
= submit_threadpool_work(item
, priority
, action
);
436 release_work_item(item
);
441 static HRESULT STDMETHODCALLTYPE
threadpool_factory_QueryInterface(
442 IActivationFactory
*iface
, REFIID iid
, void **out
)
444 struct threadpool_factory
*factory
= impl_from_IActivationFactory(iface
);
446 TRACE("iface %p, iid %s, out %p.\n", iface
, debugstr_guid(iid
), out
);
448 if (IsEqualGUID(iid
, &IID_IUnknown
) ||
449 IsEqualGUID(iid
, &IID_IInspectable
) ||
450 IsEqualGUID(iid
, &IID_IAgileObject
) ||
451 IsEqualGUID(iid
, &IID_IActivationFactory
))
453 IUnknown_AddRef(iface
);
454 *out
= &factory
->IActivationFactory_iface
;
458 if (IsEqualGUID(iid
, &IID_IThreadPoolStatics
))
460 IUnknown_AddRef(iface
);
461 *out
= &factory
->IThreadPoolStatics_iface
;
465 FIXME("%s not implemented, returning E_NOINTERFACE.\n", debugstr_guid(iid
));
467 return E_NOINTERFACE
;
470 static ULONG STDMETHODCALLTYPE
threadpool_factory_AddRef(IActivationFactory
*iface
)
472 struct threadpool_factory
*factory
= impl_from_IActivationFactory(iface
);
473 ULONG refcount
= InterlockedIncrement(&factory
->refcount
);
475 TRACE("iface %p, refcount %lu.\n", iface
, refcount
);
480 static ULONG STDMETHODCALLTYPE
threadpool_factory_Release(IActivationFactory
*iface
)
482 struct threadpool_factory
*factory
= impl_from_IActivationFactory(iface
);
483 ULONG refcount
= InterlockedDecrement(&factory
->refcount
);
485 TRACE("iface %p, refcount %lu.\n", iface
, refcount
);
490 static HRESULT STDMETHODCALLTYPE
threadpool_factory_GetIids(
491 IActivationFactory
*iface
, ULONG
*iid_count
, IID
**iids
)
493 FIXME("iface %p, iid_count %p, iids %p stub!\n", iface
, iid_count
, iids
);
497 static HRESULT STDMETHODCALLTYPE
threadpool_factory_GetRuntimeClassName(
498 IActivationFactory
*iface
, HSTRING
*class_name
)
500 FIXME("iface %p, class_name %p stub!\n", iface
, class_name
);
504 static HRESULT STDMETHODCALLTYPE
threadpool_factory_GetTrustLevel(
505 IActivationFactory
*iface
, TrustLevel
*trust_level
)
507 FIXME("iface %p, trust_level %p stub!\n", iface
, trust_level
);
511 static HRESULT STDMETHODCALLTYPE
threadpool_factory_ActivateInstance(
512 IActivationFactory
*iface
, IInspectable
**instance
)
514 FIXME("iface %p, instance %p stub!\n", iface
, instance
);
518 static const struct IActivationFactoryVtbl threadpool_factory_vtbl
=
520 threadpool_factory_QueryInterface
,
521 threadpool_factory_AddRef
,
522 threadpool_factory_Release
,
523 /* IInspectable methods */
524 threadpool_factory_GetIids
,
525 threadpool_factory_GetRuntimeClassName
,
526 threadpool_factory_GetTrustLevel
,
527 /* IActivationFactory methods */
528 threadpool_factory_ActivateInstance
,
531 static HRESULT STDMETHODCALLTYPE
threadpool_statics_QueryInterface(
532 IThreadPoolStatics
*iface
, REFIID iid
, void **object
)
534 struct threadpool_factory
*factory
= impl_from_IThreadPoolStatics(iface
);
535 return IActivationFactory_QueryInterface(&factory
->IActivationFactory_iface
, iid
, object
);
538 static ULONG STDMETHODCALLTYPE
threadpool_statics_AddRef(IThreadPoolStatics
*iface
)
540 struct threadpool_factory
*factory
= impl_from_IThreadPoolStatics(iface
);
541 return IActivationFactory_AddRef(&factory
->IActivationFactory_iface
);
544 static ULONG STDMETHODCALLTYPE
threadpool_statics_Release(IThreadPoolStatics
*iface
)
546 struct threadpool_factory
*factory
= impl_from_IThreadPoolStatics(iface
);
547 return IActivationFactory_Release(&factory
->IActivationFactory_iface
);
550 static HRESULT STDMETHODCALLTYPE
threadpool_statics_GetIids(
551 IThreadPoolStatics
*iface
, ULONG
*iid_count
, IID
**iids
)
553 FIXME("iface %p, iid_count %p, iids %p stub!\n", iface
, iid_count
, iids
);
557 static HRESULT STDMETHODCALLTYPE
threadpool_statics_GetRuntimeClassName(
558 IThreadPoolStatics
*iface
, HSTRING
*class_name
)
560 FIXME("iface %p, class_name %p stub!\n", iface
, class_name
);
564 static HRESULT STDMETHODCALLTYPE
threadpool_statics_GetTrustLevel(
565 IThreadPoolStatics
*iface
, TrustLevel
*trust_level
)
567 FIXME("iface %p, trust_level %p stub!\n", iface
, trust_level
);
571 static HRESULT STDMETHODCALLTYPE
threadpool_statics_RunAsync(
572 IThreadPoolStatics
*iface
, IWorkItemHandler
*handler
, IAsyncAction
**operation
)
574 TRACE("iface %p, handler %p, operation %p.\n", iface
, handler
, operation
);
576 return run_async(handler
, WorkItemPriority_Normal
, WorkItemOptions_None
, operation
);
579 static HRESULT STDMETHODCALLTYPE
threadpool_statics_RunWithPriorityAsync(
580 IThreadPoolStatics
*iface
, IWorkItemHandler
*handler
, WorkItemPriority priority
, IAsyncAction
**operation
)
582 TRACE("iface %p, handler %p, priority %d, operation %p.\n", iface
, handler
, priority
, operation
);
584 return run_async(handler
, priority
, WorkItemOptions_None
, operation
);
587 static HRESULT STDMETHODCALLTYPE
threadpool_statics_RunWithPriorityAndOptionsAsync(
588 IThreadPoolStatics
*iface
, IWorkItemHandler
*handler
, WorkItemPriority priority
,
589 WorkItemOptions options
, IAsyncAction
**operation
)
591 TRACE("iface %p, handler %p, priority %d, options %d, operation %p.\n", iface
, handler
, priority
, options
, operation
);
593 return run_async(handler
, priority
, options
, operation
);
596 static const struct IThreadPoolStaticsVtbl threadpool_statics_vtbl
=
598 threadpool_statics_QueryInterface
,
599 threadpool_statics_AddRef
,
600 threadpool_statics_Release
,
601 /* IInspectable methods */
602 threadpool_statics_GetIids
,
603 threadpool_statics_GetRuntimeClassName
,
604 threadpool_statics_GetTrustLevel
,
605 /* IThreadPoolStatics methods */
606 threadpool_statics_RunAsync
,
607 threadpool_statics_RunWithPriorityAsync
,
608 threadpool_statics_RunWithPriorityAndOptionsAsync
,
611 static struct threadpool_factory threadpool_factory
=
613 .IActivationFactory_iface
.lpVtbl
= &threadpool_factory_vtbl
,
614 .IThreadPoolStatics_iface
.lpVtbl
= &threadpool_statics_vtbl
,
618 HRESULT WINAPI
DllGetClassObject(REFCLSID clsid
, REFIID riid
, void **out
)
620 FIXME("clsid %s, riid %s, out %p stub!\n", debugstr_guid(clsid
), debugstr_guid(riid
), out
);
621 return CLASS_E_CLASSNOTAVAILABLE
;
624 HRESULT WINAPI
DllGetActivationFactory(HSTRING classid
, IActivationFactory
**factory
)
626 const WCHAR
*name
= WindowsGetStringRawBuffer(classid
, NULL
);
628 TRACE("classid %s, factory %p.\n", debugstr_hstring(classid
), factory
);
632 if (!wcscmp(name
, RuntimeClass_Windows_System_Threading_ThreadPool
))
634 *factory
= &threadpool_factory
.IActivationFactory_iface
;
635 IUnknown_AddRef(*factory
);
638 if (*factory
) return S_OK
;
639 return CLASS_E_CLASSNOTAVAILABLE
;