19#include <freerdp/config.h>
21#include <winpr/assert.h>
22#include <freerdp/log.h>
25#define TAG SERVER_TAG("shadow.mcevent")
32#define SHADOW_SUBSCRIBER_WAIT_TIMEOUT 1000ul
34struct rdp_shadow_multiclient_event
39 wArrayList* subscribers;
48struct rdp_shadow_multiclient_subscriber
50 rdpShadowMultiClientEvent* ref;
54rdpShadowMultiClientEvent* shadow_multiclient_new(
void)
56 rdpShadowMultiClientEvent*
event = calloc(1,
sizeof(rdpShadowMultiClientEvent));
60 if (!InitializeCriticalSectionAndSpinCount(&(event->lock), 4000))
63 event->event = CreateEvent(
nullptr, TRUE, FALSE,
nullptr);
67 event->barrierEvent = CreateEvent(
nullptr, TRUE, FALSE,
nullptr);
68 if (!event->barrierEvent)
71 event->doneEvent = CreateEvent(
nullptr, TRUE, FALSE,
nullptr);
72 if (!event->doneEvent)
75 event->subscribers = ArrayList_New(TRUE);
76 if (!event->subscribers)
82 if (!SetEvent(event->doneEvent))
87 shadow_multiclient_free(event);
91void shadow_multiclient_free(rdpShadowMultiClientEvent* event)
96 DeleteCriticalSection(&(event->lock));
98 ArrayList_Free(event->subscribers);
100 (void)CloseHandle(event->doneEvent);
101 if (event->barrierEvent)
102 (void)CloseHandle(event->barrierEvent);
103 if (event->barrierEvent)
104 (void)CloseHandle(event->event);
108static void Publish(rdpShadowMultiClientEvent* event)
111 wArrayList* subscribers =
event->subscribers;
113 WINPR_ASSERT(event->consuming == 0);
116 ArrayList_Lock(subscribers);
117 for (
size_t i = 0; i < ArrayList_Count(subscribers); i++)
119 struct rdp_shadow_multiclient_subscriber* subscriber =
120 (
struct rdp_shadow_multiclient_subscriber*)ArrayList_GetItem(subscribers, i);
122 subscriber->pleaseHandle = TRUE;
125 ArrayList_Unlock(subscribers);
127 if (event->consuming > 0)
129 event->eventid = (
event->eventid & 0xff) + 1;
130 WLog_VRB(TAG,
"Server published event %d. %d clients.\n", event->eventid, event->consuming);
131 (void)ResetEvent(event->doneEvent);
132 (void)SetEvent(event->event);
136static void DiscardRound(rdpShadowMultiClientEvent* event)
138 wArrayList* subscribers =
nullptr;
146 subscribers =
event->subscribers;
147 ArrayList_Lock(subscribers);
148 for (
size_t i = 0; i < ArrayList_Count(subscribers); i++)
150 struct rdp_shadow_multiclient_subscriber* subscriber =
151 (
struct rdp_shadow_multiclient_subscriber*)ArrayList_GetItem(subscribers, i);
152 subscriber->pleaseHandle = FALSE;
154 ArrayList_Unlock(subscribers);
156 if (event->waiting > 0)
158 (void)SetEvent(event->barrierEvent);
162 (void)SetEvent(event->doneEvent);
165 WLog_WARN(TAG,
"Event %d dropped: %d subscriber(s) unresponsive for %lu ms", event->eventid,
166 event->consuming, SHADOW_SUBSCRIBER_WAIT_TIMEOUT);
167 event->consuming = 0;
168 (void)ResetEvent(event->event);
171static void WaitForSubscribers(rdpShadowMultiClientEvent* event)
173 DWORD status = WAIT_FAILED;
175 if (event->consuming > 0)
178 WLog_VRB(TAG,
"Server wait event %d. %d clients.\n", event->eventid, event->consuming);
179 LeaveCriticalSection(&(event->lock));
180 status = WaitForSingleObject(event->doneEvent, SHADOW_SUBSCRIBER_WAIT_TIMEOUT);
181 EnterCriticalSection(&(event->lock));
183 if (status != WAIT_OBJECT_0)
186 WLog_VRB(TAG,
"Server quit event %d. %d clients.\n", event->eventid, event->consuming);
190 WINPR_ASSERT(WaitForSingleObject(event->event, 0) != WAIT_OBJECT_0);
193void shadow_multiclient_publish(rdpShadowMultiClientEvent* event)
198 EnterCriticalSection(&(event->lock));
200 LeaveCriticalSection(&(event->lock));
202void shadow_multiclient_wait(rdpShadowMultiClientEvent* event)
207 EnterCriticalSection(&(event->lock));
208 WaitForSubscribers(event);
209 LeaveCriticalSection(&(event->lock));
211void shadow_multiclient_publish_and_wait(rdpShadowMultiClientEvent* event)
216 EnterCriticalSection(&(event->lock));
218 WaitForSubscribers(event);
219 LeaveCriticalSection(&(event->lock));
222static BOOL Consume(
struct rdp_shadow_multiclient_subscriber* subscriber, BOOL wait)
224 rdpShadowMultiClientEvent*
event = subscriber->ref;
227 if (WaitForSingleObject(event->event, 0) == WAIT_OBJECT_0 && subscriber->pleaseHandle)
234 WINPR_ASSERT(event->consuming >= 0);
236 if (event->consuming == 0)
239 (void)ResetEvent(event->event);
241 if (event->waiting > 0)
244 (void)SetEvent(event->barrierEvent);
249 (void)SetEvent(event->doneEvent);
262 LeaveCriticalSection(&(event->lock));
263 (void)WaitForSingleObject(event->barrierEvent, INFINITE);
264 EnterCriticalSection(&(event->lock));
266 if (event->waiting == 0)
273 (void)ResetEvent(event->barrierEvent);
274 (void)SetEvent(event->doneEvent);
282void* shadow_multiclient_get_subscriber(rdpShadowMultiClientEvent* event)
284 struct rdp_shadow_multiclient_subscriber* subscriber =
nullptr;
289 EnterCriticalSection(&(event->lock));
291 subscriber = (
struct rdp_shadow_multiclient_subscriber*)calloc(
292 1,
sizeof(
struct rdp_shadow_multiclient_subscriber));
296 subscriber->ref = event;
297 subscriber->pleaseHandle = FALSE;
299 if (!ArrayList_Append(event->subscribers, subscriber))
302 WLog_VRB(TAG,
"Get subscriber %p. Wait event %d. %d clients.\n", (
void*)subscriber,
303 event->eventid, event->consuming);
304 (void)Consume(subscriber, TRUE);
305 WLog_VRB(TAG,
"Get subscriber %p. Quit event %d. %d clients.\n", (
void*)subscriber,
306 event->eventid, event->consuming);
308 LeaveCriticalSection(&(event->lock));
315 LeaveCriticalSection(&(event->lock));
325void shadow_multiclient_release_subscriber(
void* subscriber)
327 struct rdp_shadow_multiclient_subscriber* s =
nullptr;
328 rdpShadowMultiClientEvent*
event =
nullptr;
333 s = (
struct rdp_shadow_multiclient_subscriber*)subscriber;
336 EnterCriticalSection(&(event->lock));
338 WLog_VRB(TAG,
"Release Subscriber %p. Drop event %d. %d clients.\n", subscriber, event->eventid,
340 (void)Consume(s, FALSE);
341 WLog_VRB(TAG,
"Release Subscriber %p. Quit event %d. %d clients.\n", subscriber, event->eventid,
344 ArrayList_Remove(event->subscribers, subscriber);
346 LeaveCriticalSection(&(event->lock));
351BOOL shadow_multiclient_consume(
void* subscriber)
353 struct rdp_shadow_multiclient_subscriber* s =
nullptr;
354 rdpShadowMultiClientEvent*
event =
nullptr;
360 s = (
struct rdp_shadow_multiclient_subscriber*)subscriber;
363 EnterCriticalSection(&(event->lock));
365 WLog_VRB(TAG,
"Subscriber %p wait event %d. %d clients.\n", subscriber, event->eventid,
367 ret = Consume(s, TRUE);
368 WLog_VRB(TAG,
"Subscriber %p quit event %d. %d clients.\n", subscriber, event->eventid,
371 LeaveCriticalSection(&(event->lock));
376HANDLE shadow_multiclient_getevent(
void* subscriber)
379 return (HANDLE)
nullptr;
381 return ((
struct rdp_shadow_multiclient_subscriber*)subscriber)->ref->event;