NTSTATUS FsRtlInitializeWorkerThread ( VOID ) { OBJECT_ATTRIBUTES ObjectAttributes; HANDLE Thread; ULONG i; // // Create worker threads to handle normal and paging overflow reads. // InitializeObjectAttributes(&ObjectAttributes, NULL, 0, NULL, NULL); for (i=0; i < 2; i++) { // // Initialize the FsRtl stack overflow work Queue objects. // KeInitializeQueue(&FsRtlWorkerQueues[i], 0); if (!NT_SUCCESS(PsCreateSystemThread(&Thread, THREAD_ALL_ACCESS, &ObjectAttributes, 0L, NULL, FsRtlWorkerThread, (PVOID)i))) { return FALSE; } } ZwClose( Thread ); return TRUE; }
/* * @implemented */ NTSTATUS NTAPI INIT_FUNCTION FsRtlInitializeWorkerThread(VOID) { ULONG i; NTSTATUS Status; HANDLE ThreadHandle; OBJECT_ATTRIBUTES ObjectAttributes; /* Initialize each queue we have */ for (i = 0; i < FSRTLP_MAX_QUEUES; ++i) { InitializeObjectAttributes(&ObjectAttributes, NULL, 0, NULL, NULL); /* Initialize the queue and its associated thread and pass it the queue ID */ KeInitializeQueue(&FsRtlWorkerQueues[i], 0); Status = PsCreateSystemThread(&ThreadHandle, THREAD_ALL_ACCESS, &ObjectAttributes, 0, 0, FsRtlWorkerThread, (PVOID)i); if (!NT_SUCCESS(Status)) { return Status; } /* Don't leak handle */ ZwClose(ThreadHandle); } /* Also initialize our fallback event, set it to ensure it's already usable */ KeInitializeEvent(&StackOverflowFallbackSerialEvent, SynchronizationEvent, TRUE); return Status; }
/*++ * @name ExpInitializeWorkerThreads * * The ExpInitializeWorkerThreads routine initializes worker thread and * work queue support. * * @param None. * * @return None. * * @remarks This routine is only called once during system initialization. * *--*/ VOID INIT_FUNCTION NTAPI ExpInitializeWorkerThreads(VOID) { ULONG WorkQueueType; ULONG CriticalThreads, DelayedThreads; HANDLE ThreadHandle; PETHREAD Thread; ULONG i; /* Setup the stack swap support */ ExInitializeFastMutex(&ExpWorkerSwapinMutex); InitializeListHead(&ExpWorkerListHead); ExpWorkersCanSwap = TRUE; /* Set the number of critical and delayed threads. We shouldn't hardcode */ DelayedThreads = EX_DELAYED_WORK_THREADS; CriticalThreads = EX_CRITICAL_WORK_THREADS; /* Protect against greedy registry modifications */ ExpAdditionalDelayedWorkerThreads = min(ExpAdditionalDelayedWorkerThreads, 16); ExpAdditionalCriticalWorkerThreads = min(ExpAdditionalCriticalWorkerThreads, 16); /* Calculate final count */ DelayedThreads += ExpAdditionalDelayedWorkerThreads; CriticalThreads += ExpAdditionalCriticalWorkerThreads; /* Initialize the Array */ for (WorkQueueType = 0; WorkQueueType < MaximumWorkQueue; WorkQueueType++) { /* Clear the structure and initialize the queue */ RtlZeroMemory(&ExWorkerQueue[WorkQueueType], sizeof(EX_WORK_QUEUE)); KeInitializeQueue(&ExWorkerQueue[WorkQueueType].WorkerQueue, 0); } /* Dynamic threads are only used for the critical queue */ ExWorkerQueue[CriticalWorkQueue].Info.MakeThreadsAsNecessary = TRUE; /* Initialize the balance set manager events */ KeInitializeEvent(&ExpThreadSetManagerEvent, SynchronizationEvent, FALSE); KeInitializeEvent(&ExpThreadSetManagerShutdownEvent, NotificationEvent, FALSE); /* Create the built-in worker threads for the critical queue */ for (i = 0; i < CriticalThreads; i++) { /* Create the thread */ ExpCreateWorkerThread(CriticalWorkQueue, FALSE); ExpCriticalWorkerThreads++; } /* Create the built-in worker threads for the delayed queue */ for (i = 0; i < DelayedThreads; i++) { /* Create the thread */ ExpCreateWorkerThread(DelayedWorkQueue, FALSE); ExpDelayedWorkerThreads++; } /* Create the built-in worker thread for the hypercritical queue */ ExpCreateWorkerThread(HyperCriticalWorkQueue, FALSE); /* Create the balance set manager thread */ PsCreateSystemThread(&ThreadHandle, THREAD_ALL_ACCESS, NULL, 0, NULL, ExpWorkerThreadBalanceManager, NULL); /* Get a pointer to it for the shutdown process */ ObReferenceObjectByHandle(ThreadHandle, THREAD_ALL_ACCESS, NULL, KernelMode, (PVOID*)&Thread, NULL); ExpWorkerThreadBalanceManagerPtr = Thread; /* Close the handle and return */ ObCloseHandle(ThreadHandle, KernelMode); }
NTSTATUS ExpWorkerInitialization ( VOID ) { ULONG Index; OBJECT_ATTRIBUTES ObjectAttributes; ULONG NumberOfDelayedThreads; ULONG NumberOfCriticalThreads; ULONG NumberOfThreads; NTSTATUS Status; HANDLE Thread; BOOLEAN NtAs; WORK_QUEUE_TYPE WorkQueueType; ExInitializeFastMutex (&ExpWorkerSwapinMutex); InitializeListHead (&ExpWorkerListHead); ExpWorkersCanSwap = TRUE; // // Set the number of worker threads based on the system size. // NtAs = MmIsThisAnNtAsSystem(); NumberOfCriticalThreads = MEDIUM_NUMBER_OF_THREADS; // // Incremented boot time number of delayed threads. // We did this in Windows XP, because 3COM NICs would take a long // time with the network stack tying up the delayed worker threads. // When Mm would need a worker thread to load a driver on the critical // path of boot, it would also get stuck for a few seconds and hurt // boot times. Ideally we'd spawn new delayed threads as necessary as // well to prevent such contention from hurting boot and resume. // NumberOfDelayedThreads = MEDIUM_NUMBER_OF_THREADS + 4; switch (MmQuerySystemSize()) { case MmSmallSystem: break; case MmMediumSystem: if (NtAs) { NumberOfCriticalThreads += MEDIUM_NUMBER_OF_THREADS; } break; case MmLargeSystem: NumberOfCriticalThreads = LARGE_NUMBER_OF_THREADS; if (NtAs) { NumberOfCriticalThreads += LARGE_NUMBER_OF_THREADS; } break; default: break; } // // Initialize the work Queue objects. // if (ExpAdditionalCriticalWorkerThreads > MAX_ADDITIONAL_THREADS) { ExpAdditionalCriticalWorkerThreads = MAX_ADDITIONAL_THREADS; } if (ExpAdditionalDelayedWorkerThreads > MAX_ADDITIONAL_THREADS) { ExpAdditionalDelayedWorkerThreads = MAX_ADDITIONAL_THREADS; } // // Initialize the ExWorkerQueue[] array. // RtlZeroMemory (&ExWorkerQueue[0], MaximumWorkQueue * sizeof(EX_WORK_QUEUE)); for (WorkQueueType = 0; WorkQueueType < MaximumWorkQueue; WorkQueueType += 1) { KeInitializeQueue (&ExWorkerQueue[WorkQueueType].WorkerQueue, 0); ExWorkerQueue[WorkQueueType].Info.WaitMode = UserMode; } // // Always make stack for this thread resident // so that worker pool deadlock magic can run // even when what we are trying to do is inpage // the hyper critical worker thread's stack. // Without this fix, we hold the process lock // but this thread's stack can't come in, and // the deadlock detection cannot create new threads // to break the system deadlock. // ExWorkerQueue[HyperCriticalWorkQueue].Info.WaitMode = KernelMode; if (NtAs) { ExWorkerQueue[CriticalWorkQueue].Info.WaitMode = KernelMode; } // // We only create dynamic threads for the critical work queue (note // this doesn't apply to dynamic threads created to break deadlocks.) // // The rationale is this: folks who use the delayed work queue are // not time critical, and the hypercritical queue is used rarely // by folks who are non-blocking. // ExWorkerQueue[CriticalWorkQueue].Info.MakeThreadsAsNecessary = 1; // // Initialize the global thread set manager events // KeInitializeEvent (&ExpThreadSetManagerEvent, SynchronizationEvent, FALSE); KeInitializeEvent (&ExpThreadSetManagerShutdownEvent, SynchronizationEvent, FALSE); // // Create the desired number of executive worker threads for each // of the work queues. // // // Create the builtin critical worker threads. // NumberOfThreads = NumberOfCriticalThreads + ExpAdditionalCriticalWorkerThreads; for (Index = 0; Index < NumberOfThreads; Index += 1) { // // Create a worker thread to service the critical work queue. // Status = ExpCreateWorkerThread (CriticalWorkQueue, FALSE); if (!NT_SUCCESS(Status)) { break; } } ExCriticalWorkerThreads += Index; // // Create the delayed worker threads. // NumberOfThreads = NumberOfDelayedThreads + ExpAdditionalDelayedWorkerThreads; for (Index = 0; Index < NumberOfThreads; Index += 1) { // // Create a worker thread to service the delayed work queue. // Status = ExpCreateWorkerThread (DelayedWorkQueue, FALSE); if (!NT_SUCCESS(Status)) { break; } } ExDelayedWorkerThreads += Index; // // Create the hypercritical worker thread. // Status = ExpCreateWorkerThread (HyperCriticalWorkQueue, FALSE); // // Create the worker thread set manager thread. // InitializeObjectAttributes (&ObjectAttributes, NULL, 0, NULL, NULL); Status = PsCreateSystemThread (&Thread, THREAD_ALL_ACCESS, &ObjectAttributes, 0, NULL, ExpWorkerThreadBalanceManager, NULL); if (NT_SUCCESS(Status)) { Status = ObReferenceObjectByHandle (Thread, SYNCHRONIZE, NULL, KernelMode, &ExpWorkerThreadBalanceManagerPtr, NULL); ZwClose (Thread); } return Status; }
NTSTATUS NtCreateIoCompletion ( __out PHANDLE IoCompletionHandle, __in ACCESS_MASK DesiredAccess, __in_opt POBJECT_ATTRIBUTES ObjectAttributes, __in ULONG Count OPTIONAL ) /*++ Routine Description: This function creates an I/O completion object, sets the maximum target concurrent thread count to the specified value, and opens a handle to the object with the specified desired access. Arguments: IoCompletionHandle - Supplies a pointer to a variable that receives the I/O completion object handle. DesiredAccess - Supplies the desired types of access for the I/O completion object. ObjectAttributes - Supplies a pointer to an object attributes structure. Count - Supplies the target maximum number of threads that should be concurrently active. If this parameter is not specified, then the number of processors is used. Return Value: STATUS_SUCCESS is returned if the function is success. Otherwise, an error status is returned. --*/ { HANDLE Handle; KPROCESSOR_MODE PreviousMode; PVOID IoCompletion; NTSTATUS Status; // // Establish an exception handler, probe the output handle address, and // attempt to create an I/O completion object. If the probe fails, then // return the exception code as the service status. Otherwise, return the // status value returned by the object insertion routine. // try { // // Get previous processor mode and probe output handle address if // necessary. // PreviousMode = KeGetPreviousMode(); if (PreviousMode != KernelMode) { ProbeForWriteHandle(IoCompletionHandle); } // // Allocate I/O completion object. // Status = ObCreateObject(PreviousMode, IoCompletionObjectType, ObjectAttributes, PreviousMode, NULL, sizeof(KQUEUE), 0, 0, (PVOID *)&IoCompletion); // // If the I/O completion object was successfully allocated, then // initialize the object and attempt to insert it in the handle // table of the current process. // if (NT_SUCCESS(Status)) { KeInitializeQueue((PKQUEUE)IoCompletion, Count); Status = ObInsertObject(IoCompletion, NULL, DesiredAccess, 0, (PVOID *)NULL, &Handle); // // If the I/O completion object was successfully inserted in // the handle table of the current process, then attempt to // write the handle value. If the write attempt fails, then // do not report an error. When the caller attempts to access // the handle value, an access violation will occur. // if (NT_SUCCESS(Status)) { try { *IoCompletionHandle = Handle; } except(ExSystemExceptionFilter()) { NOTHING; } } } // // If an exception occurs during the probe of the output handle address, // then always handle the exception and return the exception code as the // status value. // } except(ExSystemExceptionFilter()) { Status = GetExceptionCode(); } // // Return service status. // return Status; }
NTSTATUS FsRtlInitializeWorkerThread ( VOID ) { OBJECT_ATTRIBUTES ObjectAttributes; HANDLE Thread; ULONG i; NTSTATUS Status = STATUS_SUCCESS; // // Create worker threads to handle normal and paging overflow reads. // InitializeObjectAttributes(&ObjectAttributes, NULL, 0, NULL, NULL); for (i=0; i < 2; i++) { // // Initialize the FsRtl stack overflow work Queue objects. // KeInitializeQueue(&FsRtlWorkerQueues[i], 0); Status = PsCreateSystemThread( &Thread, THREAD_ALL_ACCESS, &ObjectAttributes, 0L, NULL, FsRtlWorkerThread, ULongToPtr( i )); if (!NT_SUCCESS( Status )) { return Status; } ZwClose( Thread ); } // // Initialize the serial workitem so we can guarantee to post items // for paging files to the worker threads. // KeInitializeEvent( &StackOverflowFallbackSerialEvent, SynchronizationEvent, TRUE ); // // Pass a NOP routine through FsRtlPostStackOverfow() in order to flush out // any prefetchw instructions that may lie in that path. Otherwise we'll // try to patch the prefetchw instruction when we can ill afford the stack // space. // #if defined(_AMD64_) FsRtlPostStackOverflow( NULL, NULL, FsRtlpNopStackOverflowRoutine ); FsRtlPostPagingFileStackOverflow( NULL, NULL, FsRtlpNopStackOverflowRoutine ); #endif return Status; }