19#include <freerdp/config.h> 
   21#include <winpr/assert.h> 
   22#include <freerdp/log.h> 
   25#define TAG SERVER_TAG("shadow.mcevent") 
   27struct rdp_shadow_multiclient_event
 
   32  wArrayList* subscribers;
 
   41struct rdp_shadow_multiclient_subscriber
 
   43  rdpShadowMultiClientEvent* ref;
 
   47rdpShadowMultiClientEvent* shadow_multiclient_new(
void)
 
   49  rdpShadowMultiClientEvent* 
event =
 
   50      (rdpShadowMultiClientEvent*)calloc(1, 
sizeof(rdpShadowMultiClientEvent));
 
   54  event->event = CreateEvent(NULL, TRUE, FALSE, NULL);
 
   58  event->barrierEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
 
   59  if (!event->barrierEvent)
 
   62  event->doneEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
 
   63  if (!event->doneEvent)
 
   64    goto out_free_barrierEvent;
 
   66  event->subscribers = ArrayList_New(TRUE);
 
   67  if (!event->subscribers)
 
   68    goto out_free_doneEvent;
 
   70  if (!InitializeCriticalSectionAndSpinCount(&(event->lock), 4000))
 
   71    goto out_free_subscribers;
 
   76  (void)SetEvent(event->doneEvent);
 
   80  ArrayList_Free(event->subscribers);
 
   82  (void)CloseHandle(event->doneEvent);
 
   84  (void)CloseHandle(event->barrierEvent);
 
   86  (void)CloseHandle(event->event);
 
   90  return (rdpShadowMultiClientEvent*)NULL;
 
   93void shadow_multiclient_free(rdpShadowMultiClientEvent* event)
 
   98  DeleteCriticalSection(&(event->lock));
 
  100  ArrayList_Free(event->subscribers);
 
  101  (void)CloseHandle(event->doneEvent);
 
  102  (void)CloseHandle(event->barrierEvent);
 
  103  (void)CloseHandle(event->event);
 
  107static void Publish(rdpShadowMultiClientEvent* event)
 
  109  wArrayList* subscribers = NULL;
 
  110  struct rdp_shadow_multiclient_subscriber* subscriber = NULL;
 
  112  subscribers = 
