Blame server/shadow/shadow_mcevent.c

Packit Service fa4841
/**
Packit Service fa4841
 * FreeRDP: A Remote Desktop Protocol Implementation
Packit Service fa4841
 *
Packit Service fa4841
 * Copyright 2015 Jiang Zihao <zihao.jiang@yahoo.com>
Packit Service fa4841
 *
Packit Service fa4841
 * Licensed under the Apache License, Version 2.0 (the "License");
Packit Service fa4841
 * you may not use this file except in compliance with the License.
Packit Service fa4841
 * You may obtain a copy of the License at
Packit Service fa4841
 *
Packit Service fa4841
 *     http://www.apache.org/licenses/LICENSE-2.0
Packit Service fa4841
 *
Packit Service fa4841
 * Unless required by applicable law or agreed to in writing, software
Packit Service fa4841
 * distributed under the License is distributed on an "AS IS" BASIS,
Packit Service fa4841
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
Packit Service fa4841
 * See the License for the specific language governing permissions and
Packit Service fa4841
 * limitations under the License.
Packit Service fa4841
 */
Packit Service fa4841
Packit Service fa4841
#ifdef HAVE_CONFIG_H
Packit Service fa4841
#include "config.h"
Packit Service fa4841
#endif
Packit Service fa4841
Packit Service fa4841
#include <assert.h>
Packit Service fa4841
#include <freerdp/log.h>
Packit Service fa4841
#include "shadow.h"
Packit Service fa4841
Packit Service fa4841
#define TAG SERVER_TAG("shadow.mcevent")
Packit Service fa4841
Packit Service fa4841
struct rdp_shadow_multiclient_event
Packit Service fa4841
{
Packit Service fa4841
	HANDLE event;        /* Kickoff event */
Packit Service fa4841
	HANDLE barrierEvent; /* Represents that all clients have consumed event */
Packit Service fa4841
	HANDLE doneEvent;    /* Event handling finished. Server could continue */
Packit Service fa4841
	wArrayList* subscribers;
Packit Service fa4841
	CRITICAL_SECTION lock;
Packit Service fa4841
	int consuming;
Packit Service fa4841
	int waiting;
Packit Service fa4841
Packit Service fa4841
	/* For debug */
Packit Service fa4841
	int eventid;
Packit Service fa4841
};
Packit Service fa4841
Packit Service fa4841
struct rdp_shadow_multiclient_subscriber
Packit Service fa4841
{
Packit Service fa4841
	rdpShadowMultiClientEvent* ref;
Packit Service fa4841
	BOOL pleaseHandle; /* Indicate if server expects my handling in this turn */
Packit Service fa4841
};
Packit Service fa4841
Packit Service fa4841
rdpShadowMultiClientEvent* shadow_multiclient_new(void)
Packit Service fa4841
{
Packit Service fa4841
	rdpShadowMultiClientEvent* event =
Packit Service fa4841
	    (rdpShadowMultiClientEvent*)calloc(1, sizeof(rdpShadowMultiClientEvent));
Packit Service fa4841
	if (!event)
Packit Service fa4841
		goto out_error;
Packit Service fa4841
Packit Service fa4841
	event->event = CreateEvent(NULL, TRUE, FALSE, NULL);
Packit Service fa4841
	if (!event->event)
Packit Service fa4841
		goto out_free;
Packit Service fa4841
Packit Service fa4841
	event->barrierEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
Packit Service fa4841
	if (!event->barrierEvent)
Packit Service fa4841
		goto out_free_event;
Packit Service fa4841
Packit Service fa4841
	event->doneEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
Packit Service fa4841
	if (!event->doneEvent)
Packit Service fa4841
		goto out_free_barrierEvent;
Packit Service fa4841
Packit Service fa4841
	event->subscribers = ArrayList_New(TRUE);
Packit Service fa4841
	if (!event->subscribers)
Packit Service fa4841
		goto out_free_doneEvent;
Packit Service fa4841
Packit Service fa4841
	if (!InitializeCriticalSectionAndSpinCount(&(event->lock), 4000))
Packit Service fa4841
		goto out_free_subscribers;
Packit Service fa4841
Packit Service fa4841
	event->consuming = 0;
Packit Service fa4841
	event->waiting = 0;
Packit Service fa4841
	event->eventid = 0;
Packit Service fa4841
	SetEvent(event->doneEvent);
Packit Service fa4841
	return event;
Packit Service fa4841
Packit Service fa4841
out_free_subscribers:
Packit Service fa4841
	ArrayList_Free(event->subscribers);
Packit Service fa4841
out_free_doneEvent:
Packit Service fa4841
	CloseHandle(event->doneEvent);
Packit Service fa4841
out_free_barrierEvent:
Packit Service fa4841
	CloseHandle(event->barrierEvent);
Packit Service fa4841
out_free_event:
Packit Service fa4841
	CloseHandle(event->event);
Packit Service fa4841
out_free:
Packit Service fa4841
	free(event);
Packit Service fa4841
out_error:
Packit Service fa4841
	return (rdpShadowMultiClientEvent*)NULL;
Packit Service fa4841
}
Packit Service fa4841
Packit Service fa4841
void shadow_multiclient_free(rdpShadowMultiClientEvent* event)
Packit Service fa4841
{
Packit Service fa4841
	if (!event)
Packit Service fa4841
		return;
Packit Service fa4841
Packit Service fa4841
	DeleteCriticalSection(&(event->lock));
Packit Service fa4841
Packit Service fa4841
	ArrayList_Free(event->subscribers);
Packit Service fa4841
	CloseHandle(event->doneEvent);
Packit Service fa4841
	CloseHandle(event->barrierEvent);
Packit Service fa4841
	CloseHandle(event->event);
Packit Service fa4841
	free(event);
Packit Service fa4841
Packit Service fa4841
	return;
Packit Service fa4841
}
Packit Service fa4841
Packit Service fa4841
static void _Publish(rdpShadowMultiClientEvent* event)
Packit Service fa4841
{
Packit Service fa4841
	wArrayList* subscribers;
Packit Service fa4841
	struct rdp_shadow_multiclient_subscriber* subscriber = NULL;
Packit Service fa4841
	int i;
Packit Service fa4841
Packit Service fa4841
	subscribers = event->subscribers;
Packit Service fa4841
Packit Service fa4841
	assert(event->consuming == 0);
Packit Service fa4841
Packit Service fa4841
	/* Count subscribing clients */
Packit Service fa4841
	ArrayList_Lock(subscribers);
Packit Service fa4841
	for (i = 0; i < ArrayList_Count(subscribers); i++)
Packit Service fa4841
	{
Packit Service fa4841
		subscriber = (struct rdp_shadow_multiclient_subscriber*)ArrayList_GetItem(subscribers, i);
Packit Service fa4841
		/* Set flag to subscriber: I acknowledge and please handle */
Packit Service fa4841
		subscriber->pleaseHandle = TRUE;
Packit Service fa4841
		event->consuming++;
Packit Service fa4841
	}
Packit Service fa4841
	ArrayList_Unlock(subscribers);
Packit Service fa4841
Packit Service fa4841
	if (event->consuming > 0)
Packit Service fa4841
	{
Packit Service fa4841
		event->eventid = (event->eventid & 0xff) + 1;
Packit Service fa4841
		WLog_VRB(TAG, "Server published event %d. %d clients.\n", event->eventid, event->consuming);
Packit Service fa4841
		ResetEvent(event->doneEvent);
Packit Service fa4841
		SetEvent(event->event);
Packit Service fa4841
	}
Packit Service fa4841
Packit Service fa4841
	return;
Packit Service fa4841
}
Packit Service fa4841
Packit Service fa4841
static void _WaitForSubscribers(rdpShadowMultiClientEvent* event)
Packit Service fa4841
{
Packit Service fa4841
	if (event->consuming > 0)
Packit Service fa4841
	{
Packit Service fa4841
		/* Wait for clients done */
Packit Service fa4841
		WLog_VRB(TAG, "Server wait event %d. %d clients.\n", event->eventid, event->consuming);
Packit Service fa4841
		LeaveCriticalSection(&(event->lock));
Packit Service fa4841
		WaitForSingleObject(event->doneEvent, INFINITE);
Packit Service fa4841
		EnterCriticalSection(&(event->lock));
Packit Service fa4841
		WLog_VRB(TAG, "Server quit event %d. %d clients.\n", event->eventid, event->consuming);
Packit Service fa4841
	}
Packit Service fa4841
Packit Service fa4841
	/* Last subscriber should have already reset the event */
Packit Service fa4841
	assert(WaitForSingleObject(event->event, 0) != WAIT_OBJECT_0);
Packit Service fa4841
Packit Service fa4841
	return;
Packit Service fa4841
}
Packit Service fa4841
Packit Service fa4841
void shadow_multiclient_publish(rdpShadowMultiClientEvent* event)
Packit Service fa4841
{
Packit Service fa4841
	if (!event)
Packit Service fa4841
		return;
Packit Service fa4841
Packit Service fa4841
	EnterCriticalSection(&(event->lock));
Packit Service fa4841
	_Publish(event);
Packit Service fa4841
	LeaveCriticalSection(&(event->lock));
Packit Service fa4841
Packit Service fa4841
	return;
Packit Service fa4841
}
Packit Service fa4841
void shadow_multiclient_wait(rdpShadowMultiClientEvent* event)
Packit Service fa4841
{
Packit Service fa4841
	if (!event)
Packit Service fa4841
		return;
Packit Service fa4841
Packit Service fa4841
	EnterCriticalSection(&(event->lock));
Packit Service fa4841
	_WaitForSubscribers(event);
Packit Service fa4841
	LeaveCriticalSection(&(event->lock));
Packit Service fa4841
Packit Service fa4841
	return;
Packit Service fa4841
}
Packit Service fa4841
void shadow_multiclient_publish_and_wait(rdpShadowMultiClientEvent* event)
Packit Service fa4841
{
Packit Service fa4841
	if (!event)
Packit Service fa4841
		return;
Packit Service fa4841
Packit Service fa4841
	EnterCriticalSection(&(event->lock));
Packit Service fa4841
	_Publish(event);
Packit Service fa4841
	_WaitForSubscribers(event);
Packit Service fa4841
	LeaveCriticalSection(&(event->lock));
Packit Service fa4841
Packit Service fa4841
	return;
Packit Service fa4841
}
Packit Service fa4841
Packit Service fa4841
static BOOL _Consume(struct rdp_shadow_multiclient_subscriber* subscriber, BOOL wait)
Packit Service fa4841
{
Packit Service fa4841
	rdpShadowMultiClientEvent* event = subscriber->ref;
Packit Service fa4841
	BOOL ret = FALSE;
Packit Service fa4841
Packit Service fa4841
	if (WaitForSingleObject(event->event, 0) == WAIT_OBJECT_0 && subscriber->pleaseHandle)
Packit Service fa4841
	{
Packit Service fa4841
		/* Consume my share. Server is waiting for us */
Packit Service fa4841
		event->consuming--;
Packit Service fa4841
		ret = TRUE;
Packit Service fa4841
	}
Packit Service fa4841
Packit Service fa4841
	assert(event->consuming >= 0);
Packit Service fa4841
Packit Service fa4841
	if (event->consuming == 0)
Packit Service fa4841
	{
Packit Service fa4841
		/* Last client reset event before notify clients to continue */
Packit Service fa4841
		ResetEvent(event->event);
Packit Service fa4841
Packit Service fa4841
		if (event->waiting > 0)
Packit Service fa4841
		{
Packit Service fa4841
			/* Notify other clients to continue */
Packit Service fa4841
			SetEvent(event->barrierEvent);
Packit Service fa4841
		}
Packit Service fa4841
		else
Packit Service fa4841
		{
Packit Service fa4841
			/* Only one client. Notify server directly */
Packit Service fa4841
			SetEvent(event->doneEvent);
Packit Service fa4841
		}
Packit Service fa4841
	}
Packit Service fa4841
	else /* (event->consuming > 0) */
Packit Service fa4841
	{
Packit Service fa4841
		if (wait)
Packit Service fa4841
		{
Packit Service fa4841
			/*
Packit Service fa4841
			 * This client need to wait. That means the client will
Packit Service fa4841
			 * continue waiting for other clients to finish.
Packit Service fa4841
			 * The last client should reset barrierEvent.
Packit Service fa4841
			 */
Packit Service fa4841
			event->waiting++;
Packit Service fa4841
			LeaveCriticalSection(&(event->lock));
Packit Service fa4841
			WaitForSingleObject(event->barrierEvent, INFINITE);
Packit Service fa4841
			EnterCriticalSection(&(event->lock));
Packit Service fa4841
			event->waiting--;
Packit Service fa4841
			if (event->waiting == 0)
Packit Service fa4841
			{
Packit Service fa4841
				/*
Packit Service fa4841
				 * This is last client waiting for barrierEvent.
Packit Service fa4841
				 * We can now discard barrierEvent and notify
Packit Service fa4841
				 * server to continue.
Packit Service fa4841
				 */
Packit Service fa4841
				ResetEvent(event->barrierEvent);
Packit Service fa4841
				SetEvent(event->doneEvent);
Packit Service fa4841
			}
Packit Service fa4841
		}
Packit Service fa4841
	}
Packit Service fa4841
Packit Service fa4841
	return ret;
Packit Service fa4841
}
Packit Service fa4841
Packit Service fa4841
void* shadow_multiclient_get_subscriber(rdpShadowMultiClientEvent* event)
Packit Service fa4841
{
Packit Service fa4841
	struct rdp_shadow_multiclient_subscriber* subscriber;
Packit Service fa4841
Packit Service fa4841
	if (!event)
Packit Service fa4841
		return NULL;
Packit Service fa4841
Packit Service fa4841
	EnterCriticalSection(&(event->lock));
Packit Service fa4841
Packit Service fa4841
	subscriber = (struct rdp_shadow_multiclient_subscriber*)calloc(
Packit Service fa4841
	    1, sizeof(struct rdp_shadow_multiclient_subscriber));
Packit Service fa4841
	if (!subscriber)
Packit Service fa4841
		goto out_error;
Packit Service fa4841
Packit Service fa4841
	subscriber->ref = event;
Packit Service fa4841
	subscriber->pleaseHandle = FALSE;
Packit Service fa4841
Packit Service fa4841
	if (ArrayList_Add(event->subscribers, subscriber) < 0)
Packit Service fa4841
		goto out_free;
Packit Service fa4841
Packit Service fa4841
	WLog_VRB(TAG, "Get subscriber %p. Wait event %d. %d clients.\n", (void*)subscriber,
Packit Service fa4841
	         event->eventid, event->consuming);
Packit Service fa4841
	(void)_Consume(subscriber, TRUE);
Packit Service fa4841
	WLog_VRB(TAG, "Get subscriber %p. Quit event %d. %d clients.\n", (void*)subscriber,
Packit Service fa4841
	         event->eventid, event->consuming);
Packit Service fa4841
Packit Service fa4841
	LeaveCriticalSection(&(event->lock));
Packit Service fa4841
Packit Service fa4841
	return subscriber;
Packit Service fa4841
Packit Service fa4841
out_free:
Packit Service fa4841
	free(subscriber);
Packit Service fa4841
out_error:
Packit Service fa4841
	LeaveCriticalSection(&(event->lock));
Packit Service fa4841
	return NULL;
Packit Service fa4841
}
Packit Service fa4841
Packit Service fa4841
/*
Packit Service fa4841
 * Consume my share and release my register
Packit Service fa4841
 * If we have update event and pleaseHandle flag
Packit Service fa4841
 * We need to consume. Anyway we need to clear
Packit Service fa4841
 * pleaseHandle flag
Packit Service fa4841
 */
