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>
13 #include "../include/debug.h"
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
->ExceptionList
= pTeb
->Tib
.ExceptionList
;
88 pfCurFiber
->StackBase
= pTeb
->Tib
.StackBase
;
89 pfCurFiber
->StackLimit
= pTeb
->Tib
.StackLimit
;
90 pfCurFiber
->DeallocationStack
= pTeb
->DeallocationStack
;
91 pfCurFiber
->FlsData
= pTeb
->FlsData
;
92 pfCurFiber
->GuaranteedStackBytes
= pTeb
->GuaranteedStackBytes
;
93 pfCurFiber
->ActivationContextStack
= pTeb
->ActivationContextStackPointer
;
94 pfCurFiber
->Context
.ContextFlags
= CONTEXT_FULL
;
96 /* Save FPU State if requsted */
97 if (dwFlags
& FIBER_FLAG_FLOAT_SWITCH
)
99 pfCurFiber
->Context
.ContextFlags
|= CONTEXT_FLOATING_POINT
;
102 /* associate the fiber to the current thread */
103 pTeb
->Tib
.FiberData
= pfCurFiber
;
104 pTeb
->HasFiberData
= TRUE
;
107 return (LPVOID
)pfCurFiber
;
115 ConvertThreadToFiber(LPVOID lpParameter
)
117 /* Call the newer function */
118 return ConvertThreadToFiberEx(lpParameter
, 0);
126 CreateFiber(SIZE_T dwStackSize
,
127 LPFIBER_START_ROUTINE lpStartAddress
,
130 /* Call the Newer Function */
131 return CreateFiberEx(dwStackSize
, 0, 0, lpStartAddress
, lpParameter
);
139 CreateFiberEx(SIZE_T dwStackCommitSize
,
140 SIZE_T dwStackReserveSize
,
142 LPFIBER_START_ROUTINE lpStartAddress
,
147 INITIAL_TEB usFiberInitialTeb
;
148 CONTEXT ctxFiberContext
;
149 PVOID ActivationContextStack
= NULL
;
150 DPRINT1("Creating Fiber\n");
152 #ifdef SXS_SUPPORT_ENABLED
153 /* Allocate the Activation Context Stack */
154 nErrCode
= RtlAllocateActivationContextStack(&ActivationContextStack
);
157 /* Allocate the fiber */
158 pfCurFiber
= (PFIBER
)RtlAllocateHeap(GetProcessHeap(),
162 if(pfCurFiber
== NULL
)
164 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
168 /* Create the stack for the fiber */
169 nErrCode
= BasepCreateStack(NtCurrentProcess(),
174 if(!NT_SUCCESS(nErrCode
))
177 RtlFreeHeap(GetProcessHeap(), 0, pfCurFiber
);
180 SetLastErrorByStatus(nErrCode
);
184 /* Clear the context */
185 RtlZeroMemory(&pfCurFiber
->Context
, sizeof(CONTEXT
));
187 /* copy the data into the fiber */
188 pfCurFiber
->StackBase
= usFiberInitialTeb
.StackBase
;
189 pfCurFiber
->StackLimit
= usFiberInitialTeb
.StackLimit
;
190 pfCurFiber
->DeallocationStack
= usFiberInitialTeb
.AllocatedStackBase
;
191 pfCurFiber
->Parameter
= lpParameter
;
192 pfCurFiber
->ExceptionList
= (struct _EXCEPTION_REGISTRATION_RECORD
*)-1;
193 pfCurFiber
->GuaranteedStackBytes
= 0;
194 pfCurFiber
->FlsData
= NULL
;
195 pfCurFiber
->ActivationContextStack
= ActivationContextStack
;
196 pfCurFiber
->Context
.ContextFlags
= CONTEXT_FULL
;
198 /* Save FPU State if requsted */
199 if (dwFlags
& FIBER_FLAG_FLOAT_SWITCH
)
201 pfCurFiber
->Context
.ContextFlags
|= CONTEXT_FLOATING_POINT
;
204 /* initialize the context for the fiber */
205 BasepInitializeContext(&ctxFiberContext
,
208 usFiberInitialTeb
.StackBase
,
211 /* Return the Fiber */
220 DeleteFiber(LPVOID lpFiber
)
223 PVOID pStackAllocBase
= ((PFIBER
)lpFiber
)->DeallocationStack
;
226 RtlFreeHeap(GetProcessHeap(), 0, lpFiber
);
228 /* the fiber is deleting itself: let the system deallocate the stack */
229 if(NtCurrentTeb()->Tib
.FiberData
== lpFiber
) ExitThread(1);
231 /* deallocate the stack */
232 NtFreeVirtualMemory(NtCurrentProcess(),
245 return NtCurrentTeb()->HasFiberData
;
252 BaseFiberStartup(VOID
)
254 PFIBER Fiber
= GetFiberData();
256 /* Call the Thread Startup Routine */
257 DPRINT1("Starting Fiber\n");
258 BaseThreadStartup((LPTHREAD_START_ROUTINE
)Fiber
->Context
.Eax
,
259 (LPVOID
)Fiber
->Context
.Ebx
);