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>
15 typedef struct _FIBER
/* Field offsets: */
17 /* this must be the first field */
18 LPVOID Parameter
; /* 0x00 0x00 */
19 struct _EXCEPTION_REGISTRATION_RECORD
* ExceptionList
; /* 0x04 0x08 */
20 LPVOID StackBase
; /* 0x08 0x10 */
21 LPVOID StackLimit
; /* 0x0C 0x18 */
22 LPVOID DeallocationStack
; /* 0x10 0x20 */
23 CONTEXT Context
; /* 0x14 0x28 */
24 ULONG GuaranteedStackBytes
; /* 0x2E0 */
25 PVOID FlsData
; /* 0x2E4 */
26 PVOID ActivationContextStack
; /* 0x2E8 */
29 /* PRIVATE FUNCTIONS **********************************************************/
33 BaseRundownFls(IN PVOID FlsData
)
35 /* No FLS support yet */
39 /* PUBLIC FUNCTIONS ***********************************************************/
46 ConvertFiberToThread(VOID
)
50 DPRINT1("Converting Fiber to Thread\n");
52 /* Check if the thread is already not a fiber */
54 if (!Teb
->HasFiberData
)
57 SetLastError(ERROR_ALREADY_THREAD
);
61 /* this thread won't run a fiber anymore */
62 Teb
->HasFiberData
= FALSE
;
63 FiberData
= Teb
->NtTib
.FiberData
;
64 Teb
->NtTib
.FiberData
= NULL
;
67 ASSERT(FiberData
!= NULL
);
68 RtlFreeHeap(GetProcessHeap(), 0, FiberData
);
79 ConvertThreadToFiberEx(LPVOID lpParameter
,
82 PTEB pTeb
= NtCurrentTeb();
84 DPRINT1("Converting Thread to Fiber\n");
86 /* the current thread is already a fiber */
87 if(pTeb
->HasFiberData
&& pTeb
->NtTib
.FiberData
) return pTeb
->NtTib
.FiberData
;
89 /* allocate the fiber */
90 pfCurFiber
= (PFIBER
)RtlAllocateHeap(GetProcessHeap(),
95 if (pfCurFiber
== NULL
)
97 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
101 /* copy some contextual data from the thread to the fiber */
102 pfCurFiber
->Parameter
= lpParameter
;
103 pfCurFiber
->ExceptionList
= pTeb
->NtTib
.ExceptionList
;
104 pfCurFiber
->StackBase
= pTeb
->NtTib
.StackBase
;
105 pfCurFiber
->StackLimit
= pTeb
->NtTib
.StackLimit
;
106 pfCurFiber
->DeallocationStack
= pTeb
->DeallocationStack
;
107 pfCurFiber
->FlsData
= pTeb
->FlsData
;
108 pfCurFiber
->GuaranteedStackBytes
= pTeb
->GuaranteedStackBytes
;
109 pfCurFiber
->ActivationContextStack
= pTeb
->ActivationContextStackPointer
;
110 pfCurFiber
->Context
.ContextFlags
= CONTEXT_FULL
;
112 /* Save FPU State if requsted */
113 if (dwFlags
& FIBER_FLAG_FLOAT_SWITCH
)
115 pfCurFiber
->Context
.ContextFlags
|= CONTEXT_FLOATING_POINT
;
118 /* associate the fiber to the current thread */
119 pTeb
->NtTib
.FiberData
= pfCurFiber
;
120 pTeb
->HasFiberData
= TRUE
;
123 return (LPVOID
)pfCurFiber
;
131 ConvertThreadToFiber(LPVOID lpParameter
)
133 /* Call the newer function */
134 return ConvertThreadToFiberEx(lpParameter
, 0);
142 CreateFiber(SIZE_T dwStackSize
,
143 LPFIBER_START_ROUTINE lpStartAddress
,
146 /* Call the Newer Function */
147 return CreateFiberEx(dwStackSize
, 0, 0, lpStartAddress
, lpParameter
);
155 CreateFiberEx(SIZE_T dwStackCommitSize
,
156 SIZE_T dwStackReserveSize
,
158 LPFIBER_START_ROUTINE lpStartAddress
,
163 INITIAL_TEB InitialTeb
;
164 PVOID ActivationContextStack
= NULL
;
165 DPRINT("Creating Fiber\n");
167 /* Check for invalid flags */
168 if (dwFlags
&~ FIBER_FLAG_FLOAT_SWITCH
)
171 SetLastError(ERROR_INVALID_PARAMETER
);
175 /* Allocate the Activation Context Stack */
176 Status
= RtlAllocateActivationContextStack(&ActivationContextStack
);
177 if (!NT_SUCCESS(Status
))
180 BaseSetLastNTError(Status
);
184 /* Allocate the fiber */
185 Fiber
= RtlAllocateHeap(RtlGetProcessHeap(), 0, sizeof(FIBER
));
189 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
193 /* Create the stack for the fiber */
194 Status
= BasepCreateStack(NtCurrentProcess(),
198 if (!NT_SUCCESS(Status
))
201 RtlFreeHeap(GetProcessHeap(), 0, Fiber
);
203 /* Free the activation context */
204 DPRINT1("Leaking activation stack because nobody implemented free");
205 //RtlFreeActivationContextStack(&ActivationContextStack);
208 BaseSetLastNTError(Status
);
212 /* Clear the context */
213 RtlZeroMemory(&Fiber
->Context
, sizeof(CONTEXT
));
215 /* Copy the data into the fiber */
216 Fiber
->StackBase
= InitialTeb
.StackBase
;
217 Fiber
->StackLimit
= InitialTeb
.StackLimit
;
218 Fiber
->DeallocationStack
= InitialTeb
.AllocatedStackBase
;
219 Fiber
->Parameter
= lpParameter
;
220 Fiber
->ExceptionList
= EXCEPTION_CHAIN_END
;
221 Fiber
->GuaranteedStackBytes
= 0;
222 Fiber
->FlsData
= NULL
;
223 Fiber
->ActivationContextStack
= ActivationContextStack
;
224 Fiber
->Context
.ContextFlags
= CONTEXT_FULL
;
226 /* Save FPU State if requested */
227 Fiber
->Context
.ContextFlags
= (dwFlags
& FIBER_FLAG_FLOAT_SWITCH
) ? CONTEXT_FLOATING_POINT
: 0;
229 /* initialize the context for the fiber */
230 BasepInitializeContext(&Fiber
->Context
,
233 InitialTeb
.StackBase
,
236 /* Return the Fiber */
245 DeleteFiber(LPVOID lpFiber
)
248 PFIBER Fiber
= (PFIBER
)lpFiber
;
251 /* First, exit the thread */
252 Teb
= NtCurrentTeb();
253 if ((Teb
->HasFiberData
) && (Teb
->NtTib
.FiberData
== Fiber
)) ExitThread(1);
255 /* Now de-allocate the stack */
256 NtFreeVirtualMemory(NtCurrentProcess(),
257 &Fiber
->DeallocationStack
,
262 if (Fiber
->FlsData
) BaseRundownFls(Fiber
->FlsData
);
264 /* Get rid of the activation stack */
265 DPRINT1("Leaking activation stack because nobody implemented free");
266 //RtlFreeActivationContextStack(Fiber->ActivationContextStack);
268 /* Free the fiber data */
269 RtlFreeHeap(GetProcessHeap(), 0, lpFiber
);
279 return NtCurrentTeb()->HasFiberData
;
287 FlsAlloc(PFLS_CALLBACK_FUNCTION lpCallback
)
292 SetLastError(ERROR_CALL_NOT_IMPLEMENTED
);
293 return FLS_OUT_OF_INDEXES
;
302 FlsFree(DWORD dwFlsIndex
)
307 SetLastError(ERROR_CALL_NOT_IMPLEMENTED
);
317 FlsGetValue(DWORD dwFlsIndex
)
322 if(dwFlsIndex
>= 128) goto l_InvalidParam
;
324 ppFlsSlots
= NtCurrentTeb()->FlsData
;
326 if(ppFlsSlots
== NULL
) goto l_InvalidParam
;
329 pRetVal
= ppFlsSlots
[dwFlsIndex
+ 2];
334 SetLastError(ERROR_INVALID_PARAMETER
);
344 FlsSetValue(DWORD dwFlsIndex
, PVOID lpFlsData
)
347 TEB
*pTeb
= NtCurrentTeb();
349 if(dwFlsIndex
>= 128) goto l_InvalidParam
;
351 ppFlsSlots
= pTeb
->FlsData
;
353 if (ppFlsSlots
== NULL
)
355 PEB
*pPeb
= pTeb
->ProcessEnvironmentBlock
;
357 ppFlsSlots
= RtlAllocateHeap(pPeb
->ProcessHeap
,
359 (128 + 2) * sizeof(PVOID
));
360 if(ppFlsSlots
== NULL
) goto l_OutOfMemory
;
362 pTeb
->FlsData
= ppFlsSlots
;
366 /* TODO: initialization */
371 ppFlsSlots
[dwFlsIndex
+ 2] = lpFlsData
;
376 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
380 SetLastError(ERROR_INVALID_PARAMETER
);