You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
369 lines
8.7 KiB
369 lines
8.7 KiB
/*++
|
|
|
|
Copyright (c) 1985 - 1999, Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
w32init.c
|
|
|
|
Abstract:
|
|
|
|
This is the Win32 subsystem driver initializatiion module
|
|
|
|
Author:
|
|
|
|
Mark Lucovsky (markl) 31-Oct-1994
|
|
|
|
|
|
Revision History:
|
|
|
|
--*/
|
|
|
|
#include "ntosp.h"
|
|
#define DO_INLINE
|
|
#include "w32p.h"
|
|
#include "windef.h"
|
|
#include "wingdi.h"
|
|
#include "winerror.h"
|
|
#include "winddi.h"
|
|
#include "usergdi.h"
|
|
#include "w32err.h"
|
|
|
|
/*
|
|
* Globals declared and initialized in ntuser\kernel\init.c
|
|
*/
|
|
extern CONST ULONG W32ProcessSize;
|
|
extern CONST ULONG W32ProcessTag;
|
|
extern CONST ULONG W32ThreadSize;
|
|
extern CONST ULONG W32ThreadTag;
|
|
extern PFAST_MUTEX gpW32FastMutex;
|
|
|
|
__inline VOID
|
|
ReferenceW32Process(
|
|
IN PW32PROCESS pW32Process)
|
|
{
|
|
PEPROCESS pEProcess = pW32Process->Process;
|
|
|
|
UserAssert(pEProcess != NULL);
|
|
ObReferenceObject(pEProcess);
|
|
|
|
UserAssert(pW32Process->RefCount < MAXULONG);
|
|
InterlockedIncrement(&pW32Process->RefCount);
|
|
}
|
|
|
|
VOID
|
|
DereferenceW32Process(
|
|
IN PW32PROCESS pW32Process)
|
|
{
|
|
PEPROCESS pEProcess = pW32Process->Process;
|
|
|
|
/*
|
|
* Dereference the object. It'll get freed when ref count goes to zero.
|
|
*/
|
|
UserAssert(pW32Process->RefCount > 0);
|
|
if (InterlockedDecrement(&pW32Process->RefCount) == 0) {
|
|
UserDeleteW32Process(pW32Process);
|
|
}
|
|
|
|
/*
|
|
* Dereference the kernel object.
|
|
*/
|
|
UserAssert(pEProcess != NULL);
|
|
ObDereferenceObject(pEProcess);
|
|
}
|
|
|
|
VOID
|
|
LockW32Process(
|
|
IN PW32PROCESS pW32Process,
|
|
IN OUT PTL ptl)
|
|
{
|
|
PushW32ThreadLock(pW32Process, ptl, DereferenceW32Process);
|
|
if (pW32Process != NULL) {
|
|
ReferenceW32Process(pW32Process);
|
|
}
|
|
}
|
|
|
|
NTSTATUS
|
|
AllocateW32Process(
|
|
IN OUT PEPROCESS pEProcess)
|
|
{
|
|
NTSTATUS Status = STATUS_SUCCESS;
|
|
PW32PROCESS pW32Process;
|
|
|
|
KeEnterCriticalRegion();
|
|
ExAcquireFastMutexUnsafe(gpW32FastMutex);
|
|
|
|
/*
|
|
* Allocate the process object if we haven't already done so.
|
|
*/
|
|
if ((pW32Process = PsGetProcessWin32Process(pEProcess)) == NULL) {
|
|
pW32Process = Win32AllocPoolWithQuota(W32ProcessSize, W32ProcessTag);
|
|
if (pW32Process) {
|
|
RtlZeroMemory(pW32Process, W32ProcessSize);
|
|
pW32Process->Process = pEProcess;
|
|
Status = PsSetProcessWin32Process(pEProcess, pW32Process, NULL);
|
|
if (NT_SUCCESS(Status)) {
|
|
ReferenceW32Process(pW32Process);
|
|
} else {
|
|
NtCurrentTeb()->LastErrorValue = ERROR_ACCESS_DENIED;
|
|
Win32FreePool(pW32Process);
|
|
}
|
|
} else {
|
|
NtCurrentTeb()->LastErrorValue = ERROR_NOT_ENOUGH_MEMORY;
|
|
Status = STATUS_NO_MEMORY;
|
|
}
|
|
}
|
|
|
|
ExReleaseFastMutexUnsafe(gpW32FastMutex);
|
|
KeLeaveCriticalRegion();
|
|
|
|
return Status;
|
|
}
|
|
|
|
extern PEPROCESS gpepCSRSS;
|
|
|
|
__inline VOID
|
|
FreeW32Process(
|
|
IN OUT PW32PROCESS pW32Process)
|
|
{
|
|
ASSERT(pW32Process == W32GetCurrentProcess());
|
|
ASSERT(pW32Process != NULL);
|
|
|
|
/*
|
|
* Dereference the object. It'll get freed when ref count goes to zero.
|
|
*/
|
|
DereferenceW32Process(pW32Process);
|
|
}
|
|
|
|
NTSTATUS
|
|
W32pProcessCallout(
|
|
IN PEPROCESS Process,
|
|
IN BOOLEAN Initialize)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function is called whenever a Win32 process is created or deleted.
|
|
Creattion occurs when the calling process calls NtConvertToGuiThread.
|
|
|
|
Deletion occurs during PspExitthread processing for the last thread in
|
|
a process.
|
|
|
|
Arguments:
|
|
|
|
Process - Supplies the address of the W32PROCESS to initialize.
|
|
|
|
Initialize - Supplies a boolean value that is true if the process
|
|
is being created.
|
|
|
|
Return Value:
|
|
|
|
TBD
|
|
|
|
--*/
|
|
|
|
{
|
|
NTSTATUS Status;
|
|
PW32PROCESS pW32Process;
|
|
|
|
if (Initialize) {
|
|
Status = AllocateW32Process(Process);
|
|
if (!NT_SUCCESS(Status)) {
|
|
return Status;
|
|
}
|
|
pW32Process = (PW32PROCESS)PsGetProcessWin32Process(Process);
|
|
pW32Process->W32Pid = W32GetCurrentPID();
|
|
} else {
|
|
pW32Process = (PW32PROCESS)PsGetProcessWin32Process(Process);
|
|
}
|
|
|
|
TAGMSG3(DBGTAG_Callout,
|
|
"W32: Process Callout for W32P %#p EP %#p called for %s",
|
|
pW32Process,
|
|
Process,
|
|
Initialize ? "Creation" : "Deletion");
|
|
|
|
Status = xxxUserProcessCallout(pW32Process, Initialize);
|
|
if (Status == STATUS_ALREADY_WIN32) {
|
|
return Status;
|
|
}
|
|
|
|
/*
|
|
* Always call GDI at cleanup time. If GDI initialiatzion fails,
|
|
* call USER for cleanup.
|
|
*/
|
|
if (NT_SUCCESS(Status) || !Initialize) {
|
|
Status = GdiProcessCallout(pW32Process, Initialize);
|
|
if (!NT_SUCCESS(Status) && Initialize) {
|
|
xxxUserProcessCallout(pW32Process, FALSE);
|
|
}
|
|
}
|
|
|
|
/*
|
|
* If this is not an initialization or initialization failed, free the
|
|
* W32 process structure.
|
|
*/
|
|
if (!Initialize || !NT_SUCCESS(Status)) {
|
|
FreeW32Process(pW32Process);
|
|
}
|
|
|
|
return Status;
|
|
}
|
|
|
|
|
|
__inline VOID
|
|
ReferenceW32Thread(
|
|
IN PW32THREAD pW32Thread)
|
|
{
|
|
PETHREAD pEThread = pW32Thread->pEThread;
|
|
|
|
UserAssert(pEThread != NULL);
|
|
ObReferenceObject(pEThread);
|
|
|
|
UserAssert(pW32Thread->RefCount < MAXULONG);
|
|
InterlockedIncrement(&pW32Thread->RefCount);
|
|
}
|
|
|
|
VOID
|
|
DereferenceW32Thread(
|
|
IN PW32THREAD pW32Thread)
|
|
{
|
|
PETHREAD pEThread = pW32Thread->pEThread;
|
|
|
|
/*
|
|
* Dereference the object. It'll get freed when ref count goes to zero.
|
|
*/
|
|
UserAssert(pW32Thread->RefCount > 0);
|
|
if (InterlockedDecrement(&pW32Thread->RefCount) == 0) {
|
|
UserDeleteW32Thread(pW32Thread);
|
|
}
|
|
|
|
/*
|
|
* Dereference the kernel object.
|
|
*/
|
|
UserAssert(pEThread != NULL);
|
|
ObDereferenceObject(pEThread);
|
|
}
|
|
|
|
VOID
|
|
LockW32Thread(
|
|
IN PW32THREAD pW32Thread,
|
|
IN OUT PTL ptl)
|
|
{
|
|
PushW32ThreadLock(pW32Thread, ptl, DereferenceW32Thread);
|
|
if (pW32Thread != NULL) {
|
|
ReferenceW32Thread(pW32Thread);
|
|
}
|
|
}
|
|
|
|
VOID
|
|
LockExchangeW32Thread(
|
|
IN PW32THREAD pW32Thread,
|
|
IN OUT PTL ptl)
|
|
{
|
|
if (pW32Thread != NULL) {
|
|
ReferenceW32Thread(pW32Thread);
|
|
}
|
|
|
|
ExchangeW32ThreadLock(pW32Thread, ptl);
|
|
}
|
|
|
|
NTSTATUS
|
|
AllocateW32Thread(
|
|
IN OUT PETHREAD pEThread)
|
|
{
|
|
PW32THREAD pW32Thread;
|
|
|
|
UserAssert(pEThread == PsGetCurrentThread());
|
|
|
|
pW32Thread = Win32AllocPoolWithQuota(W32ThreadSize, W32ThreadTag);
|
|
if (pW32Thread) {
|
|
RtlZeroMemory(pW32Thread, W32ThreadSize);
|
|
pW32Thread->pEThread = pEThread;
|
|
PsSetThreadWin32Thread(pEThread, pW32Thread, NULL);
|
|
ReferenceW32Thread(pW32Thread);
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
return STATUS_NO_MEMORY;
|
|
}
|
|
|
|
VOID
|
|
CleanupW32ThreadLocks(
|
|
IN PW32THREAD pW32Thread)
|
|
{
|
|
PTL ptl;
|
|
|
|
while (ptl = pW32Thread->ptlW32) {
|
|
PopAndFreeW32ThreadLock(ptl);
|
|
}
|
|
}
|
|
|
|
NTSTATUS
|
|
W32pThreadCallout(
|
|
IN PETHREAD pEThread,
|
|
IN PSW32THREADCALLOUTTYPE CalloutType)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function is called whenever a Win32 Thread is initialized,
|
|
exited or deleted.
|
|
|
|
Initialization occurs when the calling thread calls NtConvertToGuiThread.
|
|
|
|
Exit occurs during PspExitthread processing and deletion during
|
|
PspThreadDelete processing.
|
|
|
|
Arguments:
|
|
|
|
Thread - Supplies the address of the ETHREAD object
|
|
|
|
CalloutType - Supplies the callout type
|
|
|
|
|
|
Return Value:
|
|
|
|
TBD
|
|
|
|
--*/
|
|
|
|
{
|
|
NTSTATUS Status;
|
|
|
|
TAGMSG2(DBGTAG_Callout,
|
|
"W32: Thread Callout for ETHREAD %x called for %s\n",
|
|
pEThread,
|
|
CalloutType == PsW32ThreadCalloutInitialize ? "Initialization" :
|
|
CalloutType == PsW32ThreadCalloutExit ? "Exit" : "Deletion");
|
|
TAGMSG2(DBGTAG_Callout,
|
|
" PID = %x TID = %x\n",
|
|
PsGetThreadProcessId(pEThread),
|
|
PsGetThreadId(pEThread));
|
|
|
|
if (CalloutType == PsW32ThreadCalloutInitialize) {
|
|
Status = AllocateW32Thread(pEThread);
|
|
if (!NT_SUCCESS(Status)) {
|
|
NtCurrentTeb()->LastErrorValue = ERROR_NOT_ENOUGH_MEMORY;
|
|
return Status;
|
|
}
|
|
}
|
|
|
|
/*
|
|
* If CalloutType == PsW32ThreadCalloutInitialize, assuming that:
|
|
* - GdiThreadCallout never fails.
|
|
* - If UserThreadCallout fails, there is no need to call
|
|
* GdiThreadCallout for clean up.
|
|
*/
|
|
GdiThreadCallout(pEThread, CalloutType);
|
|
|
|
Status = UserThreadCallout(pEThread, CalloutType);
|
|
|
|
if (CalloutType == PsW32ThreadCalloutExit || !NT_SUCCESS(Status)) {
|
|
FreeW32Thread(pEThread);
|
|
}
|
|
|
|
return Status;
|
|
}
|