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 struct threadpool_factory
42 IActivationFactory IActivationFactory_iface
;
43 IThreadPoolStatics IThreadPoolStatics_iface
;
49 IAsyncAction IAsyncAction_iface
;
50 IAsyncInfo IAsyncInfo_iface
;
54 static inline struct threadpool_factory
*impl_from_IActivationFactory(IActivationFactory
*iface
)
56 return CONTAINING_RECORD(iface
, struct threadpool_factory
, IActivationFactory_iface
);
59 static inline struct threadpool_factory
*impl_from_IThreadPoolStatics(IThreadPoolStatics
*iface
)
61 return CONTAINING_RECORD(iface
, struct threadpool_factory
, IThreadPoolStatics_iface
);
64 static inline struct async_action
*impl_from_IAsyncAction(IAsyncAction
*iface
)
66 return CONTAINING_RECORD(iface
, struct async_action
, IAsyncAction_iface
);
69 static inline struct async_action
*impl_from_IAsyncInfo(IAsyncInfo
*iface
)
71 return CONTAINING_RECORD(iface
, struct async_action
, IAsyncInfo_iface
);
74 static HRESULT STDMETHODCALLTYPE
async_action_QueryInterface(IAsyncAction
*iface
, REFIID iid
, void **out
)
76 struct async_action
*action
= impl_from_IAsyncAction(iface
);
78 TRACE("iface %p, iid %s, out %p.\n", iface
, debugstr_guid(iid
), out
);
80 if (IsEqualIID(iid
, &IID_IAsyncAction
)
81 || IsEqualIID(iid
, &IID_IInspectable
)
82 || IsEqualIID(iid
, &IID_IUnknown
))
86 else if (IsEqualIID(iid
, &IID_IAsyncInfo
))
88 *out
= &action
->IAsyncInfo_iface
;
93 WARN("Unsupported interface %s.\n", debugstr_guid(iid
));
96 IUnknown_AddRef((IUnknown
*)*out
);
100 static ULONG STDMETHODCALLTYPE
async_action_AddRef(IAsyncAction
*iface
)
102 struct async_action
*action
= impl_from_IAsyncAction(iface
);
103 ULONG refcount
= InterlockedIncrement(&action
->refcount
);
105 TRACE("iface %p, refcount %lu.\n", iface
, refcount
);
110 static ULONG STDMETHODCALLTYPE
async_action_Release(IAsyncAction
*iface
)
112 struct async_action
*action
= impl_from_IAsyncAction(iface
);
113 ULONG refcount
= InterlockedDecrement(&action
->refcount
);
115 TRACE("iface %p, refcount %lu.\n", iface
, refcount
);
123 static HRESULT STDMETHODCALLTYPE
async_action_GetIids(
124 IAsyncAction
*iface
, ULONG
*iid_count
, IID
**iids
)
126 FIXME("iface %p, iid_count %p, iids %p stub!\n", iface
, iid_count
, iids
);
131 static HRESULT STDMETHODCALLTYPE
async_action_GetRuntimeClassName(
132 IAsyncAction
*iface
, HSTRING
*class_name
)
134 FIXME("iface %p, class_name %p stub!\n", iface
, class_name
);
139 static HRESULT STDMETHODCALLTYPE
async_action_GetTrustLevel(
140 IAsyncAction
*iface
, TrustLevel
*trust_level
)
142 FIXME("iface %p, trust_level %p stub!\n", iface
, trust_level
);
147 static HRESULT STDMETHODCALLTYPE
async_action_put_Completed(IAsyncAction
*iface
, IAsyncActionCompletedHandler
*handler
)
149 FIXME("iface %p, handler %p stub!\n", iface
, handler
);
154 static HRESULT STDMETHODCALLTYPE
async_action_get_Completed(IAsyncAction
*iface
, IAsyncActionCompletedHandler
**handler
)
156 FIXME("iface %p, handler %p stub!\n", iface
, handler
);
161 static HRESULT STDMETHODCALLTYPE
async_action_GetResults(IAsyncAction
*iface
)
163 FIXME("iface %p stub!\n", iface
);
168 static const IAsyncActionVtbl async_action_vtbl
=
170 async_action_QueryInterface
,
172 async_action_Release
,
173 async_action_GetIids
,
174 async_action_GetRuntimeClassName
,
175 async_action_GetTrustLevel
,
176 async_action_put_Completed
,
177 async_action_get_Completed
,
178 async_action_GetResults
,
181 static HRESULT STDMETHODCALLTYPE
async_info_QueryInterface(IAsyncInfo
*iface
, REFIID iid
, void **out
)
183 struct async_action
*action
= impl_from_IAsyncInfo(iface
);
184 return IAsyncAction_QueryInterface(&action
->IAsyncAction_iface
, iid
, out
);
187 static ULONG STDMETHODCALLTYPE
async_info_AddRef(IAsyncInfo
*iface
)
189 struct async_action
*action
= impl_from_IAsyncInfo(iface
);
190 return IAsyncAction_AddRef(&action
->IAsyncAction_iface
);
193 static ULONG STDMETHODCALLTYPE
async_info_Release(IAsyncInfo
*iface
)
195 struct async_action
*action
= impl_from_IAsyncInfo(iface
);
196 return IAsyncAction_Release(&action
->IAsyncAction_iface
);
199 static HRESULT STDMETHODCALLTYPE
async_info_GetIids(IAsyncInfo
*iface
, ULONG
*iid_count
, IID
**iids
)
201 struct async_action
*action
= impl_from_IAsyncInfo(iface
);
202 return IAsyncAction_GetIids(&action
->IAsyncAction_iface
, iid_count
, iids
);
205 static HRESULT STDMETHODCALLTYPE
async_info_GetRuntimeClassName(IAsyncInfo
*iface
, HSTRING
*class_name
)
207 struct async_action
*action
= impl_from_IAsyncInfo(iface
);
208 return IAsyncAction_GetRuntimeClassName(&action
->IAsyncAction_iface
, class_name
);
211 static HRESULT STDMETHODCALLTYPE
async_info_GetTrustLevel(IAsyncInfo
*iface
, TrustLevel
*trust_level
)
213 struct async_action
*action
= impl_from_IAsyncInfo(iface
);
214 return IAsyncAction_GetTrustLevel(&action
->IAsyncAction_iface
, trust_level
);
217 static HRESULT STDMETHODCALLTYPE
async_info_get_Id(IAsyncInfo
*iface
, UINT32
*id
)
219 FIXME("iface %p, id %p stub!\n", iface
, id
);
224 static HRESULT STDMETHODCALLTYPE
async_info_get_Status(IAsyncInfo
*iface
, AsyncStatus
*status
)
226 FIXME("iface %p, status %p stub!\n", iface
, status
);
231 static HRESULT STDMETHODCALLTYPE
async_info_get_ErrorCode(IAsyncInfo
*iface
, HRESULT
*error_code
)
233 FIXME("iface %p, error_code %p stub!\n", iface
, error_code
);
238 static HRESULT STDMETHODCALLTYPE
async_info_Cancel(IAsyncInfo
*iface
)
240 FIXME("iface %p stub!\n", iface
);
245 static HRESULT STDMETHODCALLTYPE
async_info_Close(IAsyncInfo
*iface
)
247 FIXME("iface %p stub!\n", iface
);
252 static const IAsyncInfoVtbl async_info_vtbl
=
254 async_info_QueryInterface
,
258 async_info_GetRuntimeClassName
,
259 async_info_GetTrustLevel
,
261 async_info_get_Status
,
262 async_info_get_ErrorCode
,
267 static HRESULT
async_action_create(IAsyncAction
**ret
)
269 struct async_action
*object
;
273 if (!(object
= calloc(1, sizeof(*object
))))
274 return E_OUTOFMEMORY
;
276 object
->IAsyncAction_iface
.lpVtbl
= &async_action_vtbl
;
277 object
->IAsyncInfo_iface
.lpVtbl
= &async_info_vtbl
;
278 object
->refcount
= 1;
280 *ret
= &object
->IAsyncAction_iface
;
287 IWorkItemHandler
*handler
;
288 IAsyncAction
*action
;
291 static void release_work_item(struct work_item
*item
)
293 IWorkItemHandler_Release(item
->handler
);
294 IAsyncAction_Release(item
->action
);
298 static HRESULT
alloc_work_item(IWorkItemHandler
*handler
, struct work_item
**ret
)
300 struct work_item
*object
;
305 if (!(object
= calloc(1, sizeof(*object
))))
306 return E_OUTOFMEMORY
;
308 if (FAILED(hr
= async_action_create(&object
->action
)))
314 IWorkItemHandler_AddRef((object
->handler
= handler
));
321 static void work_item_invoke_release(struct work_item
*item
)
323 IWorkItemHandler_Invoke(item
->handler
, item
->action
);
324 release_work_item(item
);
327 static DWORD WINAPI
sliced_thread_proc(void *arg
)
329 struct work_item
*item
= arg
;
330 work_item_invoke_release(item
);
340 static struct thread_pool pools
[3];
342 static BOOL CALLBACK
pool_init_once(INIT_ONCE
*init_once
, void *param
, void **context
)
344 struct thread_pool
*pool
= param
;
346 if (!(pool
->pool
= CreateThreadpool(NULL
))) return FALSE
;
348 SetThreadpoolThreadMaximum(pool
->pool
, 10);
353 static void CALLBACK
pool_work_callback(TP_CALLBACK_INSTANCE
*instance
, void *context
, TP_WORK
*work
)
355 struct work_item
*item
= context
;
356 work_item_invoke_release(item
);
359 static HRESULT
submit_threadpool_work(struct work_item
*item
, WorkItemPriority priority
, IAsyncAction
**action
)
361 struct thread_pool
*pool
;
364 assert(priority
== WorkItemPriority_Low
365 || priority
== WorkItemPriority_Normal
366 || priority
== WorkItemPriority_High
);
368 pool
= &pools
[priority
+ 1];
370 if (!InitOnceExecuteOnce(&pool
->init_once
, pool_init_once
, pool
, NULL
))
373 if (!(work
= CreateThreadpoolWork(pool_work_callback
, item
, NULL
)))
376 IAsyncAction_AddRef((*action
= item
->action
));
377 SubmitThreadpoolWork(work
);
382 static HRESULT
submit_standalone_thread_work(struct work_item
*item
, WorkItemPriority priority
, IAsyncAction
**action
)
386 if (!(thread
= CreateThread(NULL
, 0, sliced_thread_proc
, item
, priority
== WorkItemPriority_Normal
?
387 0 : CREATE_SUSPENDED
, NULL
)))
389 WARN("Failed to create a thread, error %ld.\n", GetLastError());
390 return HRESULT_FROM_WIN32(GetLastError());
393 IAsyncAction_AddRef((*action
= item
->action
));
394 if (priority
!= WorkItemPriority_Normal
)
396 SetThreadPriority(thread
, priority
== WorkItemPriority_High
? THREAD_PRIORITY_HIGHEST
: THREAD_PRIORITY_LOWEST
);
397 ResumeThread(thread
);
404 static HRESULT
run_async(IWorkItemHandler
*handler
, WorkItemPriority priority
, WorkItemOptions options
,
405 IAsyncAction
**action
)
407 struct work_item
*item
;
415 if (priority
< WorkItemPriority_Low
|| priority
> WorkItemPriority_High
)
418 if (FAILED(hr
= alloc_work_item(handler
, &item
)))
421 if (options
== WorkItemOptions_TimeSliced
)
422 hr
= submit_standalone_thread_work(item
, priority
, action
);
424 hr
= submit_threadpool_work(item
, priority
, action
);
427 release_work_item(item
);
432 static HRESULT STDMETHODCALLTYPE
threadpool_factory_QueryInterface(
433 IActivationFactory
*iface
, REFIID iid
, void **out
)
435 struct threadpool_factory
*factory
= impl_from_IActivationFactory(iface
);
437 TRACE("iface %p, iid %s, out %p.\n", iface
, debugstr_guid(iid
), out
);
439 if (IsEqualGUID(iid
, &IID_IUnknown
) ||
440 IsEqualGUID(iid
, &IID_IInspectable
) ||
441 IsEqualGUID(iid
, &IID_IAgileObject
) ||
442 IsEqualGUID(iid
, &IID_IActivationFactory
))
444 IUnknown_AddRef(iface
);
445 *out
= &factory
->IActivationFactory_iface
;
449 if (IsEqualGUID(iid
, &IID_IThreadPoolStatics
))
451 IUnknown_AddRef(iface
);
452 *out
= &factory
->IThreadPoolStatics_iface
;
456 FIXME("%s not implemented, returning E_NOINTERFACE.\n", debugstr_guid(iid
));
458 return E_NOINTERFACE
;
461 static ULONG STDMETHODCALLTYPE
threadpool_factory_AddRef(IActivationFactory
*iface
)
463 struct threadpool_factory
*factory
= impl_from_IActivationFactory(iface
);
464 ULONG refcount
= InterlockedIncrement(&factory
->refcount
);
466 TRACE("iface %p, refcount %lu.\n", iface
, refcount
);
471 static ULONG STDMETHODCALLTYPE
threadpool_factory_Release(IActivationFactory
*iface
)
473 struct threadpool_factory
*factory
= impl_from_IActivationFactory(iface
);
474 ULONG refcount
= InterlockedDecrement(&factory
->refcount
);
476 TRACE("iface %p, refcount %lu.\n", iface
, refcount
);
481 static HRESULT STDMETHODCALLTYPE
threadpool_factory_GetIids(
482 IActivationFactory
*iface
, ULONG
*iid_count
, IID
**iids
)
484 FIXME("iface %p, iid_count %p, iids %p stub!\n", iface
, iid_count
, iids
);
488 static HRESULT STDMETHODCALLTYPE
threadpool_factory_GetRuntimeClassName(
489 IActivationFactory
*iface
, HSTRING
*class_name
)
491 FIXME("iface %p, class_name %p stub!\n", iface
, class_name
);
495 static HRESULT STDMETHODCALLTYPE
threadpool_factory_GetTrustLevel(
496 IActivationFactory
*iface
, TrustLevel
*trust_level
)
498 FIXME("iface %p, trust_level %p stub!\n", iface
, trust_level
);
502 static HRESULT STDMETHODCALLTYPE
threadpool_factory_ActivateInstance(
503 IActivationFactory
*iface
, IInspectable
**instance
)
505 FIXME("iface %p, instance %p stub!\n", iface
, instance
);
509 static const struct IActivationFactoryVtbl threadpool_factory_vtbl
=
511 threadpool_factory_QueryInterface
,
512 threadpool_factory_AddRef
,
513 threadpool_factory_Release
,
514 /* IInspectable methods */
515 threadpool_factory_GetIids
,
516 threadpool_factory_GetRuntimeClassName
,
517 threadpool_factory_GetTrustLevel
,
518 /* IActivationFactory methods */
519 threadpool_factory_ActivateInstance
,
522 static HRESULT STDMETHODCALLTYPE
threadpool_statics_QueryInterface(
523 IThreadPoolStatics
*iface
, REFIID iid
, void **object
)
525 struct threadpool_factory
*factory
= impl_from_IThreadPoolStatics(iface
);
526 return IActivationFactory_QueryInterface(&factory
->IActivationFactory_iface
, iid
, object
);
529 static ULONG STDMETHODCALLTYPE
threadpool_statics_AddRef(IThreadPoolStatics
*iface
)
531 struct threadpool_factory
*factory
= impl_from_IThreadPoolStatics(iface
);
532 return IActivationFactory_AddRef(&factory
->IActivationFactory_iface
);
535 static ULONG STDMETHODCALLTYPE
threadpool_statics_Release(IThreadPoolStatics
*iface
)
537 struct threadpool_factory
*factory
= impl_from_IThreadPoolStatics(iface
);
538 return IActivationFactory_Release(&factory
->IActivationFactory_iface
);
541 static HRESULT STDMETHODCALLTYPE
threadpool_statics_GetIids(
542 IThreadPoolStatics
*iface
, ULONG
*iid_count
, IID
**iids
)
544 FIXME("iface %p, iid_count %p, iids %p stub!\n", iface
, iid_count
, iids
);
548 static HRESULT STDMETHODCALLTYPE
threadpool_statics_GetRuntimeClassName(
549 IThreadPoolStatics
*iface
, HSTRING
*class_name
)
551 FIXME("iface %p, class_name %p stub!\n", iface
, class_name
);
555 static HRESULT STDMETHODCALLTYPE
threadpool_statics_GetTrustLevel(
556 IThreadPoolStatics
*iface
, TrustLevel
*trust_level
)
558 FIXME("iface %p, trust_level %p stub!\n", iface
, trust_level
);
562 static HRESULT STDMETHODCALLTYPE
threadpool_statics_RunAsync(
563 IThreadPoolStatics
*iface
, IWorkItemHandler
*handler
, IAsyncAction
**operation
)
565 TRACE("iface %p, handler %p, operation %p.\n", iface
, handler
, operation
);
567 return run_async(handler
, WorkItemPriority_Normal
, WorkItemOptions_None
, operation
);
570 static HRESULT STDMETHODCALLTYPE
threadpool_statics_RunWithPriorityAsync(
571 IThreadPoolStatics
*iface
, IWorkItemHandler
*handler
, WorkItemPriority priority
, IAsyncAction
**operation
)
573 TRACE("iface %p, handler %p, priority %d, operation %p.\n", iface
, handler
, priority
, operation
);
575 return run_async(handler
, priority
, WorkItemOptions_None
, operation
);
578 static HRESULT STDMETHODCALLTYPE
threadpool_statics_RunWithPriorityAndOptionsAsync(
579 IThreadPoolStatics
*iface
, IWorkItemHandler
*handler
, WorkItemPriority priority
,
580 WorkItemOptions options
, IAsyncAction
**operation
)
582 TRACE("iface %p, handler %p, priority %d, options %d, operation %p.\n", iface
, handler
, priority
, options
, operation
);
584 return run_async(handler
, priority
, options
, operation
);
587 static const struct IThreadPoolStaticsVtbl threadpool_statics_vtbl
=
589 threadpool_statics_QueryInterface
,
590 threadpool_statics_AddRef
,
591 threadpool_statics_Release
,
592 /* IInspectable methods */
593 threadpool_statics_GetIids
,
594 threadpool_statics_GetRuntimeClassName
,
595 threadpool_statics_GetTrustLevel
,
596 /* IThreadPoolStatics methods */
597 threadpool_statics_RunAsync
,
598 threadpool_statics_RunWithPriorityAsync
,
599 threadpool_statics_RunWithPriorityAndOptionsAsync
,
602 static struct threadpool_factory threadpool_factory
=
604 .IActivationFactory_iface
.lpVtbl
= &threadpool_factory_vtbl
,
605 .IThreadPoolStatics_iface
.lpVtbl
= &threadpool_statics_vtbl
,
609 HRESULT WINAPI
DllGetClassObject(REFCLSID clsid
, REFIID riid
, void **out
)
611 FIXME("clsid %s, riid %s, out %p stub!\n", debugstr_guid(clsid
), debugstr_guid(riid
), out
);
612 return CLASS_E_CLASSNOTAVAILABLE
;
615 HRESULT WINAPI
DllGetActivationFactory(HSTRING classid
, IActivationFactory
**factory
)
617 const WCHAR
*name
= WindowsGetStringRawBuffer(classid
, NULL
);
619 TRACE("classid %s, factory %p.\n", debugstr_hstring(classid
), factory
);
623 if (!wcscmp(name
, RuntimeClass_Windows_System_Threading_ThreadPool
))
625 *factory
= &threadpool_factory
.IActivationFactory_iface
;
626 IUnknown_AddRef(*factory
);
629 if (*factory
) return S_OK
;
630 return CLASS_E_CLASSNOTAVAILABLE
;