ReactOS 0.4.16-dev-290-g89a3b8f
work.c File Reference
#include <ntoskrnl.h>
#include <debug.h>
Include dependency graph for work.c:

Go to the source code of this file.

Macros

#define NDEBUG
 
#define EX_HYPERCRITICAL_WORK_THREADS   1
 
#define EX_DELAYED_WORK_THREADS   3
 
#define EX_CRITICAL_WORK_THREADS   5
 
#define EX_DYNAMIC_WORK_THREAD   0x80000000
 
#define EX_HYPERCRITICAL_QUEUE_PRIORITY_INCREMENT   7
 
#define EX_CRITICAL_QUEUE_PRIORITY_INCREMENT   5
 
#define EX_DELAYED_QUEUE_PRIORITY_INCREMENT   4
 

Functions

VOID NTAPI ExpWorkerThreadEntryPoint (IN PVOID Context)
 
VOID NTAPI ExpCreateWorkerThread (WORK_QUEUE_TYPE WorkQueueType, IN BOOLEAN Dynamic)
 
VOID NTAPI ExpDetectWorkerThreadDeadlock (VOID)
 
VOID NTAPI ExpCheckDynamicThreadCount (VOID)
 
VOID NTAPI ExpWorkerThreadBalanceManager (IN PVOID Context)
 
VOID NTAPI ExpInitializeWorkerThreads (VOID)
 
VOID NTAPI ExpSetSwappingKernelApc (IN PKAPC Apc, OUT PKNORMAL_ROUTINE *NormalRoutine, IN OUT PVOID *NormalContext, IN OUT PVOID *SystemArgument1, IN OUT PVOID *SystemArgument2)
 
VOID NTAPI ExSwapinWorkerThreads (IN BOOLEAN AllowSwap)
 
VOID NTAPI ExQueueWorkItem (IN PWORK_QUEUE_ITEM WorkItem, IN WORK_QUEUE_TYPE QueueType)
 

Variables

EX_WORK_QUEUE ExWorkerQueue [MaximumWorkQueue]
 
ULONG ExCriticalWorkerThreads
 
ULONG ExDelayedWorkerThreads
 
ULONG ExpAdditionalCriticalWorkerThreads
 
ULONG ExpAdditionalDelayedWorkerThreads
 
BOOLEAN ExpWorkersCanSwap
 
LIST_ENTRY ExpWorkerListHead
 
FAST_MUTEX ExpWorkerSwapinMutex
 
KEVENT ExpThreadSetManagerEvent
 
KEVENT ExpThreadSetManagerShutdownEvent
 
PETHREAD ExpWorkerThreadBalanceManagerPtr
 
PETHREAD ExpLastWorkerThread
 

Macro Definition Documentation

◆ EX_CRITICAL_QUEUE_PRIORITY_INCREMENT

#define EX_CRITICAL_QUEUE_PRIORITY_INCREMENT   5

Definition at line 27 of file work.c.

◆ EX_CRITICAL_WORK_THREADS

#define EX_CRITICAL_WORK_THREADS   5

Definition at line 20 of file work.c.

◆ EX_DELAYED_QUEUE_PRIORITY_INCREMENT

#define EX_DELAYED_QUEUE_PRIORITY_INCREMENT   4

Definition at line 28 of file work.c.

◆ EX_DELAYED_WORK_THREADS

#define EX_DELAYED_WORK_THREADS   3

Definition at line 19 of file work.c.

◆ EX_DYNAMIC_WORK_THREAD

#define EX_DYNAMIC_WORK_THREAD   0x80000000

Definition at line 23 of file work.c.

◆ EX_HYPERCRITICAL_QUEUE_PRIORITY_INCREMENT

#define EX_HYPERCRITICAL_QUEUE_PRIORITY_INCREMENT   7

Definition at line 26 of file work.c.

◆ EX_HYPERCRITICAL_WORK_THREADS

#define EX_HYPERCRITICAL_WORK_THREADS   1

Definition at line 18 of file work.c.

◆ NDEBUG

#define NDEBUG

Definition at line 12 of file work.c.

Function Documentation

◆ ExpCheckDynamicThreadCount()

VOID NTAPI ExpCheckDynamicThreadCount ( VOID  )

Definition at line 382 of file work.c.

