Milestone 5: deliver embedded RDP sessions and lifecycle hardening
This commit is contained in:
38
third_party/FreeRDP/winpr/libwinpr/pool/CMakeLists.txt
vendored
Normal file
38
third_party/FreeRDP/winpr/libwinpr/pool/CMakeLists.txt
vendored
Normal file
@@ -0,0 +1,38 @@
|
||||
# WinPR: Windows Portable Runtime
|
||||
# libwinpr-pool cmake build script
|
||||
#
|
||||
# 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.
|
||||
|
||||
set(WINPR_THREADPOOL_DEFAULT_MAX_COUNT "16" CACHE STRING "The maximum (default) number of threads in a pool")
|
||||
set(WINPR_THREADPOOL_DEFAULT_MIN_COUNT "4" CACHE STRING "The minimum (default) number of threads in a pool")
|
||||
winpr_definition_add(WINPR_THREADPOOL_DEFAULT_MAX_COUNT=${WINPR_THREADPOOL_DEFAULT_MAX_COUNT})
|
||||
winpr_definition_add(WINPR_THREADPOOL_DEFAULT_MIN_COUNT=${WINPR_THREADPOOL_DEFAULT_MIN_COUNT})
|
||||
winpr_module_add(
|
||||
synch.c
|
||||
work.c
|
||||
timer.c
|
||||
io.c
|
||||
cleanup_group.c
|
||||
pool.c
|
||||
pool.h
|
||||
callback.c
|
||||
callback_cleanup.c
|
||||
)
|
||||
|
||||
winpr_library_add_private(${CMAKE_THREAD_LIBS_INIT} ${CMAKE_DL_LIBS})
|
||||
|
||||
if(BUILD_TESTING_INTERNAL OR BUILD_TESTING)
|
||||
add_subdirectory(test)
|
||||
endif()
|
||||
9
third_party/FreeRDP/winpr/libwinpr/pool/ModuleOptions.cmake
vendored
Normal file
9
third_party/FreeRDP/winpr/libwinpr/pool/ModuleOptions.cmake
vendored
Normal file
@@ -0,0 +1,9 @@
|
||||
set(MINWIN_LAYER "1")
|
||||
set(MINWIN_GROUP "core")
|
||||
set(MINWIN_MAJOR_VERSION "2")
|
||||
set(MINWIN_MINOR_VERSION "1")
|
||||
set(MINWIN_SHORT_NAME "threadpool")
|
||||
set(MINWIN_LONG_NAME "Thread Pool API")
|
||||
set(MODULE_LIBRARY_NAME
|
||||
"api-ms-win-${MINWIN_GROUP}-${MINWIN_SHORT_NAME}-l${MINWIN_LAYER}-${MINWIN_MAJOR_VERSION}-${MINWIN_MINOR_VERSION}"
|
||||
)
|
||||
57
third_party/FreeRDP/winpr/libwinpr/pool/callback.c
vendored
Normal file
57
third_party/FreeRDP/winpr/libwinpr/pool/callback.c
vendored
Normal file
@@ -0,0 +1,57 @@
|
||||
/**
|
||||
* WinPR: Windows Portable Runtime
|
||||
* Thread Pool API (Callback)
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#include <winpr/config.h>
|
||||
|
||||
#include <winpr/crt.h>
|
||||
#include <winpr/pool.h>
|
||||
#include <winpr/wlog.h>
|
||||
#include <winpr/library.h>
|
||||
|
||||
#ifdef WINPR_THREAD_POOL
|
||||
|
||||
#ifdef _WIN32
|
||||
typedef BOOL(WINAPI* pCallbackMayRunLong_t)(PTP_CALLBACK_INSTANCE pci);
|
||||
static INIT_ONCE init_once_module = INIT_ONCE_STATIC_INIT;
|
||||
static pCallbackMayRunLong_t pCallbackMayRunLong = nullptr;
|
||||
|
||||
static BOOL CALLBACK init_module(PINIT_ONCE once, PVOID param, PVOID* context)
|
||||
{
|
||||
HMODULE kernel32 = LoadLibraryA("kernel32.dll");
|
||||
if (kernel32)
|
||||
pCallbackMayRunLong =
|
||||
GetProcAddressAs(kernel32, "CallbackMayRunLong", pCallbackMayRunLong_t);
|
||||
return TRUE;
|
||||
}
|
||||
#endif
|
||||
|
||||
BOOL winpr_CallbackMayRunLong(WINPR_ATTR_UNUSED PTP_CALLBACK_INSTANCE pci)
|
||||
{
|
||||
#ifdef _WIN32
|
||||
if (!InitOnceExecuteOnce(&init_once_module, init_module, nullptr, nullptr))
|
||||
return FALSE;
|
||||
if (pCallbackMayRunLong)
|
||||
return pCallbackMayRunLong(pci);
|
||||
#endif
|
||||
WLog_ERR("TODO", "TODO: implement");
|
||||
/* No default implementation */
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
#endif /* WINPR_THREAD_POOL defined */
|
||||
157
third_party/FreeRDP/winpr/libwinpr/pool/callback_cleanup.c
vendored
Normal file
157
third_party/FreeRDP/winpr/libwinpr/pool/callback_cleanup.c
vendored
Normal file
@@ -0,0 +1,157 @@
|
||||
/**
|
||||
* WinPR: Windows Portable Runtime
|
||||
* Thread Pool API (Callback Clean-up)
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#include <winpr/config.h>
|
||||
|
||||
#include <winpr/crt.h>
|
||||
#include <winpr/pool.h>
|
||||
#include <winpr/library.h>
|
||||
|
||||
#include "pool.h"
|
||||
|
||||
#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);
|
||||
static VOID(WINAPI* pLeaveCriticalSectionWhenCallbackReturns)(PTP_CALLBACK_INSTANCE pci,
|
||||
PCRITICAL_SECTION pcs);
|
||||
static VOID(WINAPI* pFreeLibraryWhenCallbackReturns)(PTP_CALLBACK_INSTANCE pci, HMODULE mod);
|
||||
static VOID(WINAPI* pDisassociateCurrentThreadFromCallback)(PTP_CALLBACK_INSTANCE pci);
|
||||
|
||||
static BOOL CALLBACK init_module(PINIT_ONCE once, PVOID param, PVOID* context)
|
||||
{
|
||||
HMODULE kernel32 = LoadLibraryA("kernel32.dll");
|
||||
if (kernel32)
|
||||
{
|
||||
pSetEventWhenCallbackReturns =
|
||||
GetProcAddressAs(kernel32, "SetEventWhenCallbackReturns"), void*);
|
||||
pReleaseSemaphoreWhenCallbackReturns =
|
||||
GetProcAddressAs(kernel32, "ReleaseSemaphoreWhenCallbackReturns", void*);
|
||||
pReleaseMutexWhenCallbackReturns =
|
||||
GetProcAddressAs(kernel32, "ReleaseMutexWhenCallbackReturns", void*);
|
||||
pLeaveCriticalSectionWhenCallbackReturns =
|
||||
GetProcAddressAs(kernel32, "LeaveCriticalSectionWhenCallbackReturns", void*);
|
||||
pFreeLibraryWhenCallbackReturns =
|
||||
GetProcAddressAs(kernel32, "FreeLibraryWhenCallbackReturns", void*);
|
||||
pDisassociateCurrentThreadFromCallback =
|
||||
GetProcAddressAs(kernel32, "DisassociateCurrentThreadFromCallback", void*);
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
#endif
|
||||
|
||||
VOID SetEventWhenCallbackReturns(WINPR_ATTR_UNUSED PTP_CALLBACK_INSTANCE pci,
|
||||
WINPR_ATTR_UNUSED HANDLE evt)
|
||||
{
|
||||
#ifdef _WIN32
|
||||
if (!InitOnceExecuteOnce(&init_once_module, init_module, nullptr, nullptr))
|
||||
return;
|
||||
if (pSetEventWhenCallbackReturns)
|
||||
{
|
||||
pSetEventWhenCallbackReturns(pci, evt);
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
WLog_ERR("TODO", "TODO: implement");
|
||||
/* No default implementation */
|
||||
}
|
||||
|
||||
VOID ReleaseSemaphoreWhenCallbackReturns(WINPR_ATTR_UNUSED PTP_CALLBACK_INSTANCE pci,
|
||||
WINPR_ATTR_UNUSED HANDLE sem, WINPR_ATTR_UNUSED DWORD crel)
|
||||
{
|
||||
#ifdef _WIN32
|
||||
if (!InitOnceExecuteOnce(&init_once_module, init_module, nullptr, nullptr))
|
||||
return;
|
||||
if (pReleaseSemaphoreWhenCallbackReturns)
|
||||
{
|
||||
pReleaseSemaphoreWhenCallbackReturns(pci, sem, crel);
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
/* No default implementation */
|
||||
WLog_ERR("TODO", "TODO: implement");
|
||||
}
|
||||
|
||||
VOID ReleaseMutexWhenCallbackReturns(WINPR_ATTR_UNUSED PTP_CALLBACK_INSTANCE pci,
|
||||
WINPR_ATTR_UNUSED HANDLE mut)
|
||||
{
|
||||
#ifdef _WIN32
|
||||
if (!InitOnceExecuteOnce(&init_once_module, init_module, nullptr, nullptr))
|
||||
return;
|
||||
if (pReleaseMutexWhenCallbackReturns)
|
||||
{
|
||||
pReleaseMutexWhenCallbackReturns(pci, mut);
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
/* No default implementation */
|
||||
WLog_ERR("TODO", "TODO: implement");
|
||||
}
|
||||
|
||||
VOID LeaveCriticalSectionWhenCallbackReturns(WINPR_ATTR_UNUSED PTP_CALLBACK_INSTANCE pci,
|
||||
WINPR_ATTR_UNUSED PCRITICAL_SECTION pcs)
|
||||
{
|
||||
#ifdef _WIN32
|
||||
if (!InitOnceExecuteOnce(&init_once_module, init_module, nullptr, nullptr))
|
||||
return;
|
||||
if (pLeaveCriticalSectionWhenCallbackReturns)
|
||||
{
|
||||
pLeaveCriticalSectionWhenCallbackReturns(pci, pcs);
|
||||
}
|
||||
#endif
|
||||
/* No default implementation */
|
||||
WLog_ERR("TODO", "TODO: implement");
|
||||
}
|
||||
|
||||
VOID FreeLibraryWhenCallbackReturns(WINPR_ATTR_UNUSED PTP_CALLBACK_INSTANCE pci,
|
||||
WINPR_ATTR_UNUSED HMODULE mod)
|
||||
{
|
||||
#ifdef _WIN32
|
||||
if (!InitOnceExecuteOnce(&init_once_module, init_module, nullptr, nullptr))
|
||||
return;
|
||||
if (pFreeLibraryWhenCallbackReturns)
|
||||
{
|
||||
pFreeLibraryWhenCallbackReturns(pci, mod);
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
/* No default implementation */
|
||||
WLog_ERR("TODO", "TODO: implement");
|
||||
}
|
||||
|
||||
VOID DisassociateCurrentThreadFromCallback(WINPR_ATTR_UNUSED PTP_CALLBACK_INSTANCE pci)
|
||||
{
|
||||
#ifdef _WIN32
|
||||
if (!InitOnceExecuteOnce(&init_once_module, init_module, nullptr, nullptr))
|
||||
return;
|
||||
if (pDisassociateCurrentThreadFromCallback)
|
||||
{
|
||||
pDisassociateCurrentThreadFromCallback(pci);
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
WLog_ERR("TODO", "TODO: implement");
|
||||
/* No default implementation */
|
||||
}
|
||||
|
||||
#endif /* WINPR_THREAD_POOL defined */
|
||||
145
third_party/FreeRDP/winpr/libwinpr/pool/cleanup_group.c
vendored
Normal file
145
third_party/FreeRDP/winpr/libwinpr/pool/cleanup_group.c
vendored
Normal file
@@ -0,0 +1,145 @@
|
||||
/**
|
||||
* WinPR: Windows Portable Runtime
|
||||
* Thread Pool API (Clean-up Group)
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#include <winpr/config.h>
|
||||
|
||||
#include <winpr/winpr.h>
|
||||
#include <winpr/crt.h>
|
||||
#include <winpr/pool.h>
|
||||
#include <winpr/library.h>
|
||||
|
||||
#include "pool.h"
|
||||
|
||||
#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 BOOL CALLBACK init_module(PINIT_ONCE once, PVOID param, PVOID* context)
|
||||
{
|
||||
HMODULE kernel32 = LoadLibraryA("kernel32.dll");
|
||||
|
||||
if (kernel32)
|
||||
{
|
||||
pCreateThreadpoolCleanupGroup =
|
||||
GetProcAddressAs(kernel32, "CreateThreadpoolCleanupGroup", void*);
|
||||
pCloseThreadpoolCleanupGroupMembers =
|
||||
GetProcAddressAs(kernel32, "CloseThreadpoolCleanupGroupMembers", void*);
|
||||
pCloseThreadpoolCleanupGroup =
|
||||
GetProcAddressAs(kernel32, "CloseThreadpoolCleanupGroup", void*);
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
#endif
|
||||
|
||||
PTP_CLEANUP_GROUP winpr_CreateThreadpoolCleanupGroup(void)
|
||||
{
|
||||
PTP_CLEANUP_GROUP cleanupGroup = nullptr;
|
||||
#ifdef _WIN32
|
||||
if (!InitOnceExecuteOnce(&init_once_module, init_module, nullptr, nullptr))
|
||||
return nullptr;
|
||||
|
||||
if (pCreateThreadpoolCleanupGroup)
|
||||
return pCreateThreadpoolCleanupGroup();
|
||||
|
||||
return cleanupGroup;
|
||||
#else
|
||||
cleanupGroup = (PTP_CLEANUP_GROUP)calloc(1, sizeof(TP_CLEANUP_GROUP));
|
||||
|
||||
if (!cleanupGroup)
|
||||
return nullptr;
|
||||
|
||||
cleanupGroup->groups = ArrayList_New(FALSE);
|
||||
|
||||
if (!cleanupGroup->groups)
|
||||
{
|
||||
free(cleanupGroup);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return cleanupGroup;
|
||||
#endif
|
||||
}
|
||||
|
||||
VOID winpr_SetThreadpoolCallbackCleanupGroup(PTP_CALLBACK_ENVIRON pcbe, PTP_CLEANUP_GROUP ptpcg,
|
||||
PTP_CLEANUP_GROUP_CANCEL_CALLBACK pfng)
|
||||
{
|
||||
pcbe->CleanupGroup = ptpcg;
|
||||
pcbe->CleanupGroupCancelCallback = pfng;
|
||||
#ifndef _WIN32
|
||||
pcbe->CleanupGroup->env = pcbe;
|
||||
#endif
|
||||
}
|
||||
|
||||
VOID winpr_CloseThreadpoolCleanupGroupMembers(WINPR_ATTR_UNUSED PTP_CLEANUP_GROUP ptpcg,
|
||||
WINPR_ATTR_UNUSED BOOL fCancelPendingCallbacks,
|
||||
WINPR_ATTR_UNUSED PVOID pvCleanupContext)
|
||||
{
|
||||
#ifdef _WIN32
|
||||
if (!InitOnceExecuteOnce(&init_once_module, init_module, nullptr, nullptr))
|
||||
return;
|
||||
|
||||
if (pCloseThreadpoolCleanupGroupMembers)
|
||||
{
|
||||
pCloseThreadpoolCleanupGroupMembers(ptpcg, fCancelPendingCallbacks, pvCleanupContext);
|
||||
return;
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
while (ArrayList_Count(ptpcg->groups) > 0)
|
||||
{
|
||||
PTP_WORK work = ArrayList_GetItem(ptpcg->groups, 0);
|
||||
winpr_CloseThreadpoolWork(work);
|
||||
}
|
||||
|
||||
#endif
|
||||
}
|
||||
|
||||
VOID winpr_CloseThreadpoolCleanupGroup(PTP_CLEANUP_GROUP ptpcg)
|
||||
{
|
||||
#ifdef _WIN32
|
||||
if (!InitOnceExecuteOnce(&init_once_module, init_module, nullptr, nullptr))
|
||||
return;
|
||||
|
||||
if (pCloseThreadpoolCleanupGroup)
|
||||
{
|
||||
pCloseThreadpoolCleanupGroup(ptpcg);
|
||||
return;
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
if (ptpcg && ptpcg->groups)
|
||||
ArrayList_Free(ptpcg->groups);
|
||||
|
||||
if (ptpcg && ptpcg->env)
|
||||
ptpcg->env->CleanupGroup = nullptr;
|
||||
|
||||
free(ptpcg);
|
||||
#endif
|
||||
}
|
||||
|
||||
#endif /* WINPR_THREAD_POOL defined */
|
||||
58
third_party/FreeRDP/winpr/libwinpr/pool/io.c
vendored
Normal file
58
third_party/FreeRDP/winpr/libwinpr/pool/io.c
vendored
Normal file
@@ -0,0 +1,58 @@
|
||||
/**
|
||||
* WinPR: Windows Portable Runtime
|
||||
* Thread Pool API (I/O)
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#include <winpr/config.h>
|
||||
|
||||
#include <winpr/crt.h>
|
||||
#include <winpr/pool.h>
|
||||
#include <winpr/wlog.h>
|
||||
|
||||
#ifdef WINPR_THREAD_POOL
|
||||
|
||||
PTP_IO winpr_CreateThreadpoolIo(WINPR_ATTR_UNUSED HANDLE fl,
|
||||
WINPR_ATTR_UNUSED PTP_WIN32_IO_CALLBACK pfnio,
|
||||
WINPR_ATTR_UNUSED PVOID pv,
|
||||
WINPR_ATTR_UNUSED PTP_CALLBACK_ENVIRON pcbe)
|
||||
{
|
||||
WLog_ERR("TODO", "TODO: Implement");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
VOID winpr_CloseThreadpoolIo(WINPR_ATTR_UNUSED PTP_IO pio)
|
||||
{
|
||||
WLog_ERR("TODO", "TODO: Implement");
|
||||
}
|
||||
|
||||
VOID winpr_StartThreadpoolIo(WINPR_ATTR_UNUSED PTP_IO pio)
|
||||
{
|
||||
WLog_ERR("TODO", "TODO: Implement");
|
||||
}
|
||||
|
||||
VOID winpr_CancelThreadpoolIo(WINPR_ATTR_UNUSED PTP_IO pio)
|
||||
{
|
||||
WLog_ERR("TODO", "TODO: Implement");
|
||||
}
|
||||
|
||||
VOID winpr_WaitForThreadpoolIoCallbacks(WINPR_ATTR_UNUSED PTP_IO pio,
|
||||
WINPR_ATTR_UNUSED BOOL fCancelPendingCallbacks)
|
||||
{
|
||||
WLog_ERR("TODO", "TODO: Implement");
|
||||
}
|
||||
|
||||
#endif
|
||||
278
third_party/FreeRDP/winpr/libwinpr/pool/pool.c
vendored
Normal file
278
third_party/FreeRDP/winpr/libwinpr/pool/pool.c
vendored
Normal file
@@ -0,0 +1,278 @@
|
||||
/**
|
||||
* WinPR: Windows Portable Runtime
|
||||
* Thread Pool API (Pool)
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#include <winpr/config.h>
|
||||
|
||||
#include <winpr/crt.h>
|
||||
#include <winpr/sysinfo.h>
|
||||
#include <winpr/pool.h>
|
||||
#include <winpr/library.h>
|
||||
|
||||
#include "pool.h"
|
||||
|
||||
#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 BOOL CALLBACK init_module(PINIT_ONCE once, PVOID param, PVOID* context)
|
||||
{
|
||||
HMODULE kernel32 = LoadLibraryA("kernel32.dll");
|
||||
if (kernel32)
|
||||
{
|
||||
pCreateThreadpool = GetProcAddressAs(kernel32, "CreateThreadpool", void*);
|
||||
pCloseThreadpool = GetProcAddressAs(kernel32, "CloseThreadpool", void*);
|
||||
pSetThreadpoolThreadMinimum =
|
||||
GetProcAddressAs(kernel32, "SetThreadpoolThreadMinimum", void*);
|
||||
pSetThreadpoolThreadMaximum =
|
||||
GetProcAddressAs(kernel32, "SetThreadpoolThreadMaximum", void*);
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
#endif
|
||||
|
||||
static TP_POOL DEFAULT_POOL = {
|
||||
0, /* DWORD Minimum */
|
||||
500, /* DWORD Maximum */
|
||||
nullptr, /* wArrayList* Threads */
|
||||
nullptr, /* wQueue* PendingQueue */
|
||||
nullptr, /* HANDLE TerminateEvent */
|
||||
nullptr, /* wCountdownEvent* WorkComplete */
|
||||
};
|
||||
|
||||
static DWORD WINAPI thread_pool_work_func(LPVOID arg)
|
||||
{
|
||||
DWORD status = 0;
|
||||
PTP_POOL pool = nullptr;
|
||||
PTP_WORK work = nullptr;
|
||||
HANDLE events[2];
|
||||
PTP_CALLBACK_INSTANCE callbackInstance = nullptr;
|
||||
|
||||
pool = (PTP_POOL)arg;
|
||||
|
||||
events[0] = pool->TerminateEvent;
|
||||
events[1] = Queue_Event(pool->PendingQueue);
|
||||
|
||||
while (1)
|
||||
{
|
||||
status = WaitForMultipleObjects(2, events, FALSE, INFINITE);
|
||||
|
||||
if (status == WAIT_OBJECT_0)
|
||||
break;
|
||||
|
||||
if (status != (WAIT_OBJECT_0 + 1))
|
||||
break;
|
||||
|
||||
callbackInstance = (PTP_CALLBACK_INSTANCE)Queue_Dequeue(pool->PendingQueue);
|
||||
|
||||
if (callbackInstance)
|
||||
{
|
||||
work = callbackInstance->Work;
|
||||
work->WorkCallback(callbackInstance, work->CallbackParameter, work);
|
||||
CountdownEvent_Signal(pool->WorkComplete, 1);
|
||||
free(callbackInstance);
|
||||
}
|
||||
}
|
||||
|
||||
ExitThread(0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void threads_close(void* thread)
|
||||
{
|
||||
(void)WaitForSingleObject(thread, INFINITE);
|
||||
(void)CloseHandle(thread);
|
||||
}
|
||||
|
||||
static BOOL InitializeThreadpool(PTP_POOL pool)
|
||||
{
|
||||
BOOL rc = FALSE;
|
||||
wObject* obj = nullptr;
|
||||
|
||||
if (pool->Threads)
|
||||
return TRUE;
|
||||
|
||||
if (!(pool->PendingQueue = Queue_New(TRUE, -1, -1)))
|
||||
goto fail;
|
||||
|
||||
if (!(pool->WorkComplete = CountdownEvent_New(0)))
|
||||
goto fail;
|
||||
|
||||
if (!(pool->TerminateEvent = CreateEvent(nullptr, TRUE, FALSE, nullptr)))
|
||||
goto fail;
|
||||
|
||||
if (!(pool->Threads = ArrayList_New(TRUE)))
|
||||
goto fail;
|
||||
|
||||
obj = ArrayList_Object(pool->Threads);
|
||||
obj->fnObjectFree = threads_close;
|
||||
|
||||
#if !defined(WINPR_THREADPOOL_DEFAULT_MIN_COUNT)
|
||||
#error "WINPR_THREADPOOL_DEFAULT_MIN_COUNT must be defined"
|
||||
#endif
|
||||
#if !defined(WINPR_THREADPOOL_DEFAULT_MAX_COUNT)
|
||||
#error "WINPR_THREADPOOL_DEFAULT_MAX_COUNT must be defined"
|
||||
#endif
|
||||
|
||||
{
|
||||
SYSTEM_INFO info = WINPR_C_ARRAY_INIT;
|
||||
GetSystemInfo(&info);
|
||||
|
||||
DWORD min = info.dwNumberOfProcessors;
|
||||
DWORD max = info.dwNumberOfProcessors;
|
||||
if (info.dwNumberOfProcessors < WINPR_THREADPOOL_DEFAULT_MIN_COUNT)
|
||||
min = WINPR_THREADPOOL_DEFAULT_MIN_COUNT;
|
||||
if (info.dwNumberOfProcessors > WINPR_THREADPOOL_DEFAULT_MAX_COUNT)
|
||||
max = WINPR_THREADPOOL_DEFAULT_MAX_COUNT;
|
||||
if (min > max)
|
||||
min = max;
|
||||
|
||||
if (!SetThreadpoolThreadMinimum(pool, min))
|
||||
goto fail;
|
||||
|
||||
SetThreadpoolThreadMaximum(pool, max);
|
||||
}
|
||||
|
||||
rc = TRUE;
|
||||
|
||||
fail:
|
||||
return rc;
|
||||
}
|
||||
|
||||
PTP_POOL GetDefaultThreadpool(void)
|
||||
{
|
||||
PTP_POOL pool = &DEFAULT_POOL;
|
||||
|
||||
if (!InitializeThreadpool(pool))
|
||||
return nullptr;
|
||||
|
||||
return pool;
|
||||
}
|
||||
|
||||
PTP_POOL winpr_CreateThreadpool(PVOID reserved)
|
||||
{
|
||||
PTP_POOL pool = nullptr;
|
||||
#ifdef _WIN32
|
||||
if (!InitOnceExecuteOnce(&init_once_module, init_module, nullptr, nullptr))
|
||||
return nullptr;
|
||||
if (pCreateThreadpool)
|
||||
return pCreateThreadpool(reserved);
|
||||
#else
|
||||
WINPR_UNUSED(reserved);
|
||||
#endif
|
||||
if (!(pool = (PTP_POOL)calloc(1, sizeof(TP_POOL))))
|
||||
return nullptr;
|
||||
|
||||
if (!InitializeThreadpool(pool))
|
||||
{
|
||||
winpr_CloseThreadpool(pool);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return pool;
|
||||
}
|
||||
|
||||
VOID winpr_CloseThreadpool(PTP_POOL ptpp)
|
||||
{
|
||||
#ifdef _WIN32
|
||||
if (!InitOnceExecuteOnce(&init_once_module, init_module, nullptr, nullptr))
|
||||
return;
|
||||
if (pCloseThreadpool)
|
||||
{
|
||||
pCloseThreadpool(ptpp);
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
(void)SetEvent(ptpp->TerminateEvent);
|
||||
|
||||
ArrayList_Free(ptpp->Threads);
|
||||
Queue_Free(ptpp->PendingQueue);
|
||||
CountdownEvent_Free(ptpp->WorkComplete);
|
||||
(void)CloseHandle(ptpp->TerminateEvent);
|
||||
|
||||
{
|
||||
TP_POOL empty = WINPR_C_ARRAY_INIT;
|
||||
*ptpp = empty;
|
||||
}
|
||||
|
||||
if (ptpp != &DEFAULT_POOL)
|
||||
free(ptpp);
|
||||
}
|
||||
|
||||
BOOL winpr_SetThreadpoolThreadMinimum(PTP_POOL ptpp, DWORD cthrdMic)
|
||||
{
|
||||
BOOL rc = FALSE;
|
||||
#ifdef _WIN32
|
||||
if (!InitOnceExecuteOnce(&init_once_module, init_module, nullptr, nullptr))
|
||||
return FALSE;
|
||||
if (pSetThreadpoolThreadMinimum)
|
||||
return pSetThreadpoolThreadMinimum(ptpp, cthrdMic);
|
||||
#endif
|
||||
ptpp->Minimum = cthrdMic;
|
||||
|
||||
ArrayList_Lock(ptpp->Threads);
|
||||
while (ArrayList_Count(ptpp->Threads) < ptpp->Minimum)
|
||||
{
|
||||
HANDLE thread = CreateThread(nullptr, 0, thread_pool_work_func, (void*)ptpp, 0, nullptr);
|
||||
if (!thread)
|
||||
goto fail;
|
||||
|
||||
if (!ArrayList_Append(ptpp->Threads, thread))
|
||||
{
|
||||
(void)CloseHandle(thread);
|
||||
goto fail;
|
||||
}
|
||||
}
|
||||
|
||||
rc = TRUE;
|
||||
fail:
|
||||
ArrayList_Unlock(ptpp->Threads);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
VOID winpr_SetThreadpoolThreadMaximum(PTP_POOL ptpp, DWORD cthrdMost)
|
||||
{
|
||||
#ifdef _WIN32
|
||||
if (!InitOnceExecuteOnce(&init_once_module, init_module, nullptr, nullptr))
|
||||
return;
|
||||
if (pSetThreadpoolThreadMaximum)
|
||||
{
|
||||
pSetThreadpoolThreadMaximum(ptpp, cthrdMost);
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
ptpp->Maximum = cthrdMost;
|
||||
|
||||
ArrayList_Lock(ptpp->Threads);
|
||||
if (ArrayList_Count(ptpp->Threads) > ptpp->Maximum)
|
||||
{
|
||||
(void)SetEvent(ptpp->TerminateEvent);
|
||||
ArrayList_Clear(ptpp->Threads);
|
||||
(void)ResetEvent(ptpp->TerminateEvent);
|
||||
}
|
||||
ArrayList_Unlock(ptpp->Threads);
|
||||
winpr_SetThreadpoolThreadMinimum(ptpp, ptpp->Minimum);
|
||||
}
|
||||
|
||||
#endif /* WINPR_THREAD_POOL defined */
|
||||
122
third_party/FreeRDP/winpr/libwinpr/pool/pool.h
vendored
Normal file
122
third_party/FreeRDP/winpr/libwinpr/pool/pool.h
vendored
Normal file
@@ -0,0 +1,122 @@
|
||||
/**
|
||||
* WinPR: Windows Portable Runtime
|
||||
* Thread Pool API (Pool)
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef WINPR_POOL_PRIVATE_H
|
||||
#define WINPR_POOL_PRIVATE_H
|
||||
|
||||
#include <winpr/windows.h>
|
||||
#include <winpr/pool.h>
|
||||
#include <winpr/synch.h>
|
||||
#include <winpr/thread.h>
|
||||
#include <winpr/collections.h>
|
||||
|
||||
#if defined(_WIN32)
|
||||
#if (_WIN32_WINNT < _WIN32_WINNT_WIN6) || defined(__MINGW32__)
|
||||
struct S_TP_CALLBACK_INSTANCE
|
||||
{
|
||||
PTP_WORK Work;
|
||||
};
|
||||
|
||||
struct S_TP_POOL
|
||||
{
|
||||
DWORD Minimum;
|
||||
DWORD Maximum;
|
||||
wArrayList* Threads;
|
||||
wQueue* PendingQueue;
|
||||
HANDLE TerminateEvent;
|
||||
wCountdownEvent* WorkComplete;
|
||||
};
|
||||
|
||||
struct S_TP_WORK
|
||||
{
|
||||
PVOID CallbackParameter;
|
||||
PTP_WORK_CALLBACK WorkCallback;
|
||||
PTP_CALLBACK_ENVIRON CallbackEnvironment;
|
||||
};
|
||||
|
||||
struct S_TP_TIMER
|
||||
{
|
||||
void* dummy;
|
||||
};
|
||||
|
||||
struct S_TP_WAIT
|
||||
{
|
||||
void* dummy;
|
||||
};
|
||||
|
||||
struct S_TP_IO
|
||||
{
|
||||
void* dummy;
|
||||
};
|
||||
|
||||
struct S_TP_CLEANUP_GROUP
|
||||
{
|
||||
void* dummy;
|
||||
};
|
||||
|
||||
#endif
|
||||
#else
|
||||
struct S_TP_CALLBACK_INSTANCE
|
||||
{
|
||||
PTP_WORK Work;
|
||||
};
|
||||
|
||||
struct S_TP_POOL
|
||||
{
|
||||
DWORD Minimum;
|
||||
DWORD Maximum;
|
||||
wArrayList* Threads;
|
||||
wQueue* PendingQueue;
|
||||
HANDLE TerminateEvent;
|
||||
wCountdownEvent* WorkComplete;
|
||||
};
|
||||
|
||||
struct S_TP_WORK
|
||||
{
|
||||
PVOID CallbackParameter;
|
||||
PTP_WORK_CALLBACK WorkCallback;
|
||||
PTP_CALLBACK_ENVIRON CallbackEnvironment;
|
||||
};
|
||||
|
||||
struct S_TP_TIMER
|
||||
{
|
||||
void* dummy;
|
||||
};
|
||||
|
||||
struct S_TP_WAIT
|
||||
{
|
||||
void* dummy;
|
||||
};
|
||||
|
||||
struct S_TP_IO
|
||||
{
|
||||
void* dummy;
|
||||
};
|
||||
|
||||
struct S_TP_CLEANUP_GROUP
|
||||
{
|
||||
wArrayList* groups;
|
||||
PTP_CALLBACK_ENVIRON env;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
PTP_POOL GetDefaultThreadpool(void);
|
||||
|
||||
#endif /* WINPR_POOL_PRIVATE_H */
|
||||
53
third_party/FreeRDP/winpr/libwinpr/pool/synch.c
vendored
Normal file
53
third_party/FreeRDP/winpr/libwinpr/pool/synch.c
vendored
Normal file
@@ -0,0 +1,53 @@
|
||||
/**
|
||||
* WinPR: Windows Portable Runtime
|
||||
* Thread Pool API (Synch)
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#include <winpr/config.h>
|
||||
|
||||
#include <winpr/crt.h>
|
||||
#include <winpr/pool.h>
|
||||
#include <winpr/wlog.h>
|
||||
|
||||
#ifdef WINPR_THREAD_POOL
|
||||
|
||||
PTP_WAIT winpr_CreateThreadpoolWait(WINPR_ATTR_UNUSED PTP_WAIT_CALLBACK pfnwa,
|
||||
WINPR_ATTR_UNUSED PVOID pv,
|
||||
WINPR_ATTR_UNUSED PTP_CALLBACK_ENVIRON pcbe)
|
||||
{
|
||||
WLog_ERR("TODO", "TODO: Implement");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
VOID winpr_CloseThreadpoolWait(WINPR_ATTR_UNUSED PTP_WAIT pwa)
|
||||
{
|
||||
WLog_ERR("TODO", "TODO: Implement");
|
||||
}
|
||||
|
||||
VOID winpr_SetThreadpoolWait(WINPR_ATTR_UNUSED PTP_WAIT pwa, WINPR_ATTR_UNUSED HANDLE h,
|
||||
WINPR_ATTR_UNUSED PFILETIME pftTimeout)
|
||||
{
|
||||
WLog_ERR("TODO", "TODO: Implement");
|
||||
}
|
||||
|
||||
VOID winpr_WaitForThreadpoolWaitCallbacks(WINPR_ATTR_UNUSED PTP_WAIT pwa,
|
||||
WINPR_ATTR_UNUSED BOOL fCancelPendingCallbacks)
|
||||
{
|
||||
WLog_ERR("TODO", "TODO: Implement");
|
||||
}
|
||||
|
||||
#endif
|
||||
23
third_party/FreeRDP/winpr/libwinpr/pool/test/CMakeLists.txt
vendored
Normal file
23
third_party/FreeRDP/winpr/libwinpr/pool/test/CMakeLists.txt
vendored
Normal file
@@ -0,0 +1,23 @@
|
||||
set(MODULE_NAME "TestPool")
|
||||
set(MODULE_PREFIX "TEST_POOL")
|
||||
|
||||
disable_warnings_for_directory(${CMAKE_CURRENT_BINARY_DIR})
|
||||
|
||||
set(${MODULE_PREFIX}_DRIVER ${MODULE_NAME}.c)
|
||||
|
||||
set(${MODULE_PREFIX}_TESTS TestPoolIO.c TestPoolSynch.c TestPoolThread.c TestPoolTimer.c TestPoolWork.c)
|
||||
|
||||
create_test_sourcelist(${MODULE_PREFIX}_SRCS ${${MODULE_PREFIX}_DRIVER} ${${MODULE_PREFIX}_TESTS})
|
||||
|
||||
add_executable(${MODULE_NAME} ${${MODULE_PREFIX}_SRCS})
|
||||
|
||||
target_link_libraries(${MODULE_NAME} winpr)
|
||||
|
||||
set_target_properties(${MODULE_NAME} PROPERTIES RUNTIME_OUTPUT_DIRECTORY "${TESTING_OUTPUT_DIRECTORY}")
|
||||
|
||||
foreach(test ${${MODULE_PREFIX}_TESTS})
|
||||
get_filename_component(TestName ${test} NAME_WE)
|
||||
add_test(${TestName} ${TESTING_OUTPUT_DIRECTORY}/${MODULE_NAME} ${TestName})
|
||||
endforeach()
|
||||
|
||||
set_property(TARGET ${MODULE_NAME} PROPERTY FOLDER "WinPR/Test")
|
||||
8
third_party/FreeRDP/winpr/libwinpr/pool/test/TestPoolIO.c
vendored
Normal file
8
third_party/FreeRDP/winpr/libwinpr/pool/test/TestPoolIO.c
vendored
Normal file
@@ -0,0 +1,8 @@
|
||||
|
||||
#include <winpr/crt.h>
|
||||
#include <winpr/pool.h>
|
||||
|
||||
int TestPoolIO(int argc, char* argv[])
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
8
third_party/FreeRDP/winpr/libwinpr/pool/test/TestPoolSynch.c
vendored
Normal file
8
third_party/FreeRDP/winpr/libwinpr/pool/test/TestPoolSynch.c
vendored
Normal file
@@ -0,0 +1,8 @@
|
||||
|
||||
#include <winpr/crt.h>
|
||||
#include <winpr/pool.h>
|
||||
|
||||
int TestPoolSynch(int argc, char* argv[])
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
41
third_party/FreeRDP/winpr/libwinpr/pool/test/TestPoolThread.c
vendored
Normal file
41
third_party/FreeRDP/winpr/libwinpr/pool/test/TestPoolThread.c
vendored
Normal file
@@ -0,0 +1,41 @@
|
||||
|
||||
#include <winpr/crt.h>
|
||||
#include <winpr/pool.h>
|
||||
|
||||
/**
|
||||
* Improve Scalability With New Thread Pool APIs:
|
||||
* http://msdn.microsoft.com/en-us/magazine/cc16332.aspx
|
||||
*
|
||||
* Developing with Thread Pool Enhancements:
|
||||
* http://msdn.microsoft.com/en-us/library/cc308561.aspx
|
||||
*
|
||||
* Introduction to the Windows Threadpool:
|
||||
* http://blogs.msdn.com/b/harip/archive/2010/10/11/introduction-to-the-windows-threadpool-part-1.aspx
|
||||
* http://blogs.msdn.com/b/harip/archive/2010/10/12/introduction-to-the-windows-threadpool-part-2.aspx
|
||||
*/
|
||||
|
||||
int TestPoolThread(int argc, char* argv[])
|
||||
{
|
||||
TP_POOL* pool = nullptr;
|
||||
|
||||
WINPR_UNUSED(argc);
|
||||
WINPR_UNUSED(argv);
|
||||
|
||||
if (!(pool = CreateThreadpool(nullptr)))
|
||||
{
|
||||
printf("CreateThreadpool failed\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (!SetThreadpoolThreadMinimum(pool, 8)) /* default is 0 */
|
||||
{
|
||||
printf("SetThreadpoolThreadMinimum failed\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
SetThreadpoolThreadMaximum(pool, 64); /* default is 500 */
|
||||
|
||||
CloseThreadpool(pool);
|
||||
|
||||
return 0;
|
||||
}
|
||||
8
third_party/FreeRDP/winpr/libwinpr/pool/test/TestPoolTimer.c
vendored
Normal file
8
third_party/FreeRDP/winpr/libwinpr/pool/test/TestPoolTimer.c
vendored
Normal file
@@ -0,0 +1,8 @@
|
||||
|
||||
#include <winpr/crt.h>
|
||||
#include <winpr/pool.h>
|
||||
|
||||
int TestPoolTimer(int argc, char* argv[])
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
134
third_party/FreeRDP/winpr/libwinpr/pool/test/TestPoolWork.c
vendored
Normal file
134
third_party/FreeRDP/winpr/libwinpr/pool/test/TestPoolWork.c
vendored
Normal file
@@ -0,0 +1,134 @@
|
||||
|
||||
#include <winpr/wtypes.h>
|
||||
#include <winpr/crt.h>
|
||||
#include <winpr/pool.h>
|
||||
#include <winpr/interlocked.h>
|
||||
|
||||
static LONG count = 0;
|
||||
|
||||
static void CALLBACK test_WorkCallback(PTP_CALLBACK_INSTANCE instance, void* context, PTP_WORK work)
|
||||
{
|
||||
printf("Hello %s: %03" PRId32 " (thread: 0x%08" PRIX32 ")\n", (char*)context,
|
||||
InterlockedIncrement(&count), GetCurrentThreadId());
|
||||
|
||||
for (int index = 0; index < 100; index++)
|
||||
{
|
||||
BYTE a[1024];
|
||||
BYTE b[1024];
|
||||
BYTE c[1024] = WINPR_C_ARRAY_INIT;
|
||||
|
||||
FillMemory(a, ARRAYSIZE(a), 0xAA);
|
||||
FillMemory(b, ARRAYSIZE(b), 0xBB);
|
||||
|
||||
CopyMemory(c, a, ARRAYSIZE(a));
|
||||
CopyMemory(c, b, ARRAYSIZE(b));
|
||||
}
|
||||
}
|
||||
|
||||
static BOOL test1(void)
|
||||
{
|
||||
PTP_WORK work = nullptr;
|
||||
printf("Global Thread Pool\n");
|
||||
work = CreateThreadpoolWork(test_WorkCallback, "world", nullptr);
|
||||
|
||||
if (!work)
|
||||
{
|
||||
printf("CreateThreadpoolWork failure\n");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/**
|
||||
* You can post a work object one or more times (up to MAXULONG) without waiting for prior
|
||||
* callbacks to complete. The callbacks will execute in parallel. To improve efficiency, the
|
||||
* thread pool may throttle the threads.
|
||||
*/
|
||||
|
||||
for (int index = 0; index < 10; index++)
|
||||
SubmitThreadpoolWork(work);
|
||||
|
||||
WaitForThreadpoolWorkCallbacks(work, FALSE);
|
||||
CloseThreadpoolWork(work);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static BOOL test2(void)
|
||||
{
|
||||
BOOL rc = FALSE;
|
||||
PTP_POOL pool = nullptr;
|
||||
PTP_WORK work = nullptr;
|
||||
PTP_CLEANUP_GROUP cleanupGroup = nullptr;
|
||||
TP_CALLBACK_ENVIRON environment;
|
||||
printf("Private Thread Pool\n");
|
||||
|
||||
if (!(pool = CreateThreadpool(nullptr)))
|
||||
{
|
||||
printf("CreateThreadpool failure\n");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (!SetThreadpoolThreadMinimum(pool, 4))
|
||||
{
|
||||
printf("SetThreadpoolThreadMinimum failure\n");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
SetThreadpoolThreadMaximum(pool, 8);
|
||||
InitializeThreadpoolEnvironment(&environment);
|
||||
SetThreadpoolCallbackPool(&environment, pool);
|
||||
cleanupGroup = CreateThreadpoolCleanupGroup();
|
||||
|
||||
if (!cleanupGroup)
|
||||
{
|
||||
printf("CreateThreadpoolCleanupGroup failure\n");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
SetThreadpoolCallbackCleanupGroup(&environment, cleanupGroup, nullptr);
|
||||
work = CreateThreadpoolWork(test_WorkCallback, "world", &environment);
|
||||
|
||||
if (!work)
|
||||
{
|
||||
printf("CreateThreadpoolWork failure\n");
|
||||
goto fail;
|
||||
}
|
||||
|
||||
for (int index = 0; index < 10; index++)
|
||||
SubmitThreadpoolWork(work);
|
||||
|
||||
WaitForThreadpoolWorkCallbacks(work, FALSE);
|
||||
rc = TRUE;
|
||||
fail:
|
||||
|
||||
if (cleanupGroup)
|
||||
{
|
||||
CloseThreadpoolCleanupGroupMembers(cleanupGroup, TRUE, nullptr);
|
||||
CloseThreadpoolCleanupGroup(cleanupGroup);
|
||||
DestroyThreadpoolEnvironment(&environment);
|
||||
/**
|
||||
* 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 rc;
|
||||
}
|
||||
|
||||
int TestPoolWork(int argc, char* argv[])
|
||||
{
|
||||
|
||||
WINPR_UNUSED(argc);
|
||||
WINPR_UNUSED(argv);
|
||||
|
||||
if (!test1())
|
||||
return -1;
|
||||
|
||||
if (!test2())
|
||||
return -1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
61
third_party/FreeRDP/winpr/libwinpr/pool/timer.c
vendored
Normal file
61
third_party/FreeRDP/winpr/libwinpr/pool/timer.c
vendored
Normal file
@@ -0,0 +1,61 @@
|
||||
/**
|
||||
* WinPR: Windows Portable Runtime
|
||||
* Thread Pool API (Timer)
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#include <winpr/config.h>
|
||||
|
||||
#include <winpr/crt.h>
|
||||
#include <winpr/pool.h>
|
||||
#include <winpr/wlog.h>
|
||||
|
||||
#ifdef WINPR_THREAD_POOL
|
||||
|
||||
PTP_TIMER winpr_CreateThreadpoolTimer(WINPR_ATTR_UNUSED PTP_TIMER_CALLBACK pfnti,
|
||||
WINPR_ATTR_UNUSED PVOID pv,
|
||||
WINPR_ATTR_UNUSED PTP_CALLBACK_ENVIRON pcbe)
|
||||
{
|
||||
WLog_ERR("TODO", "TODO: Implement");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
VOID winpr_CloseThreadpoolTimer(WINPR_ATTR_UNUSED PTP_TIMER pti)
|
||||
{
|
||||
WLog_ERR("TODO", "TODO: Implement");
|
||||
}
|
||||
|
||||
BOOL winpr_IsThreadpoolTimerSet(WINPR_ATTR_UNUSED PTP_TIMER pti)
|
||||
{
|
||||
WLog_ERR("TODO", "TODO: Implement");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
VOID winpr_SetThreadpoolTimer(WINPR_ATTR_UNUSED PTP_TIMER pti,
|
||||
WINPR_ATTR_UNUSED PFILETIME pftDueTime,
|
||||
WINPR_ATTR_UNUSED DWORD msPeriod,
|
||||
WINPR_ATTR_UNUSED DWORD msWindowLength)
|
||||
{
|
||||
WLog_ERR("TODO", "TODO: Implement");
|
||||
}
|
||||
|
||||
VOID winpr_WaitForThreadpoolTimerCallbacks(WINPR_ATTR_UNUSED PTP_TIMER pti,
|
||||
WINPR_ATTR_UNUSED BOOL fCancelPendingCallbacks)
|
||||
{
|
||||
WLog_ERR("TODO", "TODO: Implement");
|
||||
}
|
||||
|
||||
#endif
|
||||
206
third_party/FreeRDP/winpr/libwinpr/pool/work.c
vendored
Normal file
206
third_party/FreeRDP/winpr/libwinpr/pool/work.c
vendored
Normal file
@@ -0,0 +1,206 @@
|
||||
/**
|
||||
* WinPR: Windows Portable Runtime
|
||||
* Thread Pool API (Work)
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#include <winpr/config.h>
|
||||
|
||||
#include <winpr/assert.h>
|
||||
#include <winpr/crt.h>
|
||||
#include <winpr/pool.h>
|
||||
#include <winpr/library.h>
|
||||
|
||||
#include "pool.h"
|
||||
#include "../log.h"
|
||||
#define TAG WINPR_TAG("pool")
|
||||
|
||||
#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 BOOL CALLBACK init_module(PINIT_ONCE once, PVOID param, PVOID* context)
|
||||
{
|
||||
HMODULE kernel32 = LoadLibraryA("kernel32.dll");
|
||||
|
||||
if (kernel32)
|
||||
{
|
||||
pCreateThreadpoolWork = GetProcAddressAs(kernel32, "CreateThreadpoolWork", void*);
|
||||
pCloseThreadpoolWork = GetProcAddressAs(kernel32, "CloseThreadpoolWork", void*);
|
||||
pSubmitThreadpoolWork = GetProcAddressAs(kernel32, "SubmitThreadpoolWork", void*);
|
||||
pTrySubmitThreadpoolCallback =
|
||||
GetProcAddressAs(kernel32, "TrySubmitThreadpoolCallback", void*);
|
||||
pWaitForThreadpoolWorkCallbacks =
|
||||
GetProcAddressAs(kernel32, "WaitForThreadpoolWorkCallbacks", void*);
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
#endif
|
||||
|
||||
static TP_CALLBACK_ENVIRON DEFAULT_CALLBACK_ENVIRONMENT = {
|
||||
1, /* Version */
|
||||
nullptr, /* Pool */
|
||||
nullptr, /* CleanupGroup */
|
||||
nullptr, /* CleanupGroupCancelCallback */
|
||||
nullptr, /* RaceDll */
|
||||
nullptr, /* FinalizationCallback */
|
||||
{ 0 } /* Flags */
|
||||
};
|
||||
|
||||
PTP_WORK winpr_CreateThreadpoolWork(PTP_WORK_CALLBACK pfnwk, PVOID pv, PTP_CALLBACK_ENVIRON pcbe)
|
||||
{
|
||||
PTP_WORK work = nullptr;
|
||||
#ifdef _WIN32
|
||||
if (!InitOnceExecuteOnce(&init_once_module, init_module, nullptr, nullptr))
|
||||
return nullptr;
|
||||
|
||||
if (pCreateThreadpoolWork)
|
||||
return pCreateThreadpoolWork(pfnwk, pv, pcbe);
|
||||
|
||||
#endif
|
||||
work = (PTP_WORK)calloc(1, sizeof(TP_WORK));
|
||||
|
||||
if (work)
|
||||
{
|
||||
if (!pcbe)
|
||||
{
|
||||
pcbe = &DEFAULT_CALLBACK_ENVIRONMENT;
|
||||
pcbe->Pool = GetDefaultThreadpool();
|
||||
}
|
||||
|
||||
work->CallbackEnvironment = pcbe;
|
||||
work->WorkCallback = pfnwk;
|
||||
work->CallbackParameter = pv;
|
||||
#ifndef _WIN32
|
||||
|
||||
if (pcbe->CleanupGroup)
|
||||
ArrayList_Append(pcbe->CleanupGroup->groups, work);
|
||||
|
||||
#endif
|
||||
}
|
||||
|
||||
return work;
|
||||
}
|
||||
|
||||
VOID winpr_CloseThreadpoolWork(PTP_WORK pwk)
|
||||
{
|
||||
#ifdef _WIN32
|
||||
if (!InitOnceExecuteOnce(&init_once_module, init_module, nullptr, nullptr))
|
||||
return;
|
||||
|
||||
if (pCloseThreadpoolWork)
|
||||
{
|
||||
pCloseThreadpoolWork(pwk);
|
||||
return;
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
WINPR_ASSERT(pwk);
|
||||
WINPR_ASSERT(pwk->CallbackEnvironment);
|
||||
if (pwk->CallbackEnvironment->CleanupGroup)
|
||||
ArrayList_Remove(pwk->CallbackEnvironment->CleanupGroup->groups, pwk);
|
||||
|
||||
#endif
|
||||
free(pwk);
|
||||
}
|
||||
|
||||
VOID winpr_SubmitThreadpoolWork(PTP_WORK pwk)
|
||||
{
|
||||
PTP_POOL pool = nullptr;
|
||||
PTP_CALLBACK_INSTANCE callbackInstance = nullptr;
|
||||
#ifdef _WIN32
|
||||
if (!InitOnceExecuteOnce(&init_once_module, init_module, nullptr, nullptr))
|
||||
return;
|
||||
|
||||
if (pSubmitThreadpoolWork)
|
||||
{
|
||||
pSubmitThreadpoolWork(pwk);
|
||||
return;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
WINPR_ASSERT(pwk);
|
||||
WINPR_ASSERT(pwk->CallbackEnvironment);
|
||||
pool = pwk->CallbackEnvironment->Pool;
|
||||
callbackInstance = (PTP_CALLBACK_INSTANCE)calloc(1, sizeof(TP_CALLBACK_INSTANCE));
|
||||
|
||||
if (callbackInstance)
|
||||
{
|
||||
callbackInstance->Work = pwk;
|
||||
CountdownEvent_AddCount(pool->WorkComplete, 1);
|
||||
if (!Queue_Enqueue(pool->PendingQueue, callbackInstance))
|
||||
free(callbackInstance);
|
||||
}
|
||||
// NOLINTNEXTLINE(clang-analyzer-unix.Malloc): Queue_Enqueue takes ownership of callbackInstance
|
||||
}
|
||||
|
||||
BOOL winpr_TrySubmitThreadpoolCallback(WINPR_ATTR_UNUSED PTP_SIMPLE_CALLBACK pfns,
|
||||
WINPR_ATTR_UNUSED PVOID pv,
|
||||
WINPR_ATTR_UNUSED PTP_CALLBACK_ENVIRON pcbe)
|
||||
{
|
||||
#ifdef _WIN32
|
||||
if (!InitOnceExecuteOnce(&init_once_module, init_module, nullptr, nullptr))
|
||||
return FALSE;
|
||||
|
||||
if (pTrySubmitThreadpoolCallback)
|
||||
return pTrySubmitThreadpoolCallback(pfns, pv, pcbe);
|
||||
|
||||
#endif
|
||||
WLog_ERR(TAG, "TrySubmitThreadpoolCallback is not implemented");
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
VOID winpr_WaitForThreadpoolWorkCallbacks(PTP_WORK pwk,
|
||||
WINPR_ATTR_UNUSED BOOL fCancelPendingCallbacks)
|
||||
{
|
||||
HANDLE event = nullptr;
|
||||
PTP_POOL pool = nullptr;
|
||||
|
||||
#ifdef _WIN32
|
||||
if (!InitOnceExecuteOnce(&init_once_module, init_module, nullptr, nullptr))
|
||||
return;
|
||||
|
||||
if (pWaitForThreadpoolWorkCallbacks)
|
||||
{
|
||||
pWaitForThreadpoolWorkCallbacks(pwk, fCancelPendingCallbacks);
|
||||
return;
|
||||
}
|
||||
|
||||
#endif
|
||||
WINPR_ASSERT(pwk);
|
||||
WINPR_ASSERT(pwk->CallbackEnvironment);
|
||||
|
||||
pool = pwk->CallbackEnvironment->Pool;
|
||||
WINPR_ASSERT(pool);
|
||||
|
||||
event = CountdownEvent_WaitHandle(pool->WorkComplete);
|
||||
|
||||
if (WaitForSingleObject(event, INFINITE) != WAIT_OBJECT_0)
|
||||
WLog_ERR(TAG, "error waiting on work completion");
|
||||
}
|
||||
|
||||
#endif /* WINPR_THREAD_POOL defined */
|
||||
Reference in New Issue
Block a user