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 */
34 ConvertFiberToThread(VOID
)
36 PTEB pTeb
= NtCurrentTeb();
37 DPRINT1("Converting Fiber to Thread\n");
39 /* the current thread isn't running a fiber: failure */
40 if(!pTeb
->HasFiberData
)
42 SetLastError(ERROR_INVALID_PARAMETER
);
46 /* this thread won't run a fiber anymore */
47 pTeb
->HasFiberData
= FALSE
;
50 if(pTeb
->Tib
.FiberData
!= NULL
)
52 RtlFreeHeap(GetProcessHeap(), 0, pTeb
->Tib
.FiberData
);
64 ConvertThreadToFiberEx(LPVOID lpParameter
,
67 PTEB pTeb
= NtCurrentTeb();
69 DPRINT1("Converting Thread to Fiber\n");
71 /* the current thread is already a fiber */
72 if(pTeb
->HasFiberData
&& pTeb
->Tib
.FiberData
) return pTeb
->Tib
.FiberData
;
74 /* allocate the fiber */
75 pfCurFiber
= (PFIBER
)RtlAllocateHeap(GetProcessHeap(),
80 if(pfCurFiber
== NULL
)
82 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
86 /* copy some contextual data from the thread to the fiber */
87 pfCurFiber
->Parameter
= lpParameter
;
88 pfCurFiber
->ExceptionList
= pTeb
->Tib
.ExceptionList
;
89 pfCurFiber
->StackBase
= pTeb
->Tib
.StackBase
;
90 pfCurFiber
->StackLimit
= pTeb
->Tib
.StackLimit
;
91 pfCurFiber
->DeallocationStack
= pTeb
->DeallocationStack
;
92 pfCurFiber
->FlsData
= pTeb
->FlsData
;
93 pfCurFiber
->GuaranteedStackBytes
= pTeb
->GuaranteedStackBytes
;
94 pfCurFiber
->ActivationContextStack
= pTeb
->ActivationContextStackPointer
;
95 pfCurFiber
->Context
.ContextFlags
= CONTEXT_FULL
;
97 /* Save FPU State if requsted */
98 if (dwFlags
& FIBER_FLAG_FLOAT_SWITCH
)
100 pfCurFiber
->Context
.ContextFlags
|= CONTEXT_FLOATING_POINT
;
103 /* associate the fiber to the current thread */
104 pTeb
->Tib
.FiberData
= pfCurFiber
;
105 pTeb
->HasFiberData
= TRUE
;
108 return (LPVOID
)pfCurFiber
;
116 ConvertThreadToFiber(LPVOID lpParameter
)
118 /* Call the newer function */
119 return ConvertThreadToFiberEx(lpParameter
, 0);
127 CreateFiber(SIZE_T dwStackSize
,
128 LPFIBER_START_ROUTINE lpStartAddress
,
131 /* Call the Newer Function */
132 return CreateFiberEx(dwStackSize
, 0, 0, lpStartAddress
, lpParameter
);
140 CreateFiberEx(SIZE_T dwStackCommitSize
,
141 SIZE_T dwStackReserveSize
,
143 LPFIBER_START_ROUTINE lpStartAddress
,
148 INITIAL_TEB usFiberInitialTeb
;
149 CONTEXT ctxFiberContext
;
150 PVOID ActivationContextStack
= NULL
;
151 DPRINT1("Creating Fiber\n");
153 #ifdef SXS_SUPPORT_ENABLED
154 /* Allocate the Activation Context Stack */
155 nErrCode
= RtlAllocateActivationContextStack(&ActivationContextStack
);
158 /* Allocate the fiber */
159 pfCurFiber
= (PFIBER
)RtlAllocateHeap(GetProcessHeap(),
163 if(pfCurFiber
== NULL
)
165 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
169 /* Create the stack for the fiber */
170 nErrCode
= BasepCreateStack(NtCurrentProcess(),
175 if(!NT_SUCCESS(nErrCode
))
178 RtlFreeHeap(GetProcessHeap(), 0, pfCurFiber
);
181 SetLastErrorByStatus(nErrCode
);
185 /* Clear the context */
186 RtlZeroMemory(&pfCurFiber
->Context
, sizeof(CONTEXT
));
188 /* copy the data into the fiber */
189 pfCurFiber
->StackBase
= usFiberInitialTeb
.StackBase
;
190 pfCurFiber
->StackLimit
= usFiberInitialTeb
.StackLimit
;
191 pfCurFiber
->DeallocationStack
= usFiberInitialTeb
.AllocatedStackBase
;
192 pfCurFiber
->Parameter
= lpParameter
;
193 pfCurFiber
->ExceptionList
= (struct _EXCEPTION_REGISTRATION_RECORD
*)-1;
194 pfCurFiber
->GuaranteedStackBytes
= 0;
195 pfCurFiber
->FlsData
= NULL
;
196 pfCurFiber
->ActivationContextStack
= ActivationContextStack
;
197 pfCurFiber
->Context
.ContextFlags
= CONTEXT_FULL
;
199 /* Save FPU State if requsted */
200 if (dwFlags
& FIBER_FLAG_FLOAT_SWITCH
)
202 pfCurFiber
->Context
.ContextFlags
|= CONTEXT_FLOATING_POINT
;
205 /* initialize the context for the fiber */
206 BasepInitializeContext(&ctxFiberContext
,
209 usFiberInitialTeb
.StackBase
,
212 /* Return the Fiber */
221 DeleteFiber(LPVOID lpFiber
)
224 PVOID pStackAllocBase
= ((PFIBER
)lpFiber
)->DeallocationStack
;
227 RtlFreeHeap(GetProcessHeap(), 0, lpFiber
);
229 /* the fiber is deleting itself: let the system deallocate the stack */
230 if(NtCurrentTeb()->Tib
.FiberData
== lpFiber
) ExitThread(1);
232 /* deallocate the stack */
233 NtFreeVirtualMemory(NtCurrentProcess(),
246 return NtCurrentTeb()->HasFiberData
;
253 BaseFiberStartup(VOID
)
256 PFIBER Fiber
= GetFiberData();
258 /* Call the Thread Startup Routine */
259 DPRINT1("Starting Fiber\n");
260 BaseThreadStartup((LPTHREAD_START_ROUTINE
)Fiber
->Context
.Eax
,
261 (LPVOID
)Fiber
->Context
.Ebx
);
262 #elif defined(__x86_64__)
263 PFIBER Fiber
= GetFiberData();
265 /* Call the Thread Startup Routine */
266 DPRINT1("Starting Fiber\n");
267 BaseThreadStartup((LPTHREAD_START_ROUTINE
)Fiber
->Context
.Rax
,
268 (LPVOID
)Fiber
->Context
.Rbx
);
270 #warning Unknown architecture