Blame winpr/libwinpr/synch/event.c

Packit Service fa4841
/**
Packit Service fa4841
 * WinPR: Windows Portable Runtime
Packit Service fa4841
 * Synchronization Functions
Packit Service fa4841
 *
Packit Service fa4841
 * Copyright 2012 Marc-Andre Moreau <marcandre.moreau@gmail.com>
Packit Service fa4841
 * Copyright 2017 Armin Novak <armin.novak@thincast.com>
Packit Service fa4841
 * Copyright 2017 Thincast Technologies GmbH
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 <stdio.h>
Packit Service fa4841
#include <string.h>
Packit Service fa4841
#include <stdlib.h>
Packit Service fa4841
Packit Service fa4841
#include <winpr/synch.h>
Packit Service fa4841
Packit Service fa4841
#ifndef _WIN32
Packit Service fa4841
Packit Service fa4841
#include "synch.h"
Packit Service fa4841
Packit Service fa4841
#ifdef HAVE_UNISTD_H
Packit Service fa4841
#include <unistd.h>
Packit Service fa4841
#endif
Packit Service fa4841
Packit Service fa4841
#ifdef HAVE_SYS_EVENTFD_H
Packit Service fa4841
#include <sys/eventfd.h>
Packit Service fa4841
#endif
Packit Service fa4841
Packit Service fa4841
#include <errno.h>
Packit Service fa4841
Packit Service fa4841
#include "../handle/handle.h"
Packit Service fa4841
#include "../pipe/pipe.h"
Packit Service fa4841
Packit Service fa4841
#include "../log.h"
Packit Service fa4841
#define TAG WINPR_TAG("synch.event")
Packit Service fa4841
Packit Service fa4841
static BOOL EventCloseHandle(HANDLE handle);
Packit Service fa4841
Packit Service fa4841
static BOOL EventIsHandled(HANDLE handle)
Packit Service fa4841
{
Packit Service fa4841
	WINPR_TIMER* pEvent = (WINPR_TIMER*)handle;
Packit Service fa4841
Packit Service fa4841
	if (!pEvent || (pEvent->Type != HANDLE_TYPE_EVENT))
Packit Service fa4841
	{
Packit Service fa4841
		SetLastError(ERROR_INVALID_HANDLE);
Packit Service fa4841
		return FALSE;
Packit Service fa4841
	}
Packit Service fa4841
Packit Service fa4841
	return TRUE;
Packit Service fa4841
}
Packit Service fa4841
Packit Service fa4841
static int EventGetFd(HANDLE handle)
Packit Service fa4841
{
Packit Service fa4841
	WINPR_EVENT* event = (WINPR_EVENT*)handle;
Packit Service fa4841
Packit Service fa4841
	if (!EventIsHandled(handle))
Packit Service fa4841
		return -1;
Packit Service fa4841
Packit Service fa4841
	return event->pipe_fd[0];
Packit Service fa4841
}
Packit Service fa4841
Packit Service fa4841
static BOOL EventCloseHandle_(WINPR_EVENT* event)
Packit Service fa4841
{
Packit Service fa4841
	if (!event)
Packit Service fa4841
		return FALSE;
Packit Service fa4841
Packit Service fa4841
	if (!event->bAttached)
Packit Service fa4841
	{
Packit Service fa4841
		if (event->pipe_fd[0] != -1)
Packit Service fa4841
		{
Packit Service fa4841
			close(event->pipe_fd[0]);
Packit Service fa4841
			event->pipe_fd[0] = -1;
Packit Service fa4841
		}
Packit Service fa4841
Packit Service fa4841
		if (event->pipe_fd[1] != -1)
Packit Service fa4841
		{
Packit Service fa4841
			close(event->pipe_fd[1]);
Packit Service fa4841
			event->pipe_fd[1] = -1;
Packit Service fa4841
		}
Packit Service fa4841
	}
Packit Service fa4841
Packit Service fa4841
	free(event->name);
Packit Service fa4841
	free(event);
Packit Service fa4841
	return TRUE;
Packit Service fa4841
}
Packit Service fa4841
Packit Service fa4841
static BOOL EventCloseHandle(HANDLE handle)
Packit Service fa4841
{
Packit Service fa4841
	WINPR_EVENT* event = (WINPR_EVENT*)handle;
Packit Service fa4841
Packit Service fa4841
	if (!EventIsHandled(handle))
Packit Service fa4841
		return FALSE;
Packit Service fa4841
Packit Service fa4841
	return EventCloseHandle_(event);
Packit Service fa4841
}
Packit Service fa4841
Packit Service fa4841
static HANDLE_OPS ops = { EventIsHandled, EventCloseHandle,
Packit Service fa4841
	                      EventGetFd,     NULL, /* CleanupHandle */
