mirror of https://github.com/FreeRDP/FreeRDP
Merge pull request #918 from awakecoding/master
RemoteFX Parallel Processing of Tiles
This commit is contained in:
commit
683e395bf8
|
@ -31,8 +31,6 @@ set(${MODULE_PREFIX}_SRCS
|
|||
rfx_dwt.h
|
||||
rfx_encode.c
|
||||
rfx_encode.h
|
||||
rfx_pool.c
|
||||
rfx_pool.h
|
||||
rfx_quantization.c
|
||||
rfx_quantization.h
|
||||
rfx_rlgr.c
|
||||
|
@ -98,8 +96,11 @@ set_complex_link_libraries(VARIABLE ${MODULE_PREFIX}_LIBS
|
|||
MONOLITHIC ${MONOLITHIC_BUILD} INTERNAL
|
||||
MODULE freerdp
|
||||
MODULES freerdp-primitives freerdp-utils)
|
||||
|
||||
message(STATUS "libfreerdp-codec libs: ${${MODULE_PREFIX}_LIBS}")
|
||||
|
||||
set_complex_link_libraries(VARIABLE ${MODULE_PREFIX}_LIBS
|
||||
MONOLITHIC ${MONOLITHIC_BUILD}
|
||||
MODULE winpr
|
||||
MODULES winpr-crt winpr-pool winpr-registry winpr-utils)
|
||||
|
||||
if(MONOLITHIC_BUILD)
|
||||
set(FREERDP_LIBS ${FREERDP_LIBS} ${${MODULE_PREFIX}_LIBS} PARENT_SCOPE)
|
||||
|
|
|
@ -30,13 +30,13 @@
|
|||
#endif
|
||||
|
||||
#include <winpr/crt.h>
|
||||
#include <winpr/registry.h>
|
||||
|
||||
#include <freerdp/codec/rfx.h>
|
||||
#include <freerdp/constants.h>
|
||||
|
||||
#include "rfx_constants.h"
|
||||
#include "rfx_types.h"
|
||||
#include "rfx_pool.h"
|
||||
#include "rfx_decode.h"
|
||||
#include "rfx_encode.h"
|
||||
#include "rfx_quantization.h"
|
||||
|
@ -140,6 +140,11 @@ static void rfx_profiler_print(RFX_CONTEXT* context)
|
|||
|
||||
RFX_CONTEXT* rfx_context_new(void)
|
||||
{
|
||||
HKEY hKey;
|
||||
LONG status;
|
||||
DWORD dwType;
|
||||
DWORD dwSize;
|
||||
DWORD dwValue;
|
||||
RFX_CONTEXT* context;
|
||||
|
||||
context = (RFX_CONTEXT*) malloc(sizeof(RFX_CONTEXT));
|
||||
|
@ -148,18 +153,54 @@ RFX_CONTEXT* rfx_context_new(void)
|
|||
context->priv = (RFX_CONTEXT_PRIV*) malloc(sizeof(RFX_CONTEXT_PRIV));
|
||||
ZeroMemory(context->priv, sizeof(RFX_CONTEXT_PRIV));
|
||||
|
||||
context->priv->pool = rfx_pool_new();
|
||||
context->priv->TilePool = Queue_New(TRUE, -1, -1);
|
||||
context->priv->TileQueue = Queue_New(TRUE, -1, -1);
|
||||
|
||||
/*
|
||||
* align buffers to 16 byte boundary (needed for SSE/NEON instructions)
|
||||
*
|
||||
* y_r_buffer, cb_g_buffer, cr_b_buffer: 64 * 64 * 4 = 16384 (0x4000)
|
||||
* dwt_buffer: 32 * 32 * 2 * 2 * 4 = 16384, maximum sub-band width is 32
|
||||
*/
|
||||
|
||||
context->priv->BufferPool = BufferPool_New(TRUE, 16384, 16);
|
||||
|
||||
context->priv->UseThreads = FALSE;
|
||||
context->priv->MinThreadCount = 4;
|
||||
context->priv->MaxThreadCount = 0;
|
||||
|
||||
status = RegOpenKeyEx(HKEY_LOCAL_MACHINE, _T("Software\\FreeRDP\\RemoteFX"), 0, KEY_READ | KEY_WOW64_64KEY, &hKey);
|
||||
|
||||
if (status == ERROR_SUCCESS)
|
||||
{
|
||||
if (RegQueryValueEx(hKey, _T("UseThreads"), NULL, &dwType, (BYTE*) &dwValue, &dwSize) == ERROR_SUCCESS)
|
||||
context->priv->UseThreads = dwValue ? 1 : 0;
|
||||
|
||||
if (RegQueryValueEx(hKey, _T("MinThreadCount"), NULL, &dwType, (BYTE*) &dwValue, &dwSize) == ERROR_SUCCESS)
|
||||
context->priv->MinThreadCount = dwValue;
|
||||
|
||||
if (RegQueryValueEx(hKey, _T("MaxThreadCount"), NULL, &dwType, (BYTE*) &dwValue, &dwSize) == ERROR_SUCCESS)
|
||||
context->priv->MaxThreadCount = dwValue;
|
||||
|
||||
RegCloseKey(hKey);
|
||||
}
|
||||
|
||||
if (context->priv->UseThreads)
|
||||
{
|
||||
context->priv->ThreadPool = CreateThreadpool(NULL);
|
||||
InitializeThreadpoolEnvironment(&context->priv->ThreadPoolEnv);
|
||||
SetThreadpoolCallbackPool(&context->priv->ThreadPoolEnv, context->priv->ThreadPool);
|
||||
|
||||
if (context->priv->MinThreadCount)
|
||||
SetThreadpoolThreadMinimum(context->priv->ThreadPool, context->priv->MinThreadCount);
|
||||
|
||||
if (context->priv->MaxThreadCount)
|
||||
SetThreadpoolThreadMaximum(context->priv->ThreadPool, context->priv->MaxThreadCount);
|
||||
}
|
||||
|
||||
/* initialize the default pixel format */
|
||||
rfx_context_set_pixel_format(context, RDP_PIXEL_FORMAT_B8G8R8A8);
|
||||
|
||||
/* align buffers to 16 byte boundary (needed for SSE/SSE2 instructions) */
|
||||
context->priv->y_r_buffer = (INT16*)(((uintptr_t)context->priv->y_r_mem + 16) & ~ 0x0F);
|
||||
context->priv->cb_g_buffer = (INT16*)(((uintptr_t)context->priv->cb_g_mem + 16) & ~ 0x0F);
|
||||
context->priv->cr_b_buffer = (INT16*)(((uintptr_t)context->priv->cr_b_mem + 16) & ~ 0x0F);
|
||||
|
||||
context->priv->dwt_buffer = (INT16*)(((uintptr_t)context->priv->dwt_mem + 16) & ~ 0x0F);
|
||||
|
||||
/* create profilers for default decoding routines */
|
||||
rfx_profiler_create(context);
|
||||
|
||||
|
@ -183,11 +224,20 @@ void rfx_context_free(RFX_CONTEXT* context)
|
|||
{
|
||||
free(context->quants);
|
||||
|
||||
rfx_pool_free(context->priv->pool);
|
||||
Queue_Free(context->priv->TilePool);
|
||||
Queue_Free(context->priv->TileQueue);
|
||||
|
||||
rfx_profiler_print(context);
|
||||
rfx_profiler_free(context);
|
||||
|
||||
if (context->priv->UseThreads)
|
||||
{
|
||||
CloseThreadpool(context->priv->ThreadPool);
|
||||
DestroyThreadpoolEnvironment(&context->priv->ThreadPoolEnv);
|
||||
}
|
||||
|
||||
BufferPool_Free(context->priv->BufferPool);
|
||||
|
||||
free(context->priv);
|
||||
free(context);
|
||||
}
|
||||
|
@ -195,6 +245,7 @@ void rfx_context_free(RFX_CONTEXT* context)
|
|||
void rfx_context_set_pixel_format(RFX_CONTEXT* context, RDP_PIXEL_FORMAT pixel_format)
|
||||
{
|
||||
context->pixel_format = pixel_format;
|
||||
|
||||
switch (pixel_format)
|
||||
{
|
||||
case RDP_PIXEL_FORMAT_B8G8R8A8:
|
||||
|
@ -227,6 +278,30 @@ void rfx_context_reset(RFX_CONTEXT* context)
|
|||
context->frame_idx = 0;
|
||||
}
|
||||
|
||||
RFX_TILE* rfx_tile_pool_take(RFX_CONTEXT* context)
|
||||
{
|
||||
RFX_TILE* tile = NULL;
|
||||
|
||||
if (WaitForSingleObject(Queue_Event(context->priv->TilePool), 0) == WAIT_OBJECT_0)
|
||||
tile = Queue_Dequeue(context->priv->TilePool);
|
||||
|
||||
if (!tile)
|
||||
{
|
||||
tile = (RFX_TILE*) malloc(sizeof(RFX_TILE));
|
||||
|
||||
tile->x = tile->y = 0;
|
||||
tile->data = (BYTE*) malloc(4096 * 4); /* 64x64 * 4 */
|
||||
}
|
||||
|
||||
return tile;
|
||||
}
|
||||
|
||||
int rfx_tile_pool_return(RFX_CONTEXT* context, RFX_TILE* tile)
|
||||
{
|
||||
Queue_Enqueue(context->priv->TilePool, tile);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void rfx_process_message_sync(RFX_CONTEXT* context, STREAM* s)
|
||||
{
|
||||
UINT32 magic;
|
||||
|
@ -412,19 +487,35 @@ static void rfx_process_message_tile(RFX_CONTEXT* context, RFX_TILE* tile, STREA
|
|||
YLen, context->quants + (quantIdxY * 10),
|
||||
CbLen, context->quants + (quantIdxCb * 10),
|
||||
CrLen, context->quants + (quantIdxCr * 10),
|
||||
tile->data, 64*sizeof(UINT32));
|
||||
tile->data, 64 * 4);
|
||||
}
|
||||
|
||||
struct _RFX_TILE_WORK_PARAM
|
||||
{
|
||||
STREAM s;
|
||||
RFX_TILE* tile;
|
||||
RFX_CONTEXT* context;
|
||||
};
|
||||
typedef struct _RFX_TILE_WORK_PARAM RFX_TILE_WORK_PARAM;
|
||||
|
||||
void CALLBACK rfx_process_message_tile_work_callback(PTP_CALLBACK_INSTANCE instance, void* context, PTP_WORK work)
|
||||
{
|
||||
RFX_TILE_WORK_PARAM* param = (RFX_TILE_WORK_PARAM*) context;
|
||||
rfx_process_message_tile(param->context, param->tile, &(param->s));
|
||||
}
|
||||
|
||||
static void rfx_process_message_tileset(RFX_CONTEXT* context, RFX_MESSAGE* message, STREAM* s)
|
||||
{
|
||||
int i;
|
||||
int pos;
|
||||
BYTE quant;
|
||||
UINT32* quants;
|
||||
UINT16 subtype;
|
||||
UINT32 blockLen;
|
||||
UINT32 blockType;
|
||||
UINT32 tilesDataSize;
|
||||
UINT32* quants;
|
||||
BYTE quant;
|
||||
int pos;
|
||||
PTP_WORK* work_objects = NULL;
|
||||
RFX_TILE_WORK_PARAM* params = NULL;
|
||||
|
||||
stream_read_UINT16(s, subtype); /* subtype (2 bytes) must be set to CBT_TILESET (0xCAC2) */
|
||||
|
||||
|
@ -490,7 +581,14 @@ static void rfx_process_message_tileset(RFX_CONTEXT* context, RFX_MESSAGE* messa
|
|||
context->quants[i * 10 + 8], context->quants[i * 10 + 9]);
|
||||
}
|
||||
|
||||
message->tiles = rfx_pool_get_tiles(context->priv->pool, message->num_tiles);
|
||||
message->tiles = (RFX_TILE**) malloc(sizeof(RFX_TILE*) * message->num_tiles);
|
||||
ZeroMemory(message->tiles, sizeof(RFX_TILE*) * message->num_tiles);
|
||||
|
||||
if (context->priv->UseThreads)
|
||||
{
|
||||
work_objects = (PTP_WORK*) malloc(sizeof(PTP_WORK) * message->num_tiles);
|
||||
params = (RFX_TILE_WORK_PARAM*) malloc(sizeof(RFX_TILE_WORK_PARAM) * message->num_tiles);
|
||||
}
|
||||
|
||||
/* tiles */
|
||||
for (i = 0; i < message->num_tiles; i++)
|
||||
|
@ -507,10 +605,35 @@ static void rfx_process_message_tileset(RFX_CONTEXT* context, RFX_MESSAGE* messa
|
|||
break;
|
||||
}
|
||||
|
||||
rfx_process_message_tile(context, message->tiles[i], s);
|
||||
message->tiles[i] = rfx_tile_pool_take(context);
|
||||
|
||||
if (context->priv->UseThreads)
|
||||
{
|
||||
params[i].context = context;
|
||||
params[i].tile = message->tiles[i];
|
||||
CopyMemory(&(params[i].s), s, sizeof(STREAM));
|
||||
|
||||
work_objects[i] = CreateThreadpoolWork((PTP_WORK_CALLBACK) rfx_process_message_tile_work_callback,
|
||||
(void*) ¶ms[i], &context->priv->ThreadPoolEnv);
|
||||
|
||||
SubmitThreadpoolWork(work_objects[i]);
|
||||
}
|
||||
else
|
||||
{
|
||||
rfx_process_message_tile(context, message->tiles[i], s);
|
||||
}
|
||||
|
||||
stream_set_pos(s, pos);
|
||||
}
|
||||
|
||||
if (context->priv->UseThreads)
|
||||
{
|
||||
for (i = 0; i < message->num_tiles; i++)
|
||||
WaitForThreadpoolWorkCallbacks(work_objects[i], FALSE);
|
||||
|
||||
free(work_objects);
|
||||
free(params);
|
||||
}
|
||||
}
|
||||
|
||||
RFX_MESSAGE* rfx_process_message(RFX_CONTEXT* context, BYTE* data, UINT32 length)
|
||||
|
@ -621,13 +744,17 @@ RFX_RECT* rfx_message_get_rect(RFX_MESSAGE* message, int index)
|
|||
|
||||
void rfx_message_free(RFX_CONTEXT* context, RFX_MESSAGE* message)
|
||||
{
|
||||
int i;
|
||||
|
||||
if (message != NULL)
|
||||
{
|
||||
free(message->rects);
|
||||
|
||||
if (message->tiles != NULL)
|
||||
if (message->tiles)
|
||||
{
|
||||
rfx_pool_put_tiles(context->priv->pool, message->tiles, message->num_tiles);
|
||||
for (i = 0; i < message->num_tiles; i++)
|
||||
rfx_tile_pool_return(context, message->tiles[i]);
|
||||
|
||||
free(message->tiles);
|
||||
}
|
||||
|
||||
|
@ -790,9 +917,9 @@ static void rfx_compose_message_tile(RFX_CONTEXT* context, STREAM* s,
|
|||
static void rfx_compose_message_tileset(RFX_CONTEXT* context, STREAM* s,
|
||||
BYTE* image_data, int width, int height, int rowstride)
|
||||
{
|
||||
int i;
|
||||
int size;
|
||||
int start_pos, end_pos;
|
||||
int i;
|
||||
int numQuants;
|
||||
const UINT32* quantVals;
|
||||
const UINT32* quantValsPtr;
|
||||
|
|
|
@ -96,6 +96,10 @@ static void rfx_decode_format_rgb(INT16* r_buf, INT16* g_buf, INT16* b_buf,
|
|||
static void rfx_decode_component(RFX_CONTEXT* context, const UINT32* quantization_values,
|
||||
const BYTE* data, int size, INT16* buffer)
|
||||
{
|
||||
INT16* dwt_buffer;
|
||||
|
||||
dwt_buffer = BufferPool_Take(context->priv->BufferPool, -1); /* dwt_buffer */
|
||||
|
||||
PROFILER_ENTER(context->priv->prof_rfx_decode_component);
|
||||
|
||||
PROFILER_ENTER(context->priv->prof_rfx_rlgr_decode);
|
||||
|
@ -111,43 +115,50 @@ static void rfx_decode_component(RFX_CONTEXT* context, const UINT32* quantizatio
|
|||
PROFILER_EXIT(context->priv->prof_rfx_quantization_decode);
|
||||
|
||||
PROFILER_ENTER(context->priv->prof_rfx_dwt_2d_decode);
|
||||
context->dwt_2d_decode(buffer, context->priv->dwt_buffer);
|
||||
context->dwt_2d_decode(buffer, dwt_buffer);
|
||||
PROFILER_EXIT(context->priv->prof_rfx_dwt_2d_decode);
|
||||
|
||||
PROFILER_EXIT(context->priv->prof_rfx_decode_component);
|
||||
|
||||
BufferPool_Return(context->priv->BufferPool, dwt_buffer);
|
||||
}
|
||||
|
||||
/* rfx_decode_ycbcr_to_rgb code now resides in the primitives library. */
|
||||
|
||||
/* stride is bytes between rows in the output buffer. */
|
||||
void rfx_decode_rgb(RFX_CONTEXT* context, STREAM* data_in,
|
||||
int y_size, const UINT32 * y_quants,
|
||||
int cb_size, const UINT32 * cb_quants,
|
||||
int cr_size, const UINT32 * cr_quants, BYTE* rgb_buffer, int stride)
|
||||
int y_size, const UINT32* y_quants,
|
||||
int cb_size, const UINT32* cb_quants,
|
||||
int cr_size, const UINT32* cr_quants, BYTE* rgb_buffer, int stride)
|
||||
{
|
||||
INT16* pSrcDst[3];
|
||||
static const prim_size_t roi_64x64 = { 64, 64 };
|
||||
const primitives_t *prims = primitives_get();
|
||||
INT16 *pSrcDst[3];
|
||||
|
||||
PROFILER_ENTER(context->priv->prof_rfx_decode_rgb);
|
||||
|
||||
rfx_decode_component(context, y_quants, stream_get_tail(data_in), y_size, context->priv->y_r_buffer); /* YData */
|
||||
pSrcDst[0] = BufferPool_Take(context->priv->BufferPool, -1); /* y_r_buffer */
|
||||
pSrcDst[1] = BufferPool_Take(context->priv->BufferPool, -1); /* cb_g_buffer */
|
||||
pSrcDst[2] = BufferPool_Take(context->priv->BufferPool, -1); /* cr_b_buffer */
|
||||
|
||||
rfx_decode_component(context, y_quants, stream_get_tail(data_in), y_size, pSrcDst[0]); /* YData */
|
||||
stream_seek(data_in, y_size);
|
||||
rfx_decode_component(context, cb_quants, stream_get_tail(data_in), cb_size, context->priv->cb_g_buffer); /* CbData */
|
||||
rfx_decode_component(context, cb_quants, stream_get_tail(data_in), cb_size, pSrcDst[1]); /* CbData */
|
||||
stream_seek(data_in, cb_size);
|
||||
rfx_decode_component(context, cr_quants, stream_get_tail(data_in), cr_size, context->priv->cr_b_buffer); /* CrData */
|
||||
rfx_decode_component(context, cr_quants, stream_get_tail(data_in), cr_size, pSrcDst[2]); /* CrData */
|
||||
stream_seek(data_in, cr_size);
|
||||
|
||||
pSrcDst[0] = context->priv->y_r_buffer;
|
||||
pSrcDst[1] = context->priv->cb_g_buffer;
|
||||
pSrcDst[2] = context->priv->cr_b_buffer;
|
||||
prims->yCbCrToRGB_16s16s_P3P3((const INT16 **) pSrcDst, 64*sizeof(INT16),
|
||||
pSrcDst, 64*sizeof(INT16), &roi_64x64);
|
||||
prims->yCbCrToRGB_16s16s_P3P3((const INT16**) pSrcDst, 64 * sizeof(INT16),
|
||||
pSrcDst, 64 * sizeof(INT16), &roi_64x64);
|
||||
|
||||
PROFILER_ENTER(context->priv->prof_rfx_decode_format_rgb);
|
||||
rfx_decode_format_rgb(context->priv->y_r_buffer, context->priv->cb_g_buffer, context->priv->cr_b_buffer,
|
||||
rfx_decode_format_rgb(pSrcDst[0], pSrcDst[1], pSrcDst[2],
|
||||
context->pixel_format, rgb_buffer, stride);
|
||||
PROFILER_EXIT(context->priv->prof_rfx_decode_format_rgb);
|
||||
|
||||
PROFILER_EXIT(context->priv->prof_rfx_decode_rgb);
|
||||
|
||||
BufferPool_Return(context->priv->BufferPool, pSrcDst[0]);
|
||||
BufferPool_Return(context->priv->BufferPool, pSrcDst[1]);
|
||||
BufferPool_Return(context->priv->BufferPool, pSrcDst[2]);
|
||||
}
|
||||
|
|
|
@ -26,6 +26,9 @@
|
|||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <winpr/crt.h>
|
||||
#include <winpr/collections.h>
|
||||
|
||||
#include <freerdp/primitives.h>
|
||||
|
||||
#include "rfx_types.h"
|
||||
|
@ -187,10 +190,14 @@ static void rfx_encode_format_rgb(const BYTE* rgb_data, int width, int height, i
|
|||
static void rfx_encode_component(RFX_CONTEXT* context, const UINT32* quantization_values,
|
||||
INT16* data, BYTE* buffer, int buffer_size, int* size)
|
||||
{
|
||||
INT16* dwt_buffer;
|
||||
|
||||
dwt_buffer = BufferPool_Take(context->priv->BufferPool, -1); /* dwt_buffer */
|
||||
|
||||
PROFILER_ENTER(context->priv->prof_rfx_encode_component);
|
||||
|
||||
PROFILER_ENTER(context->priv->prof_rfx_dwt_2d_encode);
|
||||
context->dwt_2d_encode(data, context->priv->dwt_buffer);
|
||||
context->dwt_2d_encode(data, dwt_buffer);
|
||||
PROFILER_EXIT(context->priv->prof_rfx_dwt_2d_encode);
|
||||
|
||||
PROFILER_ENTER(context->priv->prof_rfx_quantization_encode);
|
||||
|
@ -206,49 +213,54 @@ static void rfx_encode_component(RFX_CONTEXT* context, const UINT32* quantizatio
|
|||
PROFILER_EXIT(context->priv->prof_rfx_rlgr_encode);
|
||||
|
||||
PROFILER_EXIT(context->priv->prof_rfx_encode_component);
|
||||
|
||||
BufferPool_Return(context->priv->BufferPool, dwt_buffer);
|
||||
}
|
||||
|
||||
void rfx_encode_rgb(RFX_CONTEXT* context, const BYTE* rgb_data, int width, int height, int rowstride,
|
||||
const UINT32* y_quants, const UINT32* cb_quants, const UINT32* cr_quants,
|
||||
STREAM* data_out, int* y_size, int* cb_size, int* cr_size)
|
||||
{
|
||||
primitives_t *prims = primitives_get();
|
||||
INT16* pSrcDst[3];
|
||||
primitives_t* prims = primitives_get();
|
||||
static const prim_size_t roi_64x64 = { 64, 64 };
|
||||
INT16* y_r_buffer = context->priv->y_r_buffer;
|
||||
INT16* cb_g_buffer = context->priv->cb_g_buffer;
|
||||
INT16* cr_b_buffer = context->priv->cr_b_buffer;
|
||||
|
||||
pSrcDst[0] = BufferPool_Take(context->priv->BufferPool, -1); /* y_r_buffer */
|
||||
pSrcDst[1] = BufferPool_Take(context->priv->BufferPool, -1); /* cb_g_buffer */
|
||||
pSrcDst[2] = BufferPool_Take(context->priv->BufferPool, -1); /* cr_b_buffer */
|
||||
|
||||
PROFILER_ENTER(context->priv->prof_rfx_encode_rgb);
|
||||
|
||||
PROFILER_ENTER(context->priv->prof_rfx_encode_format_rgb);
|
||||
rfx_encode_format_rgb(rgb_data, width, height, rowstride,
|
||||
context->pixel_format, context->palette, y_r_buffer, cb_g_buffer, cr_b_buffer);
|
||||
context->pixel_format, context->palette, pSrcDst[0], pSrcDst[1], pSrcDst[2]);
|
||||
PROFILER_EXIT(context->priv->prof_rfx_encode_format_rgb);
|
||||
|
||||
PROFILER_ENTER(context->priv->prof_rfx_rgb_to_ycbcr);
|
||||
pSrcDst[0] = context->priv->y_r_buffer;
|
||||
pSrcDst[1] = context->priv->cb_g_buffer;
|
||||
pSrcDst[2] = context->priv->cr_b_buffer;
|
||||
prims->RGBToYCbCr_16s16s_P3P3((const INT16 **) pSrcDst, 64*sizeof(INT16),
|
||||
pSrcDst, 64*sizeof(INT16), &roi_64x64);
|
||||
prims->RGBToYCbCr_16s16s_P3P3((const INT16**) pSrcDst, 64 * sizeof(INT16),
|
||||
pSrcDst, 64 * sizeof(INT16), &roi_64x64);
|
||||
PROFILER_EXIT(context->priv->prof_rfx_rgb_to_ycbcr);
|
||||
|
||||
/* Ensure the buffer is reasonably large enough */
|
||||
stream_check_size(data_out, 4096);
|
||||
rfx_encode_component(context, y_quants, context->priv->y_r_buffer,
|
||||
|
||||
rfx_encode_component(context, y_quants, pSrcDst[0],
|
||||
stream_get_tail(data_out), stream_get_left(data_out), y_size);
|
||||
stream_seek(data_out, *y_size);
|
||||
|
||||
stream_check_size(data_out, 4096);
|
||||
rfx_encode_component(context, cb_quants, context->priv->cb_g_buffer,
|
||||
rfx_encode_component(context, cb_quants, pSrcDst[1],
|
||||
stream_get_tail(data_out), stream_get_left(data_out), cb_size);
|
||||
stream_seek(data_out, *cb_size);
|
||||
|
||||
stream_check_size(data_out, 4096);
|
||||
rfx_encode_component(context, cr_quants, context->priv->cr_b_buffer,
|
||||
rfx_encode_component(context, cr_quants, pSrcDst[2],
|
||||
stream_get_tail(data_out), stream_get_left(data_out), cr_size);
|
||||
stream_seek(data_out, *cr_size);
|
||||
|
||||
PROFILER_EXIT(context->priv->prof_rfx_encode_rgb);
|
||||
|
||||
BufferPool_Return(context->priv->BufferPool, pSrcDst[0]);
|
||||
BufferPool_Return(context->priv->BufferPool, pSrcDst[1]);
|
||||
BufferPool_Return(context->priv->BufferPool, pSrcDst[2]);
|
||||
}
|
||||
|
|
|
@ -1,121 +0,0 @@
|
|||
/**
|
||||
* FreeRDP: A Remote Desktop Protocol Implementation
|
||||
* RemoteFX Codec Library - Memory Pool
|
||||
*
|
||||
* Copyright 2011 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 <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <winpr/crt.h>
|
||||
|
||||
#include "rfx_pool.h"
|
||||
|
||||
RFX_POOL* rfx_pool_new()
|
||||
{
|
||||
RFX_POOL* pool;
|
||||
|
||||
pool = (RFX_POOL*) malloc(sizeof(RFX_POOL));
|
||||
ZeroMemory(pool, sizeof(RFX_POOL));
|
||||
|
||||
pool->size = 64;
|
||||
pool->tiles = (RFX_TILE**) malloc(sizeof(RFX_TILE*) * pool->size);
|
||||
ZeroMemory(pool->tiles, sizeof(RFX_TILE*) * pool->size);
|
||||
|
||||
return pool;
|
||||
}
|
||||
|
||||
void rfx_pool_free(RFX_POOL* pool)
|
||||
{
|
||||
int i;
|
||||
RFX_TILE* tile;
|
||||
|
||||
for (i = 0; i < pool->count; i++)
|
||||
{
|
||||
tile = pool->tiles[i];
|
||||
|
||||
if (tile != NULL)
|
||||
{
|
||||
if (tile->data != NULL)
|
||||
free(tile->data);
|
||||
|
||||
free(tile);
|
||||
}
|
||||
}
|
||||
|
||||
free(pool->tiles);
|
||||
free(pool);
|
||||
}
|
||||
|
||||
void rfx_pool_put_tile(RFX_POOL* pool, RFX_TILE* tile)
|
||||
{
|
||||
if (pool->count >= pool->size)
|
||||
{
|
||||
pool->size *= 2;
|
||||
pool->tiles = (RFX_TILE**) realloc((void*) pool->tiles, sizeof(RFX_TILE*) * pool->size);
|
||||
}
|
||||
|
||||
pool->tiles[(pool->count)++] = tile;
|
||||
}
|
||||
|
||||
RFX_TILE* rfx_pool_get_tile(RFX_POOL* pool)
|
||||
{
|
||||
RFX_TILE* tile;
|
||||
|
||||
if (pool->count < 1)
|
||||
{
|
||||
tile = (RFX_TILE*) malloc(sizeof(RFX_TILE));
|
||||
ZeroMemory(tile, sizeof(RFX_TILE));
|
||||
|
||||
tile->data = (BYTE*) malloc(4096 * 4); /* 64x64 * 4 */
|
||||
}
|
||||
else
|
||||
{
|
||||
tile = pool->tiles[--(pool->count)];
|
||||
}
|
||||
|
||||
return tile;
|
||||
}
|
||||
|
||||
void rfx_pool_put_tiles(RFX_POOL* pool, RFX_TILE** tiles, int count)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < count; i++)
|
||||
{
|
||||
rfx_pool_put_tile(pool, tiles[i]);
|
||||
}
|
||||
}
|
||||
|
||||
RFX_TILE** rfx_pool_get_tiles(RFX_POOL* pool, int count)
|
||||
{
|
||||
int i;
|
||||
RFX_TILE** tiles;
|
||||
|
||||
tiles = (RFX_TILE**) malloc(sizeof(RFX_TILE*) * count);
|
||||
|
||||
for (i = 0; i < count; i++)
|
||||
{
|
||||
tiles[i] = rfx_pool_get_tile(pool);
|
||||
}
|
||||
|
||||
return tiles;
|
||||
}
|
|
@ -1,40 +0,0 @@
|
|||
/**
|
||||
* FreeRDP: A Remote Desktop Protocol Implementation
|
||||
* RemoteFX Codec Library - Memory Pool
|
||||
*
|
||||
* Copyright 2011 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 __RFX_POOL_H
|
||||
#define __RFX_POOL_H
|
||||
|
||||
#include <freerdp/codec/rfx.h>
|
||||
|
||||
struct _RFX_POOL
|
||||
{
|
||||
int size;
|
||||
int count;
|
||||
RFX_TILE** tiles;
|
||||
};
|
||||
typedef struct _RFX_POOL RFX_POOL;
|
||||
|
||||
RFX_POOL* rfx_pool_new();
|
||||
void rfx_pool_free(RFX_POOL* pool);
|
||||
void rfx_pool_put_tile(RFX_POOL* pool, RFX_TILE* tile);
|
||||
RFX_TILE* rfx_pool_get_tile(RFX_POOL* pool);
|
||||
void rfx_pool_put_tiles(RFX_POOL* pool, RFX_TILE** tiles, int count);
|
||||
RFX_TILE** rfx_pool_get_tiles(RFX_POOL* pool, int count);
|
||||
|
||||
#endif /* __RFX_POOL_H */
|
|
@ -24,6 +24,10 @@
|
|||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#include <winpr/crt.h>
|
||||
#include <winpr/pool.h>
|
||||
#include <winpr/collections.h>
|
||||
|
||||
#include <freerdp/utils/debug.h>
|
||||
#include <freerdp/utils/profiler.h>
|
||||
|
||||
|
@ -33,25 +37,19 @@
|
|||
#define DEBUG_RFX(fmt, ...) DEBUG_NULL(fmt, ## __VA_ARGS__)
|
||||
#endif
|
||||
|
||||
#include "rfx_pool.h"
|
||||
|
||||
struct _RFX_CONTEXT_PRIV
|
||||
{
|
||||
/* pre-allocated buffers */
|
||||
wQueue* TilePool;
|
||||
wQueue* TileQueue;
|
||||
|
||||
RFX_POOL* pool; /* memory pool */
|
||||
BOOL UseThreads;
|
||||
DWORD MinThreadCount;
|
||||
DWORD MaxThreadCount;
|
||||
|
||||
INT16 y_r_mem[4096 + 8]; /* 4096 = 64x64 (+ 8x2 = 16 for mem align) */
|
||||
INT16 cb_g_mem[4096 + 8]; /* 4096 = 64x64 (+ 8x2 = 16 for mem align) */
|
||||
INT16 cr_b_mem[4096 + 8]; /* 4096 = 64x64 (+ 8x2 = 16 for mem align) */
|
||||
PTP_POOL ThreadPool;
|
||||
TP_CALLBACK_ENVIRON ThreadPoolEnv;
|
||||
|
||||
INT16* y_r_buffer;
|
||||
INT16* cb_g_buffer;
|
||||
INT16* cr_b_buffer;
|
||||
|
||||
INT16 dwt_mem[32 * 32 * 2 * 2 + 8]; /* maximum sub-band width is 32 */
|
||||
|
||||
INT16* dwt_buffer;
|
||||
wBufferPool* BufferPool;
|
||||
|
||||
/* profilers */
|
||||
PROFILER_DEFINE(prof_rfx_decode_rgb);
|
||||
|
|
|
@ -202,4 +202,48 @@ WINPR_API UINT32 ReferenceTable_Release(wReferenceTable* referenceTable, void* p
|
|||
WINPR_API wReferenceTable* ReferenceTable_New(BOOL synchronized, void* context, REFERENCE_FREE ReferenceFree);
|
||||
WINPR_API void ReferenceTable_Free(wReferenceTable* referenceTable);
|
||||
|
||||
/* Countdown Event */
|
||||
|
||||
struct _wCountdownEvent
|
||||
{
|
||||
DWORD count;
|
||||
HANDLE mutex;
|
||||
HANDLE event;
|
||||
DWORD initialCount;
|
||||
};
|
||||
typedef struct _wCountdownEvent wCountdownEvent;
|
||||
|
||||
WINPR_API DWORD CountdownEvent_CurrentCount(wCountdownEvent* countdown);
|
||||
WINPR_API DWORD CountdownEvent_InitialCount(wCountdownEvent* countdown);
|
||||
WINPR_API BOOL CountdownEvent_IsSet(wCountdownEvent* countdown);
|
||||
WINPR_API HANDLE CountdownEvent_WaitHandle(wCountdownEvent* countdown);
|
||||
|
||||
WINPR_API void CountdownEvent_AddCount(wCountdownEvent* countdown, DWORD signalCount);
|
||||
WINPR_API BOOL CountdownEvent_Signal(wCountdownEvent* countdown, DWORD signalCount);
|
||||
WINPR_API void CountdownEvent_Reset(wCountdownEvent* countdown, DWORD count);
|
||||
|
||||
WINPR_API wCountdownEvent* CountdownEvent_New(DWORD initialCount);
|
||||
WINPR_API void CountdownEvent_Free(wCountdownEvent* countdown);
|
||||
|
||||
/* BufferPool */
|
||||
|
||||
struct _wBufferPool
|
||||
{
|
||||
int size;
|
||||
int capacity;
|
||||
void** array;
|
||||
HANDLE mutex;
|
||||
int fixedSize;
|
||||
DWORD alignment;
|
||||
BOOL synchronized;
|
||||
};
|
||||
typedef struct _wBufferPool wBufferPool;
|
||||
|
||||
WINPR_API void* BufferPool_Take(wBufferPool* pool, int bufferSize);
|
||||
WINPR_API void BufferPool_Return(wBufferPool* pool, void* buffer);
|
||||
WINPR_API void BufferPool_Clear(wBufferPool* pool);
|
||||
|
||||
WINPR_API wBufferPool* BufferPool_New(BOOL synchronized, int fixedSize, DWORD alignment);
|
||||
WINPR_API void BufferPool_Free(wBufferPool* pool);
|
||||
|
||||
#endif /* WINPR_COLLECTIONS_H */
|
||||
|
|
|
@ -26,7 +26,7 @@
|
|||
#include <winpr/synch.h>
|
||||
#include <winpr/thread.h>
|
||||
|
||||
#if (!(defined _WIN32 && (_WIN32_WINNT < 0x0600)))
|
||||
#ifndef _WIN32
|
||||
|
||||
typedef DWORD TP_VERSION, *PTP_VERSION;
|
||||
|
||||
|
@ -55,6 +55,33 @@ typedef struct _TP_CLEANUP_GROUP TP_CLEANUP_GROUP, *PTP_CLEANUP_GROUP;
|
|||
|
||||
typedef VOID (*PTP_CLEANUP_GROUP_CANCEL_CALLBACK)(PVOID ObjectContext, PVOID CleanupContext);
|
||||
|
||||
typedef struct _TP_CALLBACK_ENVIRON_V1
|
||||
{
|
||||
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_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;
|
||||
|
@ -81,27 +108,30 @@ typedef struct _TP_CALLBACK_ENVIRON_V3
|
|||
DWORD Size;
|
||||
} TP_CALLBACK_ENVIRON_V3;
|
||||
|
||||
typedef TP_CALLBACK_ENVIRON_V3 TP_CALLBACK_ENVIRON, *PTP_CALLBACK_ENVIRON;
|
||||
//typedef TP_CALLBACK_ENVIRON_V3 TP_CALLBACK_ENVIRON, *PTP_CALLBACK_ENVIRON;
|
||||
|
||||
#endif
|
||||
|
||||
typedef struct _TP_WORK TP_WORK, *PTP_WORK;
|
||||
|
||||
typedef VOID (*PTP_WORK_CALLBACK)(PTP_CALLBACK_INSTANCE Instance, PVOID Context, PTP_WORK Work);
|
||||
|
||||
typedef struct _TP_TIMER TP_TIMER, *PTP_TIMER;
|
||||
|
||||
typedef VOID (*PTP_TIMER_CALLBACK)(PTP_CALLBACK_INSTANCE Instance, PVOID Context, PTP_TIMER Timer);
|
||||
|
||||
typedef DWORD TP_WAIT_RESULT;
|
||||
|
||||
typedef struct _TP_WAIT TP_WAIT, *PTP_WAIT;
|
||||
|
||||
typedef VOID (*PTP_WAIT_CALLBACK)(PTP_CALLBACK_INSTANCE Instance, PVOID Context, PTP_WAIT Wait, TP_WAIT_RESULT WaitResult);
|
||||
|
||||
typedef struct _TP_IO TP_IO, *PTP_IO;
|
||||
|
||||
typedef TP_CALLBACK_ENVIRON_V1 TP_CALLBACK_ENVIRON, *PTP_CALLBACK_ENVIRON;
|
||||
|
||||
#ifndef _WIN32
|
||||
|
||||
typedef VOID (*PTP_WORK_CALLBACK)(PTP_CALLBACK_INSTANCE Instance, PVOID Context, PTP_WORK Work);
|
||||
typedef VOID (*PTP_TIMER_CALLBACK)(PTP_CALLBACK_INSTANCE Instance, PVOID Context, PTP_TIMER Timer);
|
||||
typedef VOID (*PTP_WAIT_CALLBACK)(PTP_CALLBACK_INSTANCE Instance, PVOID Context, PTP_WAIT Wait, TP_WAIT_RESULT WaitResult);
|
||||
typedef VOID (*PTP_WIN32_IO_CALLBACK)(PTP_CALLBACK_INSTANCE Instance, PVOID Context, PVOID Overlapped,
|
||||
ULONG IoResult, ULONG_PTR NumberOfBytesTransferred, PTP_IO Io);
|
||||
|
||||
#endif
|
||||
|
||||
/* Synch */
|
||||
|
||||
WINPR_API PTP_WAIT CreateThreadpoolWait(PTP_WAIT_CALLBACK pfnwa, PVOID pv, PTP_CALLBACK_ENVIRON pcbe);
|
||||
|
@ -136,15 +166,15 @@ WINPR_API VOID WaitForThreadpoolIoCallbacks(PTP_IO pio, BOOL fCancelPendingCallb
|
|||
/* Clean-up Group */
|
||||
|
||||
WINPR_API PTP_CLEANUP_GROUP CreateThreadpoolCleanupGroup();
|
||||
VOID CloseThreadpoolCleanupGroupMembers(PTP_CLEANUP_GROUP ptpcg, BOOL fCancelPendingCallbacks, PVOID pvCleanupContext);
|
||||
VOID CloseThreadpoolCleanupGroup(PTP_CLEANUP_GROUP ptpcg);
|
||||
WINPR_API VOID CloseThreadpoolCleanupGroupMembers(PTP_CLEANUP_GROUP ptpcg, BOOL fCancelPendingCallbacks, PVOID pvCleanupContext);
|
||||
WINPR_API VOID CloseThreadpoolCleanupGroup(PTP_CLEANUP_GROUP ptpcg);
|
||||
|
||||
/* Pool */
|
||||
|
||||
WINPR_API PTP_POOL CreateThreadpool(PVOID reserved);
|
||||
WINPR_API VOID CloseThreadpool(PTP_POOL ptpp);
|
||||
WINPR_API VOID SetThreadpoolThreadMaximum(PTP_POOL ptpp, DWORD cthrdMost);
|
||||
WINPR_API BOOL SetThreadpoolThreadMinimum(PTP_POOL ptpp, DWORD cthrdMic);
|
||||
WINPR_API VOID SetThreadpoolThreadMaximum(PTP_POOL ptpp, DWORD cthrdMost);
|
||||
|
||||
/* Callback Environment */
|
||||
|
||||
|
@ -170,7 +200,7 @@ WINPR_API VOID LeaveCriticalSectionWhenCallbackReturns(PTP_CALLBACK_INSTANCE pci
|
|||
WINPR_API VOID FreeLibraryWhenCallbackReturns(PTP_CALLBACK_INSTANCE pci, HMODULE mod);
|
||||
WINPR_API VOID DisassociateCurrentThreadFromCallback(PTP_CALLBACK_INSTANCE pci);
|
||||
|
||||
#endif
|
||||
/* Dummy */
|
||||
|
||||
WINPR_API void winpr_pool_dummy();
|
||||
|
||||
|
|
|
@ -25,6 +25,7 @@ set(${MODULE_PREFIX}_SRCS
|
|||
io.c
|
||||
cleanup_group.c
|
||||
pool.c
|
||||
pool.h
|
||||
callback_environment.c
|
||||
callback.c
|
||||
callback_cleanup.c)
|
||||
|
@ -47,14 +48,22 @@ if(${CMAKE_SYSTEM_NAME} MATCHES SunOS)
|
|||
set(${MODULE_PREFIX}_LIBS ${${MODULE_PREFIX}_LIBS} rt)
|
||||
endif()
|
||||
|
||||
set_complex_link_libraries(VARIABLE ${MODULE_PREFIX}_LIBS
|
||||
MONOLITHIC ${MONOLITHIC_BUILD} INTERNAL
|
||||
MODULE winpr
|
||||
MODULES winpr-thread winpr-synch winpr-utils)
|
||||
|
||||
if(MONOLITHIC_BUILD)
|
||||
set(WINPR_LIBS ${WINPR_LIBS} ${${MODULE_PREFIX}_LIBS} PARENT_SCOPE)
|
||||
else()
|
||||
set(${MODULE_PREFIX}_LIBS ${${MODULE_PREFIX}_LIBS} winpr-thread winpr-synch)
|
||||
|
||||
target_link_libraries(${MODULE_NAME} ${${MODULE_PREFIX}_LIBS})
|
||||
install(TARGETS ${MODULE_NAME} DESTINATION ${CMAKE_INSTALL_LIBDIR})
|
||||
endif()
|
||||
|
||||
set_property(TARGET ${MODULE_NAME} PROPERTY FOLDER "WinPR")
|
||||
|
||||
if(BUILD_TESTING)
|
||||
add_subdirectory(test)
|
||||
endif()
|
||||
|
||||
|
||||
|
|
|
@ -24,11 +24,40 @@
|
|||
#include <winpr/crt.h>
|
||||
#include <winpr/pool.h>
|
||||
|
||||
#if (!(defined _WIN32 && (_WIN32_WINNT < 0x0600)))
|
||||
#ifdef _WIN32
|
||||
|
||||
BOOL CallbackMayRunLong(PTP_CALLBACK_INSTANCE pci)
|
||||
static BOOL module_initialized = FALSE;
|
||||
static BOOL module_available = FALSE;
|
||||
static HMODULE kernel32_module = NULL;
|
||||
|
||||
static BOOL (WINAPI * pCallbackMayRunLong)(PTP_CALLBACK_INSTANCE pci);
|
||||
|
||||
static void module_init()
|
||||
{
|
||||
return FALSE;
|
||||
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");
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
BOOL CallbackMayRunLong(PTP_CALLBACK_INSTANCE pci)
|
||||
{
|
||||
#ifdef _WIN32
|
||||
module_init();
|
||||
|
||||
if (pCallbackMayRunLong)
|
||||
return pCallbackMayRunLong(pci);
|
||||
#else
|
||||
#endif
|
||||
return FALSE;
|
||||
}
|
||||
|
|
|
@ -24,37 +24,109 @@
|
|||
#include <winpr/crt.h>
|
||||
#include <winpr/pool.h>
|
||||
|
||||
#if (!(defined _WIN32 && (_WIN32_WINNT < 0x0600)))
|
||||
#include "pool.h"
|
||||
|
||||
VOID SetEventWhenCallbackReturns(PTP_CALLBACK_INSTANCE pci, HANDLE evt)
|
||||
#ifdef _WIN32
|
||||
|
||||
static BOOL module_initialized = FALSE;
|
||||
static BOOL module_available = FALSE;
|
||||
static HMODULE kernel32_module = NULL;
|
||||
|
||||
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 void module_init()
|
||||
{
|
||||
if (module_initialized)
|
||||
return;
|
||||
|
||||
}
|
||||
kernel32_module = LoadLibraryA("kernel32.dll");
|
||||
module_initialized = TRUE;
|
||||
|
||||
VOID ReleaseSemaphoreWhenCallbackReturns(PTP_CALLBACK_INSTANCE pci, HANDLE sem, DWORD crel)
|
||||
{
|
||||
if (!kernel32_module)
|
||||
return;
|
||||
|
||||
}
|
||||
|
||||
VOID ReleaseMutexWhenCallbackReturns(PTP_CALLBACK_INSTANCE pci, HANDLE mut)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
VOID LeaveCriticalSectionWhenCallbackReturns(PTP_CALLBACK_INSTANCE pci, PCRITICAL_SECTION pcs)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
VOID FreeLibraryWhenCallbackReturns(PTP_CALLBACK_INSTANCE pci, HMODULE mod)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
VOID DisassociateCurrentThreadFromCallback(PTP_CALLBACK_INSTANCE pci)
|
||||
{
|
||||
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");
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
VOID SetEventWhenCallbackReturns(PTP_CALLBACK_INSTANCE pci, HANDLE evt)
|
||||
{
|
||||
#ifdef _WIN32
|
||||
module_init();
|
||||
|
||||
if (pSetEventWhenCallbackReturns)
|
||||
pSetEventWhenCallbackReturns(pci, evt);
|
||||
#else
|
||||
#endif
|
||||
}
|
||||
|
||||
VOID ReleaseSemaphoreWhenCallbackReturns(PTP_CALLBACK_INSTANCE pci, HANDLE sem, DWORD crel)
|
||||
{
|
||||
#ifdef _WIN32
|
||||
module_init();
|
||||
|
||||
if (pReleaseSemaphoreWhenCallbackReturns)
|
||||
pReleaseSemaphoreWhenCallbackReturns(pci, sem, crel);
|
||||
#else
|
||||
#endif
|
||||
}
|
||||
|
||||
VOID ReleaseMutexWhenCallbackReturns(PTP_CALLBACK_INSTANCE pci, HANDLE mut)
|
||||
{
|
||||
#ifdef _WIN32
|
||||
module_init();
|
||||
|
||||
if (pReleaseMutexWhenCallbackReturns)
|
||||
pReleaseMutexWhenCallbackReturns(pci, mut);
|
||||
#else
|
||||
#endif
|
||||
}
|
||||
|
||||
VOID LeaveCriticalSectionWhenCallbackReturns(PTP_CALLBACK_INSTANCE pci, PCRITICAL_SECTION pcs)
|
||||
{
|
||||
#ifdef _WIN32
|
||||
module_init();
|
||||
|
||||
if (pLeaveCriticalSectionWhenCallbackReturns)
|
||||
pLeaveCriticalSectionWhenCallbackReturns(pci, pcs);
|
||||
#else
|
||||
#endif
|
||||
}
|
||||
|
||||
VOID FreeLibraryWhenCallbackReturns(PTP_CALLBACK_INSTANCE pci, HMODULE mod)
|
||||
{
|
||||
#ifdef _WIN32
|
||||
module_init();
|
||||
|
||||
if (pFreeLibraryWhenCallbackReturns)
|
||||
pFreeLibraryWhenCallbackReturns(pci, mod);
|
||||
#else
|
||||
#endif
|
||||
}
|
||||
|
||||
VOID DisassociateCurrentThreadFromCallback(PTP_CALLBACK_INSTANCE pci)
|
||||
{
|
||||
#ifdef _WIN32
|
||||
module_init();
|
||||
|
||||
if (pDisassociateCurrentThreadFromCallback)
|
||||
pDisassociateCurrentThreadFromCallback(pci);
|
||||
#else
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
|
|
@ -24,42 +24,172 @@
|
|||
#include <winpr/crt.h>
|
||||
#include <winpr/pool.h>
|
||||
|
||||
#if (!(defined _WIN32 && (_WIN32_WINNT < 0x0600)))
|
||||
#include "pool.h"
|
||||
|
||||
VOID InitializeThreadpoolEnvironment(PTP_CALLBACK_ENVIRON pcbe)
|
||||
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 DestroyThreadpoolEnvironment(PTP_CALLBACK_ENVIRON pcbe)
|
||||
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);
|
||||
}
|
||||
|
||||
VOID SetThreadpoolCallbackPool(PTP_CALLBACK_ENVIRON pcbe, PTP_POOL ptpp)
|
||||
{
|
||||
#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");
|
||||
}
|
||||
|
||||
VOID SetThreadpoolCallbackCleanupGroup(PTP_CALLBACK_ENVIRON pcbe, PTP_CLEANUP_GROUP ptpcg, PTP_CLEANUP_GROUP_CANCEL_CALLBACK pfng)
|
||||
#else
|
||||
|
||||
static TP_CALLBACK_ENVIRON DEFAULT_CALLBACK_ENVIRONMENT =
|
||||
{
|
||||
1, /* Version */
|
||||
NULL, /* Pool */
|
||||
NULL, /* CleanupGroup */
|
||||
NULL, /* CleanupGroupCancelCallback */
|
||||
NULL, /* RaceDll */
|
||||
NULL, /* ActivationContext */
|
||||
NULL, /* FinalizationCallback */
|
||||
{ 0 } /* Flags */
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
VOID SetThreadpoolCallbackRunsLong(PTP_CALLBACK_ENVIRON pcbe)
|
||||
PTP_CALLBACK_ENVIRON GetDefaultThreadpoolEnvironment()
|
||||
{
|
||||
PTP_CALLBACK_ENVIRON environment = &DEFAULT_CALLBACK_ENVIRONMENT;
|
||||
|
||||
}
|
||||
|
||||
VOID SetThreadpoolCallbackLibrary(PTP_CALLBACK_ENVIRON pcbe, PVOID mod)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
VOID SetThreadpoolCallbackPriority(PTP_CALLBACK_ENVIRON pcbe, TP_CALLBACK_PRIORITY Priority)
|
||||
{
|
||||
environment->Pool = GetDefaultThreadpool();
|
||||
|
||||
return environment;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
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
|
||||
}
|
||||
|
|
|
@ -24,22 +24,74 @@
|
|||
#include <winpr/crt.h>
|
||||
#include <winpr/pool.h>
|
||||
|
||||
#if (!(defined _WIN32 && (_WIN32_WINNT < 0x0600)))
|
||||
#include "pool.h"
|
||||
|
||||
PTP_CLEANUP_GROUP CreateThreadpoolCleanupGroup()
|
||||
#ifdef _WIN32
|
||||
|
||||
static BOOL module_initialized = FALSE;
|
||||
static BOOL module_available = FALSE;
|
||||
static HMODULE kernel32_module = NULL;
|
||||
|
||||
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()
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
if (module_initialized)
|
||||
return;
|
||||
|
||||
VOID CloseThreadpoolCleanupGroupMembers(PTP_CLEANUP_GROUP ptpcg, BOOL fCancelPendingCallbacks, PVOID pvCleanupContext)
|
||||
{
|
||||
kernel32_module = LoadLibraryA("kernel32.dll");
|
||||
module_initialized = TRUE;
|
||||
|
||||
}
|
||||
if (!kernel32_module)
|
||||
return;
|
||||
|
||||
VOID CloseThreadpoolCleanupGroup(PTP_CLEANUP_GROUP ptpcg)
|
||||
{
|
||||
module_available = TRUE;
|
||||
|
||||
pCreateThreadpoolCleanupGroup = (void*) GetProcAddress(kernel32_module, "CreateThreadpoolCleanupGroup");
|
||||
pCloseThreadpoolCleanupGroupMembers = (void*) GetProcAddress(kernel32_module, "CloseThreadpoolCleanupGroupMembers");
|
||||
pCloseThreadpoolCleanupGroup = (void*) GetProcAddress(kernel32_module, "CloseThreadpoolCleanupGroup");
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
PTP_CLEANUP_GROUP CreateThreadpoolCleanupGroup()
|
||||
{
|
||||
PTP_CLEANUP_GROUP cleanupGroup = NULL;
|
||||
#ifdef _WIN32
|
||||
module_init();
|
||||
|
||||
if (pCreateThreadpoolCleanupGroup)
|
||||
return pCreateThreadpoolCleanupGroup();
|
||||
#else
|
||||
cleanupGroup = (PTP_CLEANUP_GROUP) malloc(sizeof(TP_CLEANUP_GROUP));
|
||||
#endif
|
||||
return cleanupGroup;
|
||||
}
|
||||
|
||||
VOID CloseThreadpoolCleanupGroupMembers(PTP_CLEANUP_GROUP ptpcg, BOOL fCancelPendingCallbacks, PVOID pvCleanupContext)
|
||||
{
|
||||
#ifdef _WIN32
|
||||
module_init();
|
||||
|
||||
if (pCloseThreadpoolCleanupGroupMembers)
|
||||
pCloseThreadpoolCleanupGroupMembers(ptpcg, fCancelPendingCallbacks, pvCleanupContext);
|
||||
#else
|
||||
|
||||
#endif
|
||||
}
|
||||
|
||||
VOID CloseThreadpoolCleanupGroup(PTP_CLEANUP_GROUP ptpcg)
|
||||
{
|
||||
#ifdef _WIN32
|
||||
module_init();
|
||||
|
||||
if (pCloseThreadpoolCleanupGroup)
|
||||
pCloseThreadpoolCleanupGroup(ptpcg);
|
||||
#else
|
||||
free(ptpcg);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -24,8 +24,6 @@
|
|||
#include <winpr/crt.h>
|
||||
#include <winpr/pool.h>
|
||||
|
||||
#if (!(defined _WIN32 && (_WIN32_WINNT < 0x0600)))
|
||||
|
||||
PTP_IO CreateThreadpoolIo(HANDLE fl, PTP_WIN32_IO_CALLBACK pfnio, PVOID pv, PTP_CALLBACK_ENVIRON pcbe)
|
||||
{
|
||||
return NULL;
|
||||
|
@ -51,5 +49,3 @@ VOID WaitForThreadpoolIoCallbacks(PTP_IO pio, BOOL fCancelPendingCallbacks)
|
|||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
|
|
@ -24,29 +24,213 @@
|
|||
#include <winpr/crt.h>
|
||||
#include <winpr/pool.h>
|
||||
|
||||
#if (!(defined _WIN32 && (_WIN32_WINNT < 0x0600)))
|
||||
#include "pool.h"
|
||||
|
||||
#ifdef _WIN32
|
||||
|
||||
static BOOL module_initialized = FALSE;
|
||||
static BOOL module_available = FALSE;
|
||||
static HMODULE kernel32_module = NULL;
|
||||
|
||||
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()
|
||||
{
|
||||
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");
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
static TP_POOL DEFAULT_POOL =
|
||||
{
|
||||
0, /* Minimum */
|
||||
500, /* Maximum */
|
||||
NULL, /* Threads */
|
||||
0, /* ThreadCount */
|
||||
};
|
||||
|
||||
static void* thread_pool_work_func(void* arg)
|
||||
{
|
||||
DWORD status;
|
||||
PTP_POOL pool;
|
||||
PTP_WORK work;
|
||||
HANDLE events[2];
|
||||
PTP_CALLBACK_INSTANCE callbackInstance;
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void InitializeThreadpool(PTP_POOL pool)
|
||||
{
|
||||
int index;
|
||||
HANDLE thread;
|
||||
|
||||
if (!pool->Threads)
|
||||
{
|
||||
pool->Minimum = 0;
|
||||
pool->Maximum = 500;
|
||||
|
||||
pool->Threads = ArrayList_New(TRUE);
|
||||
|
||||
pool->PendingQueue = Queue_New(TRUE, -1, -1);
|
||||
pool->WorkComplete = CountdownEvent_New(0);
|
||||
|
||||
pool->TerminateEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
|
||||
|
||||
for (index = 0; index < 4; index++)
|
||||
{
|
||||
thread = CreateThread(NULL, 0,
|
||||
(LPTHREAD_START_ROUTINE) thread_pool_work_func,
|
||||
(void*) pool, 0, NULL);
|
||||
|
||||
ArrayList_Add(pool->Threads, thread);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
PTP_POOL GetDefaultThreadpool()
|
||||
{
|
||||
PTP_POOL pool = NULL;
|
||||
|
||||
pool = &DEFAULT_POOL;
|
||||
|
||||
InitializeThreadpool(pool);
|
||||
|
||||
return pool;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
PTP_POOL CreateThreadpool(PVOID reserved)
|
||||
{
|
||||
return NULL;
|
||||
PTP_POOL pool = NULL;
|
||||
|
||||
#ifdef _WIN32
|
||||
module_init();
|
||||
|
||||
if (pCreateThreadpool)
|
||||
return pCreateThreadpool(reserved);
|
||||
#else
|
||||
pool = (PTP_POOL) malloc(sizeof(TP_POOL));
|
||||
|
||||
if (pool)
|
||||
InitializeThreadpool(pool);
|
||||
#endif
|
||||
|
||||
return pool;
|
||||
}
|
||||
|
||||
VOID CloseThreadpool(PTP_POOL ptpp)
|
||||
{
|
||||
#ifdef _WIN32
|
||||
module_init();
|
||||
|
||||
}
|
||||
if (pCloseThreadpool)
|
||||
pCloseThreadpool(ptpp);
|
||||
#else
|
||||
int index;
|
||||
HANDLE thread;
|
||||
|
||||
VOID SetThreadpoolThreadMaximum(PTP_POOL ptpp, DWORD cthrdMost)
|
||||
{
|
||||
SetEvent(ptpp->TerminateEvent);
|
||||
|
||||
index = ArrayList_Count(ptpp->Threads) - 1;
|
||||
|
||||
while (index >= 0)
|
||||
{
|
||||
thread = (HANDLE) ArrayList_GetItem(ptpp->Threads, index);
|
||||
WaitForSingleObject(thread, INFINITE);
|
||||
index--;
|
||||
}
|
||||
|
||||
ArrayList_Free(ptpp->Threads);
|
||||
Queue_Free(ptpp->PendingQueue);
|
||||
CountdownEvent_Free(ptpp->WorkComplete);
|
||||
CloseHandle(ptpp->TerminateEvent);
|
||||
|
||||
free(ptpp);
|
||||
#endif
|
||||
}
|
||||
|
||||
BOOL SetThreadpoolThreadMinimum(PTP_POOL ptpp, DWORD cthrdMic)
|
||||
{
|
||||
return FALSE;
|
||||
#ifdef _WIN32
|
||||
module_init();
|
||||
|
||||
if (pSetThreadpoolThreadMinimum)
|
||||
return pSetThreadpoolThreadMinimum(ptpp, cthrdMic);
|
||||
#else
|
||||
HANDLE thread;
|
||||
|
||||
ptpp->Minimum = cthrdMic;
|
||||
|
||||
while (ArrayList_Count(ptpp->Threads) < ptpp->Minimum)
|
||||
{
|
||||
thread = CreateThread(NULL, 0,
|
||||
(LPTHREAD_START_ROUTINE) thread_pool_work_func,
|
||||
(void*) ptpp, 0, NULL);
|
||||
|
||||
ArrayList_Add(ptpp->Threads, thread);
|
||||
}
|
||||
#endif
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
VOID SetThreadpoolThreadMaximum(PTP_POOL ptpp, DWORD cthrdMost)
|
||||
{
|
||||
#ifdef _WIN32
|
||||
module_init();
|
||||
|
||||
if (pSetThreadpoolThreadMaximum)
|
||||
pSetThreadpoolThreadMaximum(ptpp, cthrdMost);
|
||||
#else
|
||||
ptpp->Maximum = cthrdMost;
|
||||
#endif
|
||||
}
|
||||
|
||||
/* dummy */
|
||||
|
||||
void winpr_pool_dummy()
|
||||
{
|
||||
|
|
|
@ -0,0 +1,78 @@
|
|||
/**
|
||||
* 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/pool.h>
|
||||
#include <winpr/synch.h>
|
||||
#include <winpr/thread.h>
|
||||
#include <winpr/collections.h>
|
||||
|
||||
struct _TP_CALLBACK_INSTANCE
|
||||
{
|
||||
PTP_WORK Work;
|
||||
};
|
||||
|
||||
struct _TP_POOL
|
||||
{
|
||||
DWORD Minimum;
|
||||
DWORD Maximum;
|
||||
wArrayList* Threads;
|
||||
wQueue* PendingQueue;
|
||||
HANDLE TerminateEvent;
|
||||
wCountdownEvent* WorkComplete;
|
||||
};
|
||||
|
||||
struct _TP_WORK
|
||||
{
|
||||
PVOID CallbackParameter;
|
||||
PTP_WORK_CALLBACK WorkCallback;
|
||||
PTP_CALLBACK_ENVIRON CallbackEnvironment;
|
||||
};
|
||||
|
||||
struct _TP_TIMER
|
||||
{
|
||||
void* dummy;
|
||||
};
|
||||
|
||||
struct _TP_WAIT
|
||||
{
|
||||
void* dummy;
|
||||
};
|
||||
|
||||
struct _TP_IO
|
||||
{
|
||||
void* dummy;
|
||||
};
|
||||
|
||||
struct _TP_CLEANUP_GROUP
|
||||
{
|
||||
void* dummy;
|
||||
};
|
||||
|
||||
#ifndef _WIN32
|
||||
|
||||
PTP_POOL GetDefaultThreadpool();
|
||||
PTP_CALLBACK_ENVIRON GetDefaultThreadpoolEnvironment();
|
||||
|
||||
#endif
|
||||
|
||||
#endif /* WINPR_POOL_PRIVATE_H */
|
||||
|
|
@ -24,8 +24,6 @@
|
|||
#include <winpr/crt.h>
|
||||
#include <winpr/pool.h>
|
||||
|
||||
#if (!(defined _WIN32 && (_WIN32_WINNT < 0x0600)))
|
||||
|
||||
PTP_WAIT CreateThreadpoolWait(PTP_WAIT_CALLBACK pfnwa, PVOID pv, PTP_CALLBACK_ENVIRON pcbe)
|
||||
{
|
||||
return NULL;
|
||||
|
@ -46,5 +44,4 @@ VOID WaitForThreadpoolWaitCallbacks(PTP_WAIT pwa, BOOL fCancelPendingCallbacks)
|
|||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
|
|
@ -0,0 +1,2 @@
|
|||
TestPool
|
||||
TestPool.c
|
|
@ -0,0 +1,35 @@
|
|||
|
||||
set(MODULE_NAME "TestPool")
|
||||
set(MODULE_PREFIX "TEST_POOL")
|
||||
|
||||
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})
|
||||
|
||||
set_complex_link_libraries(VARIABLE ${MODULE_PREFIX}_LIBS
|
||||
MONOLITHIC ${MONOLITHIC_BUILD}
|
||||
MODULE winpr
|
||||
MODULES winpr-pool winpr-interlocked)
|
||||
|
||||
target_link_libraries(${MODULE_NAME} ${${MODULE_PREFIX}_LIBS})
|
||||
|
||||
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")
|
||||
|
|
@ -0,0 +1,9 @@
|
|||
|
||||
#include <winpr/crt.h>
|
||||
#include <winpr/pool.h>
|
||||
|
||||
int TestPoolIO(int argc, char* argv[])
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -0,0 +1,9 @@
|
|||
|
||||
#include <winpr/crt.h>
|
||||
#include <winpr/pool.h>
|
||||
|
||||
int TestPoolSynch(int argc, char* argv[])
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -0,0 +1,29 @@
|
|||
|
||||
#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;
|
||||
|
||||
pool = CreateThreadpool(NULL);
|
||||
|
||||
SetThreadpoolThreadMinimum(pool, 8); /* default is 0 */
|
||||
SetThreadpoolThreadMaximum(pool, 64); /* default is 500 */
|
||||
|
||||
CloseThreadpool(pool);
|
||||
|
||||
return 0;
|
||||
}
|
|
@ -0,0 +1,9 @@
|
|||
|
||||
#include <winpr/crt.h>
|
||||
#include <winpr/pool.h>
|
||||
|
||||
int TestPoolTimer(int argc, char* argv[])
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -0,0 +1,102 @@
|
|||
|
||||
#include <winpr/crt.h>
|
||||
#include <winpr/pool.h>
|
||||
#include <winpr/interlocked.h>
|
||||
|
||||
static LONG count = 0;
|
||||
|
||||
void CALLBACK test_WorkCallback(PTP_CALLBACK_INSTANCE instance, void* context, PTP_WORK work)
|
||||
{
|
||||
int index;
|
||||
BYTE a[1024];
|
||||
BYTE b[1024];
|
||||
BYTE c[1024];
|
||||
|
||||
printf("Hello %s: %d (thread: %d)\n", context,
|
||||
InterlockedIncrement(&count), GetCurrentThreadId());
|
||||
|
||||
for (index = 0; index < 100; index++)
|
||||
{
|
||||
ZeroMemory(a, 1024);
|
||||
ZeroMemory(b, 1024);
|
||||
ZeroMemory(c, 1024);
|
||||
FillMemory(a, 1024, 0xAA);
|
||||
FillMemory(b, 1024, 0xBB);
|
||||
CopyMemory(c, a, 1024);
|
||||
CopyMemory(c, b, 1024);
|
||||
}
|
||||
}
|
||||
|
||||
int TestPoolWork(int argc, char* argv[])
|
||||
{
|
||||
int index;
|
||||
PTP_POOL pool;
|
||||
PTP_WORK work;
|
||||
PTP_CLEANUP_GROUP cleanupGroup;
|
||||
TP_CALLBACK_ENVIRON environment;
|
||||
|
||||
printf("Global Thread Pool\n");
|
||||
|
||||
work = CreateThreadpoolWork((PTP_WORK_CALLBACK) test_WorkCallback, "world", NULL);
|
||||
|
||||
if (!work)
|
||||
{
|
||||
printf("CreateThreadpoolWork failure\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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 (index = 0; index < 10; index++)
|
||||
SubmitThreadpoolWork(work);
|
||||
|
||||
WaitForThreadpoolWorkCallbacks(work, FALSE);
|
||||
CloseThreadpoolWork(work);
|
||||
|
||||
printf("Private Thread Pool\n");
|
||||
|
||||
pool = CreateThreadpool(NULL);
|
||||
|
||||
SetThreadpoolThreadMinimum(pool, 4);
|
||||
SetThreadpoolThreadMaximum(pool, 8);
|
||||
|
||||
InitializeThreadpoolEnvironment(&environment);
|
||||
SetThreadpoolCallbackPool(&environment, pool);
|
||||
|
||||
cleanupGroup = CreateThreadpoolCleanupGroup();
|
||||
|
||||
if (!cleanupGroup)
|
||||
{
|
||||
printf("CreateThreadpoolCleanupGroup failure\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
SetThreadpoolCallbackCleanupGroup(&environment, cleanupGroup, NULL);
|
||||
|
||||
work = CreateThreadpoolWork((PTP_WORK_CALLBACK) test_WorkCallback, "world", &environment);
|
||||
|
||||
if (!work)
|
||||
{
|
||||
printf("CreateThreadpoolWork failure\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
for (index = 0; index < 10; index++)
|
||||
SubmitThreadpoolWork(work);
|
||||
|
||||
WaitForThreadpoolWorkCallbacks(work, FALSE);
|
||||
|
||||
CloseThreadpoolCleanupGroupMembers(cleanupGroup, TRUE, NULL);
|
||||
|
||||
CloseThreadpoolCleanupGroup(cleanupGroup);
|
||||
|
||||
DestroyThreadpoolEnvironment(&environment);
|
||||
|
||||
CloseThreadpoolWork(work);
|
||||
CloseThreadpool(pool);
|
||||
|
||||
return 0;
|
||||
}
|
|
@ -24,8 +24,6 @@
|
|||
#include <winpr/crt.h>
|
||||
#include <winpr/pool.h>
|
||||
|
||||
#if (!(defined _WIN32 && (_WIN32_WINNT < 0x0600)))
|
||||
|
||||
PTP_TIMER CreateThreadpoolTimer(PTP_TIMER_CALLBACK pfnti, PVOID pv, PTP_CALLBACK_ENVIRON pcbe)
|
||||
{
|
||||
return NULL;
|
||||
|
@ -51,5 +49,4 @@ VOID WaitForThreadpoolTimerCallbacks(PTP_TIMER pti, BOOL fCancelPendingCallbacks
|
|||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
|
|
@ -24,32 +24,132 @@
|
|||
#include <winpr/crt.h>
|
||||
#include <winpr/pool.h>
|
||||
|
||||
#if (!(defined _WIN32 && (_WIN32_WINNT < 0x0600)))
|
||||
#include "pool.h"
|
||||
|
||||
#ifdef _WIN32
|
||||
|
||||
static BOOL module_initialized = FALSE;
|
||||
static BOOL module_available = FALSE;
|
||||
static HMODULE kernel32_module = NULL;
|
||||
|
||||
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()
|
||||
{
|
||||
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");
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
PTP_WORK CreateThreadpoolWork(PTP_WORK_CALLBACK pfnwk, PVOID pv, PTP_CALLBACK_ENVIRON pcbe)
|
||||
{
|
||||
return NULL;
|
||||
PTP_WORK work = NULL;
|
||||
|
||||
#ifdef _WIN32
|
||||
module_init();
|
||||
|
||||
if (pCreateThreadpoolWork)
|
||||
return pCreateThreadpoolWork(pfnwk, pv, pcbe);
|
||||
#else
|
||||
work = (PTP_WORK) malloc(sizeof(TP_WORK));
|
||||
|
||||
if (work)
|
||||
{
|
||||
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();
|
||||
|
||||
if (pCloseThreadpoolWork)
|
||||
pCloseThreadpoolWork(pwk);
|
||||
#else
|
||||
free(pwk);
|
||||
#endif
|
||||
}
|
||||
|
||||
VOID SubmitThreadpoolWork(PTP_WORK pwk)
|
||||
{
|
||||
#ifdef _WIN32
|
||||
module_init();
|
||||
|
||||
if (pSubmitThreadpoolWork)
|
||||
pSubmitThreadpoolWork(pwk);
|
||||
#else
|
||||
PTP_POOL pool;
|
||||
PTP_CALLBACK_INSTANCE callbackInstance;
|
||||
|
||||
pool = pwk->CallbackEnvironment->Pool;
|
||||
|
||||
callbackInstance = (PTP_CALLBACK_INSTANCE) malloc(sizeof(TP_CALLBACK_INSTANCE));
|
||||
|
||||
if (callbackInstance)
|
||||
{
|
||||
callbackInstance->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();
|
||||
|
||||
if (pTrySubmitThreadpoolCallback)
|
||||
return pTrySubmitThreadpoolCallback(pfns, pv, pcbe);
|
||||
#else
|
||||
#endif
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
VOID WaitForThreadpoolWorkCallbacks(PTP_WORK pwk, BOOL fCancelPendingCallbacks)
|
||||
{
|
||||
#ifdef _WIN32
|
||||
module_init();
|
||||
|
||||
}
|
||||
if (pWaitForThreadpoolWorkCallbacks)
|
||||
pWaitForThreadpoolWorkCallbacks(pwk, fCancelPendingCallbacks);
|
||||
#else
|
||||
HANDLE event;
|
||||
PTP_POOL pool;
|
||||
|
||||
pool = pwk->CallbackEnvironment->Pool;
|
||||
event = CountdownEvent_WaitHandle(pool->WorkComplete);
|
||||
|
||||
if (WaitForSingleObject(event, INFINITE) != WAIT_OBJECT_0)
|
||||
printf("WaitForThreadpoolWorkCallbacks: error waiting on work completion\n");
|
||||
#endif
|
||||
|
||||
}
|
||||
|
|
|
@ -50,14 +50,19 @@ DWORD WaitForSingleObject(HANDLE hHandle, DWORD dwMilliseconds)
|
|||
|
||||
if (Type == HANDLE_TYPE_THREAD)
|
||||
{
|
||||
int status;
|
||||
WINPR_THREAD* thread;
|
||||
void* thread_status = NULL;
|
||||
|
||||
if (dwMilliseconds != INFINITE)
|
||||
printf("WaitForSingleObject: timeout not implemented for thread wait\n");
|
||||
|
||||
thread = (WINPR_THREAD*) Object;
|
||||
|
||||
pthread_join(thread->thread, NULL);
|
||||
status = pthread_join(thread->thread, &thread_status);
|
||||
|
||||
if (status != 0)
|
||||
printf("WaitForSingleObject: pthread_join failure: %d\n", status);
|
||||
}
|
||||
if (Type == HANDLE_TYPE_MUTEX)
|
||||
{
|
||||
|
|
|
@ -81,7 +81,7 @@ void winpr_StartThread(WINPR_THREAD* thread)
|
|||
pthread_attr_t attr;
|
||||
|
||||
pthread_attr_init(&attr);
|
||||
pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
|
||||
pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);
|
||||
|
||||
if (thread->dwStackSize > 0)
|
||||
pthread_attr_setstacksize(&attr, (size_t) thread->dwStackSize);
|
||||
|
@ -135,7 +135,9 @@ HANDLE _GetCurrentThread(VOID)
|
|||
|
||||
DWORD GetCurrentThreadId(VOID)
|
||||
{
|
||||
return 0;
|
||||
pthread_t tid;
|
||||
tid = pthread_self();
|
||||
return (DWORD) tid;
|
||||
}
|
||||
|
||||
DWORD ResumeThread(HANDLE hThread)
|
||||
|
|
|
@ -25,7 +25,9 @@ set(${MODULE_PREFIX}_COLLECTIONS_SRCS
|
|||
collections/ArrayList.c
|
||||
collections/Dictionary.c
|
||||
collections/ListDictionary.c
|
||||
collections/KeyValuePair.c)
|
||||
collections/KeyValuePair.c
|
||||
collections/CountdownEvent.c
|
||||
collections/BufferPool.c)
|
||||
|
||||
set(${MODULE_PREFIX}_SRCS
|
||||
sam.c
|
||||
|
|
|
@ -0,0 +1,165 @@
|
|||
/**
|
||||
* WinPR: Windows Portable Runtime
|
||||
* Buffer 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.
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#include <winpr/crt.h>
|
||||
|
||||
#include <winpr/collections.h>
|
||||
|
||||
/**
|
||||
* C equivalent of the C# BufferManager Class:
|
||||
* http://msdn.microsoft.com/en-us/library/ms405814.aspx
|
||||
*/
|
||||
|
||||
/**
|
||||
* Methods
|
||||
*/
|
||||
|
||||
/**
|
||||
* Gets a buffer of at least the specified size from the pool.
|
||||
*/
|
||||
|
||||
void* BufferPool_Take(wBufferPool* pool, int bufferSize)
|
||||
{
|
||||
void* buffer = NULL;
|
||||
|
||||
if (pool->synchronized)
|
||||
WaitForSingleObject(pool->mutex, INFINITE);
|
||||
|
||||
if (pool->fixedSize)
|
||||
{
|
||||
if (pool->size > 0)
|
||||
buffer = pool->array[--(pool->size)];
|
||||
|
||||
if (!buffer)
|
||||
{
|
||||
if (pool->alignment)
|
||||
buffer = _aligned_malloc(pool->fixedSize, pool->alignment);
|
||||
else
|
||||
buffer = malloc(pool->fixedSize);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
printf("Variable-size BufferPool not yet implemented\n");
|
||||
}
|
||||
|
||||
if (pool->synchronized)
|
||||
ReleaseMutex(pool->mutex);
|
||||
|
||||
return buffer;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a buffer to the pool.
|
||||
*/
|
||||
|
||||
void BufferPool_Return(wBufferPool* pool, void* buffer)
|
||||
{
|
||||
if (pool->synchronized)
|
||||
WaitForSingleObject(pool->mutex, INFINITE);
|
||||
|
||||
if ((pool->size + 1) >= pool->capacity)
|
||||
{
|
||||
pool->capacity *= 2;
|
||||
pool->array = (void**) realloc(pool->array, sizeof(void*) * pool->capacity);
|
||||
}
|
||||
|
||||
pool->array[(pool->size)++] = buffer;
|
||||
|
||||
if (pool->synchronized)
|
||||
ReleaseMutex(pool->mutex);
|
||||
}
|
||||
|
||||
/**
|
||||
* Releases the buffers currently cached in the pool.
|
||||
*/
|
||||
|
||||
void BufferPool_Clear(wBufferPool* pool)
|
||||
{
|
||||
if (pool->synchronized)
|
||||
WaitForSingleObject(pool->mutex, INFINITE);
|
||||
|
||||
while (pool->size > 0)
|
||||
{
|
||||
(pool->size)--;
|
||||
|
||||
if (pool->alignment)
|
||||
_aligned_free(pool->array[pool->size]);
|
||||
else
|
||||
free(pool->array[pool->size]);
|
||||
}
|
||||
|
||||
if (pool->synchronized)
|
||||
ReleaseMutex(pool->mutex);
|
||||
}
|
||||
|
||||
/**
|
||||
* Construction, Destruction
|
||||
*/
|
||||
|
||||
wBufferPool* BufferPool_New(BOOL synchronized, int fixedSize, DWORD alignment)
|
||||
{
|
||||
wBufferPool* pool = NULL;
|
||||
|
||||
pool = (wBufferPool*) malloc(sizeof(wBufferPool));
|
||||
|
||||
if (pool)
|
||||
{
|
||||
pool->fixedSize = fixedSize;
|
||||
|
||||
if (pool->fixedSize < 0)
|
||||
pool->fixedSize = 0;
|
||||
|
||||
pool->alignment = alignment;
|
||||
pool->synchronized = synchronized;
|
||||
|
||||
if (pool->synchronized)
|
||||
pool->mutex = CreateMutex(NULL, FALSE, NULL);
|
||||
|
||||
if (!pool->fixedSize)
|
||||
{
|
||||
printf("Variable-size BufferPool not yet implemented\n");
|
||||
}
|
||||
|
||||
pool->size = 0;
|
||||
pool->capacity = 32;
|
||||
pool->array = (void**) malloc(sizeof(void*) * pool->capacity);
|
||||
}
|
||||
|
||||
return pool;
|
||||
}
|
||||
|
||||
void BufferPool_Free(wBufferPool* pool)
|
||||
{
|
||||
if (pool)
|
||||
{
|
||||
BufferPool_Clear(pool);
|
||||
|
||||
if (pool->synchronized)
|
||||
CloseHandle(pool->mutex);
|
||||
|
||||
free(pool->array);
|
||||
|
||||
free(pool);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,180 @@
|
|||
/**
|
||||
* WinPR: Windows Portable Runtime
|
||||
* Countdown Event
|
||||
*
|
||||
* 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
|
||||
|
||||
#ifdef HAVE_UNISTD_H
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
|
||||
#include <winpr/crt.h>
|
||||
|
||||
#include <winpr/collections.h>
|
||||
|
||||
/**
|
||||
* C equivalent of the C# CountdownEvent Class
|
||||
* http://msdn.microsoft.com/en-us/library/dd235708/
|
||||
*/
|
||||
|
||||
/**
|
||||
* Properties
|
||||
*/
|
||||
|
||||
/**
|
||||
* Gets the number of remaining signals required to set the event.
|
||||
*/
|
||||
|
||||
DWORD CountdownEvent_CurrentCount(wCountdownEvent* countdown)
|
||||
{
|
||||
return countdown->count;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the numbers of signals initially required to set the event.
|
||||
*/
|
||||
|
||||
DWORD CountdownEvent_InitialCount(wCountdownEvent* countdown)
|
||||
{
|
||||
return countdown->initialCount;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines whether the event is set.
|
||||
*/
|
||||
|
||||
BOOL CountdownEvent_IsSet(wCountdownEvent* countdown)
|
||||
{
|
||||
BOOL status = FALSE;
|
||||
|
||||
if (WaitForSingleObject(countdown->event, 0) == WAIT_OBJECT_0)
|
||||
status = TRUE;
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a WaitHandle that is used to wait for the event to be set.
|
||||
*/
|
||||
|
||||
HANDLE CountdownEvent_WaitHandle(wCountdownEvent* countdown)
|
||||
{
|
||||
return countdown->event;
|
||||
}
|
||||
|
||||
/**
|
||||
* Methods
|
||||
*/
|
||||
|
||||
/**
|
||||
* Increments the CountdownEvent's current count by a specified value.
|
||||
*/
|
||||
|
||||
void CountdownEvent_AddCount(wCountdownEvent* countdown, DWORD signalCount)
|
||||
{
|
||||
WaitForSingleObject(countdown->mutex, INFINITE);
|
||||
|
||||
countdown->count += signalCount;
|
||||
|
||||
if (countdown->count > 0)
|
||||
ResetEvent(countdown->event);
|
||||
|
||||
ReleaseMutex(countdown->mutex);
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers multiple signals with the CountdownEvent, decrementing the value of CurrentCount by the specified amount.
|
||||
*/
|
||||
|
||||
BOOL CountdownEvent_Signal(wCountdownEvent* countdown, DWORD signalCount)
|
||||
{
|
||||
BOOL status;
|
||||
BOOL newStatus;
|
||||
BOOL oldStatus;
|
||||
|
||||
status = newStatus = oldStatus = FALSE;
|
||||
|
||||
WaitForSingleObject(countdown->mutex, INFINITE);
|
||||
|
||||
if (WaitForSingleObject(countdown->event, 0) == WAIT_OBJECT_0)
|
||||
oldStatus = TRUE;
|
||||
|
||||
countdown->count -= signalCount;
|
||||
|
||||
if (countdown->count < 0)
|
||||
{
|
||||
printf("CountdownEvent_Signal warning: count is less than zero\n");
|
||||
countdown->count = 0;
|
||||
}
|
||||
|
||||
if (countdown->count == 0)
|
||||
newStatus = TRUE;
|
||||
|
||||
if (newStatus && (!oldStatus))
|
||||
{
|
||||
SetEvent(countdown->event);
|
||||
status = TRUE;
|
||||
}
|
||||
|
||||
ReleaseMutex(countdown->mutex);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
/**
|
||||
* Resets the InitialCount property to a specified value.
|
||||
*/
|
||||
|
||||
void CountdownEvent_Reset(wCountdownEvent* countdown, DWORD count)
|
||||
{
|
||||
countdown->initialCount = count;
|
||||
}
|
||||
|
||||
/**
|
||||
* Construction, Destruction
|
||||
*/
|
||||
|
||||
wCountdownEvent* CountdownEvent_New(DWORD initialCount)
|
||||
{
|
||||
wCountdownEvent* countdown = NULL;
|
||||
|
||||
countdown = (wCountdownEvent*) malloc(sizeof(wCountdownEvent));
|
||||
|
||||
if (countdown)
|
||||
{
|
||||
countdown->count = initialCount;
|
||||
countdown->initialCount = initialCount;
|
||||
countdown->mutex = CreateMutex(NULL, FALSE, NULL);
|
||||
countdown->event = CreateEvent(NULL, TRUE, FALSE, NULL);
|
||||
|
||||
if (countdown->count == 0)
|
||||
SetEvent(countdown->event);
|
||||
}
|
||||
|
||||
return countdown;
|
||||
}
|
||||
|
||||
void CountdownEvent_Free(wCountdownEvent* countdown)
|
||||
{
|
||||
CloseHandle(countdown->mutex);
|
||||
CloseHandle(countdown->event);
|
||||
|
||||
free(countdown);
|
||||
}
|
|
@ -138,8 +138,21 @@ void Queue_Enqueue(wQueue* queue, void* obj)
|
|||
|
||||
if (queue->size == queue->capacity)
|
||||
{
|
||||
queue->capacity *= queue->growthFactor;
|
||||
int old_capacity;
|
||||
int new_capacity;
|
||||
|
||||
old_capacity = queue->capacity;
|
||||
new_capacity = queue->capacity * queue->growthFactor;
|
||||
|
||||
queue->capacity = new_capacity;
|
||||
queue->array = (void**) realloc(queue->array, sizeof(void*) * queue->capacity);
|
||||
ZeroMemory(&(queue->array[old_capacity]), old_capacity * sizeof(void*));
|
||||
|
||||
if (queue->tail < (old_capacity - 1))
|
||||
{
|
||||
CopyMemory(&(queue->array[old_capacity]), queue->array, queue->tail * sizeof(void*));
|
||||
queue->tail += old_capacity;
|
||||
}
|
||||
}
|
||||
|
||||
queue->array[queue->tail] = obj;
|
||||
|
|
|
@ -18,7 +18,6 @@ int TestQueue(int argc, char* argv[])
|
|||
}
|
||||
|
||||
count = Queue_Count(queue);
|
||||
|
||||
printf("queue count: %d\n", count);
|
||||
|
||||
for (index = 1; index <= 10; index++)
|
||||
|
@ -29,6 +28,25 @@ int TestQueue(int argc, char* argv[])
|
|||
return -1;
|
||||
}
|
||||
|
||||
count = Queue_Count(queue);
|
||||
printf("queue count: %d\n", count);
|
||||
|
||||
Queue_Enqueue(queue, (void*) (size_t) 1);
|
||||
Queue_Enqueue(queue, (void*) (size_t) 2);
|
||||
Queue_Enqueue(queue, (void*) (size_t) 3);
|
||||
|
||||
Queue_Dequeue(queue);
|
||||
Queue_Dequeue(queue);
|
||||
|
||||
Queue_Enqueue(queue, (void*) (size_t) 4);
|
||||
Queue_Enqueue(queue, (void*) (size_t) 5);
|
||||
Queue_Enqueue(queue, (void*) (size_t) 6);
|
||||
|
||||
Queue_Dequeue(queue);
|
||||
Queue_Dequeue(queue);
|
||||
Queue_Dequeue(queue);
|
||||
Queue_Dequeue(queue);
|
||||
|
||||
Queue_Clear(queue);
|
||||
Queue_Free(queue);
|
||||
|
||||
|
|
Loading…
Reference in New Issue