diff options
Diffstat (limited to 'winpr/libwinpr/utils/collections/CountdownEvent.c')
-rw-r--r-- | winpr/libwinpr/utils/collections/CountdownEvent.c | 203 |
1 files changed, 203 insertions, 0 deletions
diff --git a/winpr/libwinpr/utils/collections/CountdownEvent.c b/winpr/libwinpr/utils/collections/CountdownEvent.c new file mode 100644 index 0000000..fd23e0c --- /dev/null +++ b/winpr/libwinpr/utils/collections/CountdownEvent.c @@ -0,0 +1,203 @@ +/** + * 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. + */ + +#include <winpr/config.h> +#include <winpr/assert.h> + +#include <winpr/crt.h> + +#include <winpr/collections.h> + +struct CountdownEvent +{ + size_t count; + CRITICAL_SECTION lock; + HANDLE event; + size_t initialCount; +}; + +/** + * 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. + */ + +size_t CountdownEvent_CurrentCount(wCountdownEvent* countdown) +{ + WINPR_ASSERT(countdown); + return countdown->count; +} + +/** + * Gets the numbers of signals initially required to set the event. + */ + +size_t CountdownEvent_InitialCount(wCountdownEvent* countdown) +{ + WINPR_ASSERT(countdown); + return countdown->initialCount; +} + +/** + * Determines whether the event is set. + */ + +BOOL CountdownEvent_IsSet(wCountdownEvent* countdown) +{ + BOOL status = FALSE; + + WINPR_ASSERT(countdown); + 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) +{ + WINPR_ASSERT(countdown); + return countdown->event; +} + +/** + * Methods + */ + +/** + * Increments the CountdownEvent's current count by a specified value. + */ + +void CountdownEvent_AddCount(wCountdownEvent* countdown, size_t signalCount) +{ + WINPR_ASSERT(countdown); + EnterCriticalSection(&countdown->lock); + + countdown->count += signalCount; + + if (countdown->count > 0) + ResetEvent(countdown->event); + + LeaveCriticalSection(&countdown->lock); +} + +/** + * Registers multiple signals with the CountdownEvent, decrementing the value of CurrentCount by the + * specified amount. + */ + +BOOL CountdownEvent_Signal(wCountdownEvent* countdown, size_t signalCount) +{ + BOOL status = FALSE; + BOOL newStatus = FALSE; + BOOL oldStatus = FALSE; + + WINPR_ASSERT(countdown); + + EnterCriticalSection(&countdown->lock); + + if (WaitForSingleObject(countdown->event, 0) == WAIT_OBJECT_0) + oldStatus = TRUE; + + if (signalCount <= countdown->count) + countdown->count -= signalCount; + else + countdown->count = 0; + + if (countdown->count == 0) + newStatus = TRUE; + + if (newStatus && (!oldStatus)) + { + SetEvent(countdown->event); + status = TRUE; + } + + LeaveCriticalSection(&countdown->lock); + + return status; +} + +/** + * Resets the InitialCount property to a specified value. + */ + +void CountdownEvent_Reset(wCountdownEvent* countdown, size_t count) +{ + WINPR_ASSERT(countdown); + countdown->initialCount = count; +} + +/** + * Construction, Destruction + */ + +wCountdownEvent* CountdownEvent_New(size_t initialCount) +{ + wCountdownEvent* countdown = (wCountdownEvent*)calloc(1, sizeof(wCountdownEvent)); + + if (!countdown) + return NULL; + + countdown->count = initialCount; + countdown->initialCount = initialCount; + + if (!InitializeCriticalSectionAndSpinCount(&countdown->lock, 4000)) + goto fail; + + countdown->event = CreateEvent(NULL, TRUE, FALSE, NULL); + if (!countdown->event) + goto fail; + + if (countdown->count == 0) + { + if (!SetEvent(countdown->event)) + goto fail; + } + + return countdown; + +fail: + WINPR_PRAGMA_DIAG_PUSH + WINPR_PRAGMA_DIAG_IGNORED_MISMATCHED_DEALLOC + CountdownEvent_Free(countdown); + WINPR_PRAGMA_DIAG_POP + return NULL; +} + +void CountdownEvent_Free(wCountdownEvent* countdown) +{ + if (!countdown) + return; + + DeleteCriticalSection(&countdown->lock); + CloseHandle(countdown->event); + + free(countdown); +} |