winpr: several pool and synch fixes
authorNorbert Federa <norbert.federa@thincast.com>
Sat, 4 Jun 2016 15:04:12 +0000 (17:04 +0200)
committerNorbert Federa <norbert.federa@thincast.com>
Sat, 4 Jun 2016 15:09:48 +0000 (17:09 +0200)
pool:
- the winpr implementation fallback was not used on older windows editions
- drop useless and conflicting TP_CALLBACK_ENVIRON_V3
- fix race conditions by using use proper one-time initialization
- on win32 WinPR tried to load several pool/callback_environment functions
  from kernel32.dll but since these are defined as inline functions in the
  windows headers, no windows edition has ever exported them in any dll.
- removed callback_environment.c and added corresponding static inline
  function to pool.h
- fix segfault in TestPoolWork: CloseThreadpoolWork() must not be called
  if there is a cleanup group associated with the work object since calling
  CloseThreadpoolCleanupGroupMember() already releases the work object

sync:
- The windows headers incorrectly define InitializeCriticalEx support if
  _WIN32_WINNT >= 0x0403 instead of >= 0x0600 (Vista)
- created a compatible define to deal with this issue

13 files changed:
winpr/include/winpr/pool.h
winpr/include/winpr/synch.h
winpr/libwinpr/file/generic.c
winpr/libwinpr/pool/CMakeLists.txt
winpr/libwinpr/pool/callback.c
winpr/libwinpr/pool/callback_cleanup.c
winpr/libwinpr/pool/callback_environment.c [deleted file]
winpr/libwinpr/pool/cleanup_group.c
winpr/libwinpr/pool/pool.c
winpr/libwinpr/pool/pool.h
winpr/libwinpr/pool/test/TestPoolWork.c
winpr/libwinpr/pool/work.c
winpr/libwinpr/synch/critical.c

index 8dc3350..c228043 100644 (file)
@@ -36,15 +36,6 @@ typedef VOID (*PTP_SIMPLE_CALLBACK)(PTP_CALLBACK_INSTANCE Instance, PVOID Contex
 
 typedef struct _TP_POOL TP_POOL, *PTP_POOL;
 
-typedef enum _TP_CALLBACK_PRIORITY
-{
-       TP_CALLBACK_PRIORITY_HIGH,
-       TP_CALLBACK_PRIORITY_NORMAL,
-       TP_CALLBACK_PRIORITY_LOW,
-       TP_CALLBACK_PRIORITY_INVALID,
-       TP_CALLBACK_PRIORITY_COUNT = TP_CALLBACK_PRIORITY_INVALID
-} TP_CALLBACK_PRIORITY;
-
 typedef struct _TP_POOL_STACK_INFORMATION
 {
        SIZE_T StackReserve;
@@ -77,40 +68,9 @@ typedef struct _TP_CALLBACK_ENVIRON_V1
        } u;
 } TP_CALLBACK_ENVIRON_V1;
 
-#endif
-
-/* Non-Windows and pre Windows 7 */
-#if ((!defined(_WIN32)) || (defined(_WIN32) && (_WIN32_WINNT < 0x0601)))
-
-typedef struct _TP_CALLBACK_ENVIRON_V3
-{
-       TP_VERSION Version;
-       PTP_POOL Pool;
-       PTP_CLEANUP_GROUP CleanupGroup;
-       PTP_CLEANUP_GROUP_CANCEL_CALLBACK CleanupGroupCancelCallback;
-       PVOID RaceDll;
-       struct _ACTIVATION_CONTEXT *ActivationContext;
-       PTP_SIMPLE_CALLBACK FinalizationCallback;
-
-       union
-       {
-               DWORD Flags;
-
-               struct
-               {
-                       DWORD LongFunction:1;
-                       DWORD Persistent:1;
-                       DWORD Private:30;
-               } s;
-       } u;
-
-       TP_CALLBACK_PRIORITY CallbackPriority;
-       DWORD Size;
-} TP_CALLBACK_ENVIRON_V3;
-
-//typedef TP_CALLBACK_ENVIRON_V3 TP_CALLBACK_ENVIRON, *PTP_CALLBACK_ENVIRON;
+typedef TP_CALLBACK_ENVIRON_V1 TP_CALLBACK_ENVIRON, *PTP_CALLBACK_ENVIRON;
 
-#endif
+#endif /* _WIN32 not defined */
 
 typedef struct _TP_WORK TP_WORK, *PTP_WORK;
 typedef struct _TP_TIMER TP_TIMER, *PTP_TIMER;
@@ -120,9 +80,6 @@ typedef struct _TP_WAIT TP_WAIT, *PTP_WAIT;
 
 typedef struct _TP_IO TP_IO, *PTP_IO;
 
-#if !defined(_WIN32) || (defined(_WIN32) && (_WIN32_WINNT < 0x0601))
-typedef TP_CALLBACK_ENVIRON_V1 TP_CALLBACK_ENVIRON, *PTP_CALLBACK_ENVIRON;
-#endif
 
 #ifndef _WIN32
 
