Coverage Report

Created: 2024-05-20 06:11

/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
  countdown->count += signalCount;
109
110
0
  if (countdown->count > 0)
111
0
    ResetEvent(countdown->event);
112
113
0
  LeaveCriticalSection(&countdown->lock);
114
0
}
115
116
/**
117
 * Registers multiple signals with the CountdownEvent, decrementing the value of CurrentCount by the
118
 * specified amount.
119
 */
120
121
BOOL CountdownEvent_Signal(wCountdownEvent* countdown, size_t signalCount)
122
0
{
123
0
  BOOL status = FALSE;
124
0
  BOOL newStatus = FALSE;
125
0
  BOOL oldStatus = FALSE;
126
127
0
  WINPR_ASSERT(countdown);
128
129
0
  EnterCriticalSection(&countdown->lock);
130
131
0
  if (WaitForSingleObject(countdown->event, 0) == WAIT_OBJECT_0)
132
0
    oldStatus = TRUE;
133
134
0
  if (signalCount <= countdown->count)
135
0
    countdown->count -= signalCount;
136
0
  else
137
0
    countdown->count = 0;
138
139
0
  if (countdown->count == 0)
140
0
    newStatus = TRUE;
141
142
0
  if (newStatus && (!oldStatus))
143
0
  {
144
0
    SetEvent(countdown->event);
145
0
    status = TRUE;
146
0
  }
147
148
0
  LeaveCriticalSection(&countdown->lock);
149
150
0
  return status;
151
0
}
152
153
/**
154
 * Resets the InitialCount property to a specified value.
155
 */
156
157
void CountdownEvent_Reset(wCountdownEvent* countdown, size_t count)
158
0
{
159
0
  WINPR_ASSERT(countdown);
160
0
  countdown->initialCount = count;
161
0
}
162
163
/**
164
 * Construction, Destruction
165
 */
166
167
wCountdownEvent* CountdownEvent_New(size_t initialCount)
168
11.4k
{
169
11.4k
  wCountdownEvent* countdown = (wCountdownEvent*)calloc(1, sizeof(wCountdownEvent));
170
171
11.4k
  if (!countdown)
172
0
    return NULL;
173
174
11.4k
  countdown->count = initialCount;
175
11.4k
  countdown->initialCount = initialCount;
176
177
11.4k
  if (!InitializeCriticalSectionAndSpinCount(&countdown->lock, 4000))
178
0
    goto fail;
179
180
11.4k
  countdown->event = CreateEvent(NULL, TRUE, FALSE, NULL);
181
11.4k
  if (!countdown->event)
182
0
    goto fail;
183
184
11.4k
  if (countdown->count == 0)
185
11.4k
  {
186
11.4k
    if (!SetEvent(countdown->event))
187
0
      goto fail;
188
11.4k
  }
189
190
11.4k
  return countdown;
191
192
0
fail:
193
0
  WINPR_PRAGMA_DIAG_PUSH
194
0
  WINPR_PRAGMA_DIAG_IGNORED_MISMATCHED_DEALLOC
195
0
  CountdownEvent_Free(countdown);
196
0
  WINPR_PRAGMA_DIAG_POP
197
0
  return NULL;
198
11.4k
}
199
200
void CountdownEvent_Free(wCountdownEvent* countdown)
201
11.4k
{
202
11.4k
  if (!countdown)
203
0
    return;
204
205
11.4k
  DeleteCriticalSection(&countdown->lock);
206
11.4k
  CloseHandle(countdown->event);
207
208
11.4k
  free(countdown);
209
11.4k
}