383{
384 ULONG i;
386
387 /* Loop the 3 queues */
388 for (i = 0; i < MaximumWorkQueue; i++)
389 {
390 /* Get the queue */
392
393 /* Check if still need a new thread. See ExQueueWorkItem */
394 if ((Queue->Info.MakeThreadsAsNecessary) &&
395 (!IsListEmpty(&Queue->WorkerQueue.EntryListHead)) &&
396 (Queue->WorkerQueue.CurrentCount <
397 Queue->WorkerQueue.MaximumCount) &&
398 (Queue->DynamicThreadCount < 16))
399 {
400 /* Create a new thread */
401 DPRINT1("EX: Creating new dynamic thread as requested\n");
403 }
404 }
405}
#define DPRINT1
Definition: precomp.h:8
#define TRUE
Definition: types.h:120
#define IsListEmpty(ListHead)
Definition: env_spec_w32.h:954
GLsizei GLenum const GLvoid GLsizei GLenum GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLint GLint GLint GLshort GLshort GLshort GLubyte GLubyte GLubyte GLuint GLuint GLuint GLushort GLushort GLushort GLbyte GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLfloat GLint GLint GLint GLint GLshort GLshort GLshort GLshort GLubyte GLubyte GLubyte GLubyte GLuint GLuint GLuint GLuint GLushort GLushort GLushort GLushort GLboolean const GLdouble const GLfloat const GLint const GLshort const GLbyte const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLdouble const GLfloat const GLfloat const GLint const GLint const GLshort const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort GLenum GLenum GLenum GLfloat GLenum GLint GLenum GLenum GLenum GLfloat GLenum GLenum GLint GLenum GLfloat GLenum GLint GLint GLushort GLenum GLenum GLfloat GLenum GLenum GLint GLfloat const GLubyte GLenum GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLint GLint GLsizei GLsizei GLint GLenum GLenum const GLvoid GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLenum const GLdouble GLenum GLenum const GLfloat GLenum GLenum const GLint GLsizei GLuint GLfloat GLuint GLbitfield GLfloat GLint GLuint GLboolean GLenum GLfloat GLenum GLbitfield GLenum GLfloat GLfloat GLint GLint const GLfloat GLenum GLfloat GLfloat GLint GLint GLfloat GLfloat GLint GLint const GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat const GLdouble const GLfloat const GLdouble const GLfloat GLint i
Definition: glfuncs.h:248
uint32_t ULONG
Definition: typedefs.h:59
_Must_inspect_result_ _In_ WDFDEVICE _In_ PIRP _In_ WDFQUEUE Queue
Definition: wdfdevice.h:2225
VOID NTAPI ExpCreateWorkerThread(WORK_QUEUE_TYPE WorkQueueType, IN BOOLEAN Dynamic)
Definition: work.c:250
EX_WORK_QUEUE ExWorkerQueue[MaximumWorkQueue]
Definition: work.c:31
@ MaximumWorkQueue
Definition: extypes.h:192

Referenced by ExpWorkerThreadBalanceManager().

◆ ExpCreateWorkerThread()

VOID NTAPI ExpCreateWorkerThread ( WORK_QUEUE_TYPE  WorkQueueType,
IN BOOLEAN  Dynamic 
)

Definition at line 250 of file work.c.

252{
258
259 /* Check if this is going to be a dynamic thread */
260 Context = WorkQueueType;
261
262 /* Add the dynamic mask */
263 if (Dynamic) Context |= EX_DYNAMIC_WORK_THREAD;
264
265 /* Create the System Thread */
268 NULL,
269 NULL,
270 NULL,
273 if (!NT_SUCCESS(Status))
274 {
275 /* Well... */
276 DPRINT1("Failed to create worker thread: 0x%08x\n", Status);
277 return;
278 }
279
280 /* If the thread is dynamic */
281 if (Dynamic)
282 {
283 /* Increase the count */
284 InterlockedIncrement(&ExWorkerQueue[WorkQueueType].DynamicThreadCount);
285 }
286
287 /* Set the priority */
288 if (WorkQueueType == DelayedWorkQueue)
289 {
290 /* Priority == 4 */
292 }
293 else if (WorkQueueType == CriticalWorkQueue)
294 {
295 /* Priority == 5 */
297 }
298 else
299 {
300 /* Priority == 7 */
302 }
303
304 /* Get the Thread */
309 (PVOID*)&Thread,
310 NULL);
311
312 /* Set the Priority */
314
315 /* Dereference and close handle */
318}
#define InterlockedIncrement
Definition: armddk.h:53
LONG NTSTATUS
Definition: precomp.h:26
#define NULL
Definition: types.h:112
#define NT_SUCCESS(StatCode)
Definition: apphelp.c:33
LONG KPRIORITY
Definition: compat.h:803
#define UlongToPtr(u)
Definition: config.h:106
_In_opt_ PFILE_OBJECT _In_opt_ PETHREAD Thread
Definition: fltkernel.h:2653
Status
Definition: gdiplustypes.h:25
#define KernelMode
Definition: asm.h:34
HANDLE hThread
Definition: wizard.c:28
#define THREAD_ALL_ACCESS
Definition: nt_native.h:1339
#define THREAD_SET_INFORMATION
Definition: nt_native.h:1337
POBJECT_TYPE PsThreadType
Definition: thread.c:20
NTSTATUS NTAPI PsCreateSystemThread(OUT PHANDLE ThreadHandle, IN ACCESS_MASK DesiredAccess, IN POBJECT_ATTRIBUTES ObjectAttributes, IN HANDLE ProcessHandle, IN PCLIENT_ID ClientId, IN PKSTART_ROUTINE StartRoutine, IN PVOID StartContext)
Definition: thread.c:602
NTSTATUS NTAPI ObCloseHandle(IN HANDLE Handle, IN KPROCESSOR_MODE AccessMode)
Definition: obhandle.c:3379
NTSTATUS NTAPI ObReferenceObjectByHandle(IN HANDLE Handle, IN ACCESS_MASK DesiredAccess, IN POBJECT_TYPE ObjectType, IN KPROCESSOR_MODE AccessMode, OUT PVOID *Object, OUT POBJECT_HANDLE_INFORMATION HandleInformation OPTIONAL)
Definition: obref.c:494
KTHREAD Tcb
Definition: pstypes.h:1104
LONG NTAPI KeSetBasePriorityThread(IN PKTHREAD Thread, IN LONG Increment)
Definition: thrdobj.c:1176
_In_ WDFINTERRUPT _In_ WDF_INTERRUPT_POLICY _In_ WDF_INTERRUPT_PRIORITY Priority
Definition: wdfinterrupt.h:655
#define EX_DELAYED_QUEUE_PRIORITY_INCREMENT
Definition: work.c:28
#define EX_HYPERCRITICAL_QUEUE_PRIORITY_INCREMENT
Definition: work.c:26
VOID NTAPI ExpWorkerThreadEntryPoint(IN PVOID Context)
Definition: work.c:78
#define EX_CRITICAL_QUEUE_PRIORITY_INCREMENT
Definition: work.c:27
#define EX_DYNAMIC_WORK_THREAD
Definition: work.c:23
@ DelayedWorkQueue
Definition: extypes.h:190
@ CriticalWorkQueue
Definition: extypes.h:189
#define ObDereferenceObject
Definition: obfuncs.h:203

