wintrust: Implement CryptCATAdminCalcHashFromFileHandle.
[wine] / dlls / kernel32 / fiber.c
index f8647ef..fda5f92 100644 (file)
@@ -34,6 +34,9 @@
 #include "winternl.h"
 #include "wine/exception.h"
 #include "wine/library.h"
+#include "wine/debug.h"
+
+WINE_DEFAULT_DEBUG_CHANNEL(fiber);
 
 struct fiber_data
 {
@@ -45,6 +48,7 @@ struct fiber_data
     sigjmp_buf            jmpbuf;            /* 14 setjmp buffer (on Windows: CONTEXT) */
     DWORD                 flags;             /*    fiber flags */
     LPFIBER_START_ROUTINE start;             /*    start routine */
+    void                **fls_slots;         /*    fiber storage slots */
 };
 
 
@@ -104,6 +108,7 @@ LPVOID WINAPI CreateFiberEx( SIZE_T stack_commit, SIZE_T stack_reserve, DWORD fl
     fiber->except      = (void *)-1;
     fiber->start       = start;
     fiber->flags       = flags;
+    fiber->fls_slots   = NULL;
     return fiber;
 }
 
@@ -122,6 +127,7 @@ void WINAPI DeleteFiber( LPVOID fiber_ptr )
         ExitThread(1);
     }
     VirtualFree( fiber->stack_allocation, 0, MEM_RELEASE );
+    HeapFree( GetProcessHeap(), 0, fiber->fls_slots );
     HeapFree( GetProcessHeap(), 0, fiber );
 }
 
@@ -154,6 +160,7 @@ LPVOID WINAPI ConvertThreadToFiberEx( LPVOID param, DWORD flags )
     fiber->stack_allocation = NtCurrentTeb()->DeallocationStack;
     fiber->start            = NULL;
     fiber->flags            = flags;
+    fiber->fls_slots        = NtCurrentTeb()->FlsSlots;
     NtCurrentTeb()->Tib.u.FiberData = fiber;
     return fiber;
 }
@@ -185,19 +192,118 @@ void WINAPI SwitchToFiber( LPVOID fiber )
 
     current_fiber->except      = NtCurrentTeb()->Tib.ExceptionList;
     current_fiber->stack_limit = NtCurrentTeb()->Tib.StackLimit;
+    current_fiber->fls_slots   = NtCurrentTeb()->FlsSlots;
     /* stack_allocation and stack_base never change */
 
     /* FIXME: should save floating point context if requested in fiber->flags */
-    if (!sigsetjmp( current_fiber->jmpbuf, 1 ))
+    if (!sigsetjmp( current_fiber->jmpbuf, 0 ))
     {
         NtCurrentTeb()->Tib.u.FiberData   = new_fiber;
         NtCurrentTeb()->Tib.ExceptionList = new_fiber->except;
         NtCurrentTeb()->Tib.StackBase     = new_fiber->stack_base;
         NtCurrentTeb()->Tib.StackLimit    = new_fiber->stack_limit;
         NtCurrentTeb()->DeallocationStack = new_fiber->stack_allocation;
+        NtCurrentTeb()->FlsSlots          = new_fiber->fls_slots;
         if (new_fiber->start)  /* first time */
             wine_switch_to_stack( start_fiber, new_fiber, new_fiber->stack_base );
         else
             siglongjmp( new_fiber->jmpbuf, 1 );
     }
 }
+
+/***********************************************************************
+ *           FlsAlloc   (KERNEL32.@)
+ */
+DWORD WINAPI FlsAlloc( PFLS_CALLBACK_FUNCTION callback )
+{
+    DWORD index;
+    PEB * const peb = NtCurrentTeb()->Peb;
+
+    RtlAcquirePebLock();
+    if (!peb->FlsCallback &&
+        !(peb->FlsCallback = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY,
+                                        8 * sizeof(peb->FlsBitmapBits) * sizeof(void*) )))
+    {
+        SetLastError( ERROR_NOT_ENOUGH_MEMORY );
+        index = FLS_OUT_OF_INDEXES;
+    }
+    else
+    {
+        index = RtlFindClearBitsAndSet( peb->FlsBitmap, 1, 0 );
+        if (index != ~0U)
+        {
+            if (!NtCurrentTeb()->FlsSlots &&
+                !(NtCurrentTeb()->FlsSlots = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY,
+                                                        8 * sizeof(peb->FlsBitmapBits) * sizeof(void*) )))
+            {
+                RtlClearBits( peb->FlsBitmap, index, 1 );
+                index = FLS_OUT_OF_INDEXES;
+                SetLastError( ERROR_NOT_ENOUGH_MEMORY );
+            }
+            else
+            {
+                NtCurrentTeb()->FlsSlots[index] = 0; /* clear the value */
+                peb->FlsCallback[index] = callback;
+            }
+        }
+        else SetLastError( ERROR_NO_MORE_ITEMS );
+    }
+    RtlReleasePebLock();
+    return index;
+}
+
+/***********************************************************************
+ *           FlsFree   (KERNEL32.@)
+ */
+BOOL WINAPI FlsFree( DWORD index )
+{
+    BOOL ret;
+
+    RtlAcquirePebLock();
+    ret = RtlAreBitsSet( NtCurrentTeb()->Peb->FlsBitmap, index, 1 );
+    if (ret) RtlClearBits( NtCurrentTeb()->Peb->FlsBitmap, index, 1 );
+    if (ret)
+    {
+        /* FIXME: call Fls callback */
+        /* FIXME: add equivalent of ThreadZeroTlsCell here */
+        if (NtCurrentTeb()->FlsSlots) NtCurrentTeb()->FlsSlots[index] = 0;
+    }
+    else SetLastError( ERROR_INVALID_PARAMETER );
+    RtlReleasePebLock();
+    return TRUE;
+}
+
+/***********************************************************************
+ *           FlsGetValue   (KERNEL32.@)
+ */
+PVOID WINAPI FlsGetValue( DWORD index )
+{
+    if (index >= 8 * sizeof(NtCurrentTeb()->Peb->FlsBitmapBits) || !NtCurrentTeb()->FlsSlots)
+    {
+        SetLastError( ERROR_INVALID_PARAMETER );
+        return NULL;
+    }
+    SetLastError( ERROR_SUCCESS );
+    return NtCurrentTeb()->FlsSlots[index];
+}
+
+/***********************************************************************
+ *           FlsSetValue   (KERNEL32.@)
+ */
+BOOL WINAPI FlsSetValue( DWORD index, PVOID data )
+{
+    if (index >= 8 * sizeof(NtCurrentTeb()->Peb->FlsBitmapBits))
+    {
+        SetLastError( ERROR_INVALID_PARAMETER );
+        return FALSE;
+    }
+    if (!NtCurrentTeb()->FlsSlots &&
+        !(NtCurrentTeb()->FlsSlots = HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY,
+                                        8 * sizeof(NtCurrentTeb()->Peb->FlsBitmapBits) * sizeof(void*) )))
+    {
+        SetLastError( ERROR_NOT_ENOUGH_MEMORY );
+        return FALSE;
+    }
+    NtCurrentTeb()->FlsSlots[index] = data;
+    return TRUE;
+}