/*++
* @name ExpCreateWorkerThread
*
* The ExpCreateWorkerThread routine creates a new worker thread for the
* specified queue.
**
* @param QueueType
* Type of the queue to use for this thread. Valid values are:
* - DelayedWorkQueue
* - CriticalWorkQueue
* - HyperCriticalWorkQueue
*
* @param Dynamic
* Specifies whether or not this thread is a dynamic thread.
*
* @return None.
*
* @remarks HyperCritical work threads run at priority 7; Critical work threads
* run at priority 5, and delayed work threads run at priority 4.
*
* This, worker threads cannot pre-empty a normal user-mode thread.
*
*--*/
VOID
NTAPI
ExpCreateWorkerThread(WORK_QUEUE_TYPE WorkQueueType,
IN BOOLEAN Dynamic)
{
PETHREAD Thread;
HANDLE hThread;
ULONG Context;
KPRIORITY Priority;
/* Check if this is going to be a dynamic thread */
Context = WorkQueueType;
/* Add the dynamic mask */
if (Dynamic) Context |= EX_DYNAMIC_WORK_THREAD;
/* Create the System Thread */
PsCreateSystemThread(&hThread,
THREAD_ALL_ACCESS,
NULL,
NULL,
NULL,
ExpWorkerThreadEntryPoint,
UlongToPtr(Context));
/* If the thread is dynamic */
if (Dynamic)
{
/* Increase the count */
InterlockedIncrement(&ExWorkerQueue[WorkQueueType].DynamicThreadCount);
}
/* Set the priority */
if (WorkQueueType == DelayedWorkQueue)
{
/* Priority == 4 */
Priority = EX_DELAYED_QUEUE_PRIORITY_INCREMENT;
}
else if (WorkQueueType == CriticalWorkQueue)
{
/* Priority == 5 */
Priority = EX_CRITICAL_QUEUE_PRIORITY_INCREMENT;
}
else
{
/* Priority == 7 */
Priority = EX_HYPERCRITICAL_QUEUE_PRIORITY_INCREMENT;
}
/* Get the Thread */
ObReferenceObjectByHandle(hThread,
THREAD_SET_INFORMATION,
PsThreadType,
KernelMode,
(PVOID*)&Thread,
NULL);
/* Set the Priority */
KeSetBasePriorityThread(&Thread->Tcb, Priority);
/* Dereference and close handle */
ObDereferenceObject(Thread);
ObCloseHandle(hThread, KernelMode);
}
VOID
NTAPI
PspExitProcess(IN BOOLEAN LastThread,
IN PEPROCESS Process)
{
ULONG Actual;
PAGED_CODE();
PSTRACE(PS_KILL_DEBUG,
"LastThread: %u Process: %p\n", LastThread, Process);
PSREFTRACE(Process);
/* Set Process Exit flag */
InterlockedOr((PLONG)&Process->Flags, PSF_PROCESS_EXITING_BIT);
/* Check if we are the last thread */
if (LastThread)
{
/* Notify the WMI Process Callback */
//WmiTraceProcess(Process, FALSE);
/* Run the Notification Routines */
PspRunCreateProcessNotifyRoutines(Process, FALSE);
}
/* Cleanup the power state */
PopCleanupPowerState((PPOWER_STATE)&Process->Pcb.PowerState);
/* Clear the security port */
if (!Process->SecurityPort)
{
/* So we don't double-dereference */
Process->SecurityPort = (PVOID)1;
}
else if (Process->SecurityPort != (PVOID)1)
{
/* Dereference it */
ObDereferenceObject(Process->SecurityPort);
Process->SecurityPort = (PVOID)1;
}
/* Check if we are the last thread */
if (LastThread)
{
/* Check if we have to set the Timer Resolution */
if (Process->SetTimerResolution)
{
/* Set it to default */
ZwSetTimerResolution(KeMaximumIncrement, 0, &Actual);
}
/* Check if we are part of a Job that has a completion port */
if ((Process->Job) && (Process->Job->CompletionPort))
{
/* FIXME: Check job status code and do I/O completion if needed */
}
/* FIXME: Notify the Prefetcher */
}
else
{
/* Clear process' address space here */
MmCleanProcessAddressSpace(Process);
}
}
NTSYSAPI
NTSTATUS
NTAPI
NtQueueApcThread(
IN HANDLE ThreadHandle,
IN PPS_APC_ROUTINE ApcRoutine,
IN PVOID ApcArgument1,
IN PVOID ApcArgument2,
IN PVOID ApcArgument3
)
/*++
Routine Description:
This function is used to queue a user-mode APC to the specified thread. The APC
will fire when the specified thread does an alertable wait
Arguments:
ThreadHandle - Supplies a handle to a thread object. The caller
must have THREAD_SET_CONTEXT access to the thread.
ApcRoutine - Supplies the address of the APC routine to execute when the
APC fires.
ApcArgument1 - Supplies the first PVOID passed to the APC
ApcArgument2 - Supplies the second PVOID passed to the APC
ApcArgument3 - Supplies the third PVOID passed to the APC
Return Value:
Returns an NT Status code indicating success or failure of the API
--*/
{
PETHREAD Thread;
NTSTATUS st;
KPROCESSOR_MODE Mode;
KIRQL Irql;
PKAPC Apc;
PAGED_CODE();
Mode = KeGetPreviousMode();
st = ObReferenceObjectByHandle(
ThreadHandle,
THREAD_SET_CONTEXT,
PsThreadType,
Mode,
(PVOID *)&Thread,
NULL
);
if ( NT_SUCCESS(st) ) {
st = STATUS_SUCCESS;
if ( IS_SYSTEM_THREAD(Thread) ) {
st = STATUS_INVALID_HANDLE;
}
else {
Apc = ExAllocatePoolWithQuotaTag(
(NonPagedPool | POOL_QUOTA_FAIL_INSTEAD_OF_RAISE),
sizeof(*Apc),
'pasP'
);
if ( !Apc ) {
st = STATUS_NO_MEMORY;
}
else {
KeInitializeApc(
Apc,
&Thread->Tcb,
OriginalApcEnvironment,
PspQueueApcSpecialApc,
NULL,
(PKNORMAL_ROUTINE)ApcRoutine,
UserMode,
ApcArgument1
);
if ( !KeInsertQueueApc(Apc,ApcArgument2,ApcArgument3,0) ) {
ExFreePool(Apc);
st = STATUS_UNSUCCESSFUL;
}
}
}
ObDereferenceObject(Thread);
}
return st;
}
开发者ID:Gaikokujin,项目名称:WinNT4,代码行数:96,代码来源:psctx.c
示例8: PspCreateThread
NTSTATUS
NTAPI
PspCreateThread(OUT PHANDLE ThreadHandle,
IN ACCESS_MASK DesiredAccess,
IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL,
IN HANDLE ProcessHandle,
IN PEPROCESS TargetProcess,
OUT PCLIENT_ID ClientId,
IN PCONTEXT ThreadContext,
IN PINITIAL_TEB InitialTeb,
IN BOOLEAN CreateSuspended,
IN PKSTART_ROUTINE StartRoutine OPTIONAL,
IN PVOID StartContext OPTIONAL)
{
HANDLE hThread;
PEPROCESS Process;
PETHREAD Thread;
PTEB TebBase = NULL;
KPROCESSOR_MODE PreviousMode = ExGetPreviousMode();
NTSTATUS Status, AccessStatus;
HANDLE_TABLE_ENTRY CidEntry;
ACCESS_STATE LocalAccessState;
PACCESS_STATE AccessState = &LocalAccessState;
AUX_ACCESS_DATA AuxData;
BOOLEAN Result, SdAllocated;
PSECURITY_DESCRIPTOR SecurityDescriptor;
SECURITY_SUBJECT_CONTEXT SubjectContext;
PAGED_CODE();
PSTRACE(PS_THREAD_DEBUG,
"ThreadContext: %p TargetProcess: %p ProcessHandle: %p\n",
ThreadContext, TargetProcess, ProcessHandle);
/* If we were called from PsCreateSystemThread, then we're kernel mode */
if (StartRoutine) PreviousMode = KernelMode;
/* Reference the Process by handle or pointer, depending on what we got */
if (ProcessHandle)
{
/* Normal thread or System Thread */
Status = ObReferenceObjectByHandle(ProcessHandle,
PROCESS_CREATE_THREAD,
PsProcessType,
PreviousMode,
(PVOID*)&Process,
NULL);
PSREFTRACE(Process);
}
else
{
/* System thread inside System Process, or Normal Thread with a bug */
if (StartRoutine)
{
/* Reference the Process by Pointer */
ObReferenceObject(TargetProcess);
Process = TargetProcess;
Status = STATUS_SUCCESS;
}
else
{
/* Fake ObReference returning this */
Status = STATUS_INVALID_HANDLE;
}
}
/* Check for success */
if (!NT_SUCCESS(Status)) return Status;
/* Also make sure that User-Mode isn't trying to create a system thread */
if ((PreviousMode != KernelMode) && (Process == PsInitialSystemProcess))
{
/* Fail */
ObDereferenceObject(Process);
return STATUS_INVALID_HANDLE;
}
/* Create Thread Object */
Status = ObCreateObject(PreviousMode,
PsThreadType,
ObjectAttributes,
PreviousMode,
NULL,
sizeof(ETHREAD),
0,
0,
(PVOID*)&Thread);
if (!NT_SUCCESS(Status))
{
/* We failed; dereference the process and exit */
ObDereferenceObject(Process);
return Status;
}
/* Zero the Object entirely */
RtlZeroMemory(Thread, sizeof(ETHREAD));
/* Initialize rundown protection */
ExInitializeRundownProtection(&Thread->RundownProtect);
/* Initialize exit code */
Thread->ExitStatus = STATUS_PENDING;
//.........这里部分代码省略.........
NTSTATUS GetProcessImageName(HANDLE processId, PUNICODE_STRING ProcessImageName)
{
NTSTATUS status;
ULONG returnedLength;
ULONG bufferLength;
HANDLE hProcess;
PVOID buffer;
PEPROCESS eProcess;
PUNICODE_STRING imageName;
PAGED_CODE(); // this eliminates the possibility of the IDLE Thread/Process
status = PsLookupProcessByProcessId(processId, &eProcess);
if(NT_SUCCESS(status))
{
status = ObOpenObjectByPointer(eProcess,0, NULL, 0,0,KernelMode,&hProcess);
if(NT_SUCCESS(status))
{
} else {
DbgPrint("ObOpenObjectByPointer Failed: %08x\n", status);
}
ObDereferenceObject(eProcess);
} else {
DbgPrint("PsLookupProcessByProcessId Failed: %08x\n", status);
}
if (NULL == ZwQueryInformationProcess) {
UNICODE_STRING routineName;
RtlInitUnicodeString(&routineName, L"ZwQueryInformationProcess");
ZwQueryInformationProcess =
(QUERY_INFO_PROCESS) MmGetSystemRoutineAddress(&routineName);
if (NULL == ZwQueryInformationProcess) {
DbgPrint("Cannot resolve ZwQueryInformationProcess\n");
}
}
/* Query the actual size of the process path */
status = ZwQueryInformationProcess( hProcess,
ProcessImageFileName,
NULL, // buffer
0, // buffer size
&returnedLength);
if (STATUS_INFO_LENGTH_MISMATCH != status) {
return status;
}
/* Check there is enough space to store the actual process
path when it is found. If not return an error with the
required size */
bufferLength = returnedLength - sizeof(UNICODE_STRING);
if (ProcessImageName->MaximumLength < bufferLength)
{
ProcessImageName->MaximumLength = (USHORT) bufferLength;
return STATUS_BUFFER_OVERFLOW;
}
/* Allocate a temporary buffer to store the path name */
buffer = ExAllocatePoolWithTag(NonPagedPool, returnedLength, PROCESS_POOL_TAG);
if (NULL == buffer)
{
return STATUS_INSUFFICIENT_RESOURCES;
}
/* Retrieve the process path from the handle to the process */
status = ZwQueryInformationProcess( hProcess,
ProcessImageFileName,
buffer,
returnedLength,
&returnedLength);
if (NT_SUCCESS(status))
{
/* Copy the path name */
imageName = (PUNICODE_STRING) buffer;
RtlCopyUnicodeString(ProcessImageName, imageName);
}
/* Free the temp buffer which stored the path */
ExFreePoolWithTag(buffer, PROCESS_POOL_TAG);
return status;
}
//.........这里部分代码省略.........
irpStack = IoGetNextIrpStackLocation(irp);
if (irp == NULL) {
Bus_KdPrint_Def( BUS_DBG_SS_ERROR, ("STATUS_INSUFFICIENT_RESOURCES\n"));
status = STATUS_INSUFFICIENT_RESOURCES;
goto cleanup;
}
//
// Set major and minor codes.
//
irpStack->MajorFunction = IRP_MJ_SCSI;
irpStack->MinorFunction = 1;
//
// Fill in SRB fields.
//
irpStack->Parameters.Others.Argument1 = &srb;
//
// Zero out the srb.
//
RtlZeroMemory(&srb, sizeof(SCSI_REQUEST_BLOCK));
srb.PathId = 0;
srb.TargetId = 0;
srb.Lun = 0;
srb.Function = SRB_FUNCTION_IO_CONTROL;
srb.Length = sizeof(SCSI_REQUEST_BLOCK);
srb.SrbFlags = /*SRB_FLAGS_DATA_IN |*/ SRB_FLAGS_NO_QUEUE_FREEZE /*| SRB_FLAGS_BYPASS_FROZEN_QUEUE */;
srb.OriginalRequest = irp;
//
// Set timeout to requested value.
//
srb.TimeOutValue = psrbIoctl->Timeout;
//
// Set the data buffer.
//
srb.DataBuffer = psrbIoctl;
srb.DataTransferLength = srbIoctlLength;
//
// Flush the data buffer for output. This will insure that the data is
// written back to memory. Since the data-in flag is the the port driver
// will flush the data again for input which will ensure the data is not
// in the cache.
//
/*
KeFlushIoBuffers(irp->MdlAddress, FALSE, TRUE);
*/
status = IoCallDriver( AttachedDevice, irp );
//
// Wait for request to complete.
//
if (status == STATUS_PENDING) {
(VOID)KeWaitForSingleObject(
&event,
Executive,
KernelMode,
FALSE,
(PLARGE_INTEGER)NULL
);
status = ioStatusBlock.Status;
}
//
// get the result
//
// if(status == STATUS_SUCCESS) {
if(OutputBuffer && OutputBufferLength)
RtlCopyMemory(OutputBuffer, srbIoctlBuffer, OutputBufferLength);
Bus_KdPrint_Def( BUS_DBG_SS_NOISE, ("%d succeeded!\n", IoctlCode));
// }
if(psrbIoctl->ControlCode == STATUS_BUFFER_TOO_SMALL) {
status = STATUS_BUFFER_TOO_SMALL;
}
cleanup:
if(psrbIoctl)
ExFreePool(psrbIoctl);
if(AttachedDevice)
ObDereferenceObject(AttachedDevice);
return status;
}
请发表评论