2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS System Libraries
4 * FILE: lib/kernel32/thread/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
, Context
) == 0x14);
21 C_ASSERT(FIELD_OFFSET(FIBER
, GuaranteedStackBytes
) == 0x2E0);
22 C_ASSERT(FIELD_OFFSET(FIBER
, FlsData
) == 0x2E4);
23 C_ASSERT(FIELD_OFFSET(FIBER
, ActivationContextStack
) == 0x2E8);
26 /* PRIVATE FUNCTIONS **********************************************************/
30 BaseRundownFls(IN PVOID FlsData
)
32 /* No FLS support yet */
36 /* PUBLIC FUNCTIONS ***********************************************************/
43 ConvertFiberToThread(VOID
)
47 DPRINT1("Converting Fiber to Thread\n");
49 /* Check if the thread is already not a fiber */
51 if (!Teb
->HasFiberData
)
54 SetLastError(ERROR_ALREADY_THREAD
);
58 /* this thread won't run a fiber anymore */
59 Teb
->HasFiberData
= FALSE
;
60 FiberData
= Teb
->NtTib
.FiberData
;
61 Teb
->NtTib
.FiberData
= NULL
;
64 ASSERT(FiberData
!= NULL
);
65 RtlFreeHeap(GetProcessHeap(), 0, FiberData
);
76 ConvertThreadToFiberEx(LPVOID lpParameter
,
81 DPRINT1("Converting Thread to Fiber\n");
83 /* Check for invalid flags */
84 if (dwFlags
&~ FIBER_FLAG_FLOAT_SWITCH
)
87 SetLastError(ERROR_INVALID_PARAMETER
);
91 /* Are we already a fiber? */
93 if (Teb
->HasFiberData
)
96 SetLastError(ERROR_ALREADY_FIBER
);
100 /* Allocate the fiber */
101 Fiber
= RtlAllocateHeap(RtlGetProcessHeap(), 0, sizeof(FIBER
));
104 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
108 /* Copy some contextual data from the thread to the fiber */
109 Fiber
->Parameter
= lpParameter
;
110 Fiber
->ExceptionList
= Teb
->NtTib
.ExceptionList
;
111 Fiber
->StackBase
= Teb
->NtTib
.StackBase
;
112 Fiber
->StackLimit
= Teb
->NtTib
.StackLimit
;
113 Fiber
->DeallocationStack
= Teb
->DeallocationStack
;
114 Fiber
->FlsData
= Teb
->FlsData
;
115 Fiber
->GuaranteedStackBytes
= Teb
->GuaranteedStackBytes
;
116 Fiber
->ActivationContextStack
= Teb
->ActivationContextStackPointer
;
117 Fiber
->Context
.ContextFlags
= CONTEXT_FULL
;
119 /* Save FPU State if requested */
120 if (dwFlags
& FIBER_FLAG_FLOAT_SWITCH
)
122 Fiber
->Context
.ContextFlags
|= CONTEXT_FLOATING_POINT
;
125 /* Associate the fiber to the current thread */
126 Teb
->NtTib
.FiberData
= Fiber
;
127 Teb
->HasFiberData
= TRUE
;
129 /* Return opaque fiber data */
130 return (LPVOID
)Fiber
;
138 ConvertThreadToFiber(LPVOID lpParameter
)
140 /* Call the newer function */
141 return ConvertThreadToFiberEx(lpParameter
, 0);
149 CreateFiber(SIZE_T dwStackSize
,
150 LPFIBER_START_ROUTINE lpStartAddress
,
153 /* Call the Newer Function */
154 return CreateFiberEx(dwStackSize
, 0, 0, lpStartAddress
, lpParameter
);
162 CreateFiberEx(SIZE_T dwStackCommitSize
,
163 SIZE_T dwStackReserveSize
,
165 LPFIBER_START_ROUTINE lpStartAddress
,
170 INITIAL_TEB InitialTeb
;
171 PACTIVATION_CONTEXT_STACK ActivationContextStack
= NULL
;
172 DPRINT("Creating Fiber\n");
174 /* Check for invalid flags */
175 if (dwFlags
&~ FIBER_FLAG_FLOAT_SWITCH
)
178 SetLastError(ERROR_INVALID_PARAMETER
);
182 /* Allocate the Activation Context Stack */
183 Status
= RtlAllocateActivationContextStack(&ActivationContextStack
);
184 if (!NT_SUCCESS(Status
))
187 BaseSetLastNTError(Status
);
191 /* Allocate the fiber */
192 Fiber
= RtlAllocateHeap(RtlGetProcessHeap(), 0, sizeof(FIBER
));
195 /* Free the activation context stack */
196 RtlFreeActivationContextStack(ActivationContextStack
);
199 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
203 /* Create the stack for the fiber */
204 Status
= BaseCreateStack(NtCurrentProcess(),
208 if (!NT_SUCCESS(Status
))
211 RtlFreeHeap(GetProcessHeap(), 0, Fiber
);
213 /* Free the activation context stack */
214 RtlFreeActivationContextStack(ActivationContextStack
);
217 BaseSetLastNTError(Status
);
221 /* Clear the context */
222 RtlZeroMemory(&Fiber
->Context
, sizeof(CONTEXT
));
224 /* Copy the data into the fiber */
225 Fiber
->StackBase
= InitialTeb
.StackBase
;
226 Fiber
->StackLimit
= InitialTeb
.StackLimit
;
227 Fiber
->DeallocationStack
= InitialTeb
.AllocatedStackBase
;
228 Fiber
->Parameter
= lpParameter
;
229 Fiber
->ExceptionList
= EXCEPTION_CHAIN_END
;
230 Fiber
->GuaranteedStackBytes
= 0;
231 Fiber
->FlsData
= NULL
;
232 Fiber
->ActivationContextStack
= ActivationContextStack
;
233 Fiber
->Context
.ContextFlags
= CONTEXT_FULL
;
235 /* Save FPU State if requested */
236 Fiber
->Context
.ContextFlags
= (dwFlags
& FIBER_FLAG_FLOAT_SWITCH
) ? CONTEXT_FLOATING_POINT
: 0;
238 /* initialize the context for the fiber */
239 BaseInitializeContext(&Fiber
->Context
,
242 InitialTeb
.StackBase
,
245 /* Return the Fiber */
254 DeleteFiber(LPVOID lpFiber
)
257 PFIBER Fiber
= (PFIBER
)lpFiber
;
260 /* First, exit the thread */
261 Teb
= NtCurrentTeb();
262 if ((Teb
->HasFiberData
) && (Teb
->NtTib
.FiberData
== Fiber
)) ExitThread(1);
264 /* Now de-allocate the stack */
265 NtFreeVirtualMemory(NtCurrentProcess(),
266 &Fiber
->DeallocationStack
,
271 if (Fiber
->FlsData
) BaseRundownFls(Fiber
->FlsData
);
273 /* Get rid of the activation context stack */
274 RtlFreeActivationContextStack(Fiber
->ActivationContextStack
);
276 /* Free the fiber data */
277 RtlFreeHeap(GetProcessHeap(), 0, lpFiber
);
287 return NtCurrentTeb()->HasFiberData
;
295 FlsAlloc(PFLS_CALLBACK_FUNCTION lpCallback
)
300 SetLastError(ERROR_CALL_NOT_IMPLEMENTED
);
301 return FLS_OUT_OF_INDEXES
;
310 FlsFree(DWORD dwFlsIndex
)
315 SetLastError(ERROR_CALL_NOT_IMPLEMENTED
);
325 FlsGetValue(DWORD dwFlsIndex
)
330 if(dwFlsIndex
>= 128) goto l_InvalidParam
;
332 ppFlsSlots
= NtCurrentTeb()->FlsData
;
334 if(ppFlsSlots
== NULL
) goto l_InvalidParam
;
337 pRetVal
= ppFlsSlots
[dwFlsIndex
+ 2];
342 SetLastError(ERROR_INVALID_PARAMETER
);
352 FlsSetValue(DWORD dwFlsIndex
, PVOID lpFlsData
)
355 TEB
*pTeb
= NtCurrentTeb();
357 if(dwFlsIndex
>= 128) goto l_InvalidParam
;
359 ppFlsSlots
= pTeb
->FlsData
;
361 if (ppFlsSlots
== NULL
)
363 PEB
*pPeb
= pTeb
->ProcessEnvironmentBlock
;
365 ppFlsSlots
= RtlAllocateHeap(pPeb
->ProcessHeap
,
367 (128 + 2) * sizeof(PVOID
));
368 if(ppFlsSlots
== NULL
) goto l_OutOfMemory
;
370 pTeb
->FlsData
= ppFlsSlots
;
374 /* TODO: initialization */
379 ppFlsSlots
[dwFlsIndex
+ 2] = lpFlsData
;
384 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
388 SetLastError(ERROR_INVALID_PARAMETER
);