winpr: several pool and synch fixes

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
This commit is contained in:
Norbert Federa 2016-06-04 17:04:12 +02:00
parent 8ea8b7c780
commit c16bee759f
13 changed files with 227 additions and 545 deletions

View 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
typedef TP_CALLBACK_ENVIRON_V1 TP_CALLBACK_ENVIRON, *PTP_CALLBACK_ENVIRON;
/* 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;
#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 */

View 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

View 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);

View File

@ -23,7 +23,6 @@ winpr_module_add(
cleanup_group.c
pool.c
pool.h
callback_environment.c
callback.c
callback_cleanup.c)

View File

@ -25,44 +25,32 @@
#include <winpr/pool.h>
#include <winpr/library.h>
#ifdef WINPR_THREAD_POOL
#ifdef _WIN32
static BOOL module_initialized = FALSE;
static BOOL module_available = FALSE;
static HMODULE kernel32_module = NULL;
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 */

View File

@ -27,12 +27,10 @@
#include "pool.h"
#ifdef WINPR_THREAD_POOL
#ifdef _WIN32
static BOOL module_initialized = FALSE;
static BOOL module_available = FALSE;
static HMODULE kernel32_module = NULL;
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 */

View File

@ -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

View File

@ -27,75 +27,64 @@
#include "pool.h"
#ifdef WINPR_THREAD_POOL
#ifdef _WIN32
static BOOL module_initialized = FALSE;
static BOOL module_available = FALSE;
static HMODULE kernel32_module = NULL;
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 */

View File

@ -27,37 +27,28 @@
#include "pool.h"
#ifdef WINPR_THREAD_POOL
#ifdef _WIN32
static BOOL module_initialized = FALSE;
static BOOL module_available = FALSE;
static HMODULE kernel32_module = NULL;
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
return;
}
#endif
ptpp->Maximum = cthrdMost;
#endif
}
#endif
/* dummy */
void winpr_pool_dummy()
{
}
#endif /* WINPR_THREAD_POOL defined */

View 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 */

View 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;

View File

@ -29,92 +29,93 @@
#include "../log.h"
#define TAG WINPR_TAG("pool")
#ifdef WINPR_THREAD_POOL
#ifdef _WIN32
static BOOL module_initialized = FALSE;
static BOOL module_available = FALSE;
static HMODULE kernel32_module = NULL;
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)
{
if (!pcbe)
{
pcbe = &DEFAULT_CALLBACK_ENVIRONMENT;
pcbe->Pool = GetDefaultThreadpool();
}
work->CallbackEnvironment = pcbe;
work->WorkCallback = pfnwk;
work->CallbackParameter = pv;
if (!pcbe)
pcbe = GetDefaultThreadpoolEnvironment();
work->CallbackEnvironment = pcbe;
}
#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)
{
#ifdef _WIN32
module_init();
if (pSubmitThreadpoolWork)
pSubmitThreadpoolWork(pwk);
#else
PTP_POOL pool;
PTP_CALLBACK_INSTANCE callbackInstance;
#ifdef _WIN32
InitOnceExecuteOnce(&init_once_module, init_module, NULL, NULL);
if (pSubmitThreadpoolWork)
{
pSubmitThreadpoolWork(pwk);
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)
{
#ifdef _WIN32
module_init();
if (pWaitForThreadpoolWorkCallbacks)
pWaitForThreadpoolWorkCallbacks(pwk, fCancelPendingCallbacks);
#else
HANDLE event;
PTP_POOL pool;
#ifdef _WIN32
InitOnceExecuteOnce(&init_once_module, init_module, NULL, NULL);
if (pWaitForThreadpoolWorkCallbacks)
{
pWaitForThreadpoolWorkCallbacks(pwk, fCancelPendingCallbacks);
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 */

View 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