Packit Service fa4841
	                      NULL,           NULL,
Packit Service fa4841
	                      NULL,           NULL,
Packit Service fa4841
	                      NULL,           NULL,
Packit Service fa4841
	                      NULL,           NULL,
Packit Service fa4841
	                      NULL,           NULL,
Packit Service fa4841
	                      NULL,           NULL,
Packit Service fa4841
	                      NULL,           NULL,
Packit Service fa4841
	                      NULL,           NULL };
Packit Service fa4841
Packit Service fa4841
HANDLE CreateEventW(LPSECURITY_ATTRIBUTES lpEventAttributes, BOOL bManualReset, BOOL bInitialState,
Packit Service fa4841
                    LPCWSTR lpName)
Packit Service fa4841
{
Packit Service fa4841
	HANDLE handle;
Packit Service fa4841
	char* name = NULL;
Packit Service fa4841
Packit Service fa4841
	if (lpName)
Packit Service fa4841
	{
Packit Service fa4841
		int rc = ConvertFromUnicode(CP_UTF8, 0, lpName, -1, &name, 0, NULL, NULL);
Packit Service fa4841
Packit Service fa4841
		if (rc < 0)
Packit Service fa4841
			return NULL;
Packit Service fa4841
	}
Packit Service fa4841
Packit Service fa4841
	handle = CreateEventA(lpEventAttributes, bManualReset, bInitialState, name);
Packit Service fa4841
	free(name);
Packit Service fa4841
	return handle;
Packit Service fa4841
}
Packit Service fa4841
Packit Service fa4841
HANDLE CreateEventA(LPSECURITY_ATTRIBUTES lpEventAttributes, BOOL bManualReset, BOOL bInitialState,
Packit Service fa4841
                    LPCSTR lpName)
Packit Service fa4841
{
Packit Service fa4841
	WINPR_EVENT* event = (WINPR_EVENT*)calloc(1, sizeof(WINPR_EVENT));
Packit Service fa4841
Packit Service fa4841
	if (lpEventAttributes)
Packit Service fa4841
		WLog_WARN(TAG, "%s [%s] does not support lpEventAttributes", __FUNCTION__, lpName);
Packit Service fa4841
Packit Service fa4841
	if (!event)
Packit Service fa4841
		return NULL;
Packit Service fa4841
Packit Service fa4841
	if (lpName)
Packit Service fa4841
		event->name = strdup(lpName);
Packit Service fa4841
Packit Service fa4841
	event->bAttached = FALSE;
Packit Service fa4841
	event->bManualReset = bManualReset;
Packit Service fa4841
	event->ops = &ops;
Packit Service fa4841
	WINPR_HANDLE_SET_TYPE_AND_MODE(event, HANDLE_TYPE_EVENT, FD_READ);
Packit Service fa4841
Packit Service fa4841
	if (!event->bManualReset)
Packit Service fa4841
		WLog_ERR(TAG, "auto-reset events not yet implemented");
Packit Service fa4841
Packit Service fa4841
	event->pipe_fd[0] = -1;
Packit Service fa4841
	event->pipe_fd[1] = -1;
Packit Service fa4841
#ifdef HAVE_SYS_EVENTFD_H
Packit Service fa4841
	event->pipe_fd[0] = eventfd(0, EFD_NONBLOCK);
Packit Service fa4841
Packit Service fa4841
	if (event->pipe_fd[0] < 0)
Packit Service fa4841
		goto fail;
Packit Service fa4841
Packit Service fa4841
#else
Packit Service fa4841
Packit Service fa4841
	if (pipe(event->pipe_fd) < 0)
Packit Service fa4841
		goto fail;
Packit Service fa4841
Packit Service fa4841
#endif
Packit Service fa4841
Packit Service fa4841
	if (bInitialState)
Packit Service fa4841
	{
Packit Service fa4841
		if (!SetEvent(event))
Packit Service fa4841
			goto fail;
Packit Service fa4841
	}
Packit Service fa4841
Packit Service fa4841
	return (HANDLE)event;
Packit Service fa4841
fail:
Packit Service fa4841
	EventCloseHandle_(event);
Packit Service fa4841
	return NULL;
Packit Service fa4841
}
Packit Service fa4841
Packit Service fa4841
HANDLE CreateEventExW(LPSECURITY_ATTRIBUTES lpEventAttributes, LPCWSTR lpName, DWORD dwFlags,
Packit Service fa4841
                      DWORD dwDesiredAccess)