event->subscribers;
 
  114  WINPR_ASSERT(event->consuming == 0);
 
  117  ArrayList_Lock(subscribers);
 
  118  for (
size_t i = 0; i < ArrayList_Count(subscribers); i++)
 
  120    subscriber = (
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 WaitForSubscribers(rdpShadowMultiClientEvent* event)
 
  138  if (event->consuming > 0)
 
  141    WLog_VRB(TAG, 
"Server wait event %d. %d clients.\n", event->eventid, event->consuming);
 
  142    LeaveCriticalSection(&(event->lock));
 
  143    (void)WaitForSingleObject(event->doneEvent, INFINITE);
 
  144    EnterCriticalSection(&(event->lock));
 
  145    WLog_VRB(TAG, 
"Server quit event %d. %d clients.\n", event->eventid, event->consuming);
 
  149  WINPR_ASSERT(WaitForSingleObject(event->event, 0) != WAIT_OBJECT_0);
 
  152void shadow_multiclient_publish(rdpShadowMultiClientEvent* event)
 
  157  EnterCriticalSection(&(event->lock));
 
  159  LeaveCriticalSection(&(event->lock));
 
  161void shadow_multiclient_wait(rdpShadowMultiClientEvent* event)
 
  166  EnterCriticalSection(&(event->lock));
 
  167  WaitForSubscribers(event);
 
  168  LeaveCriticalSection(&(event->lock));
 
  170void shadow_multiclient_publish_and_wait(rdpShadowMultiClientEvent* event)
 
  175  EnterCriticalSection(&(event->lock));
 
  177  WaitForSubscribers(event);
 
  178  LeaveCriticalSection(&(event->lock));
 
  181static BOOL Consume(
struct rdp_shadow_multiclient_subscriber* subscriber, BOOL wait)
 
  183  rdpShadowMultiClientEvent* 
event = subscriber->ref;
 
  186  if (WaitForSingleObject(event->event, 0) == WAIT_OBJECT_0 && subscriber->pleaseHandle)
 
  193  WINPR_ASSERT(event->consuming >= 0);
 
  195  if (event->consuming == 0)
 
  198    (void)ResetEvent(event->event);
 
  200    if (event->waiting > 0)
 
  203      (void)SetEvent(event->barrierEvent);
 
  208      (void)SetEvent(event->doneEvent);
 
  221      LeaveCriticalSection(&(event->lock));
 
  222      (void)WaitForSingleObject(event->barrierEvent, INFINITE);
 
  223      EnterCriticalSection(&(event->lock));
 
  225      if (event->waiting == 0)
 
  232        (void)ResetEvent(event->barrierEvent);
 
  233        (void)SetEvent(event->doneEvent);
 
  241void* shadow_multiclient_get_subscriber(rdpShadowMultiClientEvent* event)
 
  243  struct rdp_shadow_multiclient_subscriber* subscriber = NULL;
 
  248  EnterCriticalSection(&(event->lock));
 
  250  subscriber = (
struct rdp_shadow_multiclient_subscriber*)calloc(
 
  251      1, 
sizeof(
struct rdp_shadow_multiclient_subscriber));
 
  255  subscriber->ref = event;
 
  256  subscriber->pleaseHandle = FALSE;
 
  258  if (!ArrayList_Append(event->subscribers, subscriber))
 
  261  WLog_VRB(TAG, 
"Get subscriber %p. Wait event %d. %d clients.\n", (
void*)subscriber,
 
  262           event->eventid, event->consuming);
 
  263  (void)Consume(subscriber, TRUE);
 
  264  WLog_VRB(TAG, 
"Get subscriber %p. Quit event %d. %d clients.\n", (
void*)subscriber,
 
  265           event->eventid, event->consuming);
 
  267  LeaveCriticalSection(&(event->lock));
 
  274  LeaveCriticalSection(&(event->lock));
 
  284void shadow_multiclient_release_subscriber(
void* subscriber)
 
  286  struct rdp_shadow_multiclient_subscriber* s = NULL;
 
  287  rdpShadowMultiClientEvent* 
event = NULL;
 
  292  s = (
struct rdp_shadow_multiclient_subscriber*)subscriber;
 
  295  EnterCriticalSection(&(event->lock));
 
  297  WLog_VRB(TAG, 
"Release Subscriber %p. Drop event %d. %d clients.\n", subscriber, event->eventid,
 
  299  (void)Consume(s, FALSE);
 
  300  WLog_VRB(TAG, 
"Release Subscriber %p. Quit event %d. %d clients.\n", subscriber, event->eventid,
 
  303  ArrayList_Remove(event->subscribers, subscriber);
 
  305  LeaveCriticalSection(&(event->lock));
 
  310BOOL shadow_multiclient_consume(
void* subscriber)
 
  312  struct rdp_shadow_multiclient_subscriber* s = NULL;
 
  313  rdpShadowMultiClientEvent* 
event = NULL;
 
  319  s = (
struct rdp_shadow_multiclient_subscriber*)subscriber;
 
  322  EnterCriticalSection(&(event->lock));
 
  324  WLog_VRB(TAG, 
"Subscriber %p wait event %d. %d clients.\n", subscriber, event->eventid,
 
  326  ret = Consume(s, TRUE);
 
  327  WLog_VRB(TAG, 
"Subscriber %p quit event %d. %d clients.\n", subscriber, event->eventid,
 
  330  LeaveCriticalSection(&(event->lock));
 
  335HANDLE shadow_multiclient_getevent(
void* subscriber)
 
  340  return ((
struct rdp_shadow_multiclient_subscriber*)subscriber)->ref->event;