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
,
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 PVOID 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
));
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 */
214 DPRINT1("Leaking activation stack because nobody implemented free");
215 //RtlFreeActivationContextStack(&ActivationContextStack);
218 BaseSetLastNTError(Status
);
222 /* Clear the context */
223 RtlZeroMemory(&Fiber
->Context
, sizeof(CONTEXT
));
225 /* Copy the data into the fiber */
226 Fiber
->StackBase
= InitialTeb
.StackBase
;
227 Fiber
->StackLimit
= InitialTeb
.StackLimit
;
228 Fiber
->DeallocationStack
= InitialTeb
.AllocatedStackBase
;
229 Fiber
->Parameter
= lpParameter
;
230 Fiber
->ExceptionList
= EXCEPTION_CHAIN_END
;
231 Fiber
->GuaranteedStackBytes
= 0;
232 Fiber
->FlsData
= NULL
;
233 Fiber
->ActivationContextStack
= ActivationContextStack
;
234 Fiber
->Context
.ContextFlags
= CONTEXT_FULL
;
236 /* Save FPU State if requested */
237 Fiber
->Context
.ContextFlags
= (dwFlags
& FIBER_FLAG_FLOAT_SWITCH
) ? CONTEXT_FLOATING_POINT
: 0;
239 /* initialize the context for the fiber */
240 BaseInitializeContext(&Fiber
->Context
,
243 InitialTeb
.StackBase
,
246 /* Return the Fiber */
255 DeleteFiber(LPVOID lpFiber
)
258 PFIBER Fiber
= (PFIBER
)lpFiber
;
261 /* First, exit the thread */
262 Teb
= NtCurrentTeb();
263 if ((Teb
->HasFiberData
) && (Teb
->NtTib
.FiberData
== Fiber
)) ExitThread(1);
265 /* Now de-allocate the stack */
266 NtFreeVirtualMemory(NtCurrentProcess(),
267 &Fiber
->DeallocationStack
,
272 if (Fiber
->FlsData
) BaseRundownFls(Fiber
->FlsData
);
274 /* Get rid of the activation stack */
275 DPRINT1("Leaking activation stack because nobody implemented free");
276 //RtlFreeActivationContextStack(Fiber->ActivationContextStack);
278 /* Free the fiber data */
279 RtlFreeHeap(GetProcessHeap(), 0, lpFiber
);
289 return NtCurrentTeb()->HasFiberData
;
297 FlsAlloc(PFLS_CALLBACK_FUNCTION lpCallback
)
302 SetLastError(ERROR_CALL_NOT_IMPLEMENTED
);
303 return FLS_OUT_OF_INDEXES
;
312 FlsFree(DWORD dwFlsIndex
)
317 SetLastError(ERROR_CALL_NOT_IMPLEMENTED
);
327 FlsGetValue(DWORD dwFlsIndex
)
332 if(dwFlsIndex
>= 128) goto l_InvalidParam
;
334 ppFlsSlots
= NtCurrentTeb()->FlsData
;
336 if(ppFlsSlots
== NULL
) goto l_InvalidParam
;
339 pRetVal
= ppFlsSlots
[dwFlsIndex
+ 2];
344 SetLastError(ERROR_INVALID_PARAMETER
);
354 FlsSetValue(DWORD dwFlsIndex
, PVOID lpFlsData
)
357 TEB
*pTeb
= NtCurrentTeb();
359 if(dwFlsIndex
>= 128) goto l_InvalidParam
;
361 ppFlsSlots
= pTeb
->FlsData
;
363 if (ppFlsSlots
== NULL
)
365 PEB
*pPeb
= pTeb
->ProcessEnvironmentBlock
;
367 ppFlsSlots
= RtlAllocateHeap(pPeb
->ProcessHeap
,
369 (128 + 2) * sizeof(PVOID
));
370 if(ppFlsSlots
== NULL
) goto l_OutOfMemory
;
372 pTeb
->FlsData
= ppFlsSlots
;
376 /* TODO: initialization */
381 ppFlsSlots
[dwFlsIndex
+ 2] = lpFlsData
;
386 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
390 SetLastError(ERROR_INVALID_PARAMETER
);