reshuffling of dlls
[reactos.git] / reactos / 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 "../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->Tib.FiberData != NULL)
51 {
52 RtlFreeHeap(GetProcessHeap(), 0, pTeb->Tib.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->Tib.FiberData) return pTeb->Tib.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->ExceptionList = pTeb->Tib.ExceptionList;
88 pfCurFiber->StackBase = pTeb->Tib.StackBase;
89 pfCurFiber->StackLimit = pTeb->Tib.StackLimit;
90 pfCurFiber->DeallocationStack = pTeb->DeallocationStack;
91 pfCurFiber->FlsData = pTeb->FlsData;
92 pfCurFiber->GuaranteedStackBytes = pTeb->GuaranteedStackBytes;
93 pfCurFiber->ActivationContextStack = pTeb->ActivationContextStackPointer;
94 pfCurFiber->Context.ContextFlags = CONTEXT_FULL;
95
96 /* Save FPU State if requsted */
97 if (dwFlags & FIBER_FLAG_FLOAT_SWITCH)
98 {
99 pfCurFiber->Context.ContextFlags |= CONTEXT_FLOATING_POINT;
100 }
101
102 /* associate the fiber to the current thread */
103 pTeb->Tib.FiberData = pfCurFiber;
104 pTeb->HasFiberData = TRUE;
105
106 /* success */
107 return (LPVOID)pfCurFiber;
108 }
109
110 /*
111 * @implemented
112 */
113 LPVOID
114 WINAPI
115 ConvertThreadToFiber(LPVOID lpParameter)
116 {
117 /* Call the newer function */
118 return ConvertThreadToFiberEx(lpParameter, 0);
119 }
120
121 /*
122 * @implemented
123 */
124 LPVOID
125 WINAPI
126 CreateFiber(SIZE_T dwStackSize,
127 LPFIBER_START_ROUTINE lpStartAddress,
128 LPVOID lpParameter)
129 {
130 /* Call the Newer Function */
131 return CreateFiberEx(dwStackSize, 0, 0, lpStartAddress, lpParameter);
132 }
133
134 /*
135 * @implemented
136 */
137 LPVOID
138 WINAPI
139 CreateFiberEx(SIZE_T dwStackCommitSize,
140 SIZE_T dwStackReserveSize,
141 DWORD dwFlags,
142 LPFIBER_START_ROUTINE lpStartAddress,
143 LPVOID lpParameter)
144 {
145 PFIBER pfCurFiber;
146 NTSTATUS nErrCode;
147 INITIAL_TEB usFiberInitialTeb;
148 CONTEXT ctxFiberContext;
149 PVOID ActivationContextStack = NULL;
150 DPRINT1("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(&ctxFiberContext,
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()->Tib.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 PFIBER Fiber = GetFiberData();
255
256 /* Call the Thread Startup Routine */
257 DPRINT1("Starting Fiber\n");
258 BaseThreadStartup((LPTHREAD_START_ROUTINE)Fiber->Context.Eax,
259 (LPVOID)Fiber->Context.Ebx);
260 }
261
262 /* EOF */