Packit Service fa4841
void shadow_multiclient_release_subscriber(void* subscriber)
Packit Service fa4841
{
Packit Service fa4841
	struct rdp_shadow_multiclient_subscriber* s;
Packit Service fa4841
	rdpShadowMultiClientEvent* event;
Packit Service fa4841
Packit Service fa4841
	if (!subscriber)
Packit Service fa4841
		return;
Packit Service fa4841
Packit Service fa4841
	s = (struct rdp_shadow_multiclient_subscriber*)subscriber;
Packit Service fa4841
	event = s->ref;
Packit Service fa4841
Packit Service fa4841
	EnterCriticalSection(&(event->lock));
Packit Service fa4841
Packit Service fa4841
	WLog_VRB(TAG, "Release Subscriber %p. Drop event %d. %d clients.\n", subscriber, event->eventid,
Packit Service fa4841
	         event->consuming);
Packit Service fa4841
	(void)_Consume(s, FALSE);
Packit Service fa4841
	WLog_VRB(TAG, "Release Subscriber %p. Quit event %d. %d clients.\n", subscriber, event->eventid,
Packit Service fa4841
	         event->consuming);
Packit Service fa4841
Packit Service fa4841
	ArrayList_Remove(event->subscribers, subscriber);
Packit Service fa4841
Packit Service fa4841
	LeaveCriticalSection(&(event->lock));
Packit Service fa4841
Packit Service fa4841
	free(subscriber);
Packit Service fa4841
Packit Service fa4841
	return;
Packit Service fa4841
}
Packit Service fa4841
Packit Service fa4841
BOOL shadow_multiclient_consume(void* subscriber)
Packit Service fa4841
{
Packit Service fa4841
	struct rdp_shadow_multiclient_subscriber* s;
Packit Service fa4841
	rdpShadowMultiClientEvent* event;
Packit Service fa4841
	BOOL ret = FALSE;
Packit Service fa4841
Packit Service fa4841
	if (!subscriber)
Packit Service fa4841
		return ret;
Packit Service fa4841
Packit Service fa4841
	s = (struct rdp_shadow_multiclient_subscriber*)subscriber;
Packit Service fa4841
	event = s->ref;
Packit Service fa4841
Packit Service fa4841
	EnterCriticalSection(&(event->lock));
Packit Service fa4841
Packit Service fa4841
	WLog_VRB(TAG, "Subscriber %p wait event %d. %d clients.\n", subscriber, event->eventid,
Packit Service fa4841
	         event->consuming);
Packit Service fa4841
	ret = _Consume(s, TRUE);
Packit Service fa4841
	WLog_VRB(TAG, "Subscriber %p quit event %d. %d clients.\n", subscriber, event->eventid,
Packit Service fa4841
	         event->consuming);
Packit Service fa4841
Packit Service fa4841
	LeaveCriticalSection(&(event->lock));
Packit Service fa4841
Packit Service fa4841
	return ret;
Packit Service fa4841
}
Packit Service fa4841
Packit Service fa4841
HANDLE shadow_multiclient_getevent(void* subscriber)
Packit Service fa4841
{
Packit Service fa4841
	if (!subscriber)
Packit Service fa4841
		return (HANDLE)NULL;
Packit Service fa4841
Packit Service fa4841
	return ((struct rdp_shadow_multiclient_subscriber*)subscriber)->ref->event;
Packit Service fa4841
}