Partial patch of larger rosrtl removal patch. This one merely is a structure fix...
[reactos.git] / reactos / lib / kernel32 / thread / fiber.c
1 /* $Id$
2 *
3 * FILE: lib/kernel32/thread/fiber.c
4 *
5 * ReactOS Kernel32.dll
6 *
7 */
8 #include <k32.h>
9
10 /* FIXME */
11 #include <rosrtl/thread.h>
12
13 #define NDEBUG
14 #include "../include/debug.h"
15
16 struct _FIBER /* Field offsets: */
17 { /* 32 bit 64 bit */
18 /* this must be the first field */
19 LPVOID Parameter; /* 0x00 0x00 */
20
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 */
26 #if defined(_M_IX86)
27 /* control flow registers */
28 DWORD Eip; /* 0x18 ---- */
29 DWORD Esp; /* 0x1C ---- */
30 DWORD Ebp; /* 0x20 ---- */
31
32 /* general-purpose registers that must be preserved across calls */
33 DWORD Ebx; /* 0x24 ---- */
34 DWORD Esi; /* 0x28 ---- */
35 DWORD Edi; /* 0x2C ---- */
36
37 /* floating point save area (optional) */
38 FLOATING_SAVE_AREA FloatSave; /* 0x30 ---- */
39 #else
40 #error Unspecified or unsupported architecture.
41 #endif
42 };
43
44 typedef struct _FIBER FIBER, * PFIBER;
45
46 __declspec(noreturn) void WINAPI FiberStartup(PVOID lpStartAddress);
47
48 /*
49 * @implemented
50 */
51 BOOL WINAPI ConvertFiberToThread(void)
52 {
53 PTEB pTeb = NtCurrentTeb();
54
55 /* the current thread isn't running a fiber: failure */
56 if(!pTeb->HasFiberData)
57 {
58 SetLastError(ERROR_INVALID_PARAMETER);
59 return FALSE;
60 }
61
62 /* this thread won't run a fiber anymore */
63 pTeb->HasFiberData = FALSE;
64
65 /* free the fiber */
66 if(pTeb->Tib.FiberData != NULL)
67 RtlFreeHeap(pTeb->ProcessEnvironmentBlock->ProcessHeap, 0, pTeb->Tib.FiberData);
68
69 /* success */
70 return TRUE;
71 }
72
73
74 /*
75 * @implemented
76 */
77 LPVOID WINAPI ConvertThreadToFiberEx(LPVOID lpParameter, DWORD dwFlags)
78 {
79 PTEB pTeb = NtCurrentTeb();
80 PFIBER pfCurFiber;
81
82 /* the current thread is already a fiber */
83 if(pTeb->HasFiberData && pTeb->Tib.FiberData) return pTeb->Tib.FiberData;
84
85 /* allocate the fiber */
86 pfCurFiber = (PFIBER)RtlAllocateHeap(pTeb->ProcessEnvironmentBlock->ProcessHeap, 0, sizeof(FIBER));
87
88 /* failure */
89 if(pfCurFiber == NULL)
90 {
91 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
92 return NULL;
93 }
94
95 pfCurFiber->Parameter = lpParameter;
96 pfCurFiber->Flags = dwFlags;
97
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;
103
104 /* associate the fiber to the current thread */
105 pTeb->Tib.FiberData = pfCurFiber;
106 pTeb->HasFiberData = TRUE;
107
108 /* success */
109 return (LPVOID)pfCurFiber;
110 }
111
112
113 /*
114 * @implemented
115 */
116 LPVOID WINAPI ConvertThreadToFiber(LPVOID lpParameter)
117 {
118 return ConvertThreadToFiberEx(lpParameter, 0);
119 }
120
121
122 /*
123 * @implemented
124 */
125 LPVOID WINAPI CreateFiber
126 (
127 SIZE_T dwStackSize,
128 LPFIBER_START_ROUTINE lpStartAddress,
129 LPVOID lpParameter
130 )
131 {
132 return CreateFiberEx(dwStackSize, 0, 0, lpStartAddress, lpParameter);
133 }
134
135
136 /*
137 * @implemented
138 */
139 LPVOID WINAPI CreateFiberEx
140 (
141 SIZE_T dwStackCommitSize,
142 SIZE_T dwStackReserveSize,
143 DWORD dwFlags,
144 LPFIBER_START_ROUTINE lpStartAddress,
145 LPVOID lpParameter
146 )
147 {
148 PFIBER pfCurFiber;
149 NTSTATUS nErrCode;
150 PSIZE_T pnStackReserve = NULL;
151 PSIZE_T pnStackCommit = NULL;
152 INITIAL_TEB usFiberInitialTeb;
153 CONTEXT ctxFiberContext;
154 PTEB pTeb = NtCurrentTeb();
155
156 /* allocate the fiber */
157 pfCurFiber = (PFIBER)RtlAllocateHeap(pTeb->ProcessEnvironmentBlock->ProcessHeap, 0, sizeof(FIBER));
158
159 /* failure */
160 if(pfCurFiber == NULL)
161 {
162 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
163 return NULL;
164 }
165
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;
169
170 /* create the stack for the fiber */
171 nErrCode = RtlRosCreateStack
172 (
173 NtCurrentProcess(),
174 &usFiberInitialTeb,
175 0,
176 pnStackReserve,
177 pnStackCommit
178 );
179
180 /* failure */
181 if(!NT_SUCCESS(nErrCode)) goto l_CleanupFiber;
182
183 /* initialize the context for the fiber */
184 nErrCode = RtlRosInitializeContext
185 (
186 NtCurrentProcess(),
187 &ctxFiberContext,
188 FiberStartup,
189 &usFiberInitialTeb,
190 1,
191 (ULONG_PTR *)&lpStartAddress
192 );
193
194 /* failure */
195 if(!NT_SUCCESS(nErrCode)) goto l_CleanupStack;
196
197 /* copy the data into the fiber */
198
199 /* fixed-size stack */
200 if(usFiberInitialTeb.PreviousStackBase && usFiberInitialTeb.PreviousStackLimit)
201 {
202 pfCurFiber->StackBase = usFiberInitialTeb.PreviousStackBase;
203 pfCurFiber->StackLimit = usFiberInitialTeb.PreviousStackLimit;
204 pfCurFiber->DeallocationStack = usFiberInitialTeb.PreviousStackLimit;
205 }
206 /* expandable stack */
207 else if
208 (
209 usFiberInitialTeb.StackBase &&
210 usFiberInitialTeb.StackLimit &&
211 usFiberInitialTeb.AllocatedStackBase
212 )
213 {
214 pfCurFiber->StackBase = usFiberInitialTeb.StackBase;
215 pfCurFiber->StackLimit = usFiberInitialTeb.StackLimit;
216 pfCurFiber->DeallocationStack = usFiberInitialTeb.AllocatedStackBase;
217 }
218 /* bad initial stack */
219 else goto l_CleanupStack;
220
221 pfCurFiber->Parameter = lpParameter;
222 pfCurFiber->Flags = dwFlags;
223 pfCurFiber->ExceptionList = (struct _EXCEPTION_REGISTRATION_RECORD *)-1;
224
225 #if defined(_M_IX86)
226
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;
233
234 if(dwFlags & FIBER_FLAG_FLOAT_SWITCH)
235 pfCurFiber->FloatSave = ctxFiberContext.FloatSave;
236
237 #else
238 #error Unspecified or unsupported architecture.
239 #endif
240
241 return pfCurFiber;
242
243 l_CleanupStack:
244 /* free the stack */
245 RtlRosDeleteStack(NtCurrentProcess(), &usFiberInitialTeb);
246
247 l_CleanupFiber:
248 /* free the fiber */
249 RtlFreeHeap(pTeb->ProcessEnvironmentBlock->ProcessHeap, 0, pfCurFiber);
250
251 /* failure */
252 ASSERT(!NT_SUCCESS(nErrCode));
253 SetLastErrorByStatus(nErrCode);
254 return NULL;
255 }
256
257
258 /*
259 * @implemented
260 */
261 void WINAPI DeleteFiber(LPVOID lpFiber)
262 {
263 SIZE_T nSize = 0;
264 PVOID pStackAllocBase = ((PFIBER)lpFiber)->DeallocationStack;
265 PTEB pTeb = NtCurrentTeb();
266
267 /* free the fiber */
268 RtlFreeHeap(pTeb->ProcessEnvironmentBlock->ProcessHeap, 0, lpFiber);
269
270 /* the fiber is deleting itself: let the system deallocate the stack */
271 if(pTeb->Tib.FiberData == lpFiber) ExitThread(1);
272
273 /* deallocate the stack */
274 NtFreeVirtualMemory
275 (
276 NtCurrentProcess(),
277 &pStackAllocBase,
278 &nSize,
279 MEM_RELEASE
280 );
281 }
282
283
284 __declspec(noreturn) extern void WINAPI ThreadStartup
285 (
286 LPTHREAD_START_ROUTINE lpStartAddress,
287 LPVOID lpParameter
288 );
289
290
291 __declspec(noreturn) void WINAPI FiberStartup(PVOID lpStartAddress)
292 {
293 /* FIXME? this should be pretty accurate */
294 ThreadStartup(lpStartAddress, GetFiberData());
295 }
296
297 /* EOF */