1 /* $Id: fiber.c,v 1.7 2003/07/22 20:10:04 hyperion Exp $
3 * FILE: lib/kernel32/thread/fiber.c
11 #include <kernel32/kernel32.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
.Fib
.FiberData
!= NULL
)
64 RtlFreeHeap(pTeb
->Peb
->ProcessHeap
, 0, pTeb
->Tib
.Fib
.FiberData
);
73 LPVOID WINAPI
ConvertThreadToFiber(LPVOID lpParameter
)
75 return ConvertThreadToFiberEx(lpParameter
, 0);
82 LPVOID WINAPI
ConvertThreadToFiberEx(LPVOID lpParameter
, DWORD dwFlags
)
84 PTEB pTeb
= NtCurrentTeb();
87 /* the current thread is already a fiber */
88 if(pTeb
->IsFiber
&& pTeb
->Tib
.Fib
.FiberData
) return pTeb
->Tib
.Fib
.FiberData
;
90 /* allocate the fiber */
91 pfCurFiber
= (PFIBER
)RtlAllocateHeap(pTeb
->Peb
->ProcessHeap
, 0, sizeof(FIBER
));
94 if(pfCurFiber
== NULL
)
96 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
100 pfCurFiber
->Parameter
= lpParameter
;
101 pfCurFiber
->Flags
= dwFlags
;
103 /* copy some contextual data from the thread to the fiber */
104 pfCurFiber
->ExceptionList
= pTeb
->Tib
.ExceptionList
;
105 pfCurFiber
->StackBase
= pTeb
->Tib
.StackBase
;
106 pfCurFiber
->StackLimit
= pTeb
->Tib
.StackLimit
;
107 pfCurFiber
->DeallocationStack
= pTeb
->DeallocationStack
;
109 /* associate the fiber to the current thread */
110 pTeb
->Tib
.Fib
.FiberData
= pfCurFiber
;
111 pTeb
->IsFiber
= TRUE
;
114 return (LPVOID
)pfCurFiber
;
121 LPVOID WINAPI CreateFiber
124 LPFIBER_START_ROUTINE lpStartAddress
,
128 return CreateFiberEx(dwStackSize
, 0, 0, lpStartAddress
, lpParameter
);
135 LPVOID WINAPI CreateFiberEx
137 SIZE_T dwStackCommitSize
,
138 SIZE_T dwStackReserveSize
,
140 LPFIBER_START_ROUTINE lpStartAddress
,
146 PSIZE_T pnStackReserve
= NULL
;
147 PSIZE_T pnStackCommit
= NULL
;
148 USER_STACK usFiberStack
;
149 CONTEXT ctxFiberContext
;
152 PTEB pTeb
= NtCurrentTeb();
154 /* allocate the fiber */
155 pfCurFiber
= (PFIBER
)RtlAllocateHeap(pTeb
->Peb
->ProcessHeap
, 0, sizeof(FIBER
));
158 if(pfCurFiber
== NULL
)
160 SetLastError(ERROR_NOT_ENOUGH_MEMORY
);
164 /* if the stack reserve or commit size weren't specified, use defaults */
165 if(dwStackReserveSize
> 0) pnStackReserve
= &dwStackReserveSize
;
166 if(dwStackCommitSize
> 0) pnStackCommit
= &dwStackCommitSize
;
168 /* create the stack for the fiber */
169 nErrCode
= RtlRosCreateStack
179 if(!NT_SUCCESS(nErrCode
)) goto l_CleanupFiber
;
181 /* initialize the context for the fiber */
182 nErrCode
= RtlRosInitializeContext
189 (ULONG_PTR
*)&lpStartAddress
193 if(!NT_SUCCESS(nErrCode
)) goto l_CleanupStack
;
195 /* copy the data into the fiber */
197 /* fixed-size stack */
198 if(usFiberStack
.FixedStackBase
&& usFiberStack
.FixedStackLimit
)
200 pfCurFiber
->StackBase
= usFiberStack
.FixedStackBase
;
201 pfCurFiber
->StackLimit
= usFiberStack
.FixedStackLimit
;
202 pfCurFiber
->DeallocationStack
= usFiberStack
.FixedStackLimit
;
204 /* expandable stack */
207 usFiberStack
.ExpandableStackBase
&&
208 usFiberStack
.ExpandableStackLimit
&&
209 usFiberStack
.ExpandableStackBottom
212 pfCurFiber
->StackBase
= usFiberStack
.ExpandableStackBase
;
213 pfCurFiber
->StackLimit
= usFiberStack
.ExpandableStackLimit
;
214 pfCurFiber
->DeallocationStack
= usFiberStack
.ExpandableStackBottom
;
216 /* bad initial stack */
217 else goto l_CleanupStack
;
219 pfCurFiber
->Parameter
= lpParameter
;
220 pfCurFiber
->Flags
= dwFlags
;
221 pfCurFiber
->ExceptionList
= (struct _EXCEPTION_REGISTRATION_RECORD
*)-1;
225 pfCurFiber
->Eip
= ctxFiberContext
.Eip
;
226 pfCurFiber
->Esp
= ctxFiberContext
.Esp
;
227 pfCurFiber
->Ebp
= ctxFiberContext
.Ebp
;
228 pfCurFiber
->Ebx
= ctxFiberContext
.Ebx
;
229 pfCurFiber
->Esi
= ctxFiberContext
.Esi
;
230 pfCurFiber
->Edi
= ctxFiberContext
.Edi
;
232 if(dwFlags
& FIBER_FLAG_FLOAT_SWITCH
)
233 pfCurFiber
->FloatSave
= ctxFiberContext
.FloatSave
;
236 #error Unspecified or unsupported architecture.
243 RtlRosDeleteStack(NtCurrentProcess(), &usFiberStack
);
247 RtlFreeHeap(pTeb
->Peb
->ProcessHeap
, 0, pfCurFiber
);
250 assert(!NT_SUCCESS(nErrCode
));
251 SetLastErrorByStatus(nErrCode
);
259 void WINAPI
DeleteFiber(LPVOID lpFiber
)
262 PVOID pStackAllocBase
= ((PFIBER
)lpFiber
)->DeallocationStack
;
263 PTEB pTeb
= NtCurrentTeb();
266 RtlFreeHeap(pTeb
->Peb
->ProcessHeap
, 0, lpFiber
);
268 /* the fiber is deleting itself: let the system deallocate the stack */
269 if(pTeb
->Tib
.Fib
.FiberData
== lpFiber
) ExitThread(1);
271 /* deallocate the stack */
282 __declspec(noreturn
) extern void WINAPI ThreadStartup
284 LPTHREAD_START_ROUTINE lpStartAddress
,
289 __declspec(noreturn
) void WINAPI
FiberStartup(PVOID lpStartAddress
)
291 /* FIXME? this should be pretty accurate */
292 ThreadStartup(lpStartAddress
, NtCurrentTeb()->Tib
.Fib
.FiberData
);