Merge pull request #918 from awakecoding/master

RemoteFX Parallel Processing of Tiles
This commit is contained in:
Marc-André Moreau 2013-01-22 19:03:06 -08:00
commit 683e395bf8
34 changed files with 1608 additions and 322 deletions

View File

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

View File

@ -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*) &params[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;

View File

@ -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]);
}

View File

@ -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]);
}

View File

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

View File

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

View File

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

View File

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

View File

@ -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();

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -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()
{

View File

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

View File

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

2
winpr/libwinpr/pool/test/.gitignore vendored Normal file
View File

@ -0,0 +1,2 @@
TestPool
TestPool.c

View File

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

View File

@ -0,0 +1,9 @@
#include <winpr/crt.h>
#include <winpr/pool.h>
int TestPoolIO(int argc, char* argv[])
{
return 0;
}

View File

@ -0,0 +1,9 @@
#include <winpr/crt.h>
#include <winpr/pool.h>
int TestPoolSynch(int argc, char* argv[])
{
return 0;
}

View File

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

View File

@ -0,0 +1,9 @@
#include <winpr/crt.h>
#include <winpr/pool.h>
int TestPoolTimer(int argc, char* argv[])
{
return 0;
}

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -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);
}
}

View File

@ -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);
}

View File

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

View File

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