ReactOS 0.4.16-dev-197-g92996da
fxinterruptthreadpoolum.cpp
Go to the documentation of this file.
1/*++
2
3Copyright (c) Microsoft Corporation
4
5Module Name:
6
7 FxInterruptThreadpoolUm.cpp
8
9Abstract:
10
11 Threadpool functions for interrupt handling
12
13Author:
14
15
16
17
18Environment:
19
20 User mode only
21
22Revision History:
23
24--*/
25
26#include "fxmin.hpp"
27#include "FxInterruptThreadpoolUm.hpp"
28
29extern "C" {
30#include "FxInterruptThreadpoolUm.tmh"
31}
32
33#define STRSAFE_LIB
34#include <strsafe.h>
35
37 PFX_DRIVER_GLOBALS FxDriverGlobals
38 ) :
39 FxGlobalsStump(FxDriverGlobals),
40 m_Pool(NULL),
41 m_MinimumThreadCount(MINIMUM_THREAD_COUNT_DEFAULT)
42{
43 InitializeThreadpoolEnvironment(&m_CallbackEnvironment);
44}
45
47{
48 //
49 // close pool
50 //
51 if (m_Pool != NULL) {
52 CloseThreadpool(m_Pool);
53 m_Pool = NULL;
54 }
55
56 DestroyThreadpoolEnvironment(&m_CallbackEnvironment);
57}
58
62 _Out_ FxInterruptThreadpool** ppThreadpool
63 )
64{
65 HRESULT hr;
67
68 FX_VERIFY_WITH_NAME(INTERNAL, CHECK_NOT_NULL(ppThreadpool),
69 DriverGlobals->Public.DriverName);
70
71 *ppThreadpool = NULL;
72
74 if (pool == NULL)
75 {
79 "FxInterruptThreadpool creation failed, "
80 "%!hresult!", hr);
81 return hr;
82 }
83
84 hr = pool->Initialize();
85
86 if (SUCCEEDED(hr))
87 {
88 *ppThreadpool = pool;
89 }
90 else {
91 delete pool;
92 }
93
94 return hr;
95}
96
99 )
100{
101 HRESULT hr = S_OK;
102 DWORD error;
103 BOOL bRet;
104
105 //
106 // Create a thread pool using win32 APIs
107 //
108 m_Pool = CreateThreadpool(NULL);
109 if (m_Pool == NULL)
110 {
115 "Threadpool creation failed, %!winerr!", error);
116 return hr;
117 }
118
119 //
120 // Set maximum thread count to equal the total number of interrupts.
121 // Set minimum thread count (persistent threads) to equal the lower of
122 // number of interrupt and number of processors.
123 //
124 // We want minimum number of persistent threads to be at least equal to the
125 // number of interrupt objects so that there is no delay in servicing the
126 // interrupt if there are processors available (the delay can come due to
127 // thread pool delay in allocating and initializing a new thread). However,
128 // there is not much benefit in having more persistent threads than
129 // processors, as threads would have to wait for processor to become
130 // available anyways. Therefore, we chose to have the number of persistent
131 // equal to the Min(number of interrupts, number of processors).
132 //
133 // In the current design, if there are more interrupts than
134 // processors, as soon as one thread finishes servicing the interrupt, both
135 // the thread and processor will be available to service the next queued
136 // interrupt. Note that thread pool will queue all the waits and will
137 // satisfy them in a FIFO manner.
138 //
139 // Since we don't know the number of interrupts in the beginning, we will
140 // start with one and update it when we know the actual number of interrupts
141 // after processing driver's OnPrepareHardware callback.
142 //
143 // Note on interrupt servicing:
144 // When fx connects the interrupt, it queues an event-based wait block
145 // to thread pool for each interrupt, so that the interrupt can get serviced
146 // using one of the thread pool threads when the auto-reset event shared
147 // with reflector is set by reflector in the DpcForIsr routine queued by Isr.
148 // While the interrupt is being serviced by one of the threads, no wait block
149 // is queued to thread pool for that interrupt, so arrival of same interrupt
150 // signals the event in DpcForIsr but doesn't cause new threads to pick up
151 // the servicing. Note that other interrupts still have their wait blocks
152 // queued so they will be serviced as they arrive.
153 //
154 // When previous servicing is over (i.e. the ISR callback has been
155 // invoked and it has returned), Fx queues another wait block to thread pool
156 // for that interrupt. If the event is already signalled, it would result in
157 // the same thread (or another) picking up servicing immediately.
158 //
159 // This means the interrupt ISR routine can never run concurrently
160 // for same interrupt. Therefore, there is no need to have more than one
161 // thread for each interrupt.
162 //
163 SetThreadpoolThreadMaximum(m_Pool, 1);
164
165 //
166 // Create one persistent thread since atleast one interrupt is the most
167 // likely scenario. We will update this number to have either the same
168 // number of threads as there are interrupts, or the number of
169 // processors on the machine.
170 //
171 bRet = SetThreadpoolThreadMinimum(m_Pool, m_MinimumThreadCount);
172 if (bRet == FALSE) {
177 "%!FUNC!: Failed to set minimum threads (%d) in threadpool,"
178 " %!winerr!", m_MinimumThreadCount, error);
179 goto cleanup;
180 }
181
182 //
183 // Associate thread pool with callback environment.
184 //
185 SetThreadpoolCallbackPool(&m_CallbackEnvironment, m_Pool);
186
187cleanup:
188
189 if (FAILED(hr)) {
190 CloseThreadpool(m_Pool);
191 m_Pool = NULL;
192 }
193
194 return hr;
195}
196
199 _In_ ULONG InterruptCount
200 )
201{
202 BOOL bRet;
203 HRESULT hr = S_OK;
204 SYSTEM_INFO sysInfo;
205 ULONG minThreadCount = 0;
206 ULONG procs;
207 DWORD error;
208
209 FX_VERIFY(INTERNAL, CHECK_NOT_NULL(m_Pool));
210
211 //
212 // if there are more than one interrupts then we need to update minimum
213 // thread count.
214 //
215 if (m_MinimumThreadCount >= InterruptCount) {
216 //
217 // nothing to do
218 //
219 return S_OK;
220 }
221
222 //
223 // We want to have number of minimum persistent threads
224 // = Min(number of interrupts, number of processors).
225 // See comments in Initialize routine for details.
226 //
227 GetSystemInfo(&sysInfo);
228 procs = sysInfo.dwNumberOfProcessors;
229
230 minThreadCount = min(InterruptCount, procs);
231
232 if (m_MinimumThreadCount < minThreadCount) {
233 //
234 // Set threadpool min
235 //
236 bRet = SetThreadpoolThreadMinimum(m_Pool, minThreadCount);
237 if (bRet == FALSE) {
242 "Failed to set minimum threads in threadpool,"
243 " TP_POOL 0x%p to %d %!winerr!", m_Pool, minThreadCount,
244 error);
245 return hr;
246 }
247
248 m_MinimumThreadCount = minThreadCount;
249 }
250
251 //
252 // set thread pool max to max number of interrupts
253 //
254 SetThreadpoolThreadMaximum(m_Pool, InterruptCount);
255
258 "Threads in thread pool TP_POOL 0x%p updated"
259 " to Max %d Min %d threads", m_Pool,
260 InterruptCount, minThreadCount);
261
262 return hr;
263}
264
266 VOID
267 )
268{
269 //
270 // close the thread pool wait structure
271 //
272 if (m_Wait) {
273 //
274 // Make sure no event is registered.
275 //
277
278 //
279 // Wait for all the callbacks to finish.
280 //
282
283 //
284 // close the wait
285 //
287
288 m_Wait = NULL;
289 }
290
291 //
292 // close event handle
293 //
294 if (m_Event) {
296 m_Event = NULL;
297 }
298}
299
302 _In_ FxInterruptThreadpool* Threadpool,
304 _In_ PTP_WAIT_CALLBACK WaitCallback,
305 _Out_ FxInterruptWaitblock** Waitblock
306 )
307{
308 HRESULT hr = S_OK;
309 FxInterruptWaitblock* waitblock = NULL;
310 PFX_DRIVER_GLOBALS driverGlobals;
311
312 FX_VERIFY(INTERNAL, CHECK_NOT_NULL(Waitblock));
313 *Waitblock = NULL;
314 driverGlobals = Interrupt->GetDriverGlobals();
315
316 //
317 // create an instance of interrupt wait block
318 //
319 waitblock = new (driverGlobals) FxInterruptWaitblock(driverGlobals);
320 if (waitblock == NULL) {
322 DoTraceLevelMessage(driverGlobals,
324 "Waitblock creation failed %!hresult!", hr);
325 goto exit;
326 }
327
328 hr = waitblock->Initialize(Threadpool,
329 Interrupt,
330 WaitCallback);
331 if (SUCCEEDED(hr)) {
332 *Waitblock = waitblock;
333 }
334 else {
335 DoTraceLevelMessage(driverGlobals,
337 "Waitblock init failed %!hresult!", hr);
338 }
339
340exit:
341
342 if(FAILED(hr) && waitblock != NULL) {
343 delete waitblock;
344 }
345
346 return hr;
347}
348
351 __in FxInterruptThreadpool* Threadpool,
353 __in PTP_WAIT_CALLBACK WaitCallback
354 )
355{
356 HRESULT hr = S_OK;
357 DWORD error;
358
359 //
360 // create a per-interrupt auto-reset event, non-signalled to begin with.
361 //
363 NULL, // LPSECURITY_ATTRIBUTES lpEventAttributes,
364 FALSE, // BOOL bManualReset,
365 FALSE, // BOOL bInitialState,
366 NULL // LPCTSTR lpName
367 );
368
369 if (m_Event == NULL) {
374 "Event creation failed for FxInterrupt object"
375 " %!winerr!", error);
376 goto exit;
377 }
378
379 //
380 // create a per-interrupt thread pool wait structure. This wait structure is
381 // needed to associate an event-based wait callback with threadpool.
382 //
383 m_Wait = Threadpool->CreateThreadpoolWait(WaitCallback,
384 Interrupt);
385 if (m_Wait == NULL) {
390 "Event creation failed for FxInterrupt object"
391 " %!winerr!", error);
392 goto exit;
393 }
394
395exit:
396
397 return hr;
398}
399
400
static HRESULT _CreateAndInit(_In_ PFX_DRIVER_GLOBALS DriverGlobals, _Out_ FxInterruptThreadpool **ppThreadpool)
TP_CALLBACK_ENVIRON m_CallbackEnvironment
HRESULT UpdateThreadPoolThreadLimits(_In_ ULONG InterruptCount)
FxInterruptThreadpool(PFX_DRIVER_GLOBALS FxDriverGlobals)
static HRESULT _CreateAndInit(_In_ FxInterruptThreadpool *Threadpool, _In_ FxInterrupt *Interrupt, _In_ PTP_WAIT_CALLBACK WaitCallback, _Out_ FxInterruptWaitblock **Waitblock)
HRESULT Initialize(__in FxInterruptThreadpool *Threadpool, __in FxInterrupt *Interrupt, __in PTP_WAIT_CALLBACK WaitCallback)
#define __in
Definition: dbghelp.h:35
#define TRACINGPNP
Definition: dbgtrace.h:67
#define ERROR_NOT_ENOUGH_MEMORY
Definition: dderror.h:7
#define E_OUTOFMEMORY
Definition: ddrawi.h:100
#define NULL
Definition: types.h:112
#define FALSE
Definition: types.h:117
#define CloseHandle
Definition: compat.h:739
static void cleanup(void)
Definition: main.c:1335
VOID WINAPI GetSystemInfo(IN LPSYSTEM_INFO lpSystemInfo)
Definition: sysinfo.c:143
unsigned int BOOL
Definition: ntddk_ex.h:94
unsigned long DWORD
Definition: ntddk_ex.h:95
FX_VERIFY(INTERNAL, CHECK_NOT_NULL(LoaderInterface->pIWudfHost))
DoTraceLevelMessage(pFxDriverGlobals, TRACE_LEVEL_VERBOSE, TRACINGPNP, "Enter, WDFDEVICE %p", Device)
FX_VERIFY_WITH_NAME(DRIVER(BadArgument, TODO), CHECK(ERROR_STRING_HW_ACCESS_NOT_ALLOWED,(pDevice->IsDirectHardwareAccessAllowed()==TRUE)), DriverGlobals->DriverName)
DriverGlobals
#define MINIMUM_THREAD_COUNT_DEFAULT
#define S_OK
Definition: intsafe.h:52
#define SUCCEEDED(hr)
Definition: intsafe.h:50
#define FAILED(hr)
Definition: intsafe.h:51
#define error(str)
Definition: mkdosfs.c:1605
#define min(a, b)
Definition: monoChain.cc:55
#define _Out_
Definition: ms_sal.h:345
#define _In_
Definition: ms_sal.h:308
#define exit(n)
Definition: config.h:202
HRESULT hr
Definition: shlfolder.c:183
#define TRACE_LEVEL_ERROR
Definition: storswtr.h:27
PFX_DRIVER_GLOBALS GetDriverGlobals(VOID)
Definition: fxstump.hpp:98
DWORD dwNumberOfProcessors
Definition: winbase.h:1201
static TP_CALLBACK_ENVIRON *static PTP_WAIT_CALLBACK
Definition: threadpool.c:27
uint32_t ULONG
Definition: typedefs.h:59
_Must_inspect_result_ _In_ WDFDEVICE _In_ PWDF_INTERRUPT_CONFIG _In_opt_ PWDF_OBJECT_ATTRIBUTES _Out_ WDFINTERRUPT * Interrupt
Definition: wdfinterrupt.h:379
DWORD WINAPI GetLastError(void)
Definition: except.c:1042
#define CreateEvent
Definition: winbase.h:3772
#define HRESULT_FROM_WIN32(x)
Definition: winerror.h:92