reactos/dll/win32/kernel32/thread/fiber.c
Amine Khaldi c424146e2c Create a branch for cmake bringup.
svn path=/branches/cmake-bringup/; revision=48236
2010-07-24 18:52:44 +00:00

276 lines
7.5 KiB
C

/*
* COPYRIGHT: See COPYING in the top level directory
* PROJECT: ReactOS System Libraries
* FILE: lib/kernel32/thread/fiber.c
* PURPOSE: Fiber Implementation
* PROGRAMMERS:
* Alex Ionescu (alex@relsoft.net)
* KJK::Hyperion <noog@libero.it>
*/
#include <k32.h>
#define NDEBUG
#include <debug.h>
typedef struct _FIBER /* Field offsets: */
{ /* 32 bit 64 bit */
/* this must be the first field */
LPVOID Parameter; /* 0x00 0x00 */
struct _EXCEPTION_REGISTRATION_RECORD * ExceptionList; /* 0x04 0x08 */
LPVOID StackBase; /* 0x08 0x10 */
LPVOID StackLimit; /* 0x0C 0x18 */
LPVOID DeallocationStack; /* 0x10 0x20 */
CONTEXT Context; /* 0x14 0x28 */
ULONG GuaranteedStackBytes; /* 0x2E0 */
PVOID FlsData; /* 0x2E4 */
PVOID ActivationContextStack; /* 0x2E8 */
} FIBER, *PFIBER;
/*
* @implemented
*/
BOOL
WINAPI
ConvertFiberToThread(VOID)
{
PTEB pTeb = NtCurrentTeb();
DPRINT1("Converting Fiber to Thread\n");
/* the current thread isn't running a fiber: failure */
if (!pTeb->HasFiberData)
{
SetLastError(ERROR_INVALID_PARAMETER);
return FALSE;
}
/* this thread won't run a fiber anymore */
pTeb->HasFiberData = FALSE;
/* free the fiber */
if(pTeb->NtTib.FiberData != NULL)
{
RtlFreeHeap(GetProcessHeap(), 0, pTeb->NtTib.FiberData);
}
/* success */
return TRUE;
}
/*
* @implemented
*/
LPVOID
WINAPI
ConvertThreadToFiberEx(LPVOID lpParameter,
DWORD dwFlags)
{
PTEB pTeb = NtCurrentTeb();
PFIBER pfCurFiber;
DPRINT1("Converting Thread to Fiber\n");
/* the current thread is already a fiber */
if(pTeb->HasFiberData && pTeb->NtTib.FiberData) return pTeb->NtTib.FiberData;
/* allocate the fiber */
pfCurFiber = (PFIBER)RtlAllocateHeap(GetProcessHeap(),
0,
sizeof(FIBER));
/* failure */
if (pfCurFiber == NULL)
{
SetLastError(ERROR_NOT_ENOUGH_MEMORY);
return NULL;
}
/* copy some contextual data from the thread to the fiber */
pfCurFiber->Parameter = lpParameter;
pfCurFiber->ExceptionList = pTeb->NtTib.ExceptionList;
pfCurFiber->StackBase = pTeb->NtTib.StackBase;
pfCurFiber->StackLimit = pTeb->NtTib.StackLimit;
pfCurFiber->DeallocationStack = pTeb->DeallocationStack;
pfCurFiber->FlsData = pTeb->FlsData;
pfCurFiber->GuaranteedStackBytes = pTeb->GuaranteedStackBytes;
pfCurFiber->ActivationContextStack = pTeb->ActivationContextStackPointer;
pfCurFiber->Context.ContextFlags = CONTEXT_FULL;
/* Save FPU State if requsted */
if (dwFlags & FIBER_FLAG_FLOAT_SWITCH)
{
pfCurFiber->Context.ContextFlags |= CONTEXT_FLOATING_POINT;
}
/* associate the fiber to the current thread */
pTeb->NtTib.FiberData = pfCurFiber;
pTeb->HasFiberData = TRUE;
/* success */
return (LPVOID)pfCurFiber;
}
/*
* @implemented
*/
LPVOID
WINAPI
ConvertThreadToFiber(LPVOID lpParameter)
{
/* Call the newer function */
return ConvertThreadToFiberEx(lpParameter, 0);
}
/*
* @implemented
*/
LPVOID
WINAPI
CreateFiber(SIZE_T dwStackSize,
LPFIBER_START_ROUTINE lpStartAddress,
LPVOID lpParameter)
{
/* Call the Newer Function */
return CreateFiberEx(dwStackSize, 0, 0, lpStartAddress, lpParameter);
}
/*
* @implemented
*/
LPVOID
WINAPI
CreateFiberEx(SIZE_T dwStackCommitSize,
SIZE_T dwStackReserveSize,
DWORD dwFlags,
LPFIBER_START_ROUTINE lpStartAddress,
LPVOID lpParameter)
{
PFIBER pfCurFiber;
NTSTATUS nErrCode;
INITIAL_TEB usFiberInitialTeb;
PVOID ActivationContextStack = NULL;
DPRINT("Creating Fiber\n");
#ifdef SXS_SUPPORT_ENABLED
/* Allocate the Activation Context Stack */
nErrCode = RtlAllocateActivationContextStack(&ActivationContextStack);
#endif
/* Allocate the fiber */
pfCurFiber = (PFIBER)RtlAllocateHeap(GetProcessHeap(),
0,
sizeof(FIBER));
/* Failure */
if (pfCurFiber == NULL)
{
SetLastError(ERROR_NOT_ENOUGH_MEMORY);
return NULL;
}
/* Create the stack for the fiber */
nErrCode = BasepCreateStack(NtCurrentProcess(),
dwStackCommitSize,
dwStackReserveSize,
&usFiberInitialTeb);
/* Failure */
if(!NT_SUCCESS(nErrCode))
{
/* Free the fiber */
RtlFreeHeap(GetProcessHeap(), 0, pfCurFiber);
/* Failure */
SetLastErrorByStatus(nErrCode);
return NULL;
}
/* Clear the context */
RtlZeroMemory(&pfCurFiber->Context, sizeof(CONTEXT));
/* copy the data into the fiber */
pfCurFiber->StackBase = usFiberInitialTeb.StackBase;
pfCurFiber->StackLimit = usFiberInitialTeb.StackLimit;
pfCurFiber->DeallocationStack = usFiberInitialTeb.AllocatedStackBase;
pfCurFiber->Parameter = lpParameter;
pfCurFiber->ExceptionList = (struct _EXCEPTION_REGISTRATION_RECORD *)-1;
pfCurFiber->GuaranteedStackBytes = 0;
pfCurFiber->FlsData = NULL;
pfCurFiber->ActivationContextStack = ActivationContextStack;
pfCurFiber->Context.ContextFlags = CONTEXT_FULL;
/* Save FPU State if requsted */
if (dwFlags & FIBER_FLAG_FLOAT_SWITCH)
{
pfCurFiber->Context.ContextFlags |= CONTEXT_FLOATING_POINT;
}
/* initialize the context for the fiber */
BasepInitializeContext(&pfCurFiber->Context,
lpParameter,
lpStartAddress,
usFiberInitialTeb.StackBase,
2);
/* Return the Fiber */
return pfCurFiber;
}
/*
* @implemented
*/
VOID
WINAPI
DeleteFiber(LPVOID lpFiber)
{
SIZE_T nSize = 0;
PVOID pStackAllocBase = ((PFIBER)lpFiber)->DeallocationStack;
/* free the fiber */
RtlFreeHeap(GetProcessHeap(), 0, lpFiber);
/* the fiber is deleting itself: let the system deallocate the stack */
if(NtCurrentTeb()->NtTib.FiberData == lpFiber) ExitThread(1);
/* deallocate the stack */
NtFreeVirtualMemory(NtCurrentProcess(),
&pStackAllocBase,
&nSize,
MEM_RELEASE);
}
/*
* @implemented
*/
BOOL
WINAPI
IsThreadAFiber(VOID)
{
return NtCurrentTeb()->HasFiberData;
}
__declspec(noreturn)
VOID
WINAPI
BaseFiberStartup(VOID)
{
#ifdef _M_IX86
PFIBER Fiber = GetCurrentFiber();
/* Call the Thread Startup Routine */
DPRINT("Starting Fiber\n");
BaseThreadStartup((LPTHREAD_START_ROUTINE)Fiber->Context.Eax,
(LPVOID)Fiber->Context.Ebx);
#elif defined(_M_AMD64)
PFIBER Fiber = GetFiberData();
/* Call the Thread Startup Routine */
DPRINT1("Starting Fiber\n");
BaseThreadStartup((LPTHREAD_START_ROUTINE)Fiber->Context.Rax,
(LPVOID)Fiber->Context.Rbx);
#else
#warning Unknown architecture
UNIMPLEMENTED;
DbgBreakPoint();
#endif
}
/* EOF */