Coverage Report

Created: 2023-09-25 06:56

/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
  return countdown->count;
52
0
}
53
54
/**
55
 * Gets the numbers of signals initially required to set the event.
56
 */
57
58
size_t CountdownEvent_InitialCount(wCountdownEvent* countdown)
59
0
{
60
0
  WINPR_ASSERT(countdown);
61
0
  return countdown->initialCount;
62
0
}
63
64
/**
65
 * Determines whether the event is set.
66
 */
67
68
BOOL CountdownEvent_IsSet(wCountdownEvent* countdown)
69
0
{
70
0
  BOOL status = FALSE;
71
72
0
  WINPR_ASSERT(countdown);
73
0
  if (WaitForSingleObject(countdown->event, 0) == WAIT_OBJECT_0)
74
0
    status = TRUE;
75
76
0
  return status;
77
0
}
78
79
/**
80
 * Gets a WaitHandle that is used to wait for the event to be set.
81
 */
82
83
HANDLE CountdownEvent_WaitHandle(wCountdownEvent* countdown)
84
0
{
85
0
  WINPR_ASSERT(countdown);
86
0
  return countdown->event;
87
0
}
88
89
/**
90
 * Methods
91
 */
92
93
/**
94
 * Increments the CountdownEvent's current count by a specified value.
95
 */
96
97
void CountdownEvent_AddCount(wCountdownEvent* countdown, size_t signalCount)
98
0
{
99
0
  WINPR_ASSERT(countdown);
100
0
  EnterCriticalSection(&countdown->lock);
101
102
0
  countdown->count += signalCount;
103
104
0
  if (countdown->count > 0)
105
0
    ResetEvent(countdown->event);
106
107
0
  LeaveCriticalSection(&countdown->lock);
108
0
}
109
110
/**
111
 * Registers multiple signals with the CountdownEvent, decrementing the value of CurrentCount by the
112
 * specified amount.
113
 */
114
115
BOOL CountdownEvent_Signal(wCountdownEvent* countdown, size_t signalCount)
116
0
{
117
0
  BOOL status = FALSE;
118
0
  BOOL newStatus = FALSE;
119
0
  BOOL oldStatus = FALSE;
120
121
0
  WINPR_ASSERT(countdown);
122
123
0
  EnterCriticalSection(&countdown->lock);
124
125
0
  if (WaitForSingleObject(countdown->event, 0) == WAIT_OBJECT_0)
126
0
    oldStatus = TRUE;
127
128
0
  if (signalCount <= countdown->count)
129
0
    countdown->count -= signalCount;
130
0
  else
131
0
    countdown->count = 0;
132
133
0
  if (countdown->count == 0)
134
0
    newStatus = TRUE;
135
136
0
  if (newStatus && (!oldStatus))
137
0
  {
138
0
    SetEvent(countdown->event);
139
0
    status = TRUE;
140
0
  }
141
142
0
  LeaveCriticalSection(&countdown->lock);
143
144
0
  return status;
145
0
}
146
147
/**
148
 * Resets the InitialCount property to a specified value.
149
 */
150
151
void CountdownEvent_Reset(wCountdownEvent* countdown, size_t count)
152
0
{
153
0
  WINPR_ASSERT(countdown);
154
0
  countdown->initialCount = count;
155
0
}
156
157
/**
158
 * Construction, Destruction
159
 */
160
161
wCountdownEvent* CountdownEvent_New(size_t initialCount)
162
0
{
163
0
  wCountdownEvent* countdown = (wCountdownEvent*)calloc(1, sizeof(wCountdownEvent));
164
165
0
  if (!countdown)
166
0
    return NULL;
167
168
0
  countdown->count = initialCount;
169
0
  countdown->initialCount = initialCount;
170
171
0
  if (!InitializeCriticalSectionAndSpinCount(&countdown->lock, 4000))
172
0
    goto fail;
173
174
0
  countdown->event = CreateEvent(NULL, TRUE, FALSE, NULL);
175
0
  if (!countdown->event)
176
0
    goto fail;
177
178
0
  if (countdown->count == 0)
179
0
  {
180
0
    if (!SetEvent(countdown->event))
181
0
      goto fail;
182
0
  }
183
184
0
  return countdown;
185
186
0
fail:
187
0
  CountdownEvent_Free(countdown);
188
0
  return NULL;
189
0
}
190
191
void CountdownEvent_Free(wCountdownEvent* countdown)
192
0
{
193
0
  if (!countdown)
194
0
    return;
195
196
0
  DeleteCriticalSection(&countdown->lock);
197
0
  CloseHandle(countdown->event);
198
199
0
  free(countdown);
200
0
}