Referenced by ExpCheckDynamicThreadCount(), ExpDetectWorkerThreadDeadlock(), and ExpInitializeWorkerThreads().

◆ ExpDetectWorkerThreadDeadlock()

VOID NTAPI ExpDetectWorkerThreadDeadlock ( VOID  )

Definition at line 337 of file work.c.

338{
339 ULONG i;
341
342 /* Loop the 3 queues */
343 for (i = 0; i < MaximumWorkQueue; i++)
344 {
345 /* Get the queue */
347 ASSERT(Queue->DynamicThreadCount <= 16);
348
349 /* Check if stuff is on the queue that still is unprocessed */
350 if ((Queue->QueueDepthLastPass) &&
351 (Queue->WorkItemsProcessed == Queue->WorkItemsProcessedLastPass) &&
352 (Queue->DynamicThreadCount < 16))
353 {
354 /* Stuff is still on the queue and nobody did anything about it */
355 DPRINT1("EX: Work Queue Deadlock detected: %lu\n", i);
357 DPRINT1("Dynamic threads queued %d\n", Queue->DynamicThreadCount);
358 }
359
360 /* Update our data */
361 Queue->WorkItemsProcessedLastPass = Queue->WorkItemsProcessed;
362 Queue->QueueDepthLastPass = KeReadStateQueue(&Queue->WorkerQueue);
363 }
364}
#define ASSERT(a)
Definition: mode.c:44
LONG NTAPI KeReadStateQueue(IN PKQUEUE Queue)
Definition: queue.c:226

Referenced by ExpWorkerThreadBalanceManager().

◆ ExpInitializeWorkerThreads()

VOID NTAPI ExpInitializeWorkerThreads ( VOID  )

Definition at line 522 of file work.c.

