diff --git a/reactos/include/defines.h b/reactos/include/defines.h index e1917767bad..1569a4b51e7 100644 --- a/reactos/include/defines.h +++ b/reactos/include/defines.h @@ -1136,6 +1136,9 @@ extern "C" { /* FindNextPrinterNotification */ +/* FlsAlloc */ +#define FLS_OUT_OF_INDEXES (0xFFFFFFFF) + /* FMExtensionProc */ /* FoldString */ diff --git a/reactos/include/funcs.h b/reactos/include/funcs.h index d4ce50bc131..f81c4e19425 100644 --- a/reactos/include/funcs.h +++ b/reactos/include/funcs.h @@ -1515,6 +1515,7 @@ GetThreadTimes( ); +__declspec(noreturn) VOID STDCALL ExitThread( @@ -2796,6 +2797,16 @@ TlsFree( DWORD dwTlsIndex ); +typedef VOID WINAPI (*PFLS_CALLBACK_FUNCTION)(PVOID lpFlsData); + +DWORD WINAPI FlsAlloc(PFLS_CALLBACK_FUNCTION lpCallback); + +BOOL WINAPI FlsFree(DWORD dwFlsIndex); + +PVOID WINAPI FlsGetValue(DWORD dwFlsIndex); + +BOOL WINAPI FlsSetValue(DWORD dwFlsIndex, PVOID lpFlsData); + DWORD STDCALL SleepEx( @@ -7569,45 +7580,38 @@ SHLoadInProc (REFCLSID); /* Win32 Fibers */ -typedef -VOID (WINAPI *PFIBER_START_ROUTINE) ( - IN LPVOID lpFiberArgument - ); +typedef VOID (WINAPI * PFIBER_START_ROUTINE) (IN LPVOID lpFiberArgument); typedef PFIBER_START_ROUTINE LPFIBER_START_ROUTINE; -LPVOID -STDCALL -ConvertThreadToFiber ( - LPVOID lpArgument - ); -LPVOID -STDCALL -CreateFiber ( - DWORD dwStackSize, - LPFIBER_START_ROUTINE lpStartAddress, - LPVOID lpArgument - ); -VOID -STDCALL -DeleteFiber( - LPVOID lpFiber - ); -PVOID -STDCALL -GetCurrentFiber ( - VOID - ); -PVOID -STDCALL -GetFiberData ( - VOID - ); -VOID -STDCALL -SwitchToFiber ( - LPVOID lpFiber - ); +#define FIBER_FLAG_FLOAT_SWITCH (1) +BOOL WINAPI ConvertFiberToThread(void); + +LPVOID WINAPI ConvertThreadToFiber(LPVOID lpParameter); + +LPVOID WINAPI ConvertThreadToFiberEx(LPVOID lpParameter, DWORD dwFlags); + +LPVOID WINAPI CreateFiber +( + SIZE_T dwStackSize, + LPFIBER_START_ROUTINE lpStartAddress, + LPVOID lpParameter +); + +LPVOID WINAPI CreateFiberEx +( + SIZE_T dwStackCommitSize, + SIZE_T dwStackReserveSize, + DWORD dwFlags, + LPFIBER_START_ROUTINE lpStartAddress, + LPVOID lpParameter +); + +void WINAPI DeleteFiber(LPVOID lpFiber); + +void WINAPI SwitchToFiber(LPVOID lpFiber); + +#define GetFiberData() *(LPVOID *)(((PNT_TIB)NtCurrentTeb())->Fib.FiberData) WINBOOL STDCALL RegisterServicesProcess(DWORD ServicesProcessId); diff --git a/reactos/include/napi/teb.h b/reactos/include/napi/teb.h index 0cf8beb4898..fa062d21687 100644 --- a/reactos/include/napi/teb.h +++ b/reactos/include/napi/teb.h @@ -179,7 +179,7 @@ typedef struct _TEB ULONG LastErrorValue; // 34h ULONG CountOfOwnedCriticalSections; // 38h PVOID CsrClientThread; // 3Ch - struct _W32THREAD* Win32ThreadInfo; // 40h + struct _W32THREAD* Win32ThreadInfo; // 40h ULONG Win32ClientInfo[0x1F]; // 44h PVOID WOW32Reserved; // C0h ULONG CurrentLocale; // C4h @@ -220,9 +220,11 @@ typedef struct _TEB PVOID Instrumentation[0x10]; // F2Ch PVOID WinSockData; // F6Ch ULONG GdiBatchCount; // F70h - ULONG Spare2; // F74h // NOTE: RtlExitUserThread writes something here - ULONG Spare3; // F78h - ULONG Spare4; // F7Ch + USHORT Spare2; // F74h + BOOLEAN IsFiber; // F76h + UCHAR Spare3; // F77h + ULONG Spare4; // F78h + ULONG Spare5; // F7Ch PVOID ReservedForOle; // F80h ULONG WaitingOnLoaderLock; // F84h PVOID WineDebugInfo; // Needed for WINE DLL's diff --git a/reactos/include/rosrtl/thread.h b/reactos/include/rosrtl/thread.h index 3cca46a3b9c..023b54d0a4e 100644 --- a/reactos/include/rosrtl/thread.h +++ b/reactos/include/rosrtl/thread.h @@ -1,4 +1,4 @@ -/* $Id: thread.h,v 1.1 2003/04/29 02:17:00 hyperion Exp $ +/* $Id: thread.h,v 1.2 2003/05/29 00:36:41 hyperion Exp $ */ #ifdef __cplusplus @@ -14,7 +14,7 @@ NTSTATUS STDCALL RtlRosCreateUserThreadEx IN LONG StackZeroBits, IN OUT PULONG StackReserve OPTIONAL, IN OUT PULONG StackCommit OPTIONAL, - IN PTHREAD_START_ROUTINE StartAddress, + IN PVOID StartAddress, OUT PHANDLE ThreadHandle OPTIONAL, OUT PCLIENT_ID ClientId OPTIONAL, IN ULONG ParameterCount, @@ -29,7 +29,7 @@ NTSTATUS CDECL RtlRosCreateUserThreadVa IN LONG StackZeroBits, IN OUT PULONG StackReserve OPTIONAL, IN OUT PULONG StackCommit OPTIONAL, - IN PTHREAD_START_ROUTINE StartAddress, + IN PVOID StartAddress, OUT PHANDLE ThreadHandle OPTIONAL, OUT PCLIENT_ID ClientId OPTIONAL, IN ULONG ParameterCount, @@ -39,13 +39,28 @@ NTSTATUS CDECL RtlRosCreateUserThreadVa NTSTATUS NTAPI RtlRosInitializeContextEx ( IN HANDLE ProcessHandle, - IN PCONTEXT Context, - IN PTHREAD_START_ROUTINE StartAddress, + OUT PCONTEXT Context, + IN PVOID StartAddress, IN PUSER_STACK UserStack, IN ULONG ParameterCount, IN ULONG_PTR * Parameters ); +NTSTATUS NTAPI RtlRosCreateStack +( + IN HANDLE ProcessHandle, + OUT PUSER_STACK UserStack, + IN LONG StackZeroBits, + IN OUT PULONG StackReserve OPTIONAL, + IN OUT PULONG StackCommit OPTIONAL +); + +NTSTATUS NTAPI RtlRosDeleteStack +( + IN HANDLE ProcessHandle, + IN PUSER_STACK UserStack +); + #ifdef __cplusplus } #endif diff --git a/reactos/lib/kernel32/kernel32.def b/reactos/lib/kernel32/kernel32.def index 60deca5fc66..33109d7f89f 100644 --- a/reactos/lib/kernel32/kernel32.def +++ b/reactos/lib/kernel32/kernel32.def @@ -171,6 +171,10 @@ FindResourceA@12 FindResourceExA@16 FindResourceExW@16 FindResourceW@12 +FlsAlloc@4 +FlsFree@4 +FlsGetValue@4 +FlsSetValue@8 FlushConsoleInputBuffer@4 FlushFileBuffers@4 FlushInstructionCache@12 @@ -239,7 +243,6 @@ GetCurrencyFormatW@24 GetCurrentConsoleFont@12 GetCurrentDirectoryA@8 GetCurrentDirectoryW@8 -GetCurrentFiber@0 GetCurrentProcess@0 GetCurrentProcessId@0 GetCurrentThread@0 @@ -260,7 +263,6 @@ GetEnvironmentVariableA@12 GetEnvironmentVariableW@12 GetExitCodeProcess@8 GetExitCodeThread@8 -GetFiberData@0 GetFileAttributesA@4 GetFileAttributesW@4 GetFileAttributesExA diff --git a/reactos/lib/kernel32/kernel32.edf b/reactos/lib/kernel32/kernel32.edf index 20121c55fb6..3b4b1d23eb6 100644 --- a/reactos/lib/kernel32/kernel32.edf +++ b/reactos/lib/kernel32/kernel32.edf @@ -1,4 +1,4 @@ -; $Id: kernel32.edf,v 1.23 2003/04/26 00:25:01 hyperion Exp $ +; $Id: kernel32.edf,v 1.24 2003/05/29 00:36:41 hyperion Exp $ ; ; kernel32.edf ; @@ -175,6 +175,10 @@ FindResourceA=FindResourceA@12 FindResourceExA=FindResourceExA@16 FindResourceExW=FindResourceExW@16 FindResourceW=FindResourceW@12 +FlsAlloc=FlsAlloc@4 +FlsFree=FlsFree@4 +FlsGetValue=FlsGetValue@4 +FlsSetValue=FlsSetValue@8 FlushConsoleInputBuffer=FlushConsoleInputBuffer@4 FlushFileBuffers=FlushFileBuffers@4 FlushInstructionCache=FlushInstructionCache@12 @@ -243,7 +247,6 @@ GetCurrencyFormatW=GetCurrencyFormatW@24 GetCurrentConsoleFont=GetCurrentConsoleFont@12 GetCurrentDirectoryA=GetCurrentDirectoryA@8 GetCurrentDirectoryW=GetCurrentDirectoryW@8 -GetCurrentFiber=GetCurrentFiber@0 GetCurrentProcess=GetCurrentProcess@0 GetCurrentProcessId=GetCurrentProcessId@0 GetCurrentThread=GetCurrentThread@0 @@ -265,7 +268,6 @@ GetEnvironmentVariableA=GetEnvironmentVariableA@12 GetEnvironmentVariableW=GetEnvironmentVariableW@12 GetExitCodeProcess=GetExitCodeProcess@8 GetExitCodeThread=GetExitCodeThread@8 -GetFiberData=GetFiberData@0 GetFileAttributesA=GetFileAttributesA@4 GetFileAttributesW=GetFileAttributesW@4 GetFileAttributesExA=GetFileAttributesExA@12 diff --git a/reactos/lib/kernel32/makefile b/reactos/lib/kernel32/makefile index c68a56ca250..b4ba6bdf446 100644 --- a/reactos/lib/kernel32/makefile +++ b/reactos/lib/kernel32/makefile @@ -1,4 +1,4 @@ -# $Id: makefile,v 1.65 2003/05/25 17:17:03 ekohl Exp $ +# $Id: makefile,v 1.66 2003/05/29 00:36:41 hyperion Exp $ PATH_TO_TOP = ../.. @@ -44,7 +44,11 @@ NLS_OBJECTS = THREAD_OBJECTS = \ thread/fiber.o \ thread/thread.o \ - thread/tls.o + thread/tls.o \ + thread/fls.o + +THREAD_I386_OBJECTS = \ + thread/i386/fiber.o PROCESS_OBJECTS = \ process/proc.o \ @@ -58,9 +62,12 @@ EXCEPT_OBJECTS = except/except.o DEBUG_OBJECTS = debug/debugger.o debug/output.o debug/break.o +ARCH_OBJECTS = $(THREAD_I386_OBJECTS) + TARGET_OBJECTS = $(MISC_OBJECTS) $(FILE_OBJECTS) $(THREAD_OBJECTS) \ $(PROCESS_OBJECTS) $(STRING_OBJECTS) $(MEM_OBJECTS) \ - $(SYNCH_OBJECTS) $(EXCEPT_OBJECTS) $(DEBUG_OBJECTS) + $(SYNCH_OBJECTS) $(EXCEPT_OBJECTS) $(DEBUG_OBJECTS) \ + $(ARCH_OBJECTS) DEP_OBJECTS = $(TARGET_OBJECTS) diff --git a/reactos/lib/kernel32/thread/fiber.c b/reactos/lib/kernel32/thread/fiber.c index a460ec31f19..c7d89db76fe 100644 --- a/reactos/lib/kernel32/thread/fiber.c +++ b/reactos/lib/kernel32/thread/fiber.c @@ -1,4 +1,4 @@ -/* $Id: fiber.c,v 1.4 2003/01/15 21:24:36 chorns Exp $ +/* $Id: fiber.c,v 1.5 2003/05/29 00:36:41 hyperion Exp $ * * FILE: lib/kernel32/thread/fiber.c * @@ -7,88 +7,264 @@ */ #include +#define NDEBUG +#include +struct _FIBER /* Field offsets: */ +{ /* 32 bit 64 bit */ + /* this must be the first field */ + LPVOID Parameter; /* 0x00 0x00 */ -/********************************************************************** - * ConvertThreadToFiber - */ -LPVOID -STDCALL -ConvertThreadToFiber( - LPVOID lpArgument - ) + struct _EXCEPTION_REGISTRATION_RECORD * ExceptionList; /* 0x04 0x08 */ + LPVOID StackBase; /* 0x08 0x10 */ + LPVOID StackLimit; /* 0x0C 0x18 */ + LPVOID DeallocationStack; /* 0x10 0x20 */ + ULONG_PTR Flags; /* 0x14 0x28 */ +#if defined(_M_IX86) + /* control flow registers */ + DWORD Eip; /* 0x18 ---- */ + DWORD Esp; /* 0x1C ---- */ + DWORD Ebp; /* 0x20 ---- */ + + /* general-purpose registers that must be preserved across calls */ + DWORD Ebx; /* 0x24 ---- */ + DWORD Esi; /* 0x28 ---- */ + DWORD Edi; /* 0x2C ---- */ + + /* floating point save area (optional) */ + FLOATING_SAVE_AREA FloatSave; /* 0x30 ---- */ +#else +#error Unspecified or unsupported architecture. +#endif +}; + +typedef struct _FIBER FIBER, * PFIBER; + +__declspec(noreturn) void WINAPI FiberStartup(PVOID lpStartAddress); + +BOOL WINAPI ConvertFiberToThread(void) { - SetLastError(ERROR_CALL_NOT_IMPLEMENTED); - return NULL; + PTEB pTeb = NtCurrentTeb(); + + /* the current thread isn't running a fiber: failure */ + if(!pTeb->IsFiber) + { + SetLastError(ERROR_INVALID_PARAMETER); + return FALSE; + } + + /* this thread won't run a fiber anymore */ + pTeb->IsFiber = FALSE; + + /* free the fiber */ + if(pTeb->Tib.Fib.FiberData != NULL) + RtlFreeHeap(pTeb->Peb->ProcessHeap, 0, pTeb->Tib.Fib.FiberData); + + /* success */ } - -/********************************************************************** - * CreateFiber - */ -LPVOID -STDCALL -CreateFiber( - DWORD dwStackSize, - LPFIBER_START_ROUTINE lpStartAddress, - LPVOID lpArgument - ) +LPVOID WINAPI ConvertThreadToFiber(LPVOID lpParameter) { - SetLastError(ERROR_CALL_NOT_IMPLEMENTED); - return NULL; + return ConvertThreadToFiberEx(lpParameter, 0); } - -/********************************************************************** - * DeleteFiber - */ -VOID -STDCALL -DeleteFiber( - LPVOID lpFiber - ) +LPVOID WINAPI ConvertThreadToFiberEx(LPVOID lpParameter, DWORD dwFlags) { - SetLastError(ERROR_CALL_NOT_IMPLEMENTED); - return; + PTEB pTeb = NtCurrentTeb(); + PFIBER pfCurFiber; + + /* the current thread is already a fiber */ + if(pTeb->IsFiber && pTeb->Tib.Fib.FiberData) return pTeb->Tib.Fib.FiberData; + + /* allocate the fiber */ + pfCurFiber = (PFIBER)RtlAllocateHeap(pTeb->Peb->ProcessHeap, 0, sizeof(FIBER)); + + /* failure */ + if(pfCurFiber == NULL) + { + SetLastError(ERROR_NOT_ENOUGH_MEMORY); + return NULL; + } + + pfCurFiber->Parameter = lpParameter; + pfCurFiber->Flags = dwFlags; + + /* copy some contextual data from the thread to the fiber */ + pfCurFiber->ExceptionList = pTeb->Tib.ExceptionList; + pfCurFiber->StackBase = pTeb->Tib.StackBase; + pfCurFiber->StackLimit = pTeb->Tib.StackLimit; + pfCurFiber->DeallocationStack = pTeb->DeallocationStack; + + /* associate the fiber to the current thread */ + pTeb->Tib.Fib.FiberData = pfCurFiber; + pTeb->IsFiber = TRUE; + + /* success */ + return (LPVOID)pfCurFiber; } - -/********************************************************************** - * GetCurrentFiber - */ -PVOID -STDCALL -GetCurrentFiber(VOID) +LPVOID WINAPI CreateFiber +( + SIZE_T dwStackSize, + LPFIBER_START_ROUTINE lpStartAddress, + LPVOID lpParameter +) { - SetLastError(ERROR_CALL_NOT_IMPLEMENTED); - return NULL; + return CreateFiberEx(dwStackSize, 0, 0, lpStartAddress, lpParameter); } - -/********************************************************************** - * GetFiberData - */ -PVOID -STDCALL -GetFiberData(VOID) +LPVOID WINAPI CreateFiberEx +( + SIZE_T dwStackCommitSize, + SIZE_T dwStackReserveSize, + DWORD dwFlags, + LPFIBER_START_ROUTINE lpStartAddress, + LPVOID lpParameter +) { - SetLastError(ERROR_CALL_NOT_IMPLEMENTED); - return NULL; + PFIBER pfCurFiber; + NTSTATUS nErrCode; + PSIZE_T pnStackReserve = NULL; + PSIZE_T pnStackCommit = NULL; + USER_STACK usFiberStack; + CONTEXT ctxFiberContext; + PCHAR pStackBase; + PCHAR pStackLimit; + PTEB pTeb = NtCurrentTeb(); + + /* allocate the fiber */ + pfCurFiber = (PFIBER)RtlAllocateHeap(pTeb->Peb->ProcessHeap, 0, sizeof(FIBER)); + + /* failure */ + if(pfCurFiber == NULL) + { + SetLastError(ERROR_NOT_ENOUGH_MEMORY); + return NULL; + } + + /* if the stack reserve or commit size weren't specified, use defaults */ + if(dwStackReserveSize > 0) pnStackReserve = &dwStackReserveSize; + if(dwStackCommitSize > 0) pnStackCommit = &dwStackCommitSize; + + /* create the stack for the fiber */ + nErrCode = RtlRosCreateStack + ( + NtCurrentProcess(), + &usFiberStack, + 0, + pnStackReserve, + pnStackCommit + ); + + /* failure */ + if(!NT_SUCCESS(nErrCode)) goto l_CleanupFiber; + + /* initialize the context for the fiber */ + nErrCode = RtlRosInitializeContextEx + ( + NtCurrentProcess(), + &ctxFiberContext, + FiberStartup, + &usFiberStack, + 1, + (ULONG_PTR *)&lpStartAddress + ); + + /* failure */ + if(!NT_SUCCESS(nErrCode)) goto l_CleanupStack; + + /* copy the data into the fiber */ + + /* fixed-size stack */ + if(usFiberStack.FixedStackBase && usFiberStack.FixedStackLimit) + { + pfCurFiber->StackBase = usFiberStack.FixedStackBase; + pfCurFiber->StackLimit = usFiberStack.FixedStackLimit; + pfCurFiber->DeallocationStack = usFiberStack.FixedStackLimit; + } + /* expandable stack */ + else if + ( + usFiberStack.ExpandableStackBase && + usFiberStack.ExpandableStackLimit && + usFiberStack.ExpandableStackBottom + ) + { + pfCurFiber->StackBase = usFiberStack.ExpandableStackBase; + pfCurFiber->StackLimit = usFiberStack.ExpandableStackLimit; + pfCurFiber->DeallocationStack = usFiberStack.ExpandableStackBottom; + } + /* bad initial stack */ + else goto l_CleanupStack; + + pfCurFiber->Parameter = lpParameter; + pfCurFiber->Flags = dwFlags; + pfCurFiber->ExceptionList = (struct _EXCEPTION_REGISTRATION_RECORD *)-1; + +#if defined(_M_IX86) + + pfCurFiber->Eip = ctxFiberContext.Eip; + pfCurFiber->Esp = ctxFiberContext.Esp; + pfCurFiber->Ebp = ctxFiberContext.Ebp; + pfCurFiber->Ebx = ctxFiberContext.Ebx; + pfCurFiber->Esi = ctxFiberContext.Esi; + pfCurFiber->Edi = ctxFiberContext.Edi; + + if(dwFlags & FIBER_FLAG_FLOAT_SWITCH) + pfCurFiber->FloatSave = ctxFiberContext.FloatSave; + +#else +#error Unspecified or unsupported architecture. +#endif + + return pfCurFiber; + +l_CleanupStack: + /* free the stack */ + RtlRosDeleteStack(NtCurrentProcess(), &usFiberStack); + +l_CleanupFiber: + /* free the fiber */ + RtlFreeHeap(pTeb->Peb->ProcessHeap, 0, pfCurFiber); + + /* failure */ + assert(!NT_SUCCESS(nErrCode)); + SetLastErrorByStatus(nErrCode); + return NULL; } - -/********************************************************************** - * SwitchToFiber - */ -VOID -STDCALL -SwitchToFiber( - LPVOID lpFiber - ) +void WINAPI DeleteFiber(LPVOID lpFiber) { - SetLastError(ERROR_CALL_NOT_IMPLEMENTED); - return; + SIZE_T nSize = 0; + PVOID pStackAllocBase = ((PFIBER)lpFiber)->DeallocationStack; + PTEB pTeb = NtCurrentTeb(); + + /* free the fiber */ + RtlFreeHeap(pTeb->Peb->ProcessHeap, 0, lpFiber); + + /* the fiber is deleting itself: let the system deallocate the stack */ + if(pTeb->Tib.Fib.FiberData == lpFiber) ExitThread(1); + + /* deallocate the stack */ + NtFreeVirtualMemory + ( + NtCurrentProcess(), + &pStackAllocBase, + &nSize, + MEM_RELEASE + ); } +__declspec(noreturn) extern void WINAPI ThreadStartup +( + LPTHREAD_START_ROUTINE lpStartAddress, + LPVOID lpParameter +); + +__declspec(noreturn) void WINAPI FiberStartup(PVOID lpStartAddress) +{ + /* FIXME? this should be pretty accurate */ + ThreadStartup(lpStartAddress, NtCurrentTeb()->Tib.Fib.FiberData); +} /* EOF */ diff --git a/reactos/lib/kernel32/thread/fls.c b/reactos/lib/kernel32/thread/fls.c new file mode 100644 index 00000000000..bc2ee10ce2b --- /dev/null +++ b/reactos/lib/kernel32/thread/fls.c @@ -0,0 +1,55 @@ +/* $Id: fls.c,v 1.1 2003/05/29 00:36:41 hyperion Exp $ + * + * COPYRIGHT: See COPYING in the top level directory + * PROJECT: ReactOS system libraries + * FILE: lib/kernel32/thread/fls.c + * PURPOSE: Fiber local storage functions + * PROGRAMMER: KJK::Hyperion + * + * UPDATE HISTORY: + * 28/05/2003 - created. Stubs only + * + */ + +#include + +#include + +DWORD WINAPI FlsAlloc(PFLS_CALLBACK_FUNCTION lpCallback) +{ + (void)lpCallback; + + UNIMPLEMENTED; + SetLastError(ERROR_CALL_NOT_IMPLEMENTED); + return FLS_OUT_OF_INDEXES; +} + +BOOL WINAPI FlsFree(DWORD dwFlsIndex) +{ + (void)dwFlsIndex; + + UNIMPLEMENTED; + SetLastError(ERROR_CALL_NOT_IMPLEMENTED); + return FALSE; +} + +PVOID WINAPI FlsGetValue(DWORD dwFlsIndex) +{ + (void)dwFlsIndex; + + UNIMPLEMENTED; + SetLastError(ERROR_CALL_NOT_IMPLEMENTED); + return NULL; +} + +BOOL WINAPI FlsSetValue(DWORD dwFlsIndex, PVOID lpFlsData) +{ + (void)dwFlsIndex; + (void)lpFlsData; + + UNIMPLEMENTED; + SetLastError(ERROR_CALL_NOT_IMPLEMENTED); + return FALSE; +} + +/* EOF */ diff --git a/reactos/lib/kernel32/thread/i386/fiber.S b/reactos/lib/kernel32/thread/i386/fiber.S new file mode 100644 index 00000000000..b8ff8368d70 --- /dev/null +++ b/reactos/lib/kernel32/thread/i386/fiber.S @@ -0,0 +1,94 @@ +/* $Id: fiber.S,v 1.1 2003/05/29 00:36:41 hyperion Exp $ + * + * COPYRIGHT: See COPYING in the top level directory + * PROJECT: ReactOS system libraries + * FILE: lib/kernel32/thread/i386/fiber.S + * PURPOSE: Fiber context switch code for the x86 architecture + * PROGRAMMER: KJK::Hyperion + * + * UPDATE HISTORY: + * 28/05/2003 - created + * + */ + +.extern _DbgPrint + +.globl _SwitchToFiber@4 + +_SwitchToFiber@4: + +ErrStr: + .ascii \ +"(KERNEL32:" __FILE__ ") Saving and restoring the floating point context \ +currently unimplemented\n\0" + + movl %fs:0x18, %ecx /* Teb = NtCurrentTeb() */ + + /* get the current fiber */ + movl 0x10(%ecx), %eax /* Fiber = Teb->Tib.Fib.FiberData */ + + /* store the volatile context of the current fiber */ + movl 0x0(%ecx), %edx + movl %edx, 0x4(%eax) /* Fiber->ExceptionList = Teb->ExceptionList */ + movl 0x4(%ecx), %edx + movl %edx, 0x8(%eax) /* Fiber->StackBase = Teb->StackBase */ + movl 0x8(%ecx), %edx + movl %edx, 0xC(%eax) /* Fiber->StackLimit = Teb->StackLimit */ + movl 0xE0C(%ecx), %edx + movl %edx, 0x10(%eax) /* Fiber->StackBottom = Teb->StackBottom */ + movl 0x0(%esp), %edx + movl %edx, 0x18(%eax) /* Fiber->Eip = [esp] */ + movl %esp, %edx + addl $0x8, %edx + movl %edx, 0x1C(%eax) /* Fiber->Esp = esp + 8 */ + movl %ebp, 0x20(%eax) /* Fiber->Ebp = ebp */ + movl %ebx, 0x24(%eax) /* Fiber->Ebx = ebx */ + movl %esi, 0x28(%eax) /* Fiber->Esi = edi */ + movl %edi, 0x2C(%eax) /* Fiber->Edi = esi */ + + testl $1, 0x14(%eax) + jz l_NoFloatSave + + /* save the floating point context */ + /* TODO */ + pushl ErrStr + call _DbgPrint + popl %ecx + +l_NoFloatSave: + + /* switch to the specified fiber */ + movl 0x4(%esp), %eax /* Fiber = lpFiber */ + movl %eax, 0x10(%ecx) /* Teb->Tib.FiberData = Fiber */ + + /* restore the volatile context of the specified fiber */ + movl 0x4(%eax), %edx + movl %edx, 0x0(%ecx) /* Teb->ExceptionList = Fiber->ExceptionList */ + movl 0x8(%eax), %edx + movl %edx, 0x4(%ecx) /* Teb->StackBase = Fiber->StackBase */ + movl 0xC(%eax), %edx + movl %edx, 0x8(%ecx) /* Teb->StackLimit = Fiber->StackLimit */ + movl 0x10(%eax), %edx + movl %edx, 0xE0C(%ecx) /* Teb->StackBottom = Fiber->StackBottom */ + movl 0x18(%eax), %edx /* edx = Fiber->Eip */ + movl 0x1C(%eax), %esp /* esp = Fiber->Esp */ + movl 0x20(%eax), %ebp /* ebp = Fiber->Ebp */ + movl 0x24(%eax), %ebx /* ebx = Fiber->Ebx */ + movl 0x28(%eax), %esi /* esi = Fiber->Esi */ + movl 0x2C(%eax), %edi /* edi = Fiber->Edi */ + + testb $1, 0x14(%eax) + jz l_NoFloatSave + + /* restore the floating point context */ + /* TODO */ + pushl ErrStr + call _DbgPrint + popl %ecx + +l_NoFloatRestore: + + /* jump to the saved program counter */ + jmp *%edx + +/* EOF */ diff --git a/reactos/lib/kernel32/thread/thread.c b/reactos/lib/kernel32/thread/thread.c index e87b7258800..a989bbdfeb2 100644 --- a/reactos/lib/kernel32/thread/thread.c +++ b/reactos/lib/kernel32/thread/thread.c @@ -1,4 +1,4 @@ -/* $Id: thread.c,v 1.39 2003/04/30 22:00:41 gvg Exp $ +/* $Id: thread.c,v 1.40 2003/05/29 00:36:41 hyperion Exp $ * * COPYRIGHT: See COPYING in the top level directory * PROJECT: ReactOS system libraries @@ -35,9 +35,11 @@ _except_handler(EXCEPTION_RECORD *ExceptionRecord, } -static VOID STDCALL -ThreadStartup(LPTHREAD_START_ROUTINE lpStartAddress, - LPVOID lpParameter) +__declspec(noreturn) void STDCALL ThreadStartup +( + LPTHREAD_START_ROUTINE lpStartAddress, + LPVOID lpParameter +) { UINT uExitCode; diff --git a/reactos/lib/rosrtl/makefile b/reactos/lib/rosrtl/makefile index 26ccb6a69b8..f5f8055218a 100644 --- a/reactos/lib/rosrtl/makefile +++ b/reactos/lib/rosrtl/makefile @@ -1,4 +1,4 @@ -# $Id: makefile,v 1.1 2003/04/29 02:17:01 hyperion Exp $ +# $Id: makefile,v 1.2 2003/05/29 00:36:41 hyperion Exp $ PATH_TO_TOP = ../.. @@ -8,7 +8,8 @@ TARGET_NAME = rosrtl THREAD_OBJECTS = \ thread/context.o \ - thread/create.o + thread/create.o \ + thread/stack.o TARGET_OBJECTS = $(THREAD_OBJECTS) diff --git a/reactos/lib/rosrtl/thread/context.c b/reactos/lib/rosrtl/thread/context.c index fff85694e87..66b9d922b75 100644 --- a/reactos/lib/rosrtl/thread/context.c +++ b/reactos/lib/rosrtl/thread/context.c @@ -1,4 +1,4 @@ -/* $Id: context.c,v 1.1 2003/04/29 02:17:01 hyperion Exp $ +/* $Id: context.c,v 1.2 2003/05/29 00:36:41 hyperion Exp $ */ /* */ @@ -16,8 +16,8 @@ NTSTATUS NTAPI RtlRosInitializeContextEx ( IN HANDLE ProcessHandle, - IN PCONTEXT Context, - IN PTHREAD_START_ROUTINE StartAddress, + OUT PCONTEXT Context, + IN PVOID StartAddress, IN PUSER_STACK UserStack, IN ULONG ParameterCount, IN ULONG_PTR * Parameters diff --git a/reactos/lib/rosrtl/thread/create.c b/reactos/lib/rosrtl/thread/create.c index af428c7384e..b0a68dddecc 100644 --- a/reactos/lib/rosrtl/thread/create.c +++ b/reactos/lib/rosrtl/thread/create.c @@ -1,4 +1,4 @@ -/* $Id: create.c,v 1.1 2003/04/29 02:17:01 hyperion Exp $ +/* $Id: create.c,v 1.2 2003/05/29 00:36:41 hyperion Exp $ */ /* */ @@ -18,7 +18,7 @@ NTSTATUS STDCALL RtlRosCreateUserThreadEx IN LONG StackZeroBits, IN OUT PULONG StackReserve OPTIONAL, IN OUT PULONG StackCommit OPTIONAL, - IN PTHREAD_START_ROUTINE StartAddress, + IN PVOID StartAddress, OUT PHANDLE ThreadHandle OPTIONAL, OUT PCLIENT_ID ClientId OPTIONAL, IN ULONG ParameterCount, @@ -27,13 +27,6 @@ NTSTATUS STDCALL RtlRosCreateUserThreadEx { USER_STACK usUserStack; OBJECT_ATTRIBUTES oaThreadAttribs; - /* FIXME: read the defaults from the executable image */ - ULONG_PTR nStackReserve = 0x100000; - /* FIXME: when we finally have exception handling, make this PAGE_SIZE */ - ULONG_PTR nStackCommit = 0x100000; - ULONG_PTR nSize = 0; - PVOID pStackLowest = NULL; - ULONG nDummy; CONTEXT ctxInitialContext; NTSTATUS nErrCode; HANDLE hThread; @@ -41,130 +34,19 @@ NTSTATUS STDCALL RtlRosCreateUserThreadEx if(ThreadHandle == NULL) ThreadHandle = &hThread; if(ClientId == NULL) ClientId = &cidClientId; + + /* allocate the stack for the thread */ + nErrCode = RtlRosCreateStack + ( + ProcessHandle, + &usUserStack, + StackZeroBits, + StackReserve, + StackCommit + ); - if(StackReserve == NULL) StackReserve = &nStackReserve; - else ROUNDUP(*StackReserve, PAGE_SIZE); - - if(StackCommit == NULL) StackCommit = &nStackCommit; - else ROUNDUP(*StackCommit, PAGE_SIZE); - -#if 0 - /* the stack commit size must be equal to or less than the reserve size */ - if(*StackCommit > *StackReserve) *StackCommit = *StackReserve; -#else - /* FIXME: no SEH, no guard pages */ - *StackCommit = *StackReserve; -#endif - - usUserStack.FixedStackBase = NULL; - usUserStack.FixedStackLimit = NULL; - usUserStack.ExpandableStackBase = NULL; - usUserStack.ExpandableStackLimit = NULL; - usUserStack.ExpandableStackBottom = NULL; - - /* FIXME: this code assumes a stack growing downwards */ - /* fixed stack */ - if(*StackCommit == *StackReserve) - { - usUserStack.FixedStackLimit = NULL; - - /* allocate the stack */ - nErrCode = NtAllocateVirtualMemory - ( - ProcessHandle, - &(usUserStack.FixedStackLimit), - StackZeroBits, - StackReserve, - MEM_RESERVE | MEM_COMMIT, - PAGE_READWRITE - ); - - /* failure */ - if(!NT_SUCCESS(nErrCode)) goto l_Fail; - - /* store the highest (first) address of the stack */ - usUserStack.FixedStackBase = - (PUCHAR)(usUserStack.FixedStackLimit) + *StackReserve; - - *StackCommit = *StackReserve; - } - /* expandable stack */ - else - { - ULONG_PTR nGuardSize = PAGE_SIZE; - PVOID pGuardBase; - - DPRINT("Expandable stack\n"); - - usUserStack.FixedStackLimit = NULL; - usUserStack.FixedStackBase = NULL; - usUserStack.ExpandableStackBottom = NULL; - - /* reserve the stack */ - nErrCode = NtAllocateVirtualMemory - ( - ProcessHandle, - &(usUserStack.ExpandableStackBottom), - StackZeroBits, - StackReserve, - MEM_RESERVE, - PAGE_READWRITE - ); - - /* failure */ - if(!NT_SUCCESS(nErrCode)) goto l_Fail; - - DPRINT("Reserved %08X bytes\n", *StackReserve); - - /* expandable stack base - the highest address of the stack */ - usUserStack.ExpandableStackBase = - (PUCHAR)(usUserStack.ExpandableStackBottom) + *StackReserve; - - /* expandable stack limit - the lowest committed address of the stack */ - usUserStack.ExpandableStackLimit = - (PUCHAR)(usUserStack.ExpandableStackBase) - *StackCommit; - - DPRINT("Stack base %p\n", usUserStack.ExpandableStackBase); - DPRINT("Stack limit %p\n", usUserStack.ExpandableStackLimit); - DPRINT("Stack bottom %p\n", usUserStack.ExpandableStackBottom); - - /* commit as much stack as requested */ - nErrCode = NtAllocateVirtualMemory - ( - ProcessHandle, - &(usUserStack.ExpandableStackLimit), - 0, - StackCommit, - MEM_COMMIT, - PAGE_READWRITE - ); - - /* failure */ - if(!NT_SUCCESS(nErrCode)) goto l_Fail; - - assert((*StackReserve - *StackCommit) >= PAGE_SIZE); - assert((*StackReserve - *StackCommit) % PAGE_SIZE == 0); - - pGuardBase = (PUCHAR)(usUserStack.ExpandableStackLimit) - PAGE_SIZE; - - DPRINT("Guard base %p\n", usUserStack.ExpandableStackBase); - - /* set up the guard page */ - nErrCode = NtAllocateVirtualMemory - ( - ProcessHandle, - &pGuardBase, - 0, - &nGuardSize, - MEM_COMMIT, - PAGE_READWRITE | PAGE_GUARD - ); - - /* failure */ - if(!NT_SUCCESS(nErrCode)) goto l_Fail; - - DPRINT("Guard base %p\n", usUserStack.ExpandableStackBase); - } + /* failure */ + if(!NT_SUCCESS(nErrCode)) goto l_Fail; /* initialize the registers and stack for the thread */ nErrCode = RtlRosInitializeContextEx @@ -178,7 +60,7 @@ NTSTATUS STDCALL RtlRosCreateUserThreadEx ); /* failure */ - if(!NT_SUCCESS(nErrCode)) goto l_Cleanup; + if(!NT_SUCCESS(nErrCode)) goto l_Fail; /* create the thread object */ nErrCode = NtCreateThread @@ -194,25 +76,18 @@ NTSTATUS STDCALL RtlRosCreateUserThreadEx ); /* failure */ - if(!NT_SUCCESS(nErrCode)) goto l_Cleanup; + if(!NT_SUCCESS(nErrCode)) goto l_Fail; /* success */ return STATUS_SUCCESS; - /* deallocate the stack */ -l_Cleanup: - if(usUserStack.FixedStackLimit) - pStackLowest = usUserStack.FixedStackLimit; - else if(usUserStack.ExpandableStackBottom) - pStackLowest = usUserStack.ExpandableStackBottom; - - /* free the stack, if it was allocated */ - if(pStackLowest != NULL) - NtFreeVirtualMemory(ProcessHandle, &pStackLowest, &nSize, MEM_RELEASE); - /* failure */ l_Fail: assert(!NT_SUCCESS(nErrCode)); + + /* deallocate the stack */ + RtlRosDeleteStack(ProcessHandle, &usUserStack); + return nErrCode; } @@ -224,7 +99,7 @@ NTSTATUS CDECL RtlRosCreateUserThreadVa IN LONG StackZeroBits, IN OUT PULONG StackReserve OPTIONAL, IN OUT PULONG StackCommit OPTIONAL, - IN PTHREAD_START_ROUTINE StartAddress, + IN PVOID StartAddress, OUT PHANDLE ThreadHandle OPTIONAL, OUT PCLIENT_ID ClientId OPTIONAL, IN ULONG ParameterCount, diff --git a/reactos/lib/rosrtl/thread/stack.c b/reactos/lib/rosrtl/thread/stack.c new file mode 100644 index 00000000000..d0a7eb1729e --- /dev/null +++ b/reactos/lib/rosrtl/thread/stack.c @@ -0,0 +1,187 @@ +/* $Id: stack.c,v 1.1 2003/05/29 00:36:41 hyperion Exp $ +*/ +/* +*/ + +#include +#include + +#define NDEBUG +#include + +NTSTATUS NTAPI RtlRosCreateStack +( + IN HANDLE ProcessHandle, + OUT PUSER_STACK UserStack, + IN LONG StackZeroBits, + IN OUT PULONG StackReserve OPTIONAL, + IN OUT PULONG StackCommit OPTIONAL +) +{ + /* FIXME: read the defaults from the executable image */ + ULONG_PTR nStackReserve = 0x100000; + /* FIXME: when we finally have exception handling, make this PAGE_SIZE */ + ULONG_PTR nStackCommit = 0x100000; + PVOID pStackLowest; + ULONG_PTR nSize = 0; + NTSTATUS nErrCode; + + if(StackReserve == NULL) StackReserve = &nStackReserve; + else ROUNDUP(*StackReserve, PAGE_SIZE); + + if(StackCommit == NULL) StackCommit = &nStackCommit; + else ROUNDUP(*StackCommit, PAGE_SIZE); + +#if 0 + /* the stack commit size must be equal to or less than the reserve size */ + if(*StackCommit > *StackReserve) *StackCommit = *StackReserve; +#else + /* FIXME: no SEH, no guard pages */ + *StackCommit = *StackReserve; +#endif + + /* FIXME: this code assumes a stack growing downwards */ + /* fixed stack */ + if(*StackCommit == *StackReserve) + { + UserStack->ExpandableStackBase = NULL; + UserStack->ExpandableStackLimit = NULL; + UserStack->ExpandableStackBottom = NULL; + + UserStack->FixedStackLimit = NULL; + + /* allocate the stack */ + nErrCode = NtAllocateVirtualMemory + ( + ProcessHandle, + &(UserStack->FixedStackLimit), + StackZeroBits, + StackReserve, + MEM_RESERVE | MEM_COMMIT, + PAGE_READWRITE + ); + + /* failure */ + if(!NT_SUCCESS(nErrCode)) goto l_Fail; + + /* store the highest (first) address of the stack */ + UserStack->FixedStackBase = + (PUCHAR)(UserStack->FixedStackLimit) + *StackReserve; + + *StackCommit = *StackReserve; + } + /* expandable stack */ + else + { + ULONG_PTR nGuardSize = PAGE_SIZE; + PVOID pGuardBase; + + DPRINT("Expandable stack\n"); + + UserStack->FixedStackBase = NULL; + UserStack->FixedStackLimit = NULL; + + UserStack->ExpandableStackBottom = NULL; + + /* reserve the stack */ + nErrCode = NtAllocateVirtualMemory + ( + ProcessHandle, + &(UserStack->ExpandableStackBottom), + StackZeroBits, + StackReserve, + MEM_RESERVE, + PAGE_READWRITE + ); + + /* failure */ + if(!NT_SUCCESS(nErrCode)) goto l_Fail; + + DPRINT("Reserved %08X bytes\n", *StackReserve); + + /* expandable stack base - the highest address of the stack */ + UserStack->ExpandableStackBase = + (PUCHAR)(UserStack->ExpandableStackBottom) + *StackReserve; + + /* expandable stack limit - the lowest committed address of the stack */ + UserStack->ExpandableStackLimit = + (PUCHAR)(UserStack->ExpandableStackBase) - *StackCommit; + + DPRINT("Stack base %p\n", UserStack->ExpandableStackBase); + DPRINT("Stack limit %p\n", UserStack->ExpandableStackLimit); + DPRINT("Stack bottom %p\n", UserStack->ExpandableStackBottom); + + /* commit as much stack as requested */ + nErrCode = NtAllocateVirtualMemory + ( + ProcessHandle, + &(UserStack->ExpandableStackLimit), + 0, + StackCommit, + MEM_COMMIT, + PAGE_READWRITE + ); + + /* failure */ + if(!NT_SUCCESS(nErrCode)) goto l_Cleanup; + + assert((*StackReserve - *StackCommit) >= PAGE_SIZE); + assert((*StackReserve - *StackCommit) % PAGE_SIZE == 0); + + pGuardBase = (PUCHAR)(UserStack->ExpandableStackLimit) - PAGE_SIZE; + + DPRINT("Guard base %p\n", UserStack->ExpandableStackBase); + + /* set up the guard page */ + nErrCode = NtAllocateVirtualMemory + ( + ProcessHandle, + &pGuardBase, + 0, + &nGuardSize, + MEM_COMMIT, + PAGE_READWRITE | PAGE_GUARD + ); + + /* failure */ + if(!NT_SUCCESS(nErrCode)) goto l_Cleanup; + + DPRINT("Guard base %p\n", UserStack->ExpandableStackBase); + } + + + /* success */ + return STATUS_SUCCESS; + + /* deallocate the stack */ +l_Cleanup: + RtlRosDeleteStack(ProcessHandle, UserStack); + + /* failure */ +l_Fail: + assert(!NT_SUCCESS(nErrCode)); + return nErrCode; +} + +NTSTATUS NTAPI RtlRosDeleteStack +( + IN HANDLE ProcessHandle, + IN PUSER_STACK UserStack +) +{ + PVOID pStackLowest = NULL; + ULONG_PTR nSize; + + if(UserStack->FixedStackLimit) + pStackLowest = UserStack->FixedStackLimit; + else if(UserStack->ExpandableStackBottom) + pStackLowest = UserStack->ExpandableStackBottom; + + /* free the stack, if it was allocated */ + if(pStackLowest != NULL) + return NtFreeVirtualMemory(ProcessHandle, &pStackLowest, &nSize, MEM_RELEASE); + + return STATUS_SUCCESS; +} + +/* EOF */