sync with trunk (r47268)
[reactos.git] / dll / win32 / kernel32 / thread / fiber.c
1 /*
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
6 * PROGRAMMERS:
7 * Alex Ionescu (alex@relsoft.net)
8 * KJK::Hyperion <noog@libero.it>
9 */
10 #include <k32.h>
11
12 #define NDEBUG
13 #include <debug.h>
14
15 typedef struct _FIBER /* Field offsets: */
16 { /* 32 bit 64 bit */
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 */
27 } FIBER, *PFIBER;
28
29 /*
30 * @implemented
31 */
32 BOOL
33 WINAPI
34 ConvertFiberToThread(VOID)
35 {
36 PTEB pTeb = NtCurrentTeb();
37 DPRINT1("Converting Fiber to Thread\n");
38
39 /* the current thread isn't running a fiber: failure */
40 if (!pTeb->HasFiberData)
41 {
42 SetLastError(ERROR_INVALID_PARAMETER);
43 return FALSE;
44 }
45
46 /* this thread won't run a fiber anymore */
47 pTeb->HasFiberData = FALSE;
48
49 /* free the fiber */
50 if(pTeb->NtTib.FiberData != NULL)
51 {
52 RtlFreeHeap(GetProcessHeap(), 0, pTeb->NtTib.FiberData);
53 }
54
55 /* success */
56 return TRUE;
57 }
58
59 /*
60 * @implemented
61 */
62 LPVOID
63 WINAPI
64 ConvertThreadToFiberEx(LPVOID lpParameter,
65 DWORD dwFlags)
66 {
67 PTEB pTeb = NtCurrentTeb();
68 PFIBER pfCurFiber;
69 DPRINT1("Converting Thread to Fiber\n");
70
71 /* the current thread is already a fiber */
72 if(pTeb->HasFiberData && pTeb->NtTib.FiberData) return pTeb->NtTib.FiberData;
73
74 /* allocate the fiber */
75 pfCurFiber = (PFIBER)RtlAllocateHeap(GetProcessHeap(),
76 0,
77 sizeof(FIBER));
78
79 /* failure */
80 if (pfCurFiber == NULL)
81 {
82 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
83 return NULL;
84 }
85
86 /* copy some contextual data from the thread to the fiber */
87 pfCurFiber->Parameter = lpParameter;
88 pfCurFiber->ExceptionList = pTeb->NtTib.ExceptionList;
89 pfCurFiber->StackBase = pTeb->NtTib.StackBase;
90 pfCurFiber->StackLimit = pTeb->NtTib.StackLimit;
91 pfCurFiber->DeallocationStack = pTeb->DeallocationStack;
92 pfCurFiber->FlsData = pTeb->FlsData;
93 pfCurFiber->GuaranteedStackBytes = pTeb->GuaranteedStackBytes;
94 pfCurFiber->ActivationContextStack = pTeb->ActivationContextStackPointer;
95 pfCurFiber->Context.ContextFlags = CONTEXT_FULL;
96
97 /* Save FPU State if requsted */
98 if (dwFlags & FIBER_FLAG_FLOAT_SWITCH)
99 {
100 pfCurFiber->Context.ContextFlags |= CONTEXT_FLOATING_POINT;
101 }
102
103 /* associate the fiber to the current thread */
104 pTeb->NtTib.FiberData = pfCurFiber;
105 pTeb->HasFiberData = TRUE;
106
107 /* success */
108 return (LPVOID)pfCurFiber;
109 }
110
111 /*
112 * @implemented
113 */
114 LPVOID
115 WINAPI
116 ConvertThreadToFiber(LPVOID lpParameter)
117 {
118 /* Call the newer function */
119 return ConvertThreadToFiberEx(lpParameter, 0);
120 }
121
122 /*
123 * @implemented
124 */
125 LPVOID
126 WINAPI
127 CreateFiber(SIZE_T dwStackSize,
128 LPFIBER_START_ROUTINE lpStartAddress,
129 LPVOID lpParameter)
130 {
131 /* Call the Newer Function */
132 return CreateFiberEx(dwStackSize, 0, 0, lpStartAddress, lpParameter);
133 }
134
135 /*
136 * @implemented
137 */
138 LPVOID
139 WINAPI
140 CreateFiberEx(SIZE_T dwStackCommitSize,
141 SIZE_T dwStackReserveSize,
142 DWORD dwFlags,
143 LPFIBER_START_ROUTINE lpStartAddress,
144 LPVOID lpParameter)
145 {
146 PFIBER pfCurFiber;
147 NTSTATUS nErrCode;
148 INITIAL_TEB usFiberInitialTeb;
149 PVOID ActivationContextStack = NULL;
150 DPRINT("Creating Fiber\n");
151
152 #ifdef SXS_SUPPORT_ENABLED
153 /* Allocate the Activation Context Stack */
154 nErrCode = RtlAllocateActivationContextStack(&ActivationContextStack);
155 #endif
156
157 /* Allocate the fiber */
158 pfCurFiber = (PFIBER)RtlAllocateHeap(GetProcessHeap(),
159 0,
160 sizeof(FIBER));
161 /* Failure */
162 if (pfCurFiber == NULL)
163 {
164 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
165 return NULL;
166 }
167
168 /* Create the stack for the fiber */
169 nErrCode = BasepCreateStack(NtCurrentProcess(),
170 dwStackCommitSize,
171 dwStackReserveSize,
172 &usFiberInitialTeb);
173 /* Failure */
174 if(!NT_SUCCESS(nErrCode))
175 {
176 /* Free the fiber */
177 RtlFreeHeap(GetProcessHeap(), 0, pfCurFiber);
178
179 /* Failure */
180 SetLastErrorByStatus(nErrCode);
181 return NULL;
182 }
183
184 /* Clear the context */
185 RtlZeroMemory(&pfCurFiber->Context, sizeof(CONTEXT));
186
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;
197
198 /* Save FPU State if requsted */
199 if (dwFlags & FIBER_FLAG_FLOAT_SWITCH)
200 {
201 pfCurFiber->Context.ContextFlags |= CONTEXT_FLOATING_POINT;
202 }
203
204 /* initialize the context for the fiber */
205 BasepInitializeContext(&pfCurFiber->Context,
206 lpParameter,
207 lpStartAddress,
208 usFiberInitialTeb.StackBase,
209 2);
210
211 /* Return the Fiber */
212 return pfCurFiber;
213 }
214
215 /*
216 * @implemented
217 */
218 VOID
219 WINAPI
220 DeleteFiber(LPVOID lpFiber)
221 {
222 SIZE_T nSize = 0;
223 PVOID pStackAllocBase = ((PFIBER)lpFiber)->DeallocationStack;
224
225 /* free the fiber */
226 RtlFreeHeap(GetProcessHeap(), 0, lpFiber);
227
228 /* the fiber is deleting itself: let the system deallocate the stack */
229 if(NtCurrentTeb()->NtTib.FiberData == lpFiber) ExitThread(1);
230
231 /* deallocate the stack */
232 NtFreeVirtualMemory(NtCurrentProcess(),
233 &pStackAllocBase,
234 &nSize,
235 MEM_RELEASE);
236 }
237
238 /*
239 * @implemented
240 */
241 BOOL
242 WINAPI
243 IsThreadAFiber(VOID)
244 {
245 return NtCurrentTeb()->HasFiberData;
246 }
247
248
249 __declspec(noreturn)
250 VOID
251 WINAPI
252 BaseFiberStartup(VOID)
253 {
254 #ifdef _M_IX86
255 PFIBER Fiber = GetCurrentFiber();
256
257 /* Call the Thread Startup Routine */
258 DPRINT("Starting Fiber\n");
259 BaseThreadStartup((LPTHREAD_START_ROUTINE)Fiber->Context.Eax,
260 (LPVOID)Fiber->Context.Ebx);
261 #else
262 #warning Unknown architecture
263 UNIMPLEMENTED;
264 DbgBreakPoint();
265 #endif
266 }
267
268 /* EOF */