ReactOS 0.4.15-dev-7842-g558ab78
fiber.c
Go to the documentation of this file.
1/*
2 * PROJECT: ReactOS System Libraries
3 * LICENSE: GPL-2.0+ (https://spdx.org/licenses/GPL-2.0+)
4 * PURPOSE: Fiber Implementation
5 * COPYRIGHT: Copyright 2005-2011 Alex Ionescu (alex@relsoft.net)
6 * Copyright 2003-2008 KJK::Hyperion (noog@libero.it)
7 * Copyright 2018 Mark Jansen (mark.jansen@reactos.org)
8 */
9
10#include <k32.h>
11#include <ndk/rtltypes.h>
12
13#define NDEBUG
14#include <debug.h>
15
16#ifdef _M_IX86
17C_ASSERT(FIELD_OFFSET(FIBER, ExceptionList) == 0x04);
18C_ASSERT(FIELD_OFFSET(FIBER, StackBase) == 0x08);
19C_ASSERT(FIELD_OFFSET(FIBER, StackLimit) == 0x0C);
20C_ASSERT(FIELD_OFFSET(FIBER, DeallocationStack) == 0x10);
21C_ASSERT(FIELD_OFFSET(FIBER, FiberContext) == 0x14);
22C_ASSERT(FIELD_OFFSET(FIBER, GuaranteedStackBytes) == 0x2E0);
23C_ASSERT(FIELD_OFFSET(FIBER, FlsData) == 0x2E4);
24C_ASSERT(FIELD_OFFSET(FIBER, ActivationContextStackPointer) == 0x2E8);
26#endif // _M_IX86
27
28/* PRIVATE FUNCTIONS **********************************************************/
29
30VOID
33{
34 ULONG n, FlsHighIndex;
35 PRTL_FLS_DATA pFlsData;
36 PFLS_CALLBACK_FUNCTION lpCallback;
37
38 pFlsData = FlsData;
39
41 FlsHighIndex = NtCurrentPeb()->FlsHighIndex;
42 RemoveEntryList(&pFlsData->ListEntry);
44
45 for (n = 1; n <= FlsHighIndex; ++n)
46 {
47 lpCallback = NtCurrentPeb()->FlsCallback[n];
48 if (lpCallback && pFlsData->Data[n])
49 {
50 lpCallback(pFlsData->Data[n]);
51 }
52 }
53
54 RtlFreeHeap(RtlGetProcessHeap(), 0, FlsData);
55}
56
57/* PUBLIC FUNCTIONS ***********************************************************/
58
59/*
60 * @implemented
61 */
62BOOL
65{
66 PTEB Teb;
68 DPRINT1("Converting Fiber to Thread\n");
69
70 /* Check if the thread is already not a fiber */
71 Teb = NtCurrentTeb();
72 if (!Teb->HasFiberData)
73 {
74 /* Fail */
76 return FALSE;
77 }
78
79 /* This thread won't run a fiber anymore */
80 Teb->HasFiberData = FALSE;
82 Teb->NtTib.FiberData = NULL;
83
84 /* Free the fiber */
86 RtlFreeHeap(RtlGetProcessHeap(),
87 0,
88 FiberData);
89
90 /* Success */
91 return TRUE;
92}
93
94/*
95 * @implemented
96 */
101{
102 PTEB Teb;
103 PFIBER Fiber;
104 DPRINT1("Converting Thread to Fiber\n");
105
106 /* Check for invalid flags */
107 if (dwFlags & ~FIBER_FLAG_FLOAT_SWITCH)
108 {
109 /* Fail */
111 return NULL;
112 }
113
114 /* Are we already a fiber? */
115 Teb = NtCurrentTeb();
116 if (Teb->HasFiberData)
117 {
118 /* Fail */
120 return NULL;
121 }
122
123 /* Allocate the fiber */
124 Fiber = RtlAllocateHeap(RtlGetProcessHeap(),
125 0,
126 sizeof(FIBER));
127 if (!Fiber)
128 {
129 /* Fail */
131 return NULL;
132 }
133
134 /* Copy some contextual data from the thread to the fiber */
135 Fiber->FiberData = lpParameter;
136 Fiber->ExceptionList = Teb->NtTib.ExceptionList;
137 Fiber->StackBase = Teb->NtTib.StackBase;
138 Fiber->StackLimit = Teb->NtTib.StackLimit;
140 Fiber->FlsData = Teb->FlsData;
143
144 /* Save FPU State if requested, otherwise just the basic registers */
145 Fiber->FiberContext.ContextFlags = (dwFlags & FIBER_FLAG_FLOAT_SWITCH) ?
148
149 /* Associate the fiber to the current thread */
150 Teb->NtTib.FiberData = Fiber;
151 Teb->HasFiberData = TRUE;
152
153 /* Return opaque fiber data */
154 return (LPVOID)Fiber;
155}
156
157/*
158 * @implemented
159 */
160LPVOID
161WINAPI
163{
164 /* Call the newer function */
165 return ConvertThreadToFiberEx(lpParameter,
166 0);
167}
168
169/*
170 * @implemented
171 */
172LPVOID
173WINAPI
175 _In_ LPFIBER_START_ROUTINE lpStartAddress,
176 _In_opt_ LPVOID lpParameter)
177{
178 /* Call the Newer Function */
179 return CreateFiberEx(dwStackSize,
180 0,
181 0,
182 lpStartAddress,
183 lpParameter);
184}
185
186/*
187 * @implemented
188 */
189LPVOID
190WINAPI
191CreateFiberEx(_In_ SIZE_T dwStackCommitSize,
192 _In_ SIZE_T dwStackReserveSize,
194 _In_ LPFIBER_START_ROUTINE lpStartAddress,
195 _In_opt_ LPVOID lpParameter)
196{
197 PFIBER Fiber;
199 INITIAL_TEB InitialTeb;
200 PACTIVATION_CONTEXT_STACK ActivationContextStackPointer;
201 DPRINT("Creating Fiber\n");
202
203 /* Check for invalid flags */
204 if (dwFlags & ~FIBER_FLAG_FLOAT_SWITCH)
205 {
206 /* Fail */
208 return NULL;
209 }
210
211 /* Allocate the Activation Context Stack */
212 ActivationContextStackPointer = NULL;
213 Status = RtlAllocateActivationContextStack(&ActivationContextStackPointer);
214 if (!NT_SUCCESS(Status))
215 {
216 /* Fail */
218 return NULL;
219 }
220
221 /* Allocate the fiber */
222 Fiber = RtlAllocateHeap(RtlGetProcessHeap(),
223 0,
224 sizeof(FIBER));
225 if (!Fiber)
226 {
227 /* Free the activation context stack */
228 RtlFreeActivationContextStack(ActivationContextStackPointer);
229
230 /* Fail */
232 return NULL;
233 }
234
235 /* Create the stack for the fiber */
237 dwStackCommitSize,
238 dwStackReserveSize,
239 &InitialTeb);
240 if (!NT_SUCCESS(Status))
241 {
242 /* Free the fiber */
244 0,
245 Fiber);
246
247 /* Free the activation context stack */
248 RtlFreeActivationContextStack(ActivationContextStackPointer);
249
250 /* Failure */
252 return NULL;
253 }
254
255 /* Clear the context */
257 sizeof(CONTEXT));
258
259 /* Copy the data into the fiber */
260 Fiber->StackBase = InitialTeb.StackBase;
261 Fiber->StackLimit = InitialTeb.StackLimit;
262 Fiber->DeallocationStack = InitialTeb.AllocatedStackBase;
263 Fiber->FiberData = lpParameter;
265 Fiber->GuaranteedStackBytes = 0;
266 Fiber->FlsData = NULL;
267 Fiber->ActivationContextStackPointer = ActivationContextStackPointer;
268
269 /* Save FPU State if requested, otherwise just the basic registers */
270 Fiber->FiberContext.ContextFlags = (dwFlags & FIBER_FLAG_FLOAT_SWITCH) ?
273
274 /* Initialize the context for the fiber */
276 lpParameter,
277 lpStartAddress,
278 InitialTeb.StackBase,
279 2);
280
281 /* Return the Fiber */
282 return Fiber;
283}
284
285/*
286 * @implemented
287 */
288VOID
289WINAPI
291{
292 SIZE_T Size;
293 PFIBER Fiber;
294 PTEB Teb;
295
296 /* Are we deleting ourselves? */
297 Teb = NtCurrentTeb();
298 Fiber = (PFIBER)lpFiber;
299 if ((Teb->HasFiberData) &&
300 (Teb->NtTib.FiberData == Fiber))
301 {
302 /* Just exit */
303 ExitThread(1);
304 }
305
306 /* Not ourselves, de-allocate the stack */
307 Size = 0 ;
309 &Fiber->DeallocationStack,
310 &Size,
312
313 /* Get rid of FLS */
314 if (Fiber->FlsData) BaseRundownFls(Fiber->FlsData);
315
316 /* Get rid of the activation context stack */
318
319 /* Free the fiber data */
320 RtlFreeHeap(RtlGetProcessHeap(),
321 0,
322 lpFiber);
323}
324
325/*
326 * @implemented
327 */
328BOOL
329WINAPI
331{
332 /* Return flag in the TEB */
333 return NtCurrentTeb()->HasFiberData;
334}
335
336/*
337 * @implemented
338 */
339DWORD
340WINAPI
342{
343 DWORD dwFlsIndex;
345 PRTL_FLS_DATA pFlsData;
346
348
349 pFlsData = NtCurrentTeb()->FlsData;
350
351 if (!Peb->FlsCallback &&
352 !(Peb->FlsCallback = RtlAllocateHeap(RtlGetProcessHeap(), HEAP_ZERO_MEMORY,
353 FLS_MAXIMUM_AVAILABLE * sizeof(PVOID))))
354 {
356 dwFlsIndex = FLS_OUT_OF_INDEXES;
357 }
358 else
359 {
360 dwFlsIndex = RtlFindClearBitsAndSet(Peb->FlsBitmap, 1, 1);
361 if (dwFlsIndex != FLS_OUT_OF_INDEXES)
362 {
363 if (!pFlsData &&
364 !(pFlsData = RtlAllocateHeap(RtlGetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(RTL_FLS_DATA))))
365 {
366 RtlClearBits(Peb->FlsBitmap, dwFlsIndex, 1);
367 dwFlsIndex = FLS_OUT_OF_INDEXES;
369 }
370 else
371 {
372 if (!NtCurrentTeb()->FlsData)
373 {
374 NtCurrentTeb()->FlsData = pFlsData;
376 }
377
378 pFlsData->Data[dwFlsIndex] = NULL; /* clear the value */
379 Peb->FlsCallback[dwFlsIndex] = lpCallback;
380
381 if (dwFlsIndex > Peb->FlsHighIndex)
382 Peb->FlsHighIndex = dwFlsIndex;
383 }
384 }
385 else
386 {
388 }
389 }
391 return dwFlsIndex;
392}
393
394
395/*
396 * @implemented
397 */
398BOOL
399WINAPI
400FlsFree(DWORD dwFlsIndex)
401{
402 BOOL ret;
404
405 if (dwFlsIndex >= FLS_MAXIMUM_AVAILABLE)
406 {
408 return FALSE;
409 }
410
412
414 {
415 ret = RtlAreBitsSet(Peb->FlsBitmap, dwFlsIndex, 1);
416 if (ret)
417 {
419 PFLS_CALLBACK_FUNCTION lpCallback;
420
421 RtlClearBits(Peb->FlsBitmap, dwFlsIndex, 1);
422 lpCallback = Peb->FlsCallback[dwFlsIndex];
423
424 for (Entry = Peb->FlsListHead.Flink; Entry != &Peb->FlsListHead; Entry = Entry->Flink)
425 {
426 PRTL_FLS_DATA pFlsData;
427
428 pFlsData = CONTAINING_RECORD(Entry, RTL_FLS_DATA, ListEntry);
429 if (pFlsData->Data[dwFlsIndex])
430 {
431 if (lpCallback)
432 {
433 lpCallback(pFlsData->Data[dwFlsIndex]);
434 }
435 pFlsData->Data[dwFlsIndex] = NULL;
436 }
437 }
438 Peb->FlsCallback[dwFlsIndex] = NULL;
439 }
440 else
441 {
443 }
444 }
446 {
448 }
449 _SEH2_END;
450
451 return ret;
452}
453
454
455/*
456 * @implemented
457 */
458PVOID
459WINAPI
461{
462 PRTL_FLS_DATA pFlsData;
463
464 pFlsData = NtCurrentTeb()->FlsData;
465 if (!dwFlsIndex || dwFlsIndex >= FLS_MAXIMUM_AVAILABLE || !pFlsData)
466 {
468 return NULL;
469 }
470
472 return pFlsData->Data[dwFlsIndex];
473}
474
475
476/*
477 * @implemented
478 */
479BOOL
480WINAPI
482 PVOID lpFlsData)
483{
484 PRTL_FLS_DATA pFlsData;
485
486 if (!dwFlsIndex || dwFlsIndex >= FLS_MAXIMUM_AVAILABLE)
487 {
489 return FALSE;
490 }
491
492 pFlsData = NtCurrentTeb()->FlsData;
493
494 if (!NtCurrentTeb()->FlsData &&
495 !(NtCurrentTeb()->FlsData = RtlAllocateHeap(RtlGetProcessHeap(), HEAP_ZERO_MEMORY,
496 sizeof(RTL_FLS_DATA))))
497 {
499 return FALSE;
500 }
501 if (!pFlsData)
502 {
503 pFlsData = NtCurrentTeb()->FlsData;
505 InsertTailList(&NtCurrentPeb()->FlsListHead, &pFlsData->ListEntry);
507 }
508 pFlsData->Data[dwFlsIndex] = lpFlsData;
509 return TRUE;
510}
511
512/* EOF */
#define NtCurrentPeb()
Definition: FLS.c:22
LONG NTSTATUS
Definition: precomp.h:26
#define DPRINT1
Definition: precomp.h:8
PVOID NTAPI RtlAllocateHeap(IN PVOID HeapHandle, IN ULONG Flags, IN SIZE_T Size)
Definition: heap.c:590
BOOLEAN NTAPI RtlFreeHeap(IN PVOID HeapHandle, IN ULONG Flags, IN PVOID HeapBase)
Definition: heap.c:608
#define ERROR_NOT_ENOUGH_MEMORY
Definition: dderror.h:7
#define ERROR_SUCCESS
Definition: deptool.c:10
#define NULL
Definition: types.h:112
#define TRUE
Definition: types.h:120
#define FALSE
Definition: types.h:117
#define NT_SUCCESS(StatCode)
Definition: apphelp.c:32
#define GetProcessHeap()
Definition: compat.h:736
#define ERROR_INVALID_PARAMETER
Definition: compat.h:101
#define SetLastError(x)
Definition: compat.h:752
#define ERROR_NO_MORE_ITEMS
Definition: compat.h:105
#define HEAP_ZERO_MEMORY
Definition: compat.h:134
PPEB Peb
Definition: dllmain.c:27
LPVOID WINAPI ConvertThreadToFiberEx(_In_opt_ LPVOID lpParameter, _In_ DWORD dwFlags)
Definition: fiber.c:99
BOOL WINAPI ConvertFiberToThread(VOID)
Definition: fiber.c:64
LPVOID WINAPI CreateFiberEx(_In_ SIZE_T dwStackCommitSize, _In_ SIZE_T dwStackReserveSize, _In_ DWORD dwFlags, _In_ LPFIBER_START_ROUTINE lpStartAddress, _In_opt_ LPVOID lpParameter)
Definition: fiber.c:191
VOID WINAPI DeleteFiber(_In_ LPVOID lpFiber)
Definition: fiber.c:290
BOOL WINAPI IsThreadAFiber(VOID)
Definition: fiber.c:330
VOID WINAPI BaseRundownFls(_In_ PVOID FlsData)
Definition: fiber.c:32
PVOID WINAPI FlsGetValue(DWORD dwFlsIndex)
Definition: fiber.c:460
BOOL WINAPI FlsSetValue(DWORD dwFlsIndex, PVOID lpFlsData)
Definition: fiber.c:481
LPVOID WINAPI ConvertThreadToFiber(_In_opt_ LPVOID lpParameter)
Definition: fiber.c:162
BOOL WINAPI FlsFree(DWORD dwFlsIndex)
Definition: fiber.c:400
DWORD WINAPI FlsAlloc(PFLS_CALLBACK_FUNCTION lpCallback)
Definition: fiber.c:341
LPVOID WINAPI CreateFiber(_In_ SIZE_T dwStackSize, _In_ LPFIBER_START_ROUTINE lpStartAddress, _In_opt_ LPVOID lpParameter)
Definition: fiber.c:174
VOID WINAPI ExitThread(IN DWORD uExitCode)
Definition: thread.c:365
NTSTATUS WINAPI BaseCreateStack(_In_ HANDLE hProcess, _In_opt_ SIZE_T StackCommit, _In_opt_ SIZE_T StackReserve, _Out_ PINITIAL_TEB InitialTeb)
Definition: utils.c:354
VOID WINAPI BaseInitializeContext(IN PCONTEXT Context, IN PVOID Parameter, IN PVOID StartAddress, IN PVOID StackAddress, IN ULONG ContextType)
Definition: utils.c:513
#define RemoveEntryList(Entry)
Definition: env_spec_w32.h:986
#define InsertTailList(ListHead, Entry)
#define _SEH2_FINALLY
Definition: filesup.c:21
#define _SEH2_END
Definition: filesup.c:22
#define _SEH2_TRY
Definition: filesup.c:19
unsigned int BOOL
Definition: ntddk_ex.h:94
unsigned long DWORD
Definition: ntddk_ex.h:95
Status
Definition: gdiplustypes.h:25
GLdouble n
Definition: glext.h:7729
NTSYSAPI void WINAPI RtlReleasePebLock(void)
Definition: libsupp.c:82
NTSYSAPI void WINAPI RtlAcquirePebLock(void)
Definition: libsupp.c:72
NTSYSAPI ULONG WINAPI RtlFindClearBitsAndSet(PRTL_BITMAP, ULONG, ULONG)
NTSYSAPI void WINAPI RtlClearBits(PRTL_BITMAP, ULONG, ULONG)
NTSYSAPI BOOLEAN WINAPI RtlAreBitsSet(PCRTL_BITMAP, ULONG, ULONG)
#define C_ASSERT(e)
Definition: intsafe.h:73
#define NtCurrentTeb
#define ASSERT(a)
Definition: mode.c:44
#define _In_
Definition: ms_sal.h:308
#define _In_opt_
Definition: ms_sal.h:309
struct _FIBER * PFIBER
#define RTL_FLS_MAXIMUM_AVAILABLE
Definition: rtltypes.h:1220
#define EXCEPTION_CHAIN_END
Definition: rtltypes.h:63
#define NtCurrentProcess()
Definition: nt_native.h:1657
#define CONTEXT_FLOATING_POINT
Definition: nt_native.h:1372
#define MEM_RELEASE
Definition: nt_native.h:1316
#define CONTEXT_FULL
Definition: nt_native.h:1375
NTSTATUS NTAPI NtFreeVirtualMemory(IN HANDLE ProcessHandle, IN PVOID *UBaseAddress, IN PSIZE_T URegionSize, IN ULONG FreeType)
Definition: virtual.c:5278
DWORD BaseSetLastNTError(IN NTSTATUS Status)
Definition: reactos.cpp:166
NTSTATUS NTAPI RtlAllocateActivationContextStack(IN PACTIVATION_CONTEXT_STACK *Stack)
Definition: actctx.c:5906
VOID NTAPI RtlFreeActivationContextStack(IN PACTIVATION_CONTEXT_STACK Stack)
Definition: actctx.c:5440
#define DPRINT
Definition: sndvol32.h:71
base of all file and directory entries
Definition: entries.h:83
ULONG ContextFlags
Definition: nt_native.h:1426
PVOID StackLimit
Definition: ketypes.h:151
CONTEXT FiberContext
Definition: ketypes.h:153
PVOID DeallocationStack
Definition: ketypes.h:152
ULONG GuaranteedStackBytes
Definition: ketypes.h:158
PVOID StackBase
Definition: ketypes.h:150
struct _ACTIVATION_CONTEXT_STACK * ActivationContextStackPointer
Definition: ketypes.h:156
struct _EXCEPTION_REGISTRATION_RECORD * ExceptionList
Definition: ketypes.h:149
PVOID FiberData
Definition: ketypes.h:148
PVOID FlsData
Definition: ketypes.h:157
PVOID StackBase
Definition: pstypes.h:694
PVOID AllocatedStackBase
Definition: pstypes.h:696
PVOID StackLimit
Definition: pstypes.h:695
Definition: typedefs.h:120
struct _LIST_ENTRY * Flink
Definition: typedefs.h:121
PVOID FiberData
Definition: compat.h:716
PVOID StackLimit
Definition: compat.h:713
PVOID StackBase
Definition: compat.h:712
struct _EXCEPTION_REGISTRATION_RECORD * ExceptionList
Definition: compat.h:711
PVOID * FlsCallback
Definition: winternl.h:359
LIST_ENTRY FlsListHead
Definition: winternl.h:360
PRTL_BITMAP FlsBitmap
Definition: winternl.h:361
LIST_ENTRY ListEntry
Definition: rtltypes.h:1223
PVOID Data[RTL_FLS_MAXIMUM_AVAILABLE]
Definition: rtltypes.h:1224
Definition: compat.h:836
PVOID ActivationContextStackPointer
Definition: compat.h:854
NT_TIB NtTib
Definition: ntddk_ex.h:332
ULONG GuaranteedStackBytes
Definition: winternl.h:279
PVOID DeallocationStack
Definition: compat.h:878
#define FIELD_OFFSET(t, f)
Definition: typedefs.h:255
ULONG_PTR SIZE_T
Definition: typedefs.h:80
#define RtlZeroMemory(Destination, Length)
Definition: typedefs.h:262
#define CONTAINING_RECORD(address, type, field)
Definition: typedefs.h:260
uint32_t ULONG
Definition: typedefs.h:59
int ret
_Must_inspect_result_ _In_ WDFDEVICE _In_ PWDF_DEVICE_PROPERTY_DATA _In_ DEVPROPTYPE _In_ ULONG Size
Definition: wdfdevice.h:4533
#define FLS_OUT_OF_INDEXES
Definition: winbase.h:576
VOID(WINAPI * PFLS_CALLBACK_FUNCTION)(PVOID)
Definition: winbase.h:1444
PFIBER_START_ROUTINE LPFIBER_START_ROUTINE
Definition: winbase.h:1442
_In_ PCCERT_CONTEXT _In_ DWORD dwFlags
Definition: wincrypt.h:1176
#define WINAPI
Definition: msvc.h:6
#define ERROR_ALREADY_THREAD
Definition: winerror.h:778
#define ERROR_ALREADY_FIBER
Definition: winerror.h:777
#define FLS_MAXIMUM_AVAILABLE
Definition: winnt_old.h:1070