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);
74 LPVOID WINAPI ConvertThreadToFiber(LPVOID lpParameter)
76 return ConvertThreadToFiberEx(lpParameter, 0);
83 LPVOID WINAPI ConvertThreadToFiberEx(LPVOID lpParameter, DWORD dwFlags)
85 PTEB pTeb = NtCurrentTeb();
88 /* the current thread is already a fiber */
89 if(pTeb->IsFiber && pTeb->Tib.Fib.FiberData) return pTeb->Tib.Fib.FiberData;
91 /* allocate the fiber */
92 pfCurFiber = (PFIBER)RtlAllocateHeap(pTeb->Peb->ProcessHeap, 0, sizeof(FIBER));
95 if(pfCurFiber == NULL)
97 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
101 pfCurFiber->Parameter = lpParameter;
102 pfCurFiber->Flags = dwFlags;
104 /* copy some contextual data from the thread to the fiber */
105 pfCurFiber->ExceptionList = pTeb->Tib.ExceptionList;
106 pfCurFiber->StackBase = pTeb->Tib.StackBase;
107 pfCurFiber->StackLimit = pTeb->Tib.StackLimit;
108 pfCurFiber->DeallocationStack = pTeb->DeallocationStack;
110 /* associate the fiber to the current thread */
111 pTeb->Tib.Fib.FiberData = pfCurFiber;
112 pTeb->IsFiber = TRUE;
115 return (LPVOID)pfCurFiber;
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 USER_STACK usFiberStack;
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(usFiberStack.FixedStackBase && usFiberStack.FixedStackLimit)
199 pfCurFiber->StackBase = usFiberStack.FixedStackBase;
200 pfCurFiber->StackLimit = usFiberStack.FixedStackLimit;
201 pfCurFiber->DeallocationStack = usFiberStack.FixedStackLimit;
203 /* expandable stack */
206 usFiberStack.ExpandableStackBase &&
207 usFiberStack.ExpandableStackLimit &&
208 usFiberStack.ExpandableStackBottom
211 pfCurFiber->StackBase = usFiberStack.ExpandableStackBase;
212 pfCurFiber->StackLimit = usFiberStack.ExpandableStackLimit;
213 pfCurFiber->DeallocationStack = usFiberStack.ExpandableStackBottom;
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(), &usFiberStack);
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.Fib.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, NtCurrentTeb()->Tib.Fib.FiberData);