523{
524 ULONG WorkQueueType;
525 ULONG CriticalThreads, DelayedThreads;
526 HANDLE ThreadHandle;
528 ULONG i;
530
531 /* Setup the stack swap support */
535
536 /* Set the number of critical and delayed threads. We shouldn't hardcode */
537 DelayedThreads = EX_DELAYED_WORK_THREADS;
538 CriticalThreads = EX_CRITICAL_WORK_THREADS;
539
540 /* Protect against greedy registry modifications */
545
546 /* Calculate final count */
547 DelayedThreads += ExpAdditionalDelayedWorkerThreads;
548 CriticalThreads += ExpAdditionalCriticalWorkerThreads;
549
550 /* Initialize the Array */
551 for (WorkQueueType = 0; WorkQueueType < MaximumWorkQueue; WorkQueueType++)
552 {
553 /* Clear the structure and initialize the queue */
554 RtlZeroMemory(&ExWorkerQueue[WorkQueueType], sizeof(EX_WORK_QUEUE));
555 KeInitializeQueue(&ExWorkerQueue[WorkQueueType].WorkerQueue, 0);
556 }
557
558 /* Dynamic threads are only used for the critical queue */
560
561 /* Initialize the balance set manager events */
565 FALSE);
566
567 /* Create the built-in worker threads for the critical queue */
568 for (i = 0; i < CriticalThreads; i++)
569 {
570 /* Create the thread */
573 }
574
575 /* Create the built-in worker threads for the delayed queue */
576 for (i = 0; i < DelayedThreads; i++)
577 {
578 /* Create the thread */
581 }
582
583 /* Create the built-in worker thread for the hypercritical queue */
585
586 /* Create the balance set manager thread */
587 Status = PsCreateSystemThread(&ThreadHandle,
589 NULL,
590 0,
591 NULL,
593 NULL);
594 if (!NT_SUCCESS(Status))
595 {
596 KeBugCheckEx(PHASE1_INITIALIZATION_FAILED, Status, 0, 0, 0);
597 }
598
599 /* Get a pointer to it for the shutdown process */
600 ObReferenceObjectByHandle(ThreadHandle,
602 NULL,
604 (PVOID*)&Thread,
605 NULL);
607
608 /* Close the handle and return */
609 ObCloseHandle(ThreadHandle, KernelMode);
610}
#define FALSE
Definition: types.h:117
#define KeInitializeEvent(pEvt, foo, foo2)
Definition: env_spec_w32.h:477
#define InitializeListHead(ListHead)
Definition: env_spec_w32.h:944
#define min(a, b)
Definition: monoChain.cc:55
@ NotificationEvent
@ SynchronizationEvent
VOID NTAPI KeInitializeQueue(IN PKQUEUE Queue, IN ULONG Count OPTIONAL)
Definition: queue.c:148
VOID NTAPI KeBugCheckEx(_In_ ULONG BugCheckCode, _In_ ULONG_PTR BugCheckParameter1, _In_ ULONG_PTR BugCheckParameter2, _In_ ULONG_PTR BugCheckParameter3, _In_ ULONG_PTR BugCheckParameter4)
Definition: rtlcompat.c:108
ULONG MakeThreadsAsNecessary
Definition: extypes.h:400
EX_QUEUE_WORKER_INFO Info
Definition: extypes.h:412
#define RtlZeroMemory(Destination, Length)
Definition: typedefs.h:262
VOID NTAPI ExpWorkerThreadBalanceManager(IN PVOID Context)
Definition: work.c:427
ULONG ExCriticalWorkerThreads
Definition: work.c:34
KEVENT ExpThreadSetManagerEvent
Definition: work.c:45
PETHREAD ExpWorkerThreadBalanceManagerPtr
Definition: work.c:49
BOOLEAN ExpWorkersCanSwap
Definition: work.c:40
ULONG ExDelayedWorkerThreads
Definition: work.c:35
ULONG ExpAdditionalCriticalWorkerThreads
Definition: work.c:36
#define EX_DELAYED_WORK_THREADS
Definition: work.c:19
#define EX_CRITICAL_WORK_THREADS
Definition: work.c:20
KEVENT ExpThreadSetManagerShutdownEvent
Definition: work.c:46
ULONG ExpAdditionalDelayedWorkerThreads
Definition: work.c:37
FAST_MUTEX ExpWorkerSwapinMutex
Definition: work.c:42
LIST_ENTRY ExpWorkerListHead
Definition: work.c:41
FORCEINLINE VOID ExInitializeFastMutex(_Out_ PFAST_MUTEX FastMutex)
Definition: exfuncs.h:274
@ HyperCriticalWorkQueue
Definition: extypes.h:191

Referenced by ExpInitSystemPhase1().

◆ ExpSetSwappingKernelApc()

VOID NTAPI ExpSetSwappingKernelApc ( IN PKAPC  Apc,
OUT PKNORMAL_ROUTINE NormalRoutine,
IN OUT PVOID NormalContext,
IN OUT PVOID SystemArgument1,
IN OUT PVOID SystemArgument2 
)

Definition at line 614 of file work.c.

619{
620 PBOOLEAN AllowSwap;
622
623 /* Make sure it's an active worker */
624 if (PsGetCurrentThread()->ActiveExWorker)
625 {
626 /* Read the setting from the context flag */
627 AllowSwap = (PBOOLEAN)NormalContext;
628 KeSetKernelStackSwapEnable(*AllowSwap);
629 }
630
631 /* Let caller know that we're done */
633}
#define PsGetCurrentThread()
Definition: env_spec_w32.h:81
#define PKEVENT
Definition: env_spec_w32.h:70
#define KeSetEvent(pEvt, foo, foo2)
Definition: env_spec_w32.h:476
BOOLEAN NTAPI KeSetKernelStackSwapEnable(IN BOOLEAN Enable)
Definition: thrdobj.c:988
unsigned char * PBOOLEAN
Definition: typedefs.h:53
_In_opt_ PVOID _In_opt_ PVOID SystemArgument1
Definition: ketypes.h:688

Referenced by ExSwapinWorkerThreads().

◆ ExpWorkerThreadBalanceManager()

VOID NTAPI ExpWorkerThreadBalanceManager ( IN PVOID  Context)

Definition at line 427 of file work.c.