@@ -153,7 +110,7 @@ typedef VOID (*PTP_WIN32_IO_CALLBACK)(PTP_CALLBACK_INSTANCE Instance, PVOID Cont
 
 #endif
 
-#if (!defined(_WIN32) || ((defined(_WIN32) && (_WIN32_WINNT < 0x0601))))
+#if (!defined(_WIN32) || ((defined(_WIN32) && (_WIN32_WINNT < 0x0600))))
 #define WINPR_THREAD_POOL      1
 #endif
 
@@ -209,14 +166,44 @@ WINPR_API VOID SetThreadpoolThreadMaximum(PTP_POOL ptpp, DWORD cthrdMost);
 
 /* Callback Environment */
 
-WINPR_API VOID InitializeThreadpoolEnvironment(PTP_CALLBACK_ENVIRON pcbe);
-WINPR_API VOID DestroyThreadpoolEnvironment(PTP_CALLBACK_ENVIRON pcbe);
-WINPR_API VOID SetThreadpoolCallbackPool(PTP_CALLBACK_ENVIRON pcbe, PTP_POOL ptpp);
-WINPR_API VOID SetThreadpoolCallbackCleanupGroup(PTP_CALLBACK_ENVIRON pcbe,
-               PTP_CLEANUP_GROUP ptpcg, PTP_CLEANUP_GROUP_CANCEL_CALLBACK pfng);
-WINPR_API VOID SetThreadpoolCallbackRunsLong(PTP_CALLBACK_ENVIRON pcbe);
-WINPR_API VOID SetThreadpoolCallbackLibrary(PTP_CALLBACK_ENVIRON pcbe, PVOID mod);
-WINPR_API VOID SetThreadpoolCallbackPriority(PTP_CALLBACK_ENVIRON pcbe, TP_CALLBACK_PRIORITY Priority);
+static INLINE VOID InitializeThreadpoolEnvironment(PTP_CALLBACK_ENVIRON pcbe)
+{
+       pcbe->Version = 1;
+       pcbe->Pool = NULL;
+       pcbe->CleanupGroup = NULL;
+       pcbe->CleanupGroupCancelCallback = NULL;
+       pcbe->RaceDll = NULL;
+       pcbe->ActivationContext = NULL;
+       pcbe->FinalizationCallback = NULL;
+       pcbe->u.Flags = 0;
+}
+
+static INLINE VOID DestroyThreadpoolEnvironment(PTP_CALLBACK_ENVIRON pcbe)
+{
+       /* no actions, this may change in a future release. */
+}
+
+static INLINE VOID SetThreadpoolCallbackPool(PTP_CALLBACK_ENVIRON pcbe, PTP_POOL ptpp)
+{
+       pcbe->Pool = ptpp;
+}
+
+static INLINE VOID SetThreadpoolCallbackCleanupGroup(PTP_CALLBACK_ENVIRON pcbe, PTP_CLEANUP_GROUP ptpcg, PTP_CLEANUP_GROUP_CANCEL_CALLBACK pfng)
+{
+       pcbe->CleanupGroup = ptpcg;
+       pcbe->CleanupGroupCancelCallback = pfng;
+}
+
+static INLINE VOID SetThreadpoolCallbackRunsLong(PTP_CALLBACK_ENVIRON pcbe)
+{
+       pcbe->u.s.LongFunction = 1;
+}
+
+static INLINE VOID SetThreadpoolCallbackLibrary(PTP_CALLBACK_ENVIRON pcbe, PVOID mod)
+{
+       pcbe->RaceDll = mod;
+}
+
 
 /* Callback */
 
index d43a3ca..6b15e79 100644 (file)
@@ -276,16 +276,8 @@ WINPR_API BOOL DeleteTimerQueueTimer(HANDLE TimerQueue, HANDLE Timer, HANDLE Com
 
 #endif
 
-#if (defined(_WIN32) && defined(_SYNCHAPI_H_) && (_WIN32_WINNT < 0x0600))
-#define WINPR_INITIALIZE_CRITICAL_SECTION_EX   1
-#elif (defined(_WIN32) && (_WIN32_WINNT < 0x0403))
-#define WINPR_INITIALIZE_CRITICAL_SECTION_EX   1
-#endif
-
-#ifdef WINPR_INITIALIZE_CRITICAL_SECTION_EX
-
-WINPR_API BOOL InitializeCriticalSectionEx(LPCRITICAL_SECTION lpCriticalSection, DWORD dwSpinCount, DWORD Flags);
-
+#if (defined(_WIN32) && (_WIN32_WINNT < 0x0600))
+#define InitializeCriticalSectionEx(A,B,C) InitializeCriticalSectionAndSpinCount(A,B)
 #endif
 
 #ifndef _RTL_RUN_ONCE_DEF
index 96d3c12..1f2dc05 100644 (file)
@@ -860,7 +860,7 @@ int UnixChangeFileMode(const char* filename, int flags)
                return -1;
 
        /* Check for unsupported flags. */
-       if (flags & ~(_S_IREAD | _S_IWRITE) != 0)
+       if (flags & ~(_S_IREAD | _S_IWRITE))
                WLog_WARN(TAG, "Unsupported file mode %d for _wchmod", flags);
 
        rc = _wchmod(wfl, flags);
index fd70d73..acd27c4 100644 (file)
@@ -23,7 +23,6 @@ winpr_module_add(
        cleanup_group.c
        pool.c
        pool.h
-       callback_environment.c
        callback.c
        callback_cleanup.c)
 
index f521d9e..630a78c 100644 (file)
 #include <winpr/pool.h>
 #include <winpr/library.h>
 
-#ifdef _WIN32
-
-static BOOL module_initialized = FALSE;
-static BOOL module_available = FALSE;
-static HMODULE kernel32_module = NULL;
+#ifdef WINPR_THREAD_POOL
 
+#ifdef _WIN32
+static INIT_ONCE init_once_module = INIT_ONCE_STATIC_INIT;
 static BOOL (WINAPI * pCallbackMayRunLong)(PTP_CALLBACK_INSTANCE pci);
 
-static void module_init()
+static BOOL CALLBACK init_module(PINIT_ONCE once, PVOID param, PVOID *context)
 {
-       if (module_initialized)
-               return;
-
-       kernel32_module = LoadLibraryA("kernel32.dll");
-       module_initialized = TRUE;
-
-       if (!kernel32_module)
-               return;
-
-       module_available = TRUE;
-
-       pCallbackMayRunLong = (void*) GetProcAddress(kernel32_module, "CallbackMayRunLong");
+       HMODULE kernel32 = LoadLibraryA("kernel32.dll");
+       if (kernel32)
+       {
+               pCallbackMayRunLong = (void*)GetProcAddress(kernel32, "CallbackMayRunLong");
+       }
+       return TRUE;
 }
-
 #endif
 
-#ifdef WINPR_THREAD_POOL
-
 BOOL CallbackMayRunLong(PTP_CALLBACK_INSTANCE pci)
 {
 #ifdef _WIN32
-       module_init();
-
+       InitOnceExecuteOnce(&init_once_module, init_module, NULL, NULL);
        if (pCallbackMayRunLong)
                return pCallbackMayRunLong(pci);
-#else
 #endif
+       /* No default implementation */
        return FALSE;
 }
 
-#endif
+#endif /* WINPR_THREAD_POOL defined */
index 1403f3d..520b8ce 100644 (file)
 
 #include "pool.h"
 
-#ifdef _WIN32
-
-static BOOL module_initialized = FALSE;
-static BOOL module_available = FALSE;
-static HMODULE kernel32_module = NULL;
+#ifdef WINPR_THREAD_POOL
 
+#ifdef _WIN32
+static INIT_ONCE init_once_module = INIT_ONCE_STATIC_INIT;
 static VOID (WINAPI * pSetEventWhenCallbackReturns)(PTP_CALLBACK_INSTANCE pci, HANDLE evt);
 static VOID (WINAPI * pReleaseSemaphoreWhenCallbackReturns)(PTP_CALLBACK_INSTANCE pci, HANDLE sem, DWORD crel);
 static VOID (WINAPI * pReleaseMutexWhenCallbackReturns)(PTP_CALLBACK_INSTANCE pci, HANDLE mut);
@@ -40,96 +38,98 @@ static VOID (WINAPI * pLeaveCriticalSectionWhenCallbackReturns)(PTP_CALLBACK_INS
 static VOID (WINAPI * pFreeLibraryWhenCallbackReturns)(PTP_CALLBACK_INSTANCE pci, HMODULE mod);
 static VOID (WINAPI * pDisassociateCurrentThreadFromCallback)(PTP_CALLBACK_INSTANCE pci);
 
-static void module_init()
+static BOOL CALLBACK init_module(PINIT_ONCE once, PVOID param, PVOID *context)
 {
-       if (module_initialized)
-               return;
-
-       kernel32_module = LoadLibraryA("kernel32.dll");
-       module_initialized = TRUE;
-
-       if (!kernel32_module)
-               return;
-
-       module_available = TRUE;
-
-       pSetEventWhenCallbackReturns = (void*) GetProcAddress(kernel32_module, "SetEventWhenCallbackReturns");
-       pReleaseSemaphoreWhenCallbackReturns = (void*) GetProcAddress(kernel32_module, "ReleaseSemaphoreWhenCallbackReturns");
-       pReleaseMutexWhenCallbackReturns = (void*) GetProcAddress(kernel32_module, "ReleaseMutexWhenCallbackReturns");
-       pLeaveCriticalSectionWhenCallbackReturns = (void*) GetProcAddress(kernel32_module, "LeaveCriticalSectionWhenCallbackReturns");
-       pFreeLibraryWhenCallbackReturns = (void*) GetProcAddress(kernel32_module, "FreeLibraryWhenCallbackReturns");
-       pDisassociateCurrentThreadFromCallback = (void*) GetProcAddress(kernel32_module, "DisassociateCurrentThreadFromCallback");
+       HMODULE kernel32 = LoadLibraryA("kernel32.dll");
+       if (kernel32)
+       {
+               pSetEventWhenCallbackReturns = (void*)GetProcAddress(kernel32, "SetEventWhenCallbackReturns");
+               pReleaseSemaphoreWhenCallbackReturns = (void*)GetProcAddress(kernel32, "ReleaseSemaphoreWhenCallbackReturns");
+               pReleaseMutexWhenCallbackReturns = (void*)GetProcAddress(kernel32, "ReleaseMutexWhenCallbackReturns");
+               pLeaveCriticalSectionWhenCallbackReturns = (void*)GetProcAddress(kernel32, "LeaveCriticalSectionWhenCallbackReturns");
+               pFreeLibraryWhenCallbackReturns = (void*)GetProcAddress(kernel32, "FreeLibraryWhenCallbackReturns");
+               pDisassociateCurrentThreadFromCallback = (void*)GetProcAddress(kernel32, "DisassociateCurrentThreadFromCallback");
+       }
+       return TRUE;
 }
-
 #endif
 
-#ifdef WINPR_THREAD_POOL
-
 VOID SetEventWhenCallbackReturns(PTP_CALLBACK_INSTANCE pci, HANDLE evt)
 {
 #ifdef _WIN32
-       module_init();
-
+       InitOnceExecuteOnce(&init_once_module, init_module, NULL, NULL);
        if (pSetEventWhenCallbackReturns)
+       {
                pSetEventWhenCallbackReturns(pci, evt);
-#else
+               return;
+       }
 #endif
+       /* No default implementation */
 }
 
 VOID ReleaseSemaphoreWhenCallbackReturns(PTP_CALLBACK_INSTANCE pci, HANDLE sem, DWORD crel)
 {
 #ifdef _WIN32
-       module_init();
-
+       InitOnceExecuteOnce(&init_once_module, init_module, NULL, NULL);
        if (pReleaseSemaphoreWhenCallbackReturns)
+       {
                pReleaseSemaphoreWhenCallbackReturns(pci, sem, crel);
-#else
+               return;
+       }
 #endif
+       /* No default implementation */
 }
 
 VOID ReleaseMutexWhenCallbackReturns(PTP_CALLBACK_INSTANCE pci, HANDLE mut)
 {
 #ifdef _WIN32
-       module_init();
-
+       InitOnceExecuteOnce(&init_once_module, init_module, NULL, NULL);
        if (pReleaseMutexWhenCallbackReturns)
+       {
                pReleaseMutexWhenCallbackReturns(pci, mut);
-#else
+               return;
+       }
 #endif
+       /* No default implementation */
 }
 
 VOID LeaveCriticalSectionWhenCallbackReturns(PTP_CALLBACK_INSTANCE pci, PCRITICAL_SECTION pcs)
 {
 #ifdef _WIN32
-       module_init();
-
+       InitOnceExecuteOnce(&init_once_module, init_module, NULL, NULL);
        if (pLeaveCriticalSectionWhenCallbackReturns)
+       {
                pLeaveCriticalSectionWhenCallbackReturns(pci, pcs);
-#else
+       }
 #endif
+       /* No default implementation */
 }
 
 VOID FreeLibraryWhenCallbackReturns(PTP_CALLBACK_INSTANCE pci, HMODULE mod)
 {
 #ifdef _WIN32
-       module_init();
-
+       InitOnceExecuteOnce(&init_once_module, init_module, NULL, NULL);
        if (pFreeLibraryWhenCallbackReturns)
+       {
                pFreeLibraryWhenCallbackReturns(pci, mod);
-#else
+               return;
+       }
 #endif
+       /* No default implementation */
 }
 
 VOID DisassociateCurrentThreadFromCallback(PTP_CALLBACK_INSTANCE pci)
 {
 #ifdef _WIN32
-       module_init();
-
+       InitOnceExecuteOnce(&init_once_module, init_module, NULL, NULL);
        if (pDisassociateCurrentThreadFromCallback)
+       {
                pDisassociateCurrentThreadFromCallback(pci);
-#else
+               return;
+       }
 #endif
+       /* No default implementation */
 }
 
-#endif
+#endif /* WINPR_THREAD_POOL defined */
 
diff --git a/winpr/libwinpr/pool/callback_environment.c b/winpr/libwinpr/pool/callback_environment.c
deleted file mode 100644 (file)
index 5873a46..0000000
+++ /dev/null
@@ -1,204 +0,0 @@
-/**
- * WinPR: Windows Portable Runtime
- * Thread Pool API (Callback Environment)
- *
- * Copyright 2012 Marc-Andre Moreau <marcandre.moreau@gmail.com>
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-#ifdef HAVE_CONFIG_H
-#include "config.h"
-#endif
-
-#include <winpr/crt.h>
-#include <winpr/pool.h>
-#include <winpr/library.h>
-
-#include "pool.h"
-
-#ifdef WINPR_THREAD_POOL
-
-VOID InitializeCallbackEnvironment_V1(TP_CALLBACK_ENVIRON_V1* pcbe)
-{
-       pcbe->Version = 1;
-
-       pcbe->Pool = NULL;
-       pcbe->CleanupGroup = NULL;
-       pcbe->CleanupGroupCancelCallback = NULL;
-       pcbe->RaceDll = NULL;
-       pcbe->ActivationContext = NULL;
-       pcbe->FinalizationCallback = NULL;
-       pcbe->u.Flags = 0;
-}
-
-VOID InitializeCallbackEnvironment_V3(TP_CALLBACK_ENVIRON_V3* pcbe)
-{
-       pcbe->Version = 3;
-
-       pcbe->Pool = NULL;
-       pcbe->CleanupGroup = NULL;
-       pcbe->CleanupGroupCancelCallback = NULL;
-       pcbe->RaceDll = NULL;
-       pcbe->ActivationContext = NULL;
-       pcbe->FinalizationCallback = NULL;
-       pcbe->u.Flags = 0;
-
-       pcbe->CallbackPriority = TP_CALLBACK_PRIORITY_NORMAL;
-       pcbe->Size = sizeof(TP_CALLBACK_ENVIRON);
-}
-
-#endif
-
-#ifdef _WIN32
-
-static BOOL module_initialized = FALSE;
-static BOOL module_available = FALSE;
-static HMODULE kernel32_module = NULL;
-
-static VOID (WINAPI * pDestroyThreadpoolEnvironment)(PTP_CALLBACK_ENVIRON pcbe);
-static VOID (WINAPI * pSetThreadpoolCallbackPool)(PTP_CALLBACK_ENVIRON pcbe, PTP_POOL ptpp);
-static VOID (WINAPI * pSetThreadpoolCallbackCleanupGroup)(PTP_CALLBACK_ENVIRON pcbe, PTP_CLEANUP_GROUP ptpcg, PTP_CLEANUP_GROUP_CANCEL_CALLBACK pfng);
-static VOID (WINAPI * pSetThreadpoolCallbackRunsLong)(PTP_CALLBACK_ENVIRON pcbe);
-static VOID (WINAPI * pSetThreadpoolCallbackLibrary)(PTP_CALLBACK_ENVIRON pcbe, PVOID mod);
-static VOID (WINAPI * pSetThreadpoolCallbackPriority)(PTP_CALLBACK_ENVIRON pcbe, TP_CALLBACK_PRIORITY Priority);
-
-static void module_init()
-{
-       if (module_initialized)
-               return;
-
-       kernel32_module = LoadLibraryA("kernel32.dll");
-       module_initialized = TRUE;
-
-       if (!kernel32_module)
-               return;
-
-       module_available = TRUE;
-
-       /* InitializeThreadpoolEnvironment is an inline function */
-       pDestroyThreadpoolEnvironment = (void*) GetProcAddress(kernel32_module, "DestroyThreadpoolEnvironment");
-       pSetThreadpoolCallbackPool = (void*) GetProcAddress(kernel32_module, "SetThreadpoolCallbackPool");
-       pSetThreadpoolCallbackCleanupGroup = (void*) GetProcAddress(kernel32_module, "SetThreadpoolCallbackCleanupGroup");
-       pSetThreadpoolCallbackRunsLong = (void*) GetProcAddress(kernel32_module, "SetThreadpoolCallbackRunsLong");
-       pSetThreadpoolCallbackRunsLong = (void*) GetProcAddress(kernel32_module, "SetThreadpoolCallbackRunsLong");
-       pSetThreadpoolCallbackLibrary = (void*) GetProcAddress(kernel32_module, "SetThreadpoolCallbackLibrary");
-       pSetThreadpoolCallbackPriority = (void*) GetProcAddress(kernel32_module, "SetThreadpoolCallbackPriority");
-}
-
-#else
-
-static TP_CALLBACK_ENVIRON DEFAULT_CALLBACK_ENVIRONMENT =
-{
-       1, /* Version */
-       NULL, /* Pool */
-       NULL, /* CleanupGroup */
-       NULL, /* CleanupGroupCancelCallback */
-       NULL, /* RaceDll */
-       NULL, /* ActivationContext */
-       NULL, /* FinalizationCallback */
-       { 0 } /* Flags */
-};
-
-PTP_CALLBACK_ENVIRON GetDefaultThreadpoolEnvironment()
-{
-       PTP_CALLBACK_ENVIRON environment = &DEFAULT_CALLBACK_ENVIRONMENT;
-
-       environment->Pool = GetDefaultThreadpool();
-
-       return environment;
-}
-
-#endif
-
-#ifdef WINPR_THREAD_POOL
-
-VOID InitializeThreadpoolEnvironment(PTP_CALLBACK_ENVIRON pcbe)
-{
-       if (pcbe->Version == 3)
-               InitializeCallbackEnvironment_V3((TP_CALLBACK_ENVIRON_V3*) pcbe);
-       else
-               InitializeCallbackEnvironment_V1(pcbe);
-}
-
-VOID DestroyThreadpoolEnvironment(PTP_CALLBACK_ENVIRON pcbe)
-{
-#ifdef _WIN32
-       module_init();
-
-       if (pDestroyThreadpoolEnvironment)
-               pDestroyThreadpoolEnvironment(pcbe);
-#else
-#endif
-}
-
-VOID SetThreadpoolCallbackPool(PTP_CALLBACK_ENVIRON pcbe, PTP_POOL ptpp)
-{
-#ifdef _WIN32
-       module_init();
-
-       if (pSetThreadpoolCallbackPool)
-               pSetThreadpoolCallbackPool(pcbe, ptpp);
-#else
-       pcbe->Pool = ptpp;
-#endif
-}
-
-VOID SetThreadpoolCallbackCleanupGroup(PTP_CALLBACK_ENVIRON pcbe, PTP_CLEANUP_GROUP ptpcg, PTP_CLEANUP_GROUP_CANCEL_CALLBACK pfng)
-{
-#ifdef _WIN32
-       module_init();
-
-       if (pSetThreadpoolCallbackCleanupGroup)
-               pSetThreadpoolCallbackCleanupGroup(pcbe, ptpcg, pfng);
-#else
-       pcbe->CleanupGroup = ptpcg;
-       pcbe->CleanupGroupCancelCallback = pfng;
-#endif
-}
-
-VOID SetThreadpoolCallbackRunsLong(PTP_CALLBACK_ENVIRON pcbe)
-{
-#ifdef _WIN32
-       module_init();
-
-       if (pSetThreadpoolCallbackRunsLong)
-               pSetThreadpoolCallbackRunsLong(pcbe);
-#else
-       pcbe->u.s.LongFunction = TRUE;
-#endif
-}
-
-VOID SetThreadpoolCallbackLibrary(PTP_CALLBACK_ENVIRON pcbe, PVOID mod)
-{
-#ifdef _WIN32
-       module_init();
-
-       if (pSetThreadpoolCallbackLibrary)
-               pSetThreadpoolCallbackLibrary(pcbe, mod);
-#else
-#endif
-}
-
-VOID SetThreadpoolCallbackPriority(PTP_CALLBACK_ENVIRON pcbe, TP_CALLBACK_PRIORITY Priority)
-{
-#ifdef _WIN32
-       module_init();
-
-       if (pSetThreadpoolCallbackPriority)
-               pSetThreadpoolCallbackPriority(pcbe, Priority);
-#else
-#endif
-}
-
-#endif
index bf88456..8b9a89d 100644 (file)
 
 #include "pool.h"
 
-#ifdef _WIN32
-
-static BOOL module_initialized = FALSE;
-static BOOL module_available = FALSE;
-static HMODULE kernel32_module = NULL;
+#ifdef WINPR_THREAD_POOL
 
+#ifdef _WIN32
+static INIT_ONCE init_once_module = INIT_ONCE_STATIC_INIT;
 static PTP_CLEANUP_GROUP (WINAPI * pCreateThreadpoolCleanupGroup)();
 static VOID (WINAPI * pCloseThreadpoolCleanupGroupMembers)(PTP_CLEANUP_GROUP ptpcg, BOOL fCancelPendingCallbacks, PVOID pvCleanupContext);
 static VOID (WINAPI * pCloseThreadpoolCleanupGroup)(PTP_CLEANUP_GROUP ptpcg);
 
-static void module_init()
+static BOOL CALLBACK init_module(PINIT_ONCE once, PVOID param, PVOID *context)
 {
-       if (module_initialized)
-               return;
-
-       kernel32_module = LoadLibraryA("kernel32.dll");
-       module_initialized = TRUE;
-
-       if (!kernel32_module)
-               return;
-
-       module_available = TRUE;
-
-       pCreateThreadpoolCleanupGroup = (void*) GetProcAddress(kernel32_module, "CreateThreadpoolCleanupGroup");
-       pCloseThreadpoolCleanupGroupMembers = (void*) GetProcAddress(kernel32_module, "CloseThreadpoolCleanupGroupMembers");
-       pCloseThreadpoolCleanupGroup = (void*) GetProcAddress(kernel32_module, "CloseThreadpoolCleanupGroup");
+       HMODULE kernel32 = LoadLibraryA("kernel32.dll");
+       if (kernel32)
+       {
+               pCreateThreadpoolCleanupGroup = (void*)GetProcAddress(kernel32, "CreateThreadpoolCleanupGroup");
+               pCloseThreadpoolCleanupGroupMembers = (void*)GetProcAddress(kernel32, "CloseThreadpoolCleanupGroupMembers");
+               pCloseThreadpoolCleanupGroup = (void*)GetProcAddress(kernel32, "CloseThreadpoolCleanupGroup");
+       }
+       return TRUE;
 }
-
 #endif
 
-#if WINPR_THREAD_POOL
-
 PTP_CLEANUP_GROUP CreateThreadpoolCleanupGroup()
 {
        PTP_CLEANUP_GROUP cleanupGroup = NULL;
 #ifdef _WIN32
-       module_init();
-
+       InitOnceExecuteOnce(&init_once_module, init_module, NULL, NULL);
        if (pCreateThreadpoolCleanupGroup)
                return pCreateThreadpoolCleanupGroup();
-#else
-       cleanupGroup = (PTP_CLEANUP_GROUP) malloc(sizeof(TP_CLEANUP_GROUP));
 #endif
+       cleanupGroup = (PTP_CLEANUP_GROUP) malloc(sizeof(TP_CLEANUP_GROUP));
        return cleanupGroup;
 }
 
 VOID CloseThreadpoolCleanupGroupMembers(PTP_CLEANUP_GROUP ptpcg, BOOL fCancelPendingCallbacks, PVOID pvCleanupContext)
 {
 #ifdef _WIN32
-       module_init();
-
+       InitOnceExecuteOnce(&init_once_module, init_module, NULL, NULL);
        if (pCloseThreadpoolCleanupGroupMembers)
+       {
                pCloseThreadpoolCleanupGroupMembers(ptpcg, fCancelPendingCallbacks, pvCleanupContext);
-#else
-
+               return;
+       }
 #endif
+       /* No default implementation */
 }
 
 VOID CloseThreadpoolCleanupGroup(PTP_CLEANUP_GROUP ptpcg)
 {
 #ifdef _WIN32
-       module_init();
-
+       InitOnceExecuteOnce(&init_once_module, init_module, NULL, NULL);
        if (pCloseThreadpoolCleanupGroup)
+       {
                pCloseThreadpoolCleanupGroup(ptpcg);
-#else
-       free(ptpcg);
+               return;
+       }
 #endif
+       free(ptpcg);
 }
 
-#endif
+#endif /* WINPR_THREAD_POOL defined */
 
index fa9e2f5..67bb8f7 100644 (file)
 
 #include "pool.h"
 
-#ifdef _WIN32
-
-static BOOL module_initialized = FALSE;
-static BOOL module_available = FALSE;
-static HMODULE kernel32_module = NULL;
+#ifdef WINPR_THREAD_POOL
 
+#ifdef _WIN32
+static INIT_ONCE init_once_module = INIT_ONCE_STATIC_INIT;
 static PTP_POOL (WINAPI * pCreateThreadpool)(PVOID reserved);
 static VOID (WINAPI * pCloseThreadpool)(PTP_POOL ptpp);
 static BOOL (WINAPI * pSetThreadpoolThreadMinimum)(PTP_POOL ptpp, DWORD cthrdMic);
 static VOID (WINAPI * pSetThreadpoolThreadMaximum)(PTP_POOL ptpp, DWORD cthrdMost);
 
-static void module_init()
+static BOOL CALLBACK init_module(PINIT_ONCE once, PVOID param, PVOID *context)
 {
-       if (module_initialized)
-               return;
-
-       kernel32_module = LoadLibraryA("kernel32.dll");
-       module_initialized = TRUE;
-
-       if (!kernel32_module)
-               return;
-
-       module_available = TRUE;
-
-       pCreateThreadpool = (void*) GetProcAddress(kernel32_module, "CreateThreadpool");
-       pCloseThreadpool = (void*) GetProcAddress(kernel32_module, "CloseThreadpool");
-       pSetThreadpoolThreadMinimum = (void*) GetProcAddress(kernel32_module, "SetThreadpoolThreadMinimum");
-       pSetThreadpoolThreadMaximum = (void*) GetProcAddress(kernel32_module, "SetThreadpoolThreadMaximum");
+       HMODULE kernel32 = LoadLibraryA("kernel32.dll");
+       if (kernel32)
+       {
+               pCreateThreadpool = (void*)GetProcAddress(kernel32, "CreateThreadpool");
+               pCloseThreadpool = (void*)GetProcAddress(kernel32, "CloseThreadpool");
+               pSetThreadpoolThreadMinimum = (void*)GetProcAddress(kernel32, "SetThreadpoolThreadMinimum");
+               pSetThreadpoolThreadMaximum = (void*)GetProcAddress(kernel32, "SetThreadpoolThreadMaximum");
+       }
+       return TRUE;
 }
-
-#else
+#endif
 
 static TP_POOL DEFAULT_POOL =
 {
@@ -169,7 +160,6 @@ fail_countdown_event:
 fail_queue_new:
 
        return FALSE;
-
 }
 
 PTP_POOL GetDefaultThreadpool()
@@ -184,20 +174,14 @@ PTP_POOL GetDefaultThreadpool()
        return pool;
 }
 
-#endif
-
-#ifdef WINPR_THREAD_POOL
-
 PTP_POOL CreateThreadpool(PVOID reserved)
 {
        PTP_POOL pool = NULL;
-
 #ifdef _WIN32
-       module_init();
-
+       InitOnceExecuteOnce(&init_once_module, init_module, NULL, NULL);
        if (pCreateThreadpool)
                return pCreateThreadpool(reserved);
-#else
+#endif
        if (!(pool = (PTP_POOL) calloc(1, sizeof(TP_POOL))))
                return NULL;
 
@@ -206,7 +190,6 @@ PTP_POOL CreateThreadpool(PVOID reserved)
                free(pool);
                return NULL;
        }
-#endif
 
        return pool;
 }
