FreeRDP
CountdownEvent.c
1 
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 
48 size_t CountdownEvent_CurrentCount(wCountdownEvent* countdown)
49 {
50  WINPR_ASSERT(countdown);
51  EnterCriticalSection(&countdown->lock);
52  const size_t rc = countdown->count;
53  LeaveCriticalSection(&countdown->lock);
54  return rc;
55 }
56 
61 size_t CountdownEvent_InitialCount(wCountdownEvent* countdown)
62 {
63  WINPR_ASSERT(countdown);
64  EnterCriticalSection(&countdown->lock);
65  const size_t rc = countdown->initialCount;
66  LeaveCriticalSection(&countdown->lock);
67  return rc;
68 }
69 
74 BOOL CountdownEvent_IsSet(wCountdownEvent* countdown)
75 {
76  BOOL status = FALSE;
77 
78  WINPR_ASSERT(countdown);
79  if (WaitForSingleObject(countdown->event, 0) == WAIT_OBJECT_0)
80  status = TRUE;
81 
82  return status;
83 }
84 
89 HANDLE CountdownEvent_WaitHandle(wCountdownEvent* countdown)
90 {
91  WINPR_ASSERT(countdown);
92  return countdown->event;
93 }
94 
103 void CountdownEvent_AddCount(wCountdownEvent* countdown, size_t signalCount)
104 {
105  WINPR_ASSERT(countdown);
106  EnterCriticalSection(&countdown->lock);
107 
108  const BOOL signalSet = countdown->count == 0;
109  countdown->count += signalCount;
110 
111  if (signalSet)
112  (void)ResetEvent(countdown->event);
113 
114  LeaveCriticalSection(&countdown->lock);
115 }
116 
122 BOOL CountdownEvent_Signal(wCountdownEvent* countdown, size_t signalCount)
123 {
124  BOOL status = FALSE;
125  BOOL newStatus = FALSE;
126  BOOL oldStatus = FALSE;
127 
128  WINPR_ASSERT(countdown);
129 
130  EnterCriticalSection(&countdown->lock);
131 
132  if (WaitForSingleObject(countdown->event, 0) == WAIT_OBJECT_0)
133  oldStatus = TRUE;
134 
135  if (signalCount <= countdown->count)
136  countdown->count -= signalCount;
137  else
138  countdown->count = 0;
139 
140  if (countdown->count == 0)
141  newStatus = TRUE;
142 
143  if (newStatus && (!oldStatus))
144  {
145  (void)SetEvent(countdown->event);
146  status = TRUE;
147  }
148 
149  LeaveCriticalSection(&countdown->lock);
150 
151  return status;
152 }
153 
158 void CountdownEvent_Reset(wCountdownEvent* countdown, size_t count)
159 {
160  WINPR_ASSERT(countdown);
161  countdown->initialCount = count;
162 }
163 
168 wCountdownEvent* CountdownEvent_New(size_t initialCount)
169 {
170  wCountdownEvent* countdown = (wCountdownEvent*)calloc(1, sizeof(wCountdownEvent));
171 
172  if (!countdown)
173  return NULL;
174 
175  countdown->count = initialCount;
176  countdown->initialCount = initialCount;
177 
178  if (!InitializeCriticalSectionAndSpinCount(&countdown->lock, 4000))
179  goto fail;
180 
181  countdown->event = CreateEvent(NULL, TRUE, FALSE, NULL);
182  if (!countdown->event)
183  goto fail;
184 
185  if (countdown->count == 0)
186  {
187  if (!SetEvent(countdown->event))
188  goto fail;
189  }
190 
191  return countdown;
192 
193 fail:
194  WINPR_PRAGMA_DIAG_PUSH
195  WINPR_PRAGMA_DIAG_IGNORED_MISMATCHED_DEALLOC
196  CountdownEvent_Free(countdown);
197  WINPR_PRAGMA_DIAG_POP
198  return NULL;
199 }
200 
201 void CountdownEvent_Free(wCountdownEvent* countdown)
202 {
203  if (!countdown)
204  return;
205 
206  DeleteCriticalSection(&countdown->lock);
207  (void)CloseHandle(countdown->event);
208 
209  free(countdown);
210 }