428{
432 PVOID WaitEvents[3];
433 PAGED_CODE();
435
436 /* Raise our priority above all other worker threads */
439
440 /* Setup the timer */
442 Timeout.QuadPart = Int32x32To64(-1, 10000000);
443
444 /* We'll wait on the periodic timer and also the emergency event */
445 WaitEvents[0] = &Timer;
446 WaitEvents[1] = &ExpThreadSetManagerEvent;
447 WaitEvents[2] = &ExpThreadSetManagerShutdownEvent;
448
449 /* Start wait loop */
450 for (;;)
451 {
452 /* Wait for the timer */
455 WaitEvents,
456 WaitAny,
457 Executive,
459 FALSE,
460 NULL,
461 NULL);
462 if (Status == 0)
463 {
464 /* Our timer expired. Check for deadlocks */
466 }
467 else if (Status == 1)
468 {
469 /* Someone notified us, verify if we should create a new thread */
471 }
472 else if (Status == 2)
473 {
474 /* We are shutting down. Cancel the timer */
475 DPRINT1("System shutdown\n");
477
478 /* Make sure we have a final thread */
480
481 /* Wait for it */
483 Executive,
485 FALSE,
486 NULL);
487
488 /* Dereference it and kill us */
491 }
492
493 /*
494 * If WinDBG wants to attach or kill a user-mode process, and/or
495 * page-in an address region, queue a debugger worker thread.
496 */
498 {
502 }
503 }
504}
#define PAGED_CODE()
WINKD_WORKER_STATE ExpDebuggerWork
Definition: dbgctrl.c:25
VOID NTAPI ExpDebuggerWorker(IN PVOID Context)
Definition: dbgctrl.c:52
WORK_QUEUE_ITEM ExpDebuggerWorkItem
Definition: dbgctrl.c:20
#define KeWaitForSingleObject(pEvt, foo, a, b, c)
Definition: env_spec_w32.h:478
@ WinKdWorkerStart
Definition: ex.h:63
@ WinKdWorkerInitialized
Definition: ex.h:64
#define KeGetCurrentThread
Definition: hal.h:55
#define Int32x32To64(a, b)
#define UNREFERENCED_PARAMETER(P)
Definition: ntbasedef.h:325
@ WaitAny
NTSTATUS NTAPI KeWaitForMultipleObjects(IN ULONG Count, IN PVOID Object[], IN WAIT_TYPE WaitType, IN KWAIT_REASON WaitReason, IN KPROCESSOR_MODE WaitMode, IN BOOLEAN Alertable, IN PLARGE_INTEGER Timeout OPTIONAL, OUT PKWAIT_BLOCK WaitBlockArray OPTIONAL)
Definition: wait.c:586
NTSTATUS NTAPI PsTerminateSystemThread(IN NTSTATUS ExitStatus)
Definition: kill.c:1145
#define STATUS_SYSTEM_SHUTDOWN
Definition: ntstatus.h:855
static ULONG Timeout
Definition: ping.c:61
BOOLEAN NTAPI KeSetTimer(IN OUT PKTIMER Timer, IN LARGE_INTEGER DueTime, IN PKDPC Dpc OPTIONAL)
Definition: timerobj.c:281
BOOLEAN NTAPI KeCancelTimer(IN OUT PKTIMER Timer)
Definition: timerobj.c:206
VOID NTAPI KeInitializeTimer(OUT PKTIMER Timer)
Definition: timerobj.c:233
VOID NTAPI ExpCheckDynamicThreadCount(VOID)
Definition: work.c:382
PETHREAD ExpLastWorkerThread
Definition: work.c:50
VOID NTAPI ExQueueWorkItem(IN PWORK_QUEUE_ITEM WorkItem, IN WORK_QUEUE_TYPE QueueType)
Definition: work.c:723
VOID NTAPI ExpDetectWorkerThreadDeadlock(VOID)
Definition: work.c:337
#define ExInitializeWorkItem(Item, Routine, Context)
Definition: exfuncs.h:265
@ Executive
Definition: ketypes.h:415

Referenced by ExpInitializeWorkerThreads().

◆ ExpWorkerThreadEntryPoint()

VOID NTAPI ExpWorkerThreadEntryPoint ( IN PVOID  Context)

Definition at line 78 of file work.c.