@@ -214,11 +197,13 @@ PTP_POOL CreateThreadpool(PVOID reserved)
 VOID CloseThreadpool(PTP_POOL ptpp)
 {
 #ifdef _WIN32
-       module_init();
-
+       InitOnceExecuteOnce(&init_once_module, init_module, NULL, NULL);
        if (pCloseThreadpool)
+       {
                pCloseThreadpool(ptpp);
-#else
+               return;
+       }
+#endif
        SetEvent(ptpp->TerminateEvent);
 
        ArrayList_Free(ptpp->Threads);
@@ -237,19 +222,16 @@ VOID CloseThreadpool(PTP_POOL ptpp)
        {
                free(ptpp);
        }
-#endif
 }
 
 BOOL SetThreadpoolThreadMinimum(PTP_POOL ptpp, DWORD cthrdMic)
 {
+       HANDLE thread;
 #ifdef _WIN32
-       module_init();
-
+       InitOnceExecuteOnce(&init_once_module, init_module, NULL, NULL);
        if (pSetThreadpoolThreadMinimum)
                return pSetThreadpoolThreadMinimum(ptpp, cthrdMic);
-#else
-       HANDLE thread;
-
+#endif
        ptpp->Minimum = cthrdMic;
 
        while (ArrayList_Count(ptpp->Threads) < ptpp->Minimum)
@@ -264,27 +246,21 @@ BOOL SetThreadpoolThreadMinimum(PTP_POOL ptpp, DWORD cthrdMic)
                if (ArrayList_Add(ptpp->Threads, thread) < 0)
                        return FALSE;
        }