Packit Service fa4841
{
Packit Service fa4841
	BOOL initial = FALSE;
Packit Service fa4841
	BOOL manual = FALSE;
Packit Service fa4841
Packit Service fa4841
	if (dwFlags & CREATE_EVENT_INITIAL_SET)
Packit Service fa4841
		initial = TRUE;
Packit Service fa4841
Packit Service fa4841
	if (dwFlags & CREATE_EVENT_MANUAL_RESET)
Packit Service fa4841
		manual = TRUE;
Packit Service fa4841
Packit Service fa4841
	if (dwDesiredAccess != 0)
Packit Service fa4841
		WLog_WARN(TAG, "%s [%s] does not support dwDesiredAccess 0x%08" PRIx32, __FUNCTION__,
Packit Service fa4841
		          lpName, dwDesiredAccess);
Packit Service fa4841
Packit Service fa4841
	return CreateEventW(lpEventAttributes, manual, initial, lpName);
Packit Service fa4841
}
Packit Service fa4841
Packit Service fa4841
HANDLE CreateEventExA(LPSECURITY_ATTRIBUTES lpEventAttributes, LPCSTR lpName, DWORD dwFlags,
Packit Service fa4841
                      DWORD dwDesiredAccess)
Packit Service fa4841
{
Packit Service fa4841
	BOOL initial = FALSE;
Packit Service fa4841
	BOOL manual = FALSE;
Packit Service fa4841
Packit Service fa4841
	if (dwFlags & CREATE_EVENT_INITIAL_SET)
Packit Service fa4841
		initial = TRUE;
Packit Service fa4841
Packit Service fa4841
	if (dwFlags & CREATE_EVENT_MANUAL_RESET)
Packit Service fa4841
		manual = TRUE;
Packit Service fa4841
Packit Service fa4841
	if (dwDesiredAccess != 0)
Packit Service fa4841
		WLog_WARN(TAG, "%s [%s] does not support dwDesiredAccess 0x%08" PRIx32, __FUNCTION__,
Packit Service fa4841
		          lpName, dwDesiredAccess);
Packit Service fa4841
Packit Service fa4841
	return CreateEventA(lpEventAttributes, manual, initial, lpName);
Packit Service fa4841
}
Packit Service fa4841
Packit Service fa4841
HANDLE OpenEventW(DWORD dwDesiredAccess, BOOL bInheritHandle, LPCWSTR lpName)
Packit Service fa4841
{
Packit Service fa4841
	/* TODO: Implement */
Packit Service fa4841
	WINPR_UNUSED(dwDesiredAccess);
Packit Service fa4841
	WINPR_UNUSED(bInheritHandle);
Packit Service fa4841
	WINPR_UNUSED(lpName);
Packit Service fa4841
	WLog_ERR(TAG, "%s not implemented", __FUNCTION__);
Packit Service fa4841
	return NULL;
Packit Service fa4841
}
Packit Service fa4841
Packit Service fa4841
HANDLE OpenEventA(DWORD dwDesiredAccess, BOOL bInheritHandle, LPCSTR lpName)
Packit Service fa4841
{
Packit Service fa4841
	/* TODO: Implement */
Packit Service fa4841
	WINPR_UNUSED(dwDesiredAccess);
Packit Service fa4841
	WINPR_UNUSED(bInheritHandle);
Packit Service fa4841
	WINPR_UNUSED(lpName);
Packit Service fa4841
	WLog_ERR(TAG, "%s not implemented", __FUNCTION__);
Packit Service fa4841
	return NULL;
Packit Service fa4841
}
Packit Service fa4841
Packit Service fa4841
#ifdef HAVE_SYS_EVENTFD_H
Packit Service fa4841
#if !defined(WITH_EVENTFD_READ_WRITE)
Packit Service fa4841
static int eventfd_read(int fd, eventfd_t* value)
Packit Service fa4841
{
Packit Service fa4841
	return (read(fd, value, sizeof(*value)) == sizeof(*value)) ? 0 : -1;
Packit Service fa4841
}
Packit Service fa4841
Packit Service fa4841
static int eventfd_write(int fd, eventfd_t value)
Packit Service fa4841
{
Packit Service fa4841
	return (write(fd, &value, sizeof(value)) == sizeof(value)) ? 0 : -1;
Packit Service fa4841
}
Packit Service fa4841
#endif
Packit Service fa4841
#endif
Packit Service fa4841
Packit Service fa4841
BOOL SetEvent(HANDLE hEvent)
Packit Service fa4841
{
Packit Service fa4841
	ULONG Type;
Packit Service fa4841
	WINPR_HANDLE* Object;
Packit Service fa4841
	int length;
Packit Service fa4841
	BOOL status;
Packit Service fa4841
	WINPR_EVENT* event;
Packit Service fa4841
	status = FALSE;
Packit Service fa4841
Packit Service fa4841
	if (winpr_Handle_GetInfo(hEvent, &Type, &Object))
Packit Service fa4841
	{
Packit Service fa4841
		event = (WINPR_EVENT*)Object;
Packit Service fa4841
Packit Service fa4841
#ifdef HAVE_SYS_EVENTFD_H
Packit Service fa4841
		eventfd_t val = 1;
Packit Service fa4841
Packit Service fa4841
		do
Packit Service fa4841
		{
Packit Service fa4841
			length = eventfd_write(event->pipe_fd[0], val);
Packit Service fa4841
		} while ((length < 0) && (errno == EINTR));
Packit Service fa4841
Packit Service fa4841
		status = (length == 0) ? TRUE : FALSE;
Packit Service fa4841
#else
Packit Service fa4841
Packit Service fa4841
		if (WaitForSingleObject(hEvent, 0) != WAIT_OBJECT_0)
Packit Service fa4841
		{
Packit Service fa4841
			length = write(event->pipe_fd[1], "-", 1);
Packit Service fa4841
Packit Service fa4841
			if (length == 1)
Packit Service fa4841
				status = TRUE;
Packit Service fa4841
		}
Packit Service fa4841
		else
Packit Service fa4841
		{
Packit Service fa4841
			status = TRUE;
Packit Service fa4841
		}
Packit Service fa4841
Packit Service fa4841
#endif
Packit Service fa4841
	}
Packit Service fa4841
Packit Service fa4841
	return status;
Packit Service fa4841
}
Packit Service fa4841
Packit Service fa4841
BOOL ResetEvent(HANDLE hEvent)
Packit Service fa4841
{
Packit Service fa4841
	ULONG Type;
Packit Service fa4841
	WINPR_HANDLE* Object;
Packit Service fa4841
	int length;
Packit Service fa4841
	BOOL status = TRUE;
Packit Service fa4841
	WINPR_EVENT* event;
Packit Service fa4841
Packit Service fa4841
	if (!winpr_Handle_GetInfo(hEvent, &Type, &Object))
Packit Service fa4841
		return FALSE;
Packit Service fa4841
Packit Service fa4841
	event = (WINPR_EVENT*)Object;
Packit Service fa4841
Packit Service fa4841
	while (status && WaitForSingleObject(hEvent, 0) == WAIT_OBJECT_0)
Packit Service fa4841
	{
Packit Service fa4841
		do
Packit Service fa4841
		{
Packit Service fa4841
#ifdef HAVE_SYS_EVENTFD_H
Packit Service fa4841
			eventfd_t value;
Packit Service fa4841
			length = eventfd_read(event->pipe_fd[0], &value);
Packit Service fa4841
#else
Packit Service fa4841
			length = read(event->pipe_fd[0], &length, 1);
Packit Service fa4841
#endif
Packit Service fa4841
		} while ((length < 0) && (errno == EINTR));
Packit Service fa4841
Packit Service fa4841
		if (length < 0)
Packit Service fa4841
			status = FALSE;
Packit Service fa4841
	}
Packit Service fa4841
Packit Service fa4841
	return status;
Packit Service fa4841
}
Packit Service fa4841
Packit Service fa4841
#endif
Packit Service fa4841
Packit Service fa4841
HANDLE CreateFileDescriptorEventW(LPSECURITY_ATTRIBUTES lpEventAttributes, BOOL bManualReset,
Packit Service fa4841
                                  BOOL bInitialState, int FileDescriptor, ULONG mode)
