Blame winpr/libwinpr/synch/event.c

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