79{
81 PLIST_ENTRY QueueEntry;
82 WORK_QUEUE_TYPE WorkQueueType;
85 PLARGE_INTEGER TimeoutPointer = NULL;
87 KPROCESSOR_MODE WaitMode;
88 EX_QUEUE_WORKER_INFO OldValue, NewValue;
89
90 /* Check if this is a dyamic thread */
92 {
93 /* It is, which means we will eventually time out after 10 minutes */
94 Timeout.QuadPart = Int32x32To64(10, -10000000 * 60);
95 TimeoutPointer = &Timeout;
96 }
97
98 /* Get Queue Type and Worker Queue */
99 WorkQueueType = (WORK_QUEUE_TYPE)((ULONG_PTR)Context &
100 ~EX_DYNAMIC_WORK_THREAD);
101 WorkQueue = &ExWorkerQueue[WorkQueueType];
102
103 /* Select the wait mode */
104 WaitMode = (UCHAR)WorkQueue->Info.WaitMode;
105
106 /* Nobody should have initialized this yet, do it now */
108 if (WaitMode == UserMode) Thread->ExWorkerCanWaitUser = TRUE;
109
110 /* If we shouldn't swap, disable that feature */
112
113 /* Set the worker flags */
114 do
115 {
116 /* Check if the queue is being disabled */
117 if (WorkQueue->Info.QueueDisabled)
118 {
119 /* Re-enable stack swapping and kill us */
122 }
123
124 /* Increase the worker count */
125 OldValue = WorkQueue->Info;
126 NewValue = OldValue;
127 NewValue.WorkerCount++;
128 }
130 *(PLONG)&NewValue,
131 *(PLONG)&OldValue) != *(PLONG)&OldValue);
132
133 /* Success, you are now officially a worker thread! */
135
136 /* Loop forever */
137ProcessLoop:
138 for (;;)
139 {
140 /* Wait for something to happen on the queue */
141 QueueEntry = KeRemoveQueue(&WorkQueue->WorkerQueue,
142 WaitMode,
143 TimeoutPointer);
144
145 /* Check if we timed out and quit this loop in that case */
146 if ((NTSTATUS)(ULONG_PTR)QueueEntry == STATUS_TIMEOUT) break;
147
148 /* Increment Processed Work Items */
149 InterlockedIncrement((PLONG)&WorkQueue->WorkItemsProcessed);
150
151 /* Get the Work Item */
153
154 /* Make sure nobody is trying to play smart with us */
155 ASSERT((ULONG_PTR)WorkItem->WorkerRoutine > MmUserProbeAddress);
156
157 /* Call the Worker Routine */
158 WorkItem->WorkerRoutine(WorkItem->Parameter);
159
160 /* Make sure APCs are not disabled */
161 if (Thread->Tcb.CombinedApcDisable != 0)
162 {
163 /* We're nice and do it behind your back */
164 DPRINT1("Warning: Broken Worker Thread: %p %p %p came back "
165 "with APCs disabled!\n",
166 WorkItem->WorkerRoutine,
167 WorkItem->Parameter,
168 WorkItem);
171 }
172
173 /* Make sure it returned at right IRQL */
175 {
176 /* It didn't, bugcheck! */
177 KeBugCheckEx(WORKER_THREAD_RETURNED_AT_BAD_IRQL,
178 (ULONG_PTR)WorkItem->WorkerRoutine,
180 (ULONG_PTR)WorkItem->Parameter,
182 }
183
184 /* Make sure it returned with Impersionation Disabled */
186 {
187 /* It didn't, bugcheck! */
188 KeBugCheckEx(IMPERSONATING_WORKER_THREAD,
189 (ULONG_PTR)WorkItem->WorkerRoutine,
190 (ULONG_PTR)WorkItem->Parameter,
192 0);
193 }
194 }
195
196 /* This is a dynamic thread. Terminate it unless IRPs are pending */
197 if (!IsListEmpty(&Thread->IrpList)) goto ProcessLoop;
198
199 /* Don't terminate it if the queue is disabled either */
200 if (WorkQueue->Info.QueueDisabled) goto ProcessLoop;
201
202 /* Set the worker flags */
203 do
204 {
205 /* Decrease the worker count */
206 OldValue = WorkQueue->Info;
207 NewValue = OldValue;
208 NewValue.WorkerCount--;
209 }
211 *(PLONG)&NewValue,
212 *(PLONG)&OldValue) != *(PLONG)&OldValue);
213
214 /* Decrement dynamic thread count */
215 InterlockedDecrement(&WorkQueue->DynamicThreadCount);
216
217 /* We're not a worker thread anymore */
219
220 /* Re-enable the stack swap */
222 return;
223}
#define InterlockedDecrement
Definition: armddk.h:52
#define STATUS_TIMEOUT
Definition: d3dkmdt.h:49
#define PASSIVE_LEVEL
Definition: env_spec_w32.h:693
#define KeGetCurrentIrql()
Definition: env_spec_w32.h:706
#define InterlockedCompareExchange
Definition: interlocked.h:104
#define UserMode
Definition: asm.h:35
PLIST_ENTRY NTAPI KeRemoveQueue(IN PKQUEUE Queue, IN KPROCESSOR_MODE WaitMode, IN PLARGE_INTEGER Timeout OPTIONAL)
Definition: queue.c:238
ULONG MmUserProbeAddress
Definition: init.c:50
ULONG ExWorkerCanWaitUser
Definition: pstypes.h:1202
LIST_ENTRY IrpList
Definition: pstypes.h:1145
ULONG ActiveExWorker
Definition: pstypes.h:1201
ULONG ActiveImpersonationInfo
Definition: pstypes.h:1182
ULONG CombinedApcDisable
Definition: ketypes.h:1883
Definition: typedefs.h:120
uint32_t ULONG_PTR
Definition: typedefs.h:65
int32_t * PLONG
Definition: typedefs.h:58
#define CONTAINING_RECORD(address, type, field)
Definition: typedefs.h:260
_Must_inspect_result_ _In_ WDFCMRESLIST List
Definition: wdfresource.h:550
_Must_inspect_result_ _In_ PWDF_WORKITEM_CONFIG _In_ PWDF_OBJECT_ATTRIBUTES _Out_ WDFWORKITEM * WorkItem
Definition: wdfworkitem.h:115
LIST_ENTRY WorkQueue
Definition: workqueue.c:16
enum _WORK_QUEUE_TYPE WORK_QUEUE_TYPE
CCHAR KPROCESSOR_MODE
Definition: ketypes.h:7
unsigned char UCHAR
Definition: xmlstorage.h:181