-#endif
+
        return TRUE;
 }
 
 VOID SetThreadpoolThreadMaximum(PTP_POOL ptpp, DWORD cthrdMost)
 {
 #ifdef _WIN32
-       module_init();
-
+       InitOnceExecuteOnce(&init_once_module, init_module, NULL, NULL);
        if (pSetThreadpoolThreadMaximum)
+       {
                pSetThreadpoolThreadMaximum(ptpp, cthrdMost);
-#else
-       ptpp->Maximum = cthrdMost;
+               return;
+       }
 #endif
+       ptpp->Maximum = cthrdMost;
 }
 
-#endif
-
-/* dummy */
-
-void winpr_pool_dummy()
-{
-
-}
+#endif /* WINPR_THREAD_POOL defined */
index 5c67528..e84635f 100644 (file)
@@ -67,12 +67,7 @@ struct _TP_CLEANUP_GROUP
        void* dummy;
 };
 
-#ifndef _WIN32
-
-PTP_POOL GetDefaultThreadpool(void);
-PTP_CALLBACK_ENVIRON GetDefaultThreadpoolEnvironment(void);
-
-#endif
+PTP_POOL GetDefaultThreadpool();
 
 #endif /* WINPR_POOL_PRIVATE_H */
 
index 08b4c9a..67c80da 100644 (file)
@@ -12,7 +12,7 @@ void CALLBACK test_WorkCallback(PTP_CALLBACK_INSTANCE instance, void* context, P
        BYTE b[1024];
        BYTE c[1024];
 
-       printf("Hello %s: %d (thread: %d)\n", (char*) context,
+       printf("Hello %s: %3d (thread: 0x%08X)\n", (char*) context,
                InterlockedIncrement(&count), GetCurrentThreadId());
 
        for (index = 0; index < 100; index++)
@@ -104,7 +104,16 @@ int TestPoolWork(int argc, char* argv[])
 
        DestroyThreadpoolEnvironment(&environment);
 
-       CloseThreadpoolWork(work);
+       /**
+        * See Remarks at https://msdn.microsoft.com/en-us/library/windows/desktop/ms682043(v=vs.85).aspx
+        * If there is a cleanup group associated with the work object,
+        * it is not necessary to call CloseThreadpoolWork !
+        * calling the CloseThreadpoolCleanupGroupMembers function releases the work, wait,
+        * and timer objects associated with the cleanup group.
+        */
+
+       /* CloseThreadpoolWork(work); // this would segfault, see comment above. */
+
        CloseThreadpool(pool);
 
        return 0;
index ab5328c..2e32d21 100644 (file)
 #include "../log.h"
 #define TAG WINPR_TAG("pool")
 
-#ifdef _WIN32
-
-static BOOL module_initialized = FALSE;
-static BOOL module_available = FALSE;
-static HMODULE kernel32_module = NULL;
+#ifdef WINPR_THREAD_POOL
 
+#ifdef _WIN32
+static INIT_ONCE init_once_module = INIT_ONCE_STATIC_INIT;
 static PTP_WORK(WINAPI* pCreateThreadpoolWork)(PTP_WORK_CALLBACK pfnwk, PVOID pv, PTP_CALLBACK_ENVIRON pcbe);
 static VOID (WINAPI* pCloseThreadpoolWork)(PTP_WORK pwk);
 static VOID (WINAPI* pSubmitThreadpoolWork)(PTP_WORK pwk);
 static BOOL (WINAPI* pTrySubmitThreadpoolCallback)(PTP_SIMPLE_CALLBACK pfns, PVOID pv, PTP_CALLBACK_ENVIRON pcbe);
 static VOID (WINAPI* pWaitForThreadpoolWorkCallbacks)(PTP_WORK pwk, BOOL fCancelPendingCallbacks);
 
-static void module_init()
+static BOOL CALLBACK init_module(PINIT_ONCE once, PVOID param, PVOID *context)
 {
-       if (module_initialized)
-               return;
-
-       kernel32_module = LoadLibraryA("kernel32.dll");
-       module_initialized = TRUE;
-
-       if (!kernel32_module)
-               return;
-
-       module_available = TRUE;
-       pCreateThreadpoolWork = (void*) GetProcAddress(kernel32_module, "CreateThreadpoolWork");
-       pCloseThreadpoolWork = (void*) GetProcAddress(kernel32_module, "CloseThreadpoolWork");
-       pSubmitThreadpoolWork = (void*) GetProcAddress(kernel32_module, "SubmitThreadpoolWork");
-       pTrySubmitThreadpoolCallback = (void*) GetProcAddress(kernel32_module, "TrySubmitThreadpoolCallback");
-       pWaitForThreadpoolWorkCallbacks = (void*) GetProcAddress(kernel32_module, "WaitForThreadpoolWorkCallbacks");
+       HMODULE kernel32 = LoadLibraryA("kernel32.dll");
+       if (kernel32)
+       {
+               pCreateThreadpoolWork = (void*)GetProcAddress(kernel32, "CreateThreadpoolWork");
+               pCloseThreadpoolWork = (void*)GetProcAddress(kernel32, "CloseThreadpoolWork");
+               pSubmitThreadpoolWork = (void*)GetProcAddress(kernel32, "SubmitThreadpoolWork");
+               pTrySubmitThreadpoolCallback = (void*)GetProcAddress(kernel32, "TrySubmitThreadpoolCallback");
+               pWaitForThreadpoolWorkCallbacks = (void*)GetProcAddress(kernel32, "WaitForThreadpoolWorkCallbacks");
+       }
+       return TRUE;
 }
-
 #endif
 
-#ifdef WINPR_THREAD_POOL
+static TP_CALLBACK_ENVIRON DEFAULT_CALLBACK_ENVIRONMENT =
+{
+       1, /* Version */
+       NULL, /* Pool */
+       NULL, /* CleanupGroup */
+       NULL, /* CleanupGroupCancelCallback */
+       NULL, /* RaceDll */
+       NULL, /* ActivationContext */
+       NULL, /* FinalizationCallback */
+       { 0 } /* Flags */
+};
 
 PTP_WORK CreateThreadpoolWork(PTP_WORK_CALLBACK pfnwk, PVOID pv, PTP_CALLBACK_ENVIRON pcbe)
 {
        PTP_WORK work = NULL;
 #ifdef _WIN32
-       module_init();
-
+       InitOnceExecuteOnce(&init_once_module, init_module, NULL, NULL);
        if (pCreateThreadpoolWork)
                return pCreateThreadpoolWork(pfnwk, pv, pcbe);
-
-#else
+#endif
        work = (PTP_WORK) malloc(sizeof(TP_WORK));
 
        if (work)
        {
-               work->WorkCallback = pfnwk;
-               work->CallbackParameter = pv;
-
                if (!pcbe)
-                       pcbe = GetDefaultThreadpoolEnvironment();
-
+               {
+                       pcbe = &DEFAULT_CALLBACK_ENVIRONMENT;
+                       pcbe->Pool = GetDefaultThreadpool();
+               }
                work->CallbackEnvironment = pcbe;
+               work->WorkCallback = pfnwk;
+               work->CallbackParameter = pv;
        }
 
-#endif
        return work;
 }
 
 VOID CloseThreadpoolWork(PTP_WORK pwk)
 {
 #ifdef _WIN32
-       module_init();
-
+       InitOnceExecuteOnce(&init_once_module, init_module, NULL, NULL);
        if (pCloseThreadpoolWork)
+       {
                pCloseThreadpoolWork(pwk);
-
-#else
-       free(pwk);
+               return;
+       }
 #endif
+       free(pwk);
 }
 
 VOID SubmitThreadpoolWork(PTP_WORK pwk)
 {
+       PTP_POOL pool;
+       PTP_CALLBACK_INSTANCE callbackInstance;
 #ifdef _WIN32
-       module_init();
-
+       InitOnceExecuteOnce(&init_once_module, init_module, NULL, NULL);
        if (pSubmitThreadpoolWork)
+       {
                pSubmitThreadpoolWork(pwk);
-
-#else
-       PTP_POOL pool;
-       PTP_CALLBACK_INSTANCE callbackInstance;
+               return;
+       }
+#endif
        pool = pwk->CallbackEnvironment->Pool;
        callbackInstance = (PTP_CALLBACK_INSTANCE) malloc(sizeof(TP_CALLBACK_INSTANCE));
 
@@ -124,41 +125,36 @@ VOID SubmitThreadpoolWork(PTP_WORK pwk)
                CountdownEvent_AddCount(pool->WorkComplete, 1);
                Queue_Enqueue(pool->PendingQueue, callbackInstance);
        }
-
-#endif
 }
 
 BOOL TrySubmitThreadpoolCallback(PTP_SIMPLE_CALLBACK pfns, PVOID pv, PTP_CALLBACK_ENVIRON pcbe)
 {
 #ifdef _WIN32
-       module_init();
-
+       InitOnceExecuteOnce(&init_once_module, init_module, NULL, NULL);
        if (pTrySubmitThreadpoolCallback)
                return pTrySubmitThreadpoolCallback(pfns, pv, pcbe);
-
-#else
 #endif
+       WLog_ERR(TAG, "TrySubmitThreadpoolCallback is not implemented");
        return FALSE;
 }
 
 VOID WaitForThreadpoolWorkCallbacks(PTP_WORK pwk, BOOL fCancelPendingCallbacks)
 {
+       HANDLE event;
+       PTP_POOL pool;
 #ifdef _WIN32
-       module_init();
-
+       InitOnceExecuteOnce(&init_once_module, init_module, NULL, NULL);
        if (pWaitForThreadpoolWorkCallbacks)
+       {
                pWaitForThreadpoolWorkCallbacks(pwk, fCancelPendingCallbacks);
-
-#else
-       HANDLE event;
-       PTP_POOL pool;
+               return;
+       }
+#endif
        pool = pwk->CallbackEnvironment->Pool;
        event = CountdownEvent_WaitHandle(pool->WorkComplete);
 
        if (WaitForSingleObject(event, INFINITE) != WAIT_OBJECT_0)
                WLog_ERR(TAG, "error waiting on work completion");
-
-#endif
 }
 
-#endif
+#endif /* WINPR_THREAD_POOL defined */
index bc2f3de..fe2fdfe 100644 (file)
@@ -247,48 +247,3 @@ VOID DeleteCriticalSection(LPCRITICAL_SECTION lpCriticalSection)
 }
 
 #endif
