3 * FILE: lib/kernel32/thread/fiber.c
11 #include "../include/debug.h"
13 struct _FIBER
/* Field offsets: */
15 /* this must be the first field */
16 LPVOID Parameter
; /* 0x00 0x00 */
18 struct _EXCEPTION_REGISTRATION_RECORD
* ExceptionList
; /* 0x04 0x08 */
19 LPVOID StackBase
; /* 0x08 0x10 */
20 LPVOID StackLimit
; /* 0x0C 0x18 */
21 LPVOID DeallocationStack
; /* 0x10 0x20 */
22 ULONG_PTR Flags
; /* 0x14 0x28 */
24 /* control flow registers */
25 DWORD Eip
; /* 0x18 ---- */
26 DWORD Esp
; /* 0x1C ---- */
27 DWORD Ebp
; /* 0x20 ---- */
29 /* general-purpose registers that must be preserved across calls */
30 DWORD Ebx
; /* 0x24 ---- */
31 DWORD Esi
; /* 0x28 ---- */
32 DWORD Edi
; /* 0x2C ---- */
34 /* floating point save area (optional) */
35 FLOATING_SAVE_AREA FloatSave
; /* 0x30 ---- */
37 #error Unspecified or unsupported architecture.
41 typedef struct _FIBER FIBER
, * PFIBER
;
43 __declspec(noreturn
) void WINAPI
FiberStartup(PVOID lpStartAddress
);
48 BOOL WINAPI
ConvertFiberToThread(void)
50 PTEB pTeb
= NtCurrentTeb();
52 /* the current thread isn't running a fiber: failure */
55 SetLastError(ERROR_INVALID_PARAMETER
);
59 /* this thread won't run a fiber anymore */
60 pTeb
->IsFiber
= FALSE
;
63 if(pTeb
->Tib
.FiberData
!= NULL
)
64 RtlFreeHeap(pTeb
->Peb
->ProcessHeap
, 0, pTeb
->Tib
.FiberData
);
74 LPVOID WINAPI
ConvertThreadToFiberEx(LPVOID lpParameter
, DWORD dwFlags
)
76 PTEB pTeb
= NtCurrentTeb();
79 /* the current thread is already a fiber */
80 if(pTeb
->IsFiber
&& pTeb
->Tib
.FiberData
) return pTeb
->Tib
.FiberData
;
82 /* allocate the fiber */
83 pfCurFiber
= (PFIBER
)RtlAllocateHeap(pTeb
->Peb
->ProcessHeap
, 0, sizeof(FIBER
));
86 if(pfCurFiber
== NULL
)
88 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
92 pfCurFiber
->Parameter
= lpParameter
;
93 pfCurFiber
->Flags
= dwFlags
;
95 /* copy some contextual data from the thread to the fiber */
96 pfCurFiber
->ExceptionList
= pTeb
->Tib
.ExceptionList
;
97 pfCurFiber
->StackBase
= pTeb
->Tib
.StackBase
;
98 pfCurFiber
->StackLimit
= pTeb
->Tib
.StackLimit
;
99 pfCurFiber
->DeallocationStack
= pTeb
->DeallocationStack
;
101 /* associate the fiber to the current thread */
102 pTeb
->Tib
.FiberData
= pfCurFiber
;
103 pTeb
->IsFiber
= TRUE
;
106 return (LPVOID
)pfCurFiber
;
113 LPVOID WINAPI
ConvertThreadToFiber(LPVOID lpParameter
)
115 return ConvertThreadToFiberEx(lpParameter
, 0);
122 LPVOID WINAPI CreateFiber
125 LPFIBER_START_ROUTINE lpStartAddress
,
129 return CreateFiberEx(dwStackSize
, 0, 0, lpStartAddress
, lpParameter
);
136 LPVOID WINAPI CreateFiberEx
138 SIZE_T dwStackCommitSize
,
139 SIZE_T dwStackReserveSize
,
141 LPFIBER_START_ROUTINE lpStartAddress
,
147 PSIZE_T pnStackReserve
= NULL
;
148 PSIZE_T pnStackCommit
= NULL
;
149 INITIAL_TEB usFiberInitialTeb
;
150 CONTEXT ctxFiberContext
;
151 PTEB pTeb
= NtCurrentTeb();
153 /* allocate the fiber */
154 pfCurFiber
= (PFIBER
)RtlAllocateHeap(pTeb
->Peb
->ProcessHeap
, 0, sizeof(FIBER
));
157 if(pfCurFiber
== NULL
)
159 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
163 /* if the stack reserve or commit size weren't specified, use defaults */
164 if(dwStackReserveSize
> 0) pnStackReserve
= &dwStackReserveSize
;
165 if(dwStackCommitSize
> 0) pnStackCommit
= &dwStackCommitSize
;
167 /* create the stack for the fiber */
168 nErrCode
= RtlRosCreateStack
178 if(!NT_SUCCESS(nErrCode
)) goto l_CleanupFiber
;
180 /* initialize the context for the fiber */
181 nErrCode
= RtlRosInitializeContext
188 (ULONG_PTR
*)&lpStartAddress
192 if(!NT_SUCCESS(nErrCode
)) goto l_CleanupStack
;
194 /* copy the data into the fiber */
196 /* fixed-size stack */
197 if(usFiberInitialTeb
.StackBase
&& usFiberInitialTeb
.StackLimit
)
199 pfCurFiber
->StackBase
= usFiberInitialTeb
.StackBase
;
200 pfCurFiber
->StackLimit
= usFiberInitialTeb
.StackLimit
;
201 pfCurFiber
->DeallocationStack
= usFiberInitialTeb
.StackLimit
;
203 /* expandable stack */
206 usFiberInitialTeb
.StackCommit
&&
207 usFiberInitialTeb
.StackCommitMax
&&
208 usFiberInitialTeb
.StackReserved
211 pfCurFiber
->StackBase
= usFiberInitialTeb
.StackCommit
;
212 pfCurFiber
->StackLimit
= usFiberInitialTeb
.StackCommitMax
;
213 pfCurFiber
->DeallocationStack
= usFiberInitialTeb
.StackReserved
;
215 /* bad initial stack */
216 else goto l_CleanupStack
;
218 pfCurFiber
->Parameter
= lpParameter
;
219 pfCurFiber
->Flags
= dwFlags
;
220 pfCurFiber
->ExceptionList
= (struct _EXCEPTION_REGISTRATION_RECORD
*)-1;
224 pfCurFiber
->Eip
= ctxFiberContext
.Eip
;
225 pfCurFiber
->Esp
= ctxFiberContext
.Esp
;
226 pfCurFiber
->Ebp
= ctxFiberContext
.Ebp
;
227 pfCurFiber
->Ebx
= ctxFiberContext
.Ebx
;
228 pfCurFiber
->Esi
= ctxFiberContext
.Esi
;
229 pfCurFiber
->Edi
= ctxFiberContext
.Edi
;
231 if(dwFlags
& FIBER_FLAG_FLOAT_SWITCH
)
232 pfCurFiber
->FloatSave
= ctxFiberContext
.FloatSave
;
235 #error Unspecified or unsupported architecture.
242 RtlRosDeleteStack(NtCurrentProcess(), &usFiberInitialTeb
);
246 RtlFreeHeap(pTeb
->Peb
->ProcessHeap
, 0, pfCurFiber
);
249 ASSERT(!NT_SUCCESS(nErrCode
));
250 SetLastErrorByStatus(nErrCode
);
258 void WINAPI
DeleteFiber(LPVOID lpFiber
)
261 PVOID pStackAllocBase
= ((PFIBER
)lpFiber
)->DeallocationStack
;
262 PTEB pTeb
= NtCurrentTeb();
265 RtlFreeHeap(pTeb
->Peb
->ProcessHeap
, 0, lpFiber
);
267 /* the fiber is deleting itself: let the system deallocate the stack */
268 if(pTeb
->Tib
.FiberData
== lpFiber
) ExitThread(1);
270 /* deallocate the stack */
281 __declspec(noreturn
) extern void WINAPI ThreadStartup
283 LPTHREAD_START_ROUTINE lpStartAddress
,
288 __declspec(noreturn
) void WINAPI
FiberStartup(PVOID lpStartAddress
)
290 /* FIXME? this should be pretty accurate */
291 ThreadStartup(lpStartAddress
, GetFiberData());