Packit Service fa4841
{
Packit Service fa4841
#ifndef _WIN32
Packit Service fa4841
	WINPR_EVENT* event;
Packit Service fa4841
	HANDLE handle = NULL;
Packit Service fa4841
	event = (WINPR_EVENT*)calloc(1, sizeof(WINPR_EVENT));
Packit Service fa4841
Packit Service fa4841
	if (event)
Packit Service fa4841
	{
Packit Service fa4841
		event->bAttached = TRUE;
Packit Service fa4841
		event->bManualReset = bManualReset;
Packit Service fa4841
		event->pipe_fd[0] = FileDescriptor;
Packit Service fa4841
		event->pipe_fd[1] = -1;
Packit Service fa4841
		event->ops = &ops;
Packit Service fa4841
		WINPR_HANDLE_SET_TYPE_AND_MODE(event, HANDLE_TYPE_EVENT, mode);
Packit Service fa4841
		handle = (HANDLE)event;
Packit Service fa4841
	}
Packit Service fa4841
Packit Service fa4841
	return handle;
Packit Service fa4841
#else
Packit Service fa4841
	return NULL;
Packit Service fa4841
#endif
Packit Service fa4841
}
Packit Service fa4841
Packit Service fa4841
HANDLE CreateFileDescriptorEventA(LPSECURITY_ATTRIBUTES lpEventAttributes, BOOL bManualReset,
Packit Service fa4841
                                  BOOL bInitialState, int FileDescriptor, ULONG mode)
