2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS System Libraries
4 * FILE: dll/win32/kernel32/client/fiber.c
5 * PURPOSE: Fiber Implementation
7 * Alex Ionescu (alex@relsoft.net)
8 * KJK::Hyperion <noog@libero.it>
16 C_ASSERT(FIELD_OFFSET(FIBER
, ExceptionList
) == 0x04);
17 C_ASSERT(FIELD_OFFSET(FIBER
, StackBase
) == 0x08);
18 C_ASSERT(FIELD_OFFSET(FIBER
, StackLimit
) == 0x0C);
19 C_ASSERT(FIELD_OFFSET(FIBER
, DeallocationStack
) == 0x10);
20 C_ASSERT(FIELD_OFFSET(FIBER
, FiberContext
) == 0x14);
21 C_ASSERT(FIELD_OFFSET(FIBER
, GuaranteedStackBytes
) == 0x2E0);
22 C_ASSERT(FIELD_OFFSET(FIBER
, FlsData
) == 0x2E4);
23 C_ASSERT(FIELD_OFFSET(FIBER
, ActivationContextStackPointer
) == 0x2E8);
26 /* PRIVATE FUNCTIONS **********************************************************/
30 BaseRundownFls(_In_ PVOID FlsData
)
32 /* No FLS support yet */
35 /* PUBLIC FUNCTIONS ***********************************************************/
42 ConvertFiberToThread(VOID
)
46 DPRINT1("Converting Fiber to Thread\n");
48 /* Check if the thread is already not a fiber */
50 if (!Teb
->HasFiberData
)
53 SetLastError(ERROR_ALREADY_THREAD
);
57 /* This thread won't run a fiber anymore */
58 Teb
->HasFiberData
= FALSE
;
59 FiberData
= Teb
->NtTib
.FiberData
;
60 Teb
->NtTib
.FiberData
= NULL
;
63 ASSERT(FiberData
!= NULL
);
64 RtlFreeHeap(GetProcessHeap(),
77 ConvertThreadToFiberEx(_In_opt_ LPVOID lpParameter
,
82 DPRINT1("Converting Thread to Fiber\n");
84 /* Check for invalid flags */
85 if (dwFlags
& ~FIBER_FLAG_FLOAT_SWITCH
)
88 SetLastError(ERROR_INVALID_PARAMETER
);
92 /* Are we already a fiber? */
94 if (Teb
->HasFiberData
)
97 SetLastError(ERROR_ALREADY_FIBER
);
101 /* Allocate the fiber */
102 Fiber
= RtlAllocateHeap(RtlGetProcessHeap(),
108 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
112 /* Copy some contextual data from the thread to the fiber */
113 Fiber
->FiberData
= lpParameter
;
114 Fiber
->ExceptionList
= Teb
->NtTib
.ExceptionList
;
115 Fiber
->StackBase
= Teb
->NtTib
.StackBase
;
116 Fiber
->StackLimit
= Teb
->NtTib
.StackLimit
;
117 Fiber
->DeallocationStack
= Teb
->DeallocationStack
;
118 Fiber
->FlsData
= Teb
->FlsData
;
119 Fiber
->GuaranteedStackBytes
= Teb
->GuaranteedStackBytes
;
120 Fiber
->ActivationContextStackPointer
= Teb
->ActivationContextStackPointer
;
122 /* Save FPU State if requested, otherwise just the basic registers */
123 Fiber
->FiberContext
.ContextFlags
= (dwFlags
& FIBER_FLAG_FLOAT_SWITCH
) ?
124 (CONTEXT_FULL
| CONTEXT_FLOATING_POINT
) :
127 /* Associate the fiber to the current thread */
128 Teb
->NtTib
.FiberData
= Fiber
;
129 Teb
->HasFiberData
= TRUE
;
131 /* Return opaque fiber data */
132 return (LPVOID
)Fiber
;
140 ConvertThreadToFiber(_In_opt_ LPVOID lpParameter
)
142 /* Call the newer function */
143 return ConvertThreadToFiberEx(lpParameter
,
152 CreateFiber(_In_ SIZE_T dwStackSize
,
153 _In_ LPFIBER_START_ROUTINE lpStartAddress
,
154 _In_opt_ LPVOID lpParameter
)
156 /* Call the Newer Function */
157 return CreateFiberEx(dwStackSize
,
169 CreateFiberEx(_In_ SIZE_T dwStackCommitSize
,
170 _In_ SIZE_T dwStackReserveSize
,
172 _In_ LPFIBER_START_ROUTINE lpStartAddress
,
173 _In_opt_ LPVOID lpParameter
)
177 INITIAL_TEB InitialTeb
;
178 PACTIVATION_CONTEXT_STACK ActivationContextStackPointer
;
179 DPRINT("Creating Fiber\n");
181 /* Check for invalid flags */
182 if (dwFlags
& ~FIBER_FLAG_FLOAT_SWITCH
)
185 SetLastError(ERROR_INVALID_PARAMETER
);
189 /* Allocate the Activation Context Stack */
190 ActivationContextStackPointer
= NULL
;
191 Status
= RtlAllocateActivationContextStack(&ActivationContextStackPointer
);
192 if (!NT_SUCCESS(Status
))
195 BaseSetLastNTError(Status
);
199 /* Allocate the fiber */
200 Fiber
= RtlAllocateHeap(RtlGetProcessHeap(),
205 /* Free the activation context stack */
206 RtlFreeActivationContextStack(ActivationContextStackPointer
);
209 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
213 /* Create the stack for the fiber */
214 Status
= BaseCreateStack(NtCurrentProcess(),
218 if (!NT_SUCCESS(Status
))
221 RtlFreeHeap(GetProcessHeap(),
225 /* Free the activation context stack */
226 RtlFreeActivationContextStack(ActivationContextStackPointer
);
229 BaseSetLastNTError(Status
);
233 /* Clear the context */
234 RtlZeroMemory(&Fiber
->FiberContext
,
237 /* Copy the data into the fiber */
238 Fiber
->StackBase
= InitialTeb
.StackBase
;
239 Fiber
->StackLimit
= InitialTeb
.StackLimit
;
240 Fiber
->DeallocationStack
= InitialTeb
.AllocatedStackBase
;
241 Fiber
->FiberData
= lpParameter
;
242 Fiber
->ExceptionList
= EXCEPTION_CHAIN_END
;
243 Fiber
->GuaranteedStackBytes
= 0;
244 Fiber
->FlsData
= NULL
;
245 Fiber
->ActivationContextStackPointer
= ActivationContextStackPointer
;
247 /* Save FPU State if requested, otherwise just the basic registers */
248 Fiber
->FiberContext
.ContextFlags
= (dwFlags
& FIBER_FLAG_FLOAT_SWITCH
) ?
249 (CONTEXT_FULL
| CONTEXT_FLOATING_POINT
) :
252 /* Initialize the context for the fiber */
253 BaseInitializeContext(&Fiber
->FiberContext
,
256 InitialTeb
.StackBase
,
259 /* Return the Fiber */
268 DeleteFiber(_In_ LPVOID lpFiber
)
274 /* Are we deleting ourselves? */
275 Teb
= NtCurrentTeb();
276 Fiber
= (PFIBER
)lpFiber
;
277 if ((Teb
->HasFiberData
) &&
278 (Teb
->NtTib
.FiberData
== Fiber
))
284 /* Not ourselves, de-allocate the stack */
286 NtFreeVirtualMemory(NtCurrentProcess(),
287 &Fiber
->DeallocationStack
,
292 if (Fiber
->FlsData
) BaseRundownFls(Fiber
->FlsData
);
294 /* Get rid of the activation context stack */
295 RtlFreeActivationContextStack(Fiber
->ActivationContextStackPointer
);
297 /* Free the fiber data */
298 RtlFreeHeap(GetProcessHeap(),
310 /* Return flag in the TEB */
311 return NtCurrentTeb()->HasFiberData
;
319 FlsAlloc(PFLS_CALLBACK_FUNCTION lpCallback
)
324 SetLastError(ERROR_CALL_NOT_IMPLEMENTED
);
325 return FLS_OUT_OF_INDEXES
;
334 FlsFree(DWORD dwFlsIndex
)
339 SetLastError(ERROR_CALL_NOT_IMPLEMENTED
);
349 FlsGetValue(DWORD dwFlsIndex
)
354 if(dwFlsIndex
>= 128) goto l_InvalidParam
;
356 ppFlsSlots
= NtCurrentTeb()->FlsData
;
358 if(ppFlsSlots
== NULL
) goto l_InvalidParam
;
361 pRetVal
= ppFlsSlots
[dwFlsIndex
+ 2];
366 SetLastError(ERROR_INVALID_PARAMETER
);
376 FlsSetValue(DWORD dwFlsIndex
,
380 TEB
*pTeb
= NtCurrentTeb();
382 if(dwFlsIndex
>= 128) goto l_InvalidParam
;
384 ppFlsSlots
= pTeb
->FlsData
;
386 if (ppFlsSlots
== NULL
)
388 PEB
*pPeb
= pTeb
->ProcessEnvironmentBlock
;
390 ppFlsSlots
= RtlAllocateHeap(pPeb
->ProcessHeap
,
392 (128 + 2) * sizeof(PVOID
));
393 if(ppFlsSlots
== NULL
) goto l_OutOfMemory
;
395 pTeb
->FlsData
= ppFlsSlots
;
399 /* TODO: initialization */
404 ppFlsSlots
[dwFlsIndex
+ 2] = lpFlsData
;
409 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
413 SetLastError(ERROR_INVALID_PARAMETER
);