ReactOS  0.4.14-dev-608-gd495a4f
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
17 C_ASSERT(FIELD_OFFSET(FIBER, ExceptionList) == 0x04);
18 C_ASSERT(FIELD_OFFSET(FIBER, StackBase) == 0x08);
19 C_ASSERT(FIELD_OFFSET(FIBER, StackLimit) == 0x0C);
20 C_ASSERT(FIELD_OFFSET(FIBER, DeallocationStack) == 0x10);
21 C_ASSERT(FIELD_OFFSET(FIBER, FiberContext) == 0x14);
22 C_ASSERT(FIELD_OFFSET(FIBER, GuaranteedStackBytes) == 0x2E0);
23 C_ASSERT(FIELD_OFFSET(FIBER, FlsData) == 0x2E4);
24 C_ASSERT(FIELD_OFFSET(FIBER, ActivationContextStackPointer) == 0x2E8);
26 #endif // _M_IX86
27 
28 /* PRIVATE FUNCTIONS **********************************************************/
29 
30 VOID
31 WINAPI
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  */
62 BOOL
63 WINAPI
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;
81  FiberData = Teb->NtTib.FiberData;
82  Teb->NtTib.FiberData = NULL;
83 
84  /* Free the fiber */
85  ASSERT(FiberData != NULL);
86  RtlFreeHeap(RtlGetProcessHeap(),
87  0,
88  FiberData);
89 
90  /* Success */
91  return TRUE;
92 }
93 
94 /*
95  * @implemented
96  */
97 LPVOID
98 WINAPI
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;
139  Fiber->DeallocationStack = Teb->DeallocationStack;
140  Fiber->FlsData = Teb->FlsData;
141  Fiber->GuaranteedStackBytes = Teb->GuaranteedStackBytes;
143 
144  /* Save FPU State if requested, otherwise just the basic registers */
145  Fiber->FiberContext.ContextFlags = (dwFlags & FIBER_FLAG_FLOAT_SWITCH) ?
147  CONTEXT_FULL;
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  */
160 LPVOID
161 WINAPI
163 {
164  /* Call the newer function */
166  0);
167 }
168 
169 /*
170  * @implemented
171  */
172 LPVOID
173 WINAPI
174 CreateFiber(_In_ SIZE_T dwStackSize,
175  _In_ LPFIBER_START_ROUTINE lpStartAddress,
177 {
178  /* Call the Newer Function */
179  return CreateFiberEx(dwStackSize,
180  0,
181  0,
182  lpStartAddress,
183  lpParameter);
184 }
185 
186 /*
187  * @implemented
188  */
189 LPVOID
190 WINAPI
191 CreateFiberEx(_In_ SIZE_T dwStackCommitSize,
192  _In_ SIZE_T dwStackReserveSize,
194  _In_ LPFIBER_START_ROUTINE lpStartAddress,
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 */
256  RtlZeroMemory(&Fiber->FiberContext,
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) ?
272  CONTEXT_FULL;
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  */
288 VOID
289 WINAPI
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,
311  MEM_RELEASE);
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  */
328 BOOL
329 WINAPI
331 {
332  /* Return flag in the TEB */
333  return NtCurrentTeb()->HasFiberData;
334 }
335 
336 /*
337  * @implemented
338  */
339 DWORD
340 WINAPI
342 {
343  DWORD dwFlsIndex;
344  PPEB Peb = NtCurrentPeb();
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;
375  InsertTailList(&Peb->FlsListHead, &pFlsData->ListEntry);
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  */
398 BOOL
399 WINAPI
400 FlsFree(DWORD dwFlsIndex)
401 {
402  BOOL ret;
403  PPEB Peb = NtCurrentPeb();
404 
405  if (dwFlsIndex >= FLS_MAXIMUM_AVAILABLE)
406  {
408  return FALSE;
409  }
410 
412 
413  _SEH2_TRY
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  */
458 PVOID
459 WINAPI
460 FlsGetValue(DWORD dwFlsIndex)
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  */
479 BOOL
480 WINAPI
481 FlsSetValue(DWORD dwFlsIndex,
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 ERROR_INVALID_PARAMETER
Definition: compat.h:91
LPVOID WINAPI ConvertThreadToFiberEx(_In_opt_ LPVOID lpParameter, _In_ DWORD dwFlags)
Definition: fiber.c:99
PVOID StackBase
Definition: ketypes.h:183
CONTEXT FiberContext
Definition: ketypes.h:186
NTSTATUS WINAPI BaseCreateStack(_In_ HANDLE hProcess, _In_opt_ SIZE_T StackCommit, _In_opt_ SIZE_T StackReserve, _Out_ PINITIAL_TEB InitialTeb)
Definition: utils.c:354
NTSYSAPI void WINAPI RtlClearBits(PRTL_BITMAP, ULONG, ULONG)
VOID WINAPI BaseInitializeContext(IN PCONTEXT Context, IN PVOID Parameter, IN PVOID StartAddress, IN PVOID StackAddress, IN ULONG ContextType)
Definition: utils.c:513
#define TRUE
Definition: types.h:120
PPEB Peb
Definition: dllmain.c:27
#define FLS_OUT_OF_INDEXES
Definition: winbase.h:557
#define ERROR_SUCCESS
Definition: deptool.c:10
struct _Entry Entry
Definition: kefuncs.h:640
VOID WINAPI BaseRundownFls(_In_ PVOID FlsData)
Definition: fiber.c:32
#define ERROR_NO_MORE_ITEMS
Definition: compat.h:95
struct _EXCEPTION_REGISTRATION_RECORD * ExceptionList
Definition: ketypes.h:182
VOID(WINAPI * PFLS_CALLBACK_FUNCTION)(PVOID)
Definition: winbase.h:1404
PVOID StackLimit
Definition: ketypes.h:184
LONG NTSTATUS
Definition: precomp.h:26
BOOLEAN NTAPI RtlFreeHeap(IN PVOID HeapHandle, IN ULONG Flags, IN PVOID HeapBase)
Definition: heap.c:606
BOOL WINAPI FlsSetValue(DWORD dwFlsIndex, PVOID lpFlsData)
Definition: fiber.c:481
GLdouble n
Definition: glext.h:7729
#define CONTEXT_FLOATING_POINT
Definition: nt_native.h:1372
#define ERROR_NOT_ENOUGH_MEMORY
Definition: dderror.h:7
VOID NTAPI RtlReleasePebLock(VOID)
Definition: libsupp.c:82
BOOL WINAPI ConvertFiberToThread(VOID)
Definition: fiber.c:64
#define ERROR_ALREADY_THREAD
Definition: winerror.h:778
#define _In_opt_
Definition: no_sal2.h:213
_SEH2_TRY
Definition: create.c:4250
FORCEINLINE BOOLEAN RemoveEntryList(_In_ PLIST_ENTRY Entry)
Definition: rtlfuncs.h:105
PVOID FiberData
Definition: ketypes.h:181
DWORD WINAPI FlsAlloc(PFLS_CALLBACK_FUNCTION lpCallback)
Definition: fiber.c:341
BOOL WINAPI IsThreadAFiber(VOID)
Definition: fiber.c:330
unsigned int BOOL
Definition: ntddk_ex.h:94
LPVOID WINAPI ConvertThreadToFiber(_In_opt_ LPVOID lpParameter)
Definition: fiber.c:162
PVOID WINAPI FlsGetValue(DWORD dwFlsIndex)
Definition: fiber.c:460
smooth NULL
Definition: ftsmooth.c:416
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
PVOID StackBase
Definition: pstypes.h:678
void DPRINT(...)
Definition: polytest.cpp:61
#define C_ASSERT(e)
Definition: intsafe.h:79
PVOID DeallocationStack
Definition: ketypes.h:185
VOID WINAPI ExitThread(IN DWORD uExitCode)
Definition: thread.c:364
DWORD BaseSetLastNTError(IN NTSTATUS Status)
Definition: reactos.cpp:166
PVOID FlsData
Definition: ketypes.h:190
PFLT_MESSAGE_WAITER_QUEUE CONTAINING_RECORD(Csq, DEVICE_EXTENSION, IrpQueue)) -> WaiterQ.mLock) _IRQL_raises_(DISPATCH_LEVEL) VOID NTAPI FltpAcquireMessageWaiterLock(_In_ PIO_CSQ Csq, _Out_ PKIRQL Irql)
Definition: Messaging.c:560
ULONG ContextFlags
Definition: nt_native.h:1426
#define NtCurrentProcess()
Definition: nt_native.h:1657
PVOID NTAPI RtlAllocateHeap(IN PVOID HeapHandle, IN ULONG Flags, IN SIZE_T Size)
Definition: heap.c:588
LIST_ENTRY FlsListHead
Definition: winternl.h:360
struct _FIBER * PFIBER
struct _LIST_ENTRY * Flink
Definition: typedefs.h:119
#define CONTEXT_FULL
Definition: nt_native.h:1375
#define GetProcessHeap()
Definition: compat.h:403
#define NT_SUCCESS(StatCode)
Definition: apphelp.c:32
PVOID DeallocationStack
Definition: compat.h:535
PVOID FiberData
Definition: compat.h:384
VOID WINAPI DeleteFiber(_In_ LPVOID lpFiber)
Definition: fiber.c:290
struct _EXCEPTION_REGISTRATION_RECORD * ExceptionList
Definition: compat.h:379
#define WINAPI
Definition: msvc.h:6
unsigned long DWORD
Definition: ntddk_ex.h:95
#define SetLastError(x)
Definition: compat.h:417
ASSERT((InvokeOnSuccess||InvokeOnError||InvokeOnCancel) ?(CompletionRoutine !=NULL) :TRUE)
PVOID StackLimit
Definition: pstypes.h:679
ULONG GuaranteedStackBytes
Definition: ketypes.h:191
int ret
PVOID Data[RTL_FLS_MAXIMUM_AVAILABLE]
Definition: rtltypes.h:1220
_In_ PCCERT_CONTEXT _In_ DWORD dwFlags
Definition: wincrypt.h:1175
LPVOID lpParameter
Definition: kernel32.h:241
PVOID AllocatedStackBase
Definition: pstypes.h:680
#define InsertTailList(PLH__, PLE__)
Definition: fiber.c:33
Definition: typedefs.h:117
IN PVOID IN PVOID IN USHORT IN USHORT Size
Definition: pci.h:359
NTSYSAPI ULONG WINAPI RtlFindClearBitsAndSet(PRTL_BITMAP, ULONG, ULONG)
Status
Definition: gdiplustypes.h:24
#define _In_
Definition: no_sal2.h:204
PFIBER_START_ROUTINE LPFIBER_START_ROUTINE
Definition: winbase.h:1402
ULONG_PTR SIZE_T
Definition: typedefs.h:78
LIST_ENTRY ListEntry
Definition: rtltypes.h:1219
Definition: compat.h:492
_SEH2_END
Definition: create.c:4424
NTSYSAPI BOOLEAN WINAPI RtlAreBitsSet(PCRTL_BITMAP, ULONG, ULONG)
#define EXCEPTION_CHAIN_END
Definition: rtltypes.h:63
FORCEINLINE struct _TEB * NtCurrentTeb(VOID)
Definition: psfuncs.h:420
#define FLS_MAXIMUM_AVAILABLE
Definition: winnt_old.h:1101
PVOID StackBase
Definition: compat.h:380
#define NtCurrentPeb()
Definition: FLS.c:20
PVOID * FlsCallback
Definition: winternl.h:359
#define FIELD_OFFSET(t, f)
Definition: typedefs.h:254
_SEH2_FINALLY
Definition: create.c:4395
#define HEAP_ZERO_MEMORY
Definition: compat.h:123
VOID NTAPI RtlAcquirePebLock(VOID)
Definition: libsupp.c:72
#define DPRINT1
Definition: precomp.h:8
#define RTL_FLS_MAXIMUM_AVAILABLE
Definition: rtltypes.h:1216
#define MEM_RELEASE
Definition: nt_native.h:1316
NTSTATUS NTAPI RtlAllocateActivationContextStack(IN PACTIVATION_CONTEXT_STACK *Stack)
Definition: actctx.c:5834
PRTL_BITMAP FlsBitmap
Definition: winternl.h:361
unsigned int ULONG
Definition: retypes.h:1
#define RtlZeroMemory(Destination, Length)
Definition: typedefs.h:261
PVOID StackLimit
Definition: compat.h:381
PVOID ActivationContextStackPointer
Definition: compat.h:511
BOOL WINAPI FlsFree(DWORD dwFlsIndex)
Definition: fiber.c:400
NT_TIB NtTib
Definition: ntddk_ex.h:332
LPVOID WINAPI CreateFiber(_In_ SIZE_T dwStackSize, _In_ LPFIBER_START_ROUTINE lpStartAddress, _In_opt_ LPVOID lpParameter)
Definition: fiber.c:174
base of all file and directory entries
Definition: entries.h:82
struct _ACTIVATION_CONTEXT_STACK * ActivationContextStackPointer
Definition: ketypes.h:189
#define ERROR_ALREADY_FIBER
Definition: winerror.h:777
VOID NTAPI RtlFreeActivationContextStack(IN PACTIVATION_CONTEXT_STACK Stack)
Definition: actctx.c:5368
NTSTATUS NTAPI NtFreeVirtualMemory(IN HANDLE ProcessHandle, IN PVOID *UBaseAddress, IN PSIZE_T URegionSize, IN ULONG FreeType)
Definition: virtual.c:5090