Packit Service fa4841
{
Packit Service fa4841
	return CreateFileDescriptorEventW(lpEventAttributes, bManualReset, bInitialState,
Packit Service fa4841
	                                  FileDescriptor, mode);
Packit Service fa4841
}
Packit Service fa4841
Packit Service fa4841
/**
Packit Service fa4841
 * Returns an event based on the handle returned by GetEventWaitObject()
Packit Service fa4841
 */
Packit Service fa4841
HANDLE CreateWaitObjectEvent(LPSECURITY_ATTRIBUTES lpEventAttributes, BOOL bManualReset,
Packit Service fa4841
                             BOOL bInitialState, void* pObject)
Packit Service fa4841
{
Packit Service fa4841
#ifndef _WIN32
Packit Service fa4841
	return CreateFileDescriptorEventW(lpEventAttributes, bManualReset, bInitialState,
Packit Service fa4841
	                                  (int)(ULONG_PTR)pObject, WINPR_FD_READ);
Packit Service fa4841
#else
Packit Service fa4841
	HANDLE hEvent = NULL;
Packit Service fa4841
	DuplicateHandle(GetCurrentProcess(), pObject, GetCurrentProcess(), &hEvent, 0, FALSE,
Packit Service fa4841
	                DUPLICATE_SAME_ACCESS);
Packit Service fa4841
	return hEvent;
Packit Service fa4841
#endif
Packit Service fa4841
}
Packit Service fa4841
Packit Service fa4841
/*
Packit Service fa4841
 * Returns inner file descriptor for usage with select()
Packit Service fa4841
 * This file descriptor is not usable on Windows
Packit Service fa4841
 */
