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 PVOID Parameter
; /* 0x00 0x00 */
19 PEXCEPTION_REGISTRATION_RECORD ExceptionList
; /* 0x04 0x08 */
20 PVOID StackBase
; /* 0x08 0x10 */
21 PVOID StackLimit
; /* 0x0C 0x18 */
22 PVOID DeallocationStack
; /* 0x10 0x20 */
23 CONTEXT Context
; /* 0x14 0x28 */
24 ULONG GuaranteedStackBytes
; /* 0x2E0 */
25 PVOID FlsData
; /* 0x2E4 */
26 PACTIVATION_CONTEXT_STACK 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
,
84 DPRINT1("Converting Thread to Fiber\n");
86 /* Check for invalid flags */
87 if (dwFlags
&~ FIBER_FLAG_FLOAT_SWITCH
)
90 SetLastError(ERROR_INVALID_PARAMETER
);
94 /* Are we already a fiber? */
96 if (Teb
->HasFiberData
)
99 SetLastError(ERROR_ALREADY_FIBER
);
103 /* Allocate the fiber */
104 Fiber
= RtlAllocateHeap(RtlGetProcessHeap(), 0, sizeof(FIBER
));
107 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
111 /* Copy some contextual data from the thread to the fiber */
112 Fiber
->Parameter
= lpParameter
;
113 Fiber
->ExceptionList
= Teb
->NtTib
.ExceptionList
;
114 Fiber
->StackBase
= Teb
->NtTib
.StackBase
;
115 Fiber
->StackLimit
= Teb
->NtTib
.StackLimit
;
116 Fiber
->DeallocationStack
= Teb
->DeallocationStack
;
117 Fiber
->FlsData
= Teb
->FlsData
;
118 Fiber
->GuaranteedStackBytes
= Teb
->GuaranteedStackBytes
;
119 Fiber
->ActivationContextStack
= Teb
->ActivationContextStackPointer
;
120 Fiber
->Context
.ContextFlags
= CONTEXT_FULL
;
122 /* Save FPU State if requested */
123 if (dwFlags
& FIBER_FLAG_FLOAT_SWITCH
)
125 Fiber
->Context
.ContextFlags
|= CONTEXT_FLOATING_POINT
;
128 /* Associate the fiber to the current thread */
129 Teb
->NtTib
.FiberData
= Fiber
;
130 Teb
->HasFiberData
= TRUE
;
132 /* Return opaque fiber data */
133 return (LPVOID
)Fiber
;
141 ConvertThreadToFiber(LPVOID lpParameter
)
143 /* Call the newer function */
144 return ConvertThreadToFiberEx(lpParameter
, 0);
152 CreateFiber(SIZE_T dwStackSize
,
153 LPFIBER_START_ROUTINE lpStartAddress
,
156 /* Call the Newer Function */
157 return CreateFiberEx(dwStackSize
, 0, 0, lpStartAddress
, lpParameter
);
165 CreateFiberEx(SIZE_T dwStackCommitSize
,
166 SIZE_T dwStackReserveSize
,
168 LPFIBER_START_ROUTINE lpStartAddress
,
173 INITIAL_TEB InitialTeb
;
174 PACTIVATION_CONTEXT_STACK ActivationContextStack
= NULL
;
175 DPRINT("Creating Fiber\n");
177 /* Check for invalid flags */
178 if (dwFlags
&~ FIBER_FLAG_FLOAT_SWITCH
)
181 SetLastError(ERROR_INVALID_PARAMETER
);
185 /* Allocate the Activation Context Stack */
186 Status
= RtlAllocateActivationContextStack(&ActivationContextStack
);
187 if (!NT_SUCCESS(Status
))
190 BaseSetLastNTError(Status
);
194 /* Allocate the fiber */
195 Fiber
= RtlAllocateHeap(RtlGetProcessHeap(), 0, sizeof(FIBER
));
198 /* Free the activation context stack */
199 RtlFreeActivationContextStack(ActivationContextStack
);
202 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
206 /* Create the stack for the fiber */
207 Status
= BaseCreateStack(NtCurrentProcess(),
211 if (!NT_SUCCESS(Status
))
214 RtlFreeHeap(GetProcessHeap(), 0, Fiber
);
216 /* Free the activation context stack */
217 RtlFreeActivationContextStack(ActivationContextStack
);
220 BaseSetLastNTError(Status
);
224 /* Clear the context */
225 RtlZeroMemory(&Fiber
->Context
, sizeof(CONTEXT
));
227 /* Copy the data into the fiber */
228 Fiber
->StackBase
= InitialTeb
.StackBase
;
229 Fiber
->StackLimit
= InitialTeb
.StackLimit
;
230 Fiber
->DeallocationStack
= InitialTeb
.AllocatedStackBase
;
231 Fiber
->Parameter
= lpParameter
;
232 Fiber
->ExceptionList
= EXCEPTION_CHAIN_END
;
233 Fiber
->GuaranteedStackBytes
= 0;
234 Fiber
->FlsData
= NULL
;
235 Fiber
->ActivationContextStack
= ActivationContextStack
;
236 Fiber
->Context
.ContextFlags
= CONTEXT_FULL
;
238 /* Save FPU State if requested */
239 Fiber
->Context
.ContextFlags
= (dwFlags
& FIBER_FLAG_FLOAT_SWITCH
) ? CONTEXT_FLOATING_POINT
: 0;
241 /* initialize the context for the fiber */
242 BaseInitializeContext(&Fiber
->Context
,
245 InitialTeb
.StackBase
,
248 /* Return the Fiber */
257 DeleteFiber(LPVOID lpFiber
)
260 PFIBER Fiber
= (PFIBER
)lpFiber
;
263 /* First, exit the thread */
264 Teb
= NtCurrentTeb();
265 if ((Teb
->HasFiberData
) && (Teb
->NtTib
.FiberData
== Fiber
)) ExitThread(1);
267 /* Now de-allocate the stack */
268 NtFreeVirtualMemory(NtCurrentProcess(),
269 &Fiber
->DeallocationStack
,
274 if (Fiber
->FlsData
) BaseRundownFls(Fiber
->FlsData
);
276 /* Get rid of the activation context stack */
277 RtlFreeActivationContextStack(Fiber
->ActivationContextStack
);
279 /* Free the fiber data */
280 RtlFreeHeap(GetProcessHeap(), 0, lpFiber
);
290 return NtCurrentTeb()->HasFiberData
;
298 FlsAlloc(PFLS_CALLBACK_FUNCTION lpCallback
)
303 SetLastError(ERROR_CALL_NOT_IMPLEMENTED
);
304 return FLS_OUT_OF_INDEXES
;
313 FlsFree(DWORD dwFlsIndex
)
318 SetLastError(ERROR_CALL_NOT_IMPLEMENTED
);
328 FlsGetValue(DWORD dwFlsIndex
)
333 if(dwFlsIndex
>= 128) goto l_InvalidParam
;
335 ppFlsSlots
= NtCurrentTeb()->FlsData
;
337 if(ppFlsSlots
== NULL
) goto l_InvalidParam
;
340 pRetVal
= ppFlsSlots
[dwFlsIndex
+ 2];
345 SetLastError(ERROR_INVALID_PARAMETER
);
355 FlsSetValue(DWORD dwFlsIndex
, PVOID lpFlsData
)
358 TEB
*pTeb
= NtCurrentTeb();
360 if(dwFlsIndex
>= 128) goto l_InvalidParam
;
362 ppFlsSlots
= pTeb
->FlsData
;
364 if (ppFlsSlots
== NULL
)
366 PEB
*pPeb
= pTeb
->ProcessEnvironmentBlock
;
368 ppFlsSlots
= RtlAllocateHeap(pPeb
->ProcessHeap
,
370 (128 + 2) * sizeof(PVOID
));
371 if(ppFlsSlots
== NULL
) goto l_OutOfMemory
;
373 pTeb
->FlsData
= ppFlsSlots
;
377 /* TODO: initialization */
382 ppFlsSlots
[dwFlsIndex
+ 2] = lpFlsData
;
387 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
391 SetLastError(ERROR_INVALID_PARAMETER
);