/*
* COPYRIGHT: See COPYING in the top level directory
* PROJECT: ReactOS System Libraries
- * FILE: lib/kernel32/thread/fiber.c
+ * FILE: dll/win32/kernel32/client/fiber.c
* PURPOSE: Fiber Implementation
- * PROGRAMMERS:
+ * PROGRAMMERS:
* Alex Ionescu (alex@relsoft.net)
* KJK::Hyperion <noog@libero.it>
*/
#define NDEBUG
#include <debug.h>
-typedef struct _FIBER /* Field offsets: */
-{ /* 32 bit 64 bit */
- /* this must be the first field */
- PVOID Parameter; /* 0x00 0x00 */
- PEXCEPTION_REGISTRATION_RECORD ExceptionList; /* 0x04 0x08 */
- PVOID StackBase; /* 0x08 0x10 */
- PVOID StackLimit; /* 0x0C 0x18 */
- PVOID DeallocationStack; /* 0x10 0x20 */
- CONTEXT Context; /* 0x14 0x28 */
- ULONG GuaranteedStackBytes; /* 0x2E0 */
- PVOID FlsData; /* 0x2E4 */
- PACTIVATION_CONTEXT_STACK ActivationContextStack; /* 0x2E8 */
-} FIBER, *PFIBER;
+#ifdef _M_IX86
+C_ASSERT(FIELD_OFFSET(FIBER, ExceptionList) == 0x04);
+C_ASSERT(FIELD_OFFSET(FIBER, StackBase) == 0x08);
+C_ASSERT(FIELD_OFFSET(FIBER, StackLimit) == 0x0C);
+C_ASSERT(FIELD_OFFSET(FIBER, DeallocationStack) == 0x10);
+C_ASSERT(FIELD_OFFSET(FIBER, FiberContext) == 0x14);
+C_ASSERT(FIELD_OFFSET(FIBER, GuaranteedStackBytes) == 0x2E0);
+C_ASSERT(FIELD_OFFSET(FIBER, FlsData) == 0x2E4);
+C_ASSERT(FIELD_OFFSET(FIBER, ActivationContextStackPointer) == 0x2E8);
+#endif // _M_IX86
/* PRIVATE FUNCTIONS **********************************************************/
VOID
WINAPI
-BaseRundownFls(IN PVOID FlsData)
+BaseRundownFls(_In_ PVOID FlsData)
{
/* No FLS support yet */
-
}
/* PUBLIC FUNCTIONS ***********************************************************/
return FALSE;
}
- /* this thread won't run a fiber anymore */
+ /* This thread won't run a fiber anymore */
Teb->HasFiberData = FALSE;
FiberData = Teb->NtTib.FiberData;
Teb->NtTib.FiberData = NULL;
/* Free the fiber */
ASSERT(FiberData != NULL);
- RtlFreeHeap(GetProcessHeap(), 0, FiberData);
+ RtlFreeHeap(GetProcessHeap(),
+ 0,
+ FiberData);
- /* success */
+ /* Success */
return TRUE;
}
*/
LPVOID
WINAPI
-ConvertThreadToFiberEx(LPVOID lpParameter,
- DWORD dwFlags)
+ConvertThreadToFiberEx(_In_opt_ LPVOID lpParameter,
+ _In_ DWORD dwFlags)
{
PTEB Teb;
PFIBER Fiber;
DPRINT1("Converting Thread to Fiber\n");
/* Check for invalid flags */
- if (dwFlags &~ FIBER_FLAG_FLOAT_SWITCH)
+ if (dwFlags & ~FIBER_FLAG_FLOAT_SWITCH)
{
/* Fail */
SetLastError(ERROR_INVALID_PARAMETER);
}
/* Allocate the fiber */
- Fiber = RtlAllocateHeap(RtlGetProcessHeap(), 0, sizeof(FIBER));
+ Fiber = RtlAllocateHeap(RtlGetProcessHeap(),
+ 0,
+ sizeof(FIBER));
if (!Fiber)
{
+ /* Fail */
SetLastError(ERROR_NOT_ENOUGH_MEMORY);
return NULL;
}
/* Copy some contextual data from the thread to the fiber */
- Fiber->Parameter = lpParameter;
+ Fiber->FiberData = lpParameter;
Fiber->ExceptionList = Teb->NtTib.ExceptionList;
Fiber->StackBase = Teb->NtTib.StackBase;
Fiber->StackLimit = Teb->NtTib.StackLimit;
Fiber->DeallocationStack = Teb->DeallocationStack;
Fiber->FlsData = Teb->FlsData;
Fiber->GuaranteedStackBytes = Teb->GuaranteedStackBytes;
- Fiber->ActivationContextStack = Teb->ActivationContextStackPointer;
- Fiber->Context.ContextFlags = CONTEXT_FULL;
+ Fiber->ActivationContextStackPointer = Teb->ActivationContextStackPointer;
- /* Save FPU State if requested */
- if (dwFlags & FIBER_FLAG_FLOAT_SWITCH)
- {
- Fiber->Context.ContextFlags |= CONTEXT_FLOATING_POINT;
- }
+ /* Save FPU State if requested, otherwise just the basic registers */
+ Fiber->FiberContext.ContextFlags = (dwFlags & FIBER_FLAG_FLOAT_SWITCH) ?
+ (CONTEXT_FULL | CONTEXT_FLOATING_POINT) :
+ CONTEXT_FULL;
/* Associate the fiber to the current thread */
Teb->NtTib.FiberData = Fiber;
*/
LPVOID
WINAPI
-ConvertThreadToFiber(LPVOID lpParameter)
+ConvertThreadToFiber(_In_opt_ LPVOID lpParameter)
{
/* Call the newer function */
- return ConvertThreadToFiberEx(lpParameter, 0);
+ return ConvertThreadToFiberEx(lpParameter,
+ 0);
}
/*
*/
LPVOID
WINAPI
-CreateFiber(SIZE_T dwStackSize,
- LPFIBER_START_ROUTINE lpStartAddress,
- LPVOID lpParameter)
+CreateFiber(_In_ SIZE_T dwStackSize,
+ _In_ LPFIBER_START_ROUTINE lpStartAddress,
+ _In_opt_ LPVOID lpParameter)
{
/* Call the Newer Function */
- return CreateFiberEx(dwStackSize, 0, 0, lpStartAddress, lpParameter);
+ return CreateFiberEx(dwStackSize,
+ 0,
+ 0,
+ lpStartAddress,
+ lpParameter);
}
/*
*/
LPVOID
WINAPI
-CreateFiberEx(SIZE_T dwStackCommitSize,
- SIZE_T dwStackReserveSize,
- DWORD dwFlags,
- LPFIBER_START_ROUTINE lpStartAddress,
- LPVOID lpParameter)
+CreateFiberEx(_In_ SIZE_T dwStackCommitSize,
+ _In_ SIZE_T dwStackReserveSize,
+ _In_ DWORD dwFlags,
+ _In_ LPFIBER_START_ROUTINE lpStartAddress,
+ _In_opt_ LPVOID lpParameter)
{
PFIBER Fiber;
NTSTATUS Status;
INITIAL_TEB InitialTeb;
- PACTIVATION_CONTEXT_STACK ActivationContextStack = NULL;
+ PACTIVATION_CONTEXT_STACK ActivationContextStackPointer;
DPRINT("Creating Fiber\n");
/* Check for invalid flags */
- if (dwFlags &~ FIBER_FLAG_FLOAT_SWITCH)
+ if (dwFlags & ~FIBER_FLAG_FLOAT_SWITCH)
{
/* Fail */
SetLastError(ERROR_INVALID_PARAMETER);
}
/* Allocate the Activation Context Stack */
- Status = RtlAllocateActivationContextStack(&ActivationContextStack);
+ ActivationContextStackPointer = NULL;
+ Status = RtlAllocateActivationContextStack(&ActivationContextStackPointer);
if (!NT_SUCCESS(Status))
{
/* Fail */
}
/* Allocate the fiber */
- Fiber = RtlAllocateHeap(RtlGetProcessHeap(), 0, sizeof(FIBER));
+ Fiber = RtlAllocateHeap(RtlGetProcessHeap(),
+ 0,
+ sizeof(FIBER));
if (!Fiber)
{
/* Free the activation context stack */
- RtlFreeActivationContextStack(ActivationContextStack);
+ RtlFreeActivationContextStack(ActivationContextStackPointer);
/* Fail */
SetLastError(ERROR_NOT_ENOUGH_MEMORY);
if (!NT_SUCCESS(Status))
{
/* Free the fiber */
- RtlFreeHeap(GetProcessHeap(), 0, Fiber);
+ RtlFreeHeap(GetProcessHeap(),
+ 0,
+ Fiber);
/* Free the activation context stack */
- RtlFreeActivationContextStack(ActivationContextStack);
+ RtlFreeActivationContextStack(ActivationContextStackPointer);
/* Failure */
BaseSetLastNTError(Status);
}
/* Clear the context */
- RtlZeroMemory(&Fiber->Context, sizeof(CONTEXT));
+ RtlZeroMemory(&Fiber->FiberContext,
+ sizeof(CONTEXT));
/* Copy the data into the fiber */
Fiber->StackBase = InitialTeb.StackBase;
Fiber->StackLimit = InitialTeb.StackLimit;
Fiber->DeallocationStack = InitialTeb.AllocatedStackBase;
- Fiber->Parameter = lpParameter;
+ Fiber->FiberData = lpParameter;
Fiber->ExceptionList = EXCEPTION_CHAIN_END;
Fiber->GuaranteedStackBytes = 0;
Fiber->FlsData = NULL;
- Fiber->ActivationContextStack = ActivationContextStack;
- Fiber->Context.ContextFlags = CONTEXT_FULL;
+ Fiber->ActivationContextStackPointer = ActivationContextStackPointer;
- /* Save FPU State if requested */
- Fiber->Context.ContextFlags = (dwFlags & FIBER_FLAG_FLOAT_SWITCH) ? CONTEXT_FLOATING_POINT : 0;
+ /* Save FPU State if requested, otherwise just the basic registers */
+ Fiber->FiberContext.ContextFlags = (dwFlags & FIBER_FLAG_FLOAT_SWITCH) ?
+ (CONTEXT_FULL | CONTEXT_FLOATING_POINT) :
+ CONTEXT_FULL;
- /* initialize the context for the fiber */
- BaseInitializeContext(&Fiber->Context,
+ /* Initialize the context for the fiber */
+ BaseInitializeContext(&Fiber->FiberContext,
lpParameter,
lpStartAddress,
InitialTeb.StackBase,
*/
VOID
WINAPI
-DeleteFiber(LPVOID lpFiber)
+DeleteFiber(_In_ LPVOID lpFiber)
{
- SIZE_T Size = 0;
- PFIBER Fiber = (PFIBER)lpFiber;
+ SIZE_T Size;
+ PFIBER Fiber;
PTEB Teb;
- /* First, exit the thread */
+ /* Are we deleting ourselves? */
Teb = NtCurrentTeb();
- if ((Teb->HasFiberData) && (Teb->NtTib.FiberData == Fiber)) ExitThread(1);
+ Fiber = (PFIBER)lpFiber;
+ if ((Teb->HasFiberData) &&
+ (Teb->NtTib.FiberData == Fiber))
+ {
+ /* Just exit */
+ ExitThread(1);
+ }
- /* Now de-allocate the stack */
+ /* Not ourselves, de-allocate the stack */
+ Size = 0 ;
NtFreeVirtualMemory(NtCurrentProcess(),
&Fiber->DeallocationStack,
&Size,
if (Fiber->FlsData) BaseRundownFls(Fiber->FlsData);
/* Get rid of the activation context stack */
- RtlFreeActivationContextStack(Fiber->ActivationContextStack);
+ RtlFreeActivationContextStack(Fiber->ActivationContextStackPointer);
/* Free the fiber data */
- RtlFreeHeap(GetProcessHeap(), 0, lpFiber);
+ RtlFreeHeap(GetProcessHeap(),
+ 0,
+ lpFiber);
}
/*
WINAPI
IsThreadAFiber(VOID)
{
+ /* Return flag in the TEB */
return NtCurrentTeb()->HasFiberData;
}
/*
- * @unimplemented
+ * @implemented
*/
DWORD
WINAPI
FlsAlloc(PFLS_CALLBACK_FUNCTION lpCallback)
{
- (void)lpCallback;
+ DWORD dwFlsIndex;
+ PPEB Peb = NtCurrentPeb();
+ PVOID *ppFlsSlots;
- UNIMPLEMENTED;
- SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
- return FLS_OUT_OF_INDEXES;
+ RtlAcquirePebLock();
+
+ ppFlsSlots = NtCurrentTeb()->FlsData;
+
+ if (!Peb->FlsCallback &&
+ !(Peb->FlsCallback = RtlAllocateHeap(RtlGetProcessHeap(), HEAP_ZERO_MEMORY,
+ FLS_MAXIMUM_AVAILABLE * sizeof(PVOID))))
+ {
+ SetLastError(ERROR_NOT_ENOUGH_MEMORY);
+ dwFlsIndex = FLS_OUT_OF_INDEXES;
+ }
+ else
+ {
+ dwFlsIndex = RtlFindClearBitsAndSet(Peb->FlsBitmap, 1, 1);
+ if (dwFlsIndex != FLS_OUT_OF_INDEXES)
+ {
+ if (!ppFlsSlots &&
+ !(ppFlsSlots = RtlAllocateHeap(RtlGetProcessHeap(), HEAP_ZERO_MEMORY,
+ (FLS_MAXIMUM_AVAILABLE + 2) * sizeof(PVOID))))
+ {
+ RtlClearBits(Peb->FlsBitmap, dwFlsIndex, 1);
+ dwFlsIndex = FLS_OUT_OF_INDEXES;
+ SetLastError(ERROR_NOT_ENOUGH_MEMORY);
+ }
+ else
+ {
+ if (!NtCurrentTeb()->FlsData)
+ NtCurrentTeb()->FlsData = ppFlsSlots;
+
+ if (lpCallback)
+ DPRINT1("FlsAlloc: Got lpCallback 0x%p, UNIMPLEMENTED!", lpCallback);
+
+ ppFlsSlots[dwFlsIndex + 2] = NULL; /* clear the value */
+ Peb->FlsCallback[dwFlsIndex] = lpCallback;
+ }
+ }
+ else
+ {
+ SetLastError(ERROR_NO_MORE_ITEMS);
+ }
+ }
+ RtlReleasePebLock();
+ return dwFlsIndex;
}
/*
- * @unimplemented
+ * @implemented
*/
BOOL
WINAPI
FlsFree(DWORD dwFlsIndex)
{
- (void)dwFlsIndex;
+ BOOL ret;
+ PPEB Peb = NtCurrentPeb();
+ PVOID *ppFlsSlots;
+
+ if (dwFlsIndex >= FLS_MAXIMUM_AVAILABLE)
+ {
+ SetLastError(ERROR_INVALID_PARAMETER);
+ return FALSE;
+ }
+
+ RtlAcquirePebLock();
- UNIMPLEMENTED;
- SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
- return FALSE;
+ ppFlsSlots = NtCurrentTeb()->FlsData;
+ ret = RtlAreBitsSet(Peb->FlsBitmap, dwFlsIndex, 1);
+ if (ret)
+ {
+ RtlClearBits(Peb->FlsBitmap, dwFlsIndex, 1);
+ /* FIXME: call Fls callback */
+ /* FIXME: add equivalent of ThreadZeroTlsCell here */
+ if (ppFlsSlots)
+ ppFlsSlots[dwFlsIndex + 2] = NULL;
+ }
+ else
+ {
+ SetLastError(ERROR_INVALID_PARAMETER);
+ }
+ RtlReleasePebLock();
+ return ret;
}
FlsGetValue(DWORD dwFlsIndex)
{
PVOID *ppFlsSlots;
- PVOID pRetVal;
-
- if(dwFlsIndex >= 128) goto l_InvalidParam;
ppFlsSlots = NtCurrentTeb()->FlsData;
+ if (!dwFlsIndex || dwFlsIndex >= FLS_MAXIMUM_AVAILABLE || !ppFlsSlots)
+ {
+ SetLastError(ERROR_INVALID_PARAMETER);
+ return NULL;
+ }
- if(ppFlsSlots == NULL) goto l_InvalidParam;
-
- SetLastError(0);
- pRetVal = ppFlsSlots[dwFlsIndex + 2];
-
- return pRetVal;
-
-l_InvalidParam:
- SetLastError(ERROR_INVALID_PARAMETER);
- return NULL;
+ SetLastError(ERROR_SUCCESS);
+ return ppFlsSlots[dwFlsIndex + 2];
}
*/
BOOL
WINAPI
-FlsSetValue(DWORD dwFlsIndex, PVOID lpFlsData)
+FlsSetValue(DWORD dwFlsIndex,
+ PVOID lpFlsData)
{
PVOID *ppFlsSlots;
- TEB *pTeb = NtCurrentTeb();
-
- if(dwFlsIndex >= 128) goto l_InvalidParam;
-
- ppFlsSlots = pTeb->FlsData;
- if (ppFlsSlots == NULL)
+ if (!dwFlsIndex || dwFlsIndex >= FLS_MAXIMUM_AVAILABLE)
{
- PEB *pPeb = pTeb->ProcessEnvironmentBlock;
-
- ppFlsSlots = RtlAllocateHeap(pPeb->ProcessHeap,
- HEAP_ZERO_MEMORY,
- (128 + 2) * sizeof(PVOID));
- if(ppFlsSlots == NULL) goto l_OutOfMemory;
-
- pTeb->FlsData = ppFlsSlots;
-
- RtlAcquirePebLock();
-
- /* TODO: initialization */
-
- RtlReleasePebLock();
+ SetLastError(ERROR_INVALID_PARAMETER);
+ return FALSE;
}
-
+ if (!NtCurrentTeb()->FlsData &&
+ !(NtCurrentTeb()->FlsData = RtlAllocateHeap(RtlGetProcessHeap(), HEAP_ZERO_MEMORY,
+ (FLS_MAXIMUM_AVAILABLE + 2) * sizeof(PVOID))))
+ {
+ SetLastError(ERROR_NOT_ENOUGH_MEMORY);
+ return FALSE;
+ }
+ ppFlsSlots = NtCurrentTeb()->FlsData;
ppFlsSlots[dwFlsIndex + 2] = lpFlsData;
-
return TRUE;
-
-l_OutOfMemory:
- SetLastError(ERROR_NOT_ENOUGH_MEMORY);
- goto l_Fail;
-
-l_InvalidParam:
- SetLastError(ERROR_INVALID_PARAMETER);
-
-l_Fail:
- return FALSE;
}
/* EOF */