-
-#ifdef WINPR_INITIALIZE_CRITICAL_SECTION_EX
-
-typedef BOOL (WINAPI* PINITIALIZE_CRITICAL_SECTION_EX_FN)(LPCRITICAL_SECTION lpCriticalSection, DWORD dwSpinCount, DWORD Flags);
-
-static HMODULE g_KERNEL32_Library = NULL;
-static BOOL g_InitializeCriticalSectionEx_Detected = FALSE;
-static BOOL g_InitializeCriticalSectionEx_Available = FALSE;
-static PINITIALIZE_CRITICAL_SECTION_EX_FN g_pInitializeCriticalSectionEx = NULL;
-
-BOOL InitializeCriticalSectionEx(LPCRITICAL_SECTION lpCriticalSection, DWORD dwSpinCount, DWORD Flags)
-{
-       if (!g_InitializeCriticalSectionEx_Detected)
-       {
-               g_KERNEL32_Library = LoadLibrary(_T("kernel32.dll"));
-
-               if (g_KERNEL32_Library)
-               {
-                       g_pInitializeCriticalSectionEx = (PINITIALIZE_CRITICAL_SECTION_EX_FN)
-                                                                                        GetProcAddress(g_KERNEL32_Library, "InitializeCriticalSectionEx");
-                       g_InitializeCriticalSectionEx_Available = (g_pInitializeCriticalSectionEx) ? TRUE : FALSE;
-               }
-               else
-               {
-                       g_InitializeCriticalSectionEx_Available = FALSE;
-               }
-
-               g_InitializeCriticalSectionEx_Detected = TRUE;
-       }
-
-       if (g_InitializeCriticalSectionEx_Available)
-       {
-               /* Vista and later */
-               return (*g_pInitializeCriticalSectionEx)(lpCriticalSection, dwSpinCount, Flags);
-       }
-       else
-       {
-               /* Windows XP */
-               InitializeCriticalSection(lpCriticalSection);
-       }
-
-       return TRUE;
-}
-
-#endif