From 5b4aaf276f6d5a480390b0ae46fdc41ab2f93c89 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marc-Andr=C3=A9=20Moreau?= Date: Fri, 18 Jan 2013 13:50:35 -0500 Subject: [PATCH] libfreerdp-core: added reference counter for receive buffers --- libfreerdp/core/transport.c | 12 +- libfreerdp/core/transport.h | 2 + libfreerdp/core/update.c | 2 + winpr/include/winpr/collections.h | 28 +++ winpr/libwinpr/thread/process.c | 6 +- winpr/libwinpr/utils/CMakeLists.txt | 1 + winpr/libwinpr/utils/collections/Reference.c | 171 +++++++++++++++++++ 7 files changed, 218 insertions(+), 4 deletions(-) create mode 100644 winpr/libwinpr/utils/collections/Reference.c diff --git a/libfreerdp/core/transport.c b/libfreerdp/core/transport.c index cbdbe89ef..f89410149 100644 --- a/libfreerdp/core/transport.c +++ b/libfreerdp/core/transport.c @@ -693,14 +693,15 @@ int transport_check_fds(rdpTransport** ptransport) * 1: asynchronous return */ + ReferenceTable_Add(transport->ReceiveReferences, received); + recv_status = transport->ReceiveCallback(transport, received, transport->ReceiveExtra); + ReferenceTable_Release(transport->ReceiveReferences, received); + if (recv_status < 0) status = -1; - if (recv_status == 0) - transport_receive_pool_return(transport, received); - if (status < 0) return status; @@ -789,6 +790,9 @@ rdpTransport* transport_new(rdpSettings* settings) transport->ReceiveQueue = Queue_New(TRUE, -1, -1); Queue_Object(transport->ReceivePool)->fnObjectFree = (OBJECT_FREE_FN) stream_free; Queue_Object(transport->ReceiveQueue)->fnObjectFree = (OBJECT_FREE_FN) stream_free; + + transport->ReceiveReferences = ReferenceTable_New(TRUE, + (void*) transport, (REFERENCE_FREE) transport_receive_pool_return); } return transport; @@ -819,6 +823,8 @@ void transport_free(rdpTransport* transport) Queue_Free(transport->ReceivePool); Queue_Free(transport->ReceiveQueue); + ReferenceTable_Free(transport->ReceiveReferences); + free(transport); } } diff --git a/libfreerdp/core/transport.h b/libfreerdp/core/transport.h index cca3d090b..92ec3b090 100644 --- a/libfreerdp/core/transport.h +++ b/libfreerdp/core/transport.h @@ -69,6 +69,8 @@ struct rdp_transport wQueue* ReceivePool; wQueue* ReceiveQueue; + + wReferenceTable* ReceiveReferences; }; STREAM* transport_recv_stream_init(rdpTransport* transport, int size); diff --git a/libfreerdp/core/update.c b/libfreerdp/core/update.c index 9baea0e8e..3b0ad5ab8 100644 --- a/libfreerdp/core/update.c +++ b/libfreerdp/core/update.c @@ -701,6 +701,8 @@ void update_free(rdpUpdate* update) CloseHandle(update->thread); + Queue_Free(update->queue); + free(update); } } diff --git a/winpr/include/winpr/collections.h b/winpr/include/winpr/collections.h index f092255d7..ad0e77237 100644 --- a/winpr/include/winpr/collections.h +++ b/winpr/include/winpr/collections.h @@ -174,4 +174,32 @@ struct _wKeyValuePair }; typedef struct _wKeyValuePair wKeyValuePair; +/* Reference Table */ + +struct _wReference +{ + UINT32 Count; + void* Pointer; +}; +typedef struct _wReference wReference; + +typedef int (*REFERENCE_FREE)(void* context, void* ptr); + +struct _wReferenceTable +{ + UINT32 size; + HANDLE mutex; + void* context; + BOOL synchronized; + wReference* array; + REFERENCE_FREE ReferenceFree; +}; +typedef struct _wReferenceTable wReferenceTable; + +WINPR_API UINT32 ReferenceTable_Add(wReferenceTable* referenceTable, void* ptr); +WINPR_API UINT32 ReferenceTable_Release(wReferenceTable* referenceTable, void* ptr); + +WINPR_API wReferenceTable* ReferenceTable_New(BOOL synchronized, void* context, REFERENCE_FREE ReferenceFree); +WINPR_API void ReferenceTable_Free(wReferenceTable* referenceTable); + #endif /* WINPR_COLLECTIONS_H */ diff --git a/winpr/libwinpr/thread/process.c b/winpr/libwinpr/thread/process.c index c786178f2..092773469 100644 --- a/winpr/libwinpr/thread/process.c +++ b/winpr/libwinpr/thread/process.c @@ -51,6 +51,10 @@ #ifndef _WIN32 +#ifdef HAVE_UNISTD_H +#include +#endif + #include typedef void *(*pthread_start_routine)(void*); @@ -95,7 +99,7 @@ HANDLE GetCurrentProcess(VOID) DWORD GetCurrentProcessId(VOID) { - return 0; + return ((DWORD) getpid()); } DWORD GetProcessId(HANDLE Process) diff --git a/winpr/libwinpr/utils/CMakeLists.txt b/winpr/libwinpr/utils/CMakeLists.txt index 6b0e096f1..453cd54de 100644 --- a/winpr/libwinpr/utils/CMakeLists.txt +++ b/winpr/libwinpr/utils/CMakeLists.txt @@ -21,6 +21,7 @@ set(MODULE_PREFIX "WINPR_UTILS") set(${MODULE_PREFIX}_COLLECTIONS_SRCS collections/Queue.c collections/Stack.c + collections/Reference.c collections/ArrayList.c collections/Dictionary.c collections/ListDictionary.c diff --git a/winpr/libwinpr/utils/collections/Reference.c b/winpr/libwinpr/utils/collections/Reference.c new file mode 100644 index 000000000..7df1c84b2 --- /dev/null +++ b/winpr/libwinpr/utils/collections/Reference.c @@ -0,0 +1,171 @@ +/** + * WinPR: Windows Portable Runtime + * Reference Count Table + * + * Copyright 2012 Marc-Andre Moreau + * + * 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 +#endif + +#include + +#include + +/** + * C reference counting + * http://msdn.microsoft.com/en-us/library/windows/desktop/ms693431/ + */ + +wReference* ReferenceTable_FindEntry(wReferenceTable* referenceTable, void* ptr) +{ + int index = 0; + BOOL found = FALSE; + wReference* reference = NULL; + + for (index = 0; index < referenceTable->size; index++) + { + reference = &referenceTable->array[index]; + + if (reference->Pointer == ptr) + found = TRUE; + } + + return (found) ? reference : NULL; +} + +wReference* ReferenceTable_GetFreeEntry(wReferenceTable* referenceTable) +{ + int index = 0; + BOOL found = FALSE; + wReference* reference = NULL; + + for (index = 0; index < referenceTable->size; index++) + { + reference = &referenceTable->array[index]; + + if (reference->Pointer == NULL) + { + reference->Count = 0; + found = TRUE; + } + } + + if (!found) + { + referenceTable->size *= 2; + referenceTable->array = (wReference*) realloc(referenceTable->array, sizeof(wReference) * referenceTable->size); + + ZeroMemory(&referenceTable->array[(referenceTable->size / 2)], + sizeof(wReference) * (referenceTable->size / 2)); + + return ReferenceTable_GetFreeEntry(referenceTable); + } + + return reference; +} + +UINT32 ReferenceTable_Add(wReferenceTable* referenceTable, void* ptr) +{ + UINT32 count = 0; + wReference* reference = NULL; + + if (referenceTable->synchronized) + WaitForSingleObject(referenceTable->mutex, INFINITE); + + reference = ReferenceTable_FindEntry(referenceTable, ptr); + + if (!reference) + { + reference = ReferenceTable_GetFreeEntry(referenceTable); + reference->Pointer = ptr; + reference->Count = 0; + } + + count = ++(reference->Count); + + if (referenceTable->synchronized) + ReleaseMutex(referenceTable->mutex); + + return count; +} + +UINT32 ReferenceTable_Release(wReferenceTable* referenceTable, void* ptr) +{ + UINT32 count = 0; + wReference* reference = NULL; + + if (referenceTable->synchronized) + WaitForSingleObject(referenceTable->mutex, INFINITE); + + reference = ReferenceTable_FindEntry(referenceTable, ptr); + + if (reference) + { + count = --(reference->Count); + + if (count < 1) + { + if (referenceTable->ReferenceFree) + { + referenceTable->ReferenceFree(referenceTable->context, ptr); + reference->Pointer = NULL; + reference->Count = 0; + } + } + } + + if (referenceTable->synchronized) + ReleaseMutex(referenceTable->mutex); + + return count; +} + +wReferenceTable* ReferenceTable_New(BOOL synchronized, void* context, REFERENCE_FREE ReferenceFree) +{ + wReferenceTable* referenceTable; + + referenceTable = (wReferenceTable*) malloc(sizeof(wReferenceTable)); + + if (referenceTable) + { + referenceTable->context = context; + referenceTable->ReferenceFree = ReferenceFree; + + referenceTable->size = 32; + referenceTable->array = (wReference*) malloc(sizeof(wReference) * referenceTable->size); + ZeroMemory(referenceTable->array, sizeof(wReference) * referenceTable->size); + + referenceTable->synchronized = synchronized; + referenceTable->mutex = CreateMutex(NULL, FALSE, NULL); + } + + return referenceTable; +} + +void ReferenceTable_Free(wReferenceTable* referenceTable) +{ + if (referenceTable) + { + CloseHandle(referenceTable->mutex); + free(referenceTable->array); + free(referenceTable); + } +}