Referenced by ExpCreateWorkerThread().

◆ ExQueueWorkItem()

VOID NTAPI ExQueueWorkItem ( IN PWORK_QUEUE_ITEM  WorkItem,
IN WORK_QUEUE_TYPE  QueueType 
)

Definition at line 723 of file work.c.

725{
728 ASSERT(WorkItem->List.Flink == NULL);
729
730 /* Don't try to trick us */
731 if ((ULONG_PTR)WorkItem->WorkerRoutine < MmUserProbeAddress)
732 {
733 /* Bugcheck the system */
734 KeBugCheckEx(WORKER_INVALID,
735 1,
737 (ULONG_PTR)WorkItem->WorkerRoutine,
738 0);
739 }
740
741 /* Insert the Queue */
742 KeInsertQueue(&WorkQueue->WorkerQueue, &WorkItem->List);
743 ASSERT(!WorkQueue->Info.QueueDisabled);
744
745 /*
746 * Check if we need a new thread. Our decision is as follows:
747 * - This queue type must support Dynamic Threads (duh!)
748 * - It actually has to have unprocessed items
749 * - We have CPUs which could be handling another thread
750 * - We haven't abused our usage of dynamic threads.
751 */
752 if ((WorkQueue->Info.MakeThreadsAsNecessary) &&
753 (!IsListEmpty(&WorkQueue->WorkerQueue.EntryListHead)) &&
754 (WorkQueue->WorkerQueue.CurrentCount <
755 WorkQueue->WorkerQueue.MaximumCount) &&
756 (WorkQueue->DynamicThreadCount < 16))
757 {
758 /* Let the balance manager know about it */
759 DPRINT1("Requesting a new thread. CurrentCount: %lu. MaxCount: %lu\n",
760 WorkQueue->WorkerQueue.CurrentCount,
761 WorkQueue->WorkerQueue.MaximumCount);
763 }
764}
_Must_inspect_result_ _In_ PFLT_CALLBACK_DATA _In_ PFLT_DEFERRED_IO_WORKITEM_ROUTINE _In_ WORK_QUEUE_TYPE QueueType
Definition: fltkernel.h:1978
LONG NTAPI KeInsertQueue(IN PKQUEUE Queue, IN PLIST_ENTRY Entry)
Definition: queue.c:198

Referenced by _Function_class_(), _IRQL_requires_max_(), ACPIDispatchDeviceControl(), add_thread_job(), CcpDereferenceCache(), CcPostWorkQueue(), CcScheduleReadAhead(), CdAddToWorkque(), CTEScheduleEvent(), DriverEntry(), ExpWorkerThreadBalanceManager(), Ext2FloppyFlushDpc(), Ext2QueueCloseRequest(), Ext2QueueRequest(), FatAddToWorkque(), FatCleanVolumeDpc(), FatDeferredFlushDpc(), FatPagingFileErrorHandler(), FltpFastIoDetachDevice(), ForwardedIoCompletionRoutine(), HalAllocateAdapterChannel(), IopDoLoadUnloadDriver(), IopLogDpcRoutine(), IoQueueWorkItem(), IoReportTargetDeviceChangeAsynchronous(), IoWriteErrorLogEntry(), KdpTimeSlipDpcRoutine(), KsGenerateEvent(), KsInstallBusEnumInterface(), KspBusDpcRoutine(), KsQueueWorkItem(), KsRemoveBusEnumInterface(), NdisScheduleWorkItem(), NtfsQueueRequest(), NtSetSystemPowerState(), ObpDeferObjectDeletion(), PiQueueDeviceAction(), PostOnlineNotification(), RxAddToWorkque(), SendOnlineNotificationWorker(), UDFPostRequest(), UDFQueueDelayedClose(), UDFStartEjectWaiter(), UDFVVerify(), USBPORT_TimerDpc(), USBSTOR_QueueWorkItem(), USBSTOR_TimerRoutine(), and VfatQueueRequest().

◆ ExSwapinWorkerThreads()

VOID NTAPI ExSwapinWorkerThreads ( IN BOOLEAN  AllowSwap)

Definition at line 637 of file work.c.

