/*++ 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; }