3 * FILE: lib/kernel32/thread/fiber.c
11 #include <rosrtl/thread.h>
14 #include "../include/debug.h"
16 struct _FIBER
/* Field offsets: */
18 /* this must be the first field */
19 LPVOID Parameter
; /* 0x00 0x00 */
21 struct _EXCEPTION_REGISTRATION_RECORD
* ExceptionList
; /* 0x04 0x08 */
22 LPVOID StackBase
; /* 0x08 0x10 */
23 LPVOID StackLimit
; /* 0x0C 0x18 */
24 LPVOID DeallocationStack
; /* 0x10 0x20 */
25 ULONG_PTR Flags
; /* 0x14 0x28 */
27 /* control flow registers */
28 DWORD Eip
; /* 0x18 ---- */
29 DWORD Esp
; /* 0x1C ---- */
30 DWORD Ebp
; /* 0x20 ---- */
32 /* general-purpose registers that must be preserved across calls */
33 DWORD Ebx
; /* 0x24 ---- */
34 DWORD Esi
; /* 0x28 ---- */
35 DWORD Edi
; /* 0x2C ---- */
37 /* floating point save area (optional) */
38 FLOATING_SAVE_AREA FloatSave
; /* 0x30 ---- */
40 #error Unspecified or unsupported architecture.
44 typedef struct _FIBER FIBER
, * PFIBER
;
46 __declspec(noreturn
) void WINAPI
FiberStartup(PVOID lpStartAddress
);
51 BOOL WINAPI
ConvertFiberToThread(void)
53 PTEB pTeb
= NtCurrentTeb();
55 /* the current thread isn't running a fiber: failure */
56 if(!pTeb
->HasFiberData
)
58 SetLastError(ERROR_INVALID_PARAMETER
);
62 /* this thread won't run a fiber anymore */
63 pTeb
->HasFiberData
= FALSE
;
66 if(pTeb
->Tib
.FiberData
!= NULL
)
67 RtlFreeHeap(pTeb
->ProcessEnvironmentBlock
->ProcessHeap
, 0, pTeb
->Tib
.FiberData
);
77 LPVOID WINAPI
ConvertThreadToFiberEx(LPVOID lpParameter
, DWORD dwFlags
)
79 PTEB pTeb
= NtCurrentTeb();
82 /* the current thread is already a fiber */
83 if(pTeb
->HasFiberData
&& pTeb
->Tib
.FiberData
) return pTeb
->Tib
.FiberData
;
85 /* allocate the fiber */
86 pfCurFiber
= (PFIBER
)RtlAllocateHeap(pTeb
->ProcessEnvironmentBlock
->ProcessHeap
, 0, sizeof(FIBER
));
89 if(pfCurFiber
== NULL
)
91 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
95 pfCurFiber
->Parameter
= lpParameter
;
96 pfCurFiber
->Flags
= dwFlags
;
98 /* copy some contextual data from the thread to the fiber */
99 pfCurFiber
->ExceptionList
= pTeb
->Tib
.ExceptionList
;
100 pfCurFiber
->StackBase
= pTeb
->Tib
.StackBase
;
101 pfCurFiber
->StackLimit
= pTeb
->Tib
.StackLimit
;
102 pfCurFiber
->DeallocationStack
= pTeb
->DeallocationStack
;
104 /* associate the fiber to the current thread */
105 pTeb
->Tib
.FiberData
= pfCurFiber
;
106 pTeb
->HasFiberData
= TRUE
;
109 return (LPVOID
)pfCurFiber
;
116 LPVOID WINAPI
ConvertThreadToFiber(LPVOID lpParameter
)
118 return ConvertThreadToFiberEx(lpParameter
, 0);
125 LPVOID WINAPI CreateFiber
128 LPFIBER_START_ROUTINE lpStartAddress
,
132 return CreateFiberEx(dwStackSize
, 0, 0, lpStartAddress
, lpParameter
);
139 LPVOID WINAPI CreateFiberEx
141 SIZE_T dwStackCommitSize
,
142 SIZE_T dwStackReserveSize
,
144 LPFIBER_START_ROUTINE lpStartAddress
,
150 PSIZE_T pnStackReserve
= NULL
;
151 PSIZE_T pnStackCommit
= NULL
;
152 INITIAL_TEB usFiberInitialTeb
;
153 CONTEXT ctxFiberContext
;
154 PTEB pTeb
= NtCurrentTeb();
156 /* allocate the fiber */
157 pfCurFiber
= (PFIBER
)RtlAllocateHeap(pTeb
->ProcessEnvironmentBlock
->ProcessHeap
, 0, sizeof(FIBER
));
160 if(pfCurFiber
== NULL
)
162 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
166 /* if the stack reserve or commit size weren't specified, use defaults */
167 if(dwStackReserveSize
> 0) pnStackReserve
= &dwStackReserveSize
;
168 if(dwStackCommitSize
> 0) pnStackCommit
= &dwStackCommitSize
;
170 /* create the stack for the fiber */
171 nErrCode
= RtlRosCreateStack
181 if(!NT_SUCCESS(nErrCode
)) goto l_CleanupFiber
;
183 /* initialize the context for the fiber */
184 nErrCode
= RtlRosInitializeContext
191 (ULONG_PTR
*)&lpStartAddress
195 if(!NT_SUCCESS(nErrCode
)) goto l_CleanupStack
;
197 /* copy the data into the fiber */
199 /* fixed-size stack */
200 if(usFiberInitialTeb
.PreviousStackBase
&& usFiberInitialTeb
.PreviousStackLimit
)
202 pfCurFiber
->StackBase
= usFiberInitialTeb
.PreviousStackBase
;
203 pfCurFiber
->StackLimit
= usFiberInitialTeb
.PreviousStackLimit
;
204 pfCurFiber
->DeallocationStack
= usFiberInitialTeb
.PreviousStackLimit
;
206 /* expandable stack */
209 usFiberInitialTeb
.StackBase
&&
210 usFiberInitialTeb
.StackLimit
&&
211 usFiberInitialTeb
.AllocatedStackBase
214 pfCurFiber
->StackBase
= usFiberInitialTeb
.StackBase
;
215 pfCurFiber
->StackLimit
= usFiberInitialTeb
.StackLimit
;
216 pfCurFiber
->DeallocationStack
= usFiberInitialTeb
.AllocatedStackBase
;
218 /* bad initial stack */
219 else goto l_CleanupStack
;
221 pfCurFiber
->Parameter
= lpParameter
;
222 pfCurFiber
->Flags
= dwFlags
;
223 pfCurFiber
->ExceptionList
= (struct _EXCEPTION_REGISTRATION_RECORD
*)-1;
227 pfCurFiber
->Eip
= ctxFiberContext
.Eip
;
228 pfCurFiber
->Esp
= ctxFiberContext
.Esp
;
229 pfCurFiber
->Ebp
= ctxFiberContext
.Ebp
;
230 pfCurFiber
->Ebx
= ctxFiberContext
.Ebx
;
231 pfCurFiber
->Esi
= ctxFiberContext
.Esi
;
232 pfCurFiber
->Edi
= ctxFiberContext
.Edi
;
234 if(dwFlags
& FIBER_FLAG_FLOAT_SWITCH
)
235 pfCurFiber
->FloatSave
= ctxFiberContext
.FloatSave
;
238 #error Unspecified or unsupported architecture.
245 RtlRosDeleteStack(NtCurrentProcess(), &usFiberInitialTeb
);
249 RtlFreeHeap(pTeb
->ProcessEnvironmentBlock
->ProcessHeap
, 0, pfCurFiber
);
252 ASSERT(!NT_SUCCESS(nErrCode
));
253 SetLastErrorByStatus(nErrCode
);
261 void WINAPI
DeleteFiber(LPVOID lpFiber
)
264 PVOID pStackAllocBase
= ((PFIBER
)lpFiber
)->DeallocationStack
;
265 PTEB pTeb
= NtCurrentTeb();
268 RtlFreeHeap(pTeb
->ProcessEnvironmentBlock
->ProcessHeap
, 0, lpFiber
);
270 /* the fiber is deleting itself: let the system deallocate the stack */
271 if(pTeb
->Tib
.FiberData
== lpFiber
) ExitThread(1);
273 /* deallocate the stack */
284 __declspec(noreturn
) extern void WINAPI ThreadStartup
286 LPTHREAD_START_ROUTINE lpStartAddress
,
291 __declspec(noreturn
) void WINAPI
FiberStartup(PVOID lpStartAddress
)
293 /* FIXME? this should be pretty accurate */
294 ThreadStartup(lpStartAddress
, GetFiberData());