638{
640 PETHREAD CurrentThread = PsGetCurrentThread(), Thread;
642 KAPC Apc;
643 PAGED_CODE();
644
645 /* Initialize an event so we know when we're done */
647
648 /* Lock this routine */
650
651 /* New threads cannot swap anymore */
652 ExpWorkersCanSwap = AllowSwap;
653
654 /* Loop all threads in the system process */
656 while (Thread)
657 {
658 /* Skip threads with explicit permission to do this */
659 if (Thread->ExWorkerCanWaitUser) goto Next;
660
661 /* Check if we reached ourselves */
662 if (Thread == CurrentThread)
663 {
664 /* Do it inline */
666 }
667 else
668 {
669 /* Queue an APC */
670 KeInitializeApc(&Apc,
671 &Thread->Tcb,
674 NULL,
675 NULL,
677 &AllowSwap);
678 if (KeInsertQueueApc(&Apc, &Event, NULL, 3))
679 {
680 /* Wait for the APC to run */
683 }
684 }
685
686 /* Next thread */
687Next:
689 }
690
691 /* Release the lock */
693}
VOID NTAPI KeClearEvent(IN PKEVENT Event)
Definition: eventobj.c:22
_Must_inspect_result_ _In_ PLARGE_INTEGER _In_ PLARGE_INTEGER _In_ ULONG _In_ PFILE_OBJECT _In_ PVOID Process
Definition: fsrtlfuncs.h:223
VOID FASTCALL ExAcquireFastMutex(IN PFAST_MUTEX FastMutex)
Definition: fmutex.c:23
VOID FASTCALL ExReleaseFastMutex(IN PFAST_MUTEX FastMutex)
Definition: fmutex.c:31
@ InsertApcEnvironment
Definition: ketypes.h:770
BOOLEAN NTAPI KeInsertQueueApc(IN PKAPC Apc, IN PVOID SystemArgument1, IN PVOID SystemArgument2, IN KPRIORITY PriorityBoost)
Definition: apc.c:735
VOID NTAPI KeInitializeApc(IN PKAPC Apc, IN PKTHREAD Thread, IN KAPC_ENVIRONMENT TargetEnvironment, IN PKKERNEL_ROUTINE KernelRoutine, IN PKRUNDOWN_ROUTINE RundownRoutine OPTIONAL, IN PKNORMAL_ROUTINE NormalRoutine, IN KPROCESSOR_MODE Mode, IN PVOID Context)
Definition: apc.c:651
PETHREAD NTAPI PsGetNextProcessThread(IN PEPROCESS Process, IN PETHREAD Thread OPTIONAL)
Definition: process.c:75
PEPROCESS PsInitialSystemProcess
Definition: psmgr.c:50
Definition: ketypes.h:547
VOID NTAPI ExpSetSwappingKernelApc(IN PKAPC Apc, OUT PKNORMAL_ROUTINE *NormalRoutine, IN OUT PVOID *NormalContext, IN OUT PVOID *SystemArgument1, IN OUT PVOID *SystemArgument2)
Definition: work.c:614

Referenced by NtSetSystemPowerState().

Variable Documentation

◆ ExCriticalWorkerThreads

ULONG ExCriticalWorkerThreads

Definition at line 34 of file work.c.

Referenced by CcInitializeCacheManager(), and ExpInitializeWorkerThreads().

◆ ExDelayedWorkerThreads

ULONG ExDelayedWorkerThreads

Definition at line 35 of file work.c.

Referenced by ExpInitializeWorkerThreads().

◆ ExpAdditionalCriticalWorkerThreads

ULONG ExpAdditionalCriticalWorkerThreads

Definition at line 36 of file work.c.

Referenced by ExpInitializeWorkerThreads().

◆ ExpAdditionalDelayedWorkerThreads

ULONG ExpAdditionalDelayedWorkerThreads

Definition at line 37 of file work.c.

Referenced by ExpInitializeWorkerThreads().

◆ ExpLastWorkerThread

PETHREAD ExpLastWorkerThread

Definition at line 50 of file work.c.

Referenced by ExpWorkerThreadBalanceManager().

◆ ExpThreadSetManagerEvent

KEVENT ExpThreadSetManagerEvent

◆ ExpThreadSetManagerShutdownEvent

KEVENT ExpThreadSetManagerShutdownEvent

Definition at line 46 of file work.c.

Referenced by ExpInitializeWorkerThreads(), and ExpWorkerThreadBalanceManager().

◆ ExpWorkerListHead

LIST_ENTRY ExpWorkerListHead

Definition at line 41 of file work.c.

Referenced by ExpInitializeWorkerThreads().

◆ ExpWorkersCanSwap

BOOLEAN ExpWorkersCanSwap

◆ ExpWorkerSwapinMutex

FAST_MUTEX ExpWorkerSwapinMutex

Definition at line 42 of file work.c.

Referenced by ExpInitializeWorkerThreads(), and ExSwapinWorkerThreads().

◆ ExpWorkerThreadBalanceManagerPtr

PETHREAD ExpWorkerThreadBalanceManagerPtr

Definition at line 49 of file work.c.

Referenced by ExpInitializeWorkerThreads().

◆ ExWorkerQueue