From 07ea12ee5bb834199199438c51aaa4f6e5606fb1 Mon Sep 17 00:00:00 2001 From: Alex Ionescu Date: Sun, 19 Feb 2012 10:06:31 +0000 Subject: [PATCH] [RTL/NTDLL/KERNEL32]: Rtl provides worker queue and timer queue functionality, which queues a worker thread associated with a caller-supplied callback. In Windows, Rtl by default calls RtlCreateUserThread, but as soon as kernel32 loads, it's DllMain calls an exported function RtlSetThreadPoolStartFunc which changes that default to a special Base function that calls CreateRemoteThread instead. The net result is that Win32 processes using the Rtl functionality get their threads properly registered with CSRSS. In ReactOS, this did not happen, so when those threads called into CSRSS, CSRSS had no CSR_THREAD structure/state for them, which is why CsrCreateThread (and the API loop) are so badly hacked. This commit implements RtlSetThreadPoolStartFunc, implements the kernel32 base functions which wrap CreateRemoteThread, and implements the rtl functions which wrap RtlCreateUserThread. Services, Setup, and any ReactOS application using RPC now have the worker threads correctly registered. svn path=/trunk/; revision=55706 --- reactos/dll/ntdll/def/ntdll.pspec | 2 +- reactos/dll/ntdll/def/ntdll.spec | 2 +- reactos/dll/win32/kernel32/client/dllmain.c | 43 ++++++++++++++ reactos/dll/win32/kernel32/client/proc.c | 2 +- reactos/include/ndk/rtlfuncs.h | 8 +++ reactos/include/ndk/rtltypes.h | 15 +++++ reactos/lib/rtl/timerqueue.c | 8 ++- reactos/lib/rtl/workitem.c | 65 ++++++++++++++++----- 8 files changed, 124 insertions(+), 21 deletions(-) diff --git a/reactos/dll/ntdll/def/ntdll.pspec b/reactos/dll/ntdll/def/ntdll.pspec index 7eb3e5519e9..0ce536711f4 100644 --- a/reactos/dll/ntdll/def/ntdll.pspec +++ b/reactos/dll/ntdll/def/ntdll.pspec @@ -896,7 +896,7 @@ //@ stdcall RtlSetSecurityObjectEx //@ stdcall RtlSetThreadErrorMode @ stdcall RtlSetThreadIsCritical(long ptr long) -//@ stdcall RtlSetThreadPoolStartFunc +@ stdcall RtlSetThreadPoolStartFunc(ptr ptr) @ stdcall RtlSetTimeZoneInformation(ptr) //@ stdcall RtlSetTimer @ stdcall RtlSetUnhandledExceptionFilter(ptr) diff --git a/reactos/dll/ntdll/def/ntdll.spec b/reactos/dll/ntdll/def/ntdll.spec index 3464847710f..9a9deff0689 100644 --- a/reactos/dll/ntdll/def/ntdll.spec +++ b/reactos/dll/ntdll/def/ntdll.spec @@ -896,7 +896,7 @@ ;@ stdcall RtlSetSecurityObjectEx ;@ stdcall RtlSetThreadErrorMode @ stdcall RtlSetThreadIsCritical(long ptr long) -;@ stdcall RtlSetThreadPoolStartFunc +@ stdcall RtlSetThreadPoolStartFunc(ptr ptr) @ stdcall RtlSetTimeZoneInformation(ptr) ;@ stdcall RtlSetTimer @ stdcall RtlSetUnhandledExceptionFilter(ptr) diff --git a/reactos/dll/win32/kernel32/client/dllmain.c b/reactos/dll/win32/kernel32/client/dllmain.c index b0068fefe00..0b34785c9bb 100644 --- a/reactos/dll/win32/kernel32/client/dllmain.c +++ b/reactos/dll/win32/kernel32/client/dllmain.c @@ -220,6 +220,46 @@ BasepInitConsole(VOID) return TRUE; } +NTSTATUS +NTAPI +BaseCreateThreadPoolThread(IN PTHREAD_START_ROUTINE Function, + IN PVOID Parameter, + OUT PHANDLE ThreadHandle) +{ + NTSTATUS Status; + + /* Create a Win32 thread */ + *ThreadHandle = CreateRemoteThread(NtCurrentProcess(), + NULL, + 0, + Function, + Parameter, + CREATE_SUSPENDED, + NULL); + if (!(*ThreadHandle)) + { + /* Get the status value if we couldn't get a handle */ + Status = NtCurrentTeb()->LastStatusValue; + if (NT_SUCCESS(Status)) Status = STATUS_UNSUCCESSFUL; + } + else + { + /* Set success code */ + Status = STATUS_SUCCESS; + } + + /* All done */ + return Status; +} + +NTSTATUS +NTAPI +BaseExitThreadPoolThread(IN NTSTATUS ExitStatus) +{ + /* Exit the thread */ + ExitThread(ExitStatus); +} + BOOL WINAPI DllMain(HANDLE hDll, @@ -246,6 +286,9 @@ DllMain(HANDLE hDll, /* Set no filter intially */ GlobalTopLevelExceptionFilter = RtlEncodePointer(NULL); + + /* Enable the Rtl thread pool and timer queue to use proper Win32 thread */ + RtlSetThreadPoolStartFunc(BaseCreateThreadPoolThread, BaseExitThreadPoolThread); /* Don't bother us for each thread */ LdrDisableThreadCalloutsForDll((PVOID)hDll); diff --git a/reactos/dll/win32/kernel32/client/proc.c b/reactos/dll/win32/kernel32/client/proc.c index b3e200ea194..9bc61f5bf63 100644 --- a/reactos/dll/win32/kernel32/client/proc.c +++ b/reactos/dll/win32/kernel32/client/proc.c @@ -544,7 +544,7 @@ BasepNotifyCsrOfThread(IN HANDLE ThreadHandle, sizeof(CSR_API_MESSAGE)); if (!NT_SUCCESS(Status) || !NT_SUCCESS(CsrRequest.Status)) { - DPRINT1("Failed to tell csrss about new thread\n"); + DPRINT1("Failed to tell csrss about new thread: %lx %lx\n", Status, CsrRequest.Status); return CsrRequest.Status; } diff --git a/reactos/include/ndk/rtlfuncs.h b/reactos/include/ndk/rtlfuncs.h index 235c2d836e7..39b5b23fec3 100644 --- a/reactos/include/ndk/rtlfuncs.h +++ b/reactos/include/ndk/rtlfuncs.h @@ -2410,6 +2410,14 @@ RtlGetCurrentProcessorNumber( // // Thread Pool Functions // +// +NTSTATUS +NTAPI +RtlSetThreadPoolStartFunc( + IN PRTL_START_POOL_THREAD StartPoolThread, + IN PRTL_EXIT_POOL_THREAD ExitPoolThread +); + NTSYSAPI NTSTATUS NTAPI diff --git a/reactos/include/ndk/rtltypes.h b/reactos/include/ndk/rtltypes.h index 198af634e52..ac08f574bff 100644 --- a/reactos/include/ndk/rtltypes.h +++ b/reactos/include/ndk/rtltypes.h @@ -522,6 +522,21 @@ typedef VOID PVOID Parameter ); +// +// Worker Start/Exit Function +// +typedef NTSTATUS +(NTAPI *PRTL_START_POOL_THREAD)( + IN PTHREAD_START_ROUTINE Function, + IN PVOID Parameter, + OUT PHANDLE ThreadHandle +); + +typedef NTSTATUS +(NTAPI *PRTL_EXIT_POOL_THREAD)( + IN NTSTATUS ExitStatus +); + // // Declare empty structure definitions so that they may be referenced by // routines before they are defined diff --git a/reactos/lib/rtl/timerqueue.c b/reactos/lib/rtl/timerqueue.c index 8e4821be902..6174d7bc2f7 100644 --- a/reactos/lib/rtl/timerqueue.c +++ b/reactos/lib/rtl/timerqueue.c @@ -19,6 +19,8 @@ /* FUNCTIONS ***************************************************************/ +extern PRTL_START_POOL_THREAD RtlpStartThreadFunc; +extern PRTL_EXIT_POOL_THREAD RtlpExitThreadFunc; HANDLE TimerThreadHandle = NULL; NTSTATUS @@ -239,7 +241,7 @@ static void WINAPI timer_queue_thread_proc(LPVOID p) NtClose(q->event); RtlDeleteCriticalSection(&q->cs); RtlFreeHeap(RtlGetProcessHeap(), 0, q); - RtlExitUserThread(STATUS_SUCCESS); + RtlpExitThreadFunc(STATUS_SUCCESS); } static void queue_destroy_timer(struct queue_timer *t) @@ -285,8 +287,7 @@ NTSTATUS WINAPI RtlCreateTimerQueue(PHANDLE NewTimerQueue) RtlFreeHeap(RtlGetProcessHeap(), 0, q); return status; } - status = RtlCreateUserThread(NtCurrentProcess(), NULL, FALSE, 0, 0, 0, - (PTHREAD_START_ROUTINE)timer_queue_thread_proc, q, &q->thread, NULL); + status = RtlpStartThreadFunc((PVOID)timer_queue_thread_proc, q, &q->thread); if (status != STATUS_SUCCESS) { NtClose(q->event); @@ -294,6 +295,7 @@ NTSTATUS WINAPI RtlCreateTimerQueue(PHANDLE NewTimerQueue) return status; } + NtResumeThread(q->thread, NULL); *NewTimerQueue = q; return STATUS_SUCCESS; } diff --git a/reactos/lib/rtl/workitem.c b/reactos/lib/rtl/workitem.c index cb6c83ab35a..f33771351dd 100644 --- a/reactos/lib/rtl/workitem.c +++ b/reactos/lib/rtl/workitem.c @@ -15,6 +15,36 @@ /* FUNCTIONS ***************************************************************/ +NTSTATUS +NTAPI +RtlpStartThread(IN PTHREAD_START_ROUTINE Function, + IN PVOID Parameter, + OUT PHANDLE ThreadHandle) +{ + /* Create a native worker thread -- used for SMSS, CSRSS, etc... */ + return RtlCreateUserThread(NtCurrentProcess(), + NULL, + TRUE, + 0, + 0, + 0, + Function, + Parameter, + ThreadHandle, + NULL); +} + +NTSTATUS +NTAPI +RtlpExitThread(IN NTSTATUS ExitStatus) +{ + /* Kill a native worker thread -- used for SMSS, CSRSS, etc... */ + return NtTerminateThread(NtCurrentThread(), ExitStatus); +} + +PRTL_START_POOL_THREAD RtlpStartThreadFunc = RtlpStartThread; +PRTL_EXIT_POOL_THREAD RtlpExitThreadFunc = RtlpExitThread; + #define MAX_WORKERTHREADS 0x100 #define WORKERTHREAD_CREATION_THRESHOLD 0x5 @@ -141,19 +171,11 @@ RtlpStartWorkerThread(PTHREAD_START_ROUTINE StartRoutine) Timeout.QuadPart = -10000LL; /* Wait for 100ms */ /* Start the thread */ - Status = RtlCreateUserThread(NtCurrentProcess(), - NULL, - FALSE, - 0, - 0, - 0, - StartRoutine, - (PVOID)&WorkerInitialized, - &ThreadHandle, - NULL); - + Status = RtlpStartThreadFunc(StartRoutine, (PVOID)&WorkerInitialized, &ThreadHandle); if (NT_SUCCESS(Status)) { + NtResumeThread(ThreadHandle, NULL); + /* Poll until the thread got a chance to initialize */ while (WorkerInitialized == 0) { @@ -568,7 +590,7 @@ InitFailed: InterlockedExchange((PLONG)Parameter, 1); - RtlExitUserThread(Status); + RtlpExitThreadFunc(Status); return 0; } @@ -647,7 +669,7 @@ Wait: } NtClose(ThreadInfo.ThreadHandle); - RtlExitUserThread(Status); + RtlpExitThreadFunc(Status); return 0; } @@ -670,7 +692,7 @@ RtlpWorkerThreadProc(IN PVOID Parameter) 1); /* Oops, too many worker threads... */ - RtlExitUserThread(Status); + RtlpExitThreadFunc(Status); return 0; } @@ -743,7 +765,7 @@ RtlpWorkerThreadProc(IN PVOID Parameter) } } - RtlExitUserThread(Status); + RtlpExitThreadFunc(Status); return 0; } @@ -892,3 +914,16 @@ RtlSetIoCompletionCallback(IN HANDLE FileHandle, UNIMPLEMENTED; return STATUS_NOT_IMPLEMENTED; } + +/* + * @implemented + */ +NTSTATUS +NTAPI +RtlSetThreadPoolStartFunc(IN PRTL_START_POOL_THREAD StartPoolThread, + IN PRTL_EXIT_POOL_THREAD ExitPoolThread) +{ + RtlpStartThreadFunc = StartPoolThread; + RtlpExitThreadFunc = ExitPoolThread; + return STATUS_SUCCESS; +}