Packit Service fa4841
Packit Service fa4841
int GetEventFileDescriptor(HANDLE hEvent)
Packit Service fa4841
{
Packit Service fa4841
#ifndef _WIN32
Packit Service fa4841
	return winpr_Handle_getFd(hEvent);
Packit Service fa4841
#else
Packit Service fa4841
	return -1;
Packit Service fa4841
#endif
Packit Service fa4841
}
Packit Service fa4841
Packit Service fa4841
/*
Packit Service fa4841
 * Set inner file descriptor for usage with select()
Packit Service fa4841
 * This file descriptor is not usable on Windows
Packit Service fa4841
 */
Packit Service fa4841
Packit Service fa4841
int SetEventFileDescriptor(HANDLE hEvent, int FileDescriptor, ULONG mode)
Packit Service fa4841
{
Packit Service fa4841
#ifndef _WIN32
Packit Service fa4841
	ULONG Type;
Packit Service fa4841
	WINPR_HANDLE* Object;
Packit Service fa4841
	WINPR_EVENT* event;
Packit Service fa4841
Packit Service fa4841
	if (!winpr_Handle_GetInfo(hEvent, &Type, &Object))
Packit Service fa4841
		return -1;
Packit Service fa4841
Packit Service fa4841
	event = (WINPR_EVENT*)Object;
Packit Service fa4841
Packit Service fa4841
	if (!event->bAttached && event->pipe_fd[0] >= 0 && event->pipe_fd[0] != FileDescriptor)
Packit Service fa4841
		close(event->pipe_fd[0]);
Packit Service fa4841
Packit Service fa4841
	event->bAttached = TRUE;
Packit Service fa4841
	event->Mode = mode;
Packit Service fa4841
	event->pipe_fd[0] = FileDescriptor;
Packit Service fa4841
	return 0;
Packit Service fa4841
#else
Packit Service fa4841
	return -1;
Packit Service fa4841
#endif
Packit Service fa4841
}
Packit Service fa4841
Packit Service fa4841
/**
Packit Service fa4841
 * Returns platform-specific wait object as a void pointer
Packit Service fa4841
 *
Packit Service fa4841
 * On Windows, the returned object is the same as the hEvent
Packit Service fa4841
 * argument and is an event HANDLE usable in WaitForMultipleObjects
Packit Service fa4841
 *
Packit Service fa4841
 * On other platforms, the returned object can be cast to an int
Packit Service fa4841
 * to obtain a file descriptor usable in select()
Packit Service fa4841
 */
Packit Service fa4841
Packit Service fa4841
void* GetEventWaitObject(HANDLE hEvent)
Packit Service fa4841
{
Packit Service fa4841
#ifndef _WIN32
Packit Service fa4841
	int fd;
Packit Service fa4841
	void* obj;
Packit Service fa4841
	fd = GetEventFileDescriptor(hEvent);
Packit Service fa4841
	obj = ((void*)(long)fd);
Packit Service fa4841
	return obj;
Packit Service fa4841
#else
Packit Service fa4841
	return hEvent;
Packit Service fa4841
#endif
Packit Service fa4841
}