Coverage Report

Created: 2025-07-01 06:46

/src/FreeRDP/winpr/libwinpr/utils/collections/CountdownEvent.c
Line
Count
Source (jump to first uncovered line)
1
/**
2
 * WinPR: Windows Portable Runtime
3
 * Countdown Event
4
 *
5
 * Copyright 2012 Marc-Andre Moreau <marcandre.moreau@gmail.com>
6
 *
7
 * Licensed under the Apache License, Version 2.0 (the "License");
8
 * you may not use this file except in compliance with the License.
9
 * You may obtain a copy of the License at
10
 *
11
 *     http://www.apache.org/licenses/LICENSE-2.0
12
 *
13
 * Unless required by applicable law or agreed to in writing, software
14
 * distributed under the License is distributed on an "AS IS" BASIS,
15
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16
 * See the License for the specific language governing permissions and
17
 * limitations under the License.
18
 */
19
20
#include <winpr/config.h>
21
#include <winpr/assert.h>
22
23
#include <winpr/crt.h>
24
25
#include <winpr/collections.h>
26
27
struct CountdownEvent
28
{
29
  size_t count;
30
  CRITICAL_SECTION lock;
31
  HANDLE event;
32
  size_t initialCount;
33
};
34
35
/**
36
 * C equivalent of the C# CountdownEvent Class
37
 * http://msdn.microsoft.com/en-us/library/dd235708/
38
 */
39
40
/**
41
 * Properties
42
 */
43
44
/**
45
 * Gets the number of remaining signals required to set the event.
46
 */
47
48
size_t CountdownEvent_CurrentCount(wCountdownEvent* countdown)
49
0
{
50
0
  WINPR_ASSERT(countdown);
51
0
  EnterCriticalSection(&countdown->lock);
52
0
  const size_t rc = countdown->count;
53
0
  LeaveCriticalSection(&countdown->lock);
54
0
  return rc;
55
0
}
56
57
/**
58
 * Gets the numbers of signals initially required to set the event.
59
 */
60
61
size_t CountdownEvent_InitialCount(wCountdownEvent* countdown)
62
0
{
63
0
  WINPR_ASSERT(countdown);
64
0
  EnterCriticalSection(&countdown->lock);
65
0
  const size_t rc = countdown->initialCount;
66
0
  LeaveCriticalSection(&countdown->lock);
67
0
  return rc;
68
0
}
69
70
/**
71
 * Determines whether the event is set.
72
 */
73
74
BOOL CountdownEvent_IsSet(wCountdownEvent* countdown)
75
0
{
76
0
  BOOL status = FALSE;
77
78
0
  WINPR_ASSERT(countdown);
79
0
  if (WaitForSingleObject(countdown->event, 0) == WAIT_OBJECT_0)
80
0
    status = TRUE;
81
82
0
  return status;
83
0
}
84
85
/**
86
 * Gets a WaitHandle that is used to wait for the event to be set.
87
 */
88
89
HANDLE CountdownEvent_WaitHandle(wCountdownEvent* countdown)
90
0
{
91
0
  WINPR_ASSERT(countdown);
92
0
  return countdown->event;
93
0
}
94
95
/**
96
 * Methods
97
 */
98
99
/**
100
 * Increments the CountdownEvent's current count by a specified value.
101
 */
102
103
void CountdownEvent_AddCount(wCountdownEvent* countdown, size_t signalCount)
104
0
{
105
0
  WINPR_ASSERT(countdown);
106
0
  EnterCriticalSection(&countdown->lock);
107
108
0
  const BOOL signalSet = countdown->count == 0;
109
0
  countdown->count += signalCount;
110
111
0
  if (signalSet)
112
0
    (void)ResetEvent(countdown->event);
113
114
0
  LeaveCriticalSection(&countdown->lock);
115
0
}
116
117
/**
118
 * Registers multiple signals with the CountdownEvent, decrementing the value of CurrentCount by the
119
 * specified amount.
120
 */
121
122
BOOL CountdownEvent_Signal(wCountdownEvent* countdown, size_t signalCount)
123
0
{
124
0
  BOOL status = FALSE;
125
0
  BOOL newStatus = FALSE;
126
0
  BOOL oldStatus = FALSE;
127
128
0
  WINPR_ASSERT(countdown);
129
130
0
  EnterCriticalSection(&countdown->lock);
131
132
0
  if (WaitForSingleObject(countdown->event, 0) == WAIT_OBJECT_0)
133
0
    oldStatus = TRUE;
134
135
0
  if (signalCount <= countdown->count)
136
0
    countdown->count -= signalCount;
137
0
  else
138
0
    countdown->count = 0;
139
140
0
  if (countdown->count == 0)
141
0
    newStatus = TRUE;
142
143
0
  if (newStatus && (!oldStatus))
144
0
  {
145
0
    (void)SetEvent(countdown->event);
146
0
    status = TRUE;
147
0
  }
148
149
0
  LeaveCriticalSection(&countdown->lock);
150
151
0
  return status;
152
0
}
153
154
/**
155
 * Resets the InitialCount property to a specified value.
156
 */
157
158
void CountdownEvent_Reset(wCountdownEvent* countdown, size_t count)
159
0
{
160
0
  WINPR_ASSERT(countdown);
161
0
  countdown->initialCount = count;
162
0
}
163
164
/**
165
 * Construction, Destruction
166
 */
167
168
wCountdownEvent* CountdownEvent_New(size_t initialCount)
169
0
{
170
0
  wCountdownEvent* countdown = (wCountdownEvent*)calloc(1, sizeof(wCountdownEvent));
171
172
0
  if (!countdown)
173
0
    return NULL;
174
175
0
  countdown->count = initialCount;
176
0
  countdown->initialCount = initialCount;
177
178
0
  if (!InitializeCriticalSectionAndSpinCount(&countdown->lock, 4000))
179
0
    goto fail;
180
181
0
  countdown->event = CreateEvent(NULL, TRUE, FALSE, NULL);
182
0
  if (!countdown->event)
183
0
    goto fail;
184
185
0
  if (countdown->count == 0)
186
0
  {
187
0
    if (!SetEvent(countdown->event))
188
0
      goto fail;
189
0
  }
190
191
0
  return countdown;
192
193
0
fail:
194
0
  WINPR_PRAGMA_DIAG_PUSH
195
0
  WINPR_PRAGMA_DIAG_IGNORED_MISMATCHED_DEALLOC
196
0
  CountdownEvent_Free(countdown);
197
0
  WINPR_PRAGMA_DIAG_POP
198
0
  return NULL;
199
0
}
200
201
void CountdownEvent_Free(wCountdownEvent* countdown)
202
0
{
203
0
  if (!countdown)
204
0
    return;
205
206
0
  DeleteCriticalSection(&countdown->lock);
207
0
  (void)CloseHandle(countdown->event);
208
209
0
  free(countdown);
210
0
}