blob: 54addad51cc771fb7972a03aab62dc510510181a [file]
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
// See the LICENSE file in the project root for more information.
/*++
Module Name:
event.cpp
Abstract:
Implementation of event synchronization object as described in
the WIN32 API
Revision History:
--*/
#include "pal/event.hpp"
#include "pal/thread.hpp"
#include "pal/dbgmsg.h"
using namespace CorUnix;
/* ------------------- Definitions ------------------------------*/
SET_DEFAULT_DEBUG_CHANNEL(SYNC);
CObjectType CorUnix::otManualResetEvent(
otiManualResetEvent,
NULL, // No cleanup routine
NULL, // No initialization routine
0, // No immutable data
0, // No process local data
0, // No shared data
EVENT_ALL_ACCESS, // Currently ignored (no Win32 security)
CObjectType::SecuritySupported,
CObjectType::SecurityInfoNotPersisted,
CObjectType::UnnamedObject,
CObjectType::LocalDuplicationOnly,
CObjectType::WaitableObject,
CObjectType::ObjectCanBeUnsignaled,
CObjectType::ThreadReleaseHasNoSideEffects,
CObjectType::NoOwner
);
CObjectType CorUnix::otAutoResetEvent(
otiAutoResetEvent,
NULL, // No cleanup routine
NULL, // No initialization routine
0, // No immutable data
0, // No process local data
0, // No shared data
EVENT_ALL_ACCESS, // Currently ignored (no Win32 security)
CObjectType::SecuritySupported,
CObjectType::SecurityInfoNotPersisted,
CObjectType::UnnamedObject,
CObjectType::LocalDuplicationOnly,
CObjectType::WaitableObject,
CObjectType::ObjectCanBeUnsignaled,
CObjectType::ThreadReleaseAltersSignalCount,
CObjectType::NoOwner
);
PalObjectTypeId rgEventIds[] = {otiManualResetEvent, otiAutoResetEvent};
CAllowedObjectTypes aotEvent(rgEventIds, sizeof(rgEventIds)/sizeof(rgEventIds[0]));
/*++
Function:
CreateEventA
Note:
lpEventAttributes currentely ignored:
-- Win32 object security not supported
-- handles to event objects are not inheritable
Parameters:
See MSDN doc.
--*/
HANDLE
PALAPI
CreateEventA(
IN LPSECURITY_ATTRIBUTES lpEventAttributes,
IN BOOL bManualReset,
IN BOOL bInitialState,
IN LPCSTR lpName)
{
HANDLE hEvent = NULL;
CPalThread *pthr = NULL;
PAL_ERROR palError;
PERF_ENTRY(CreateEventA);
ENTRY("CreateEventA(lpEventAttr=%p, bManualReset=%d, bInitialState=%d, lpName=%p (%s)\n",
lpEventAttributes, bManualReset, bInitialState, lpName, lpName?lpName:"NULL");
pthr = InternalGetCurrentThread();
if (lpName != nullptr)
{
ASSERT("lpName: Cross-process named objects are not supported in PAL");
palError = ERROR_NOT_SUPPORTED;
}
else
{
palError = InternalCreateEvent(
pthr,
lpEventAttributes,
bManualReset,
bInitialState,
NULL,
&hEvent
);
}
//
// We always need to set last error, even on success:
// we need to protect ourselves from the situation
// where last error is set to ERROR_ALREADY_EXISTS on
// entry to the function
//
pthr->SetLastError(palError);
LOGEXIT("CreateEventA returns HANDLE %p\n", hEvent);
PERF_EXIT(CreateEventA);
return hEvent;
}
/*++
Function:
CreateEventW
Note:
lpEventAttributes currentely ignored:
-- Win32 object security not supported
-- handles to event objects are not inheritable
Parameters:
See MSDN doc.
--*/
HANDLE
PALAPI
CreateEventW(
IN LPSECURITY_ATTRIBUTES lpEventAttributes,
IN BOOL bManualReset,
IN BOOL bInitialState,
IN LPCWSTR lpName)
{
HANDLE hEvent = NULL;
PAL_ERROR palError;
CPalThread *pthr = NULL;
PERF_ENTRY(CreateEventW);
ENTRY("CreateEventW(lpEventAttr=%p, bManualReset=%d, "
"bInitialState=%d, lpName=%p (%S)\n", lpEventAttributes, bManualReset,
bInitialState, lpName, lpName?lpName:W16_NULLSTRING);
pthr = InternalGetCurrentThread();
palError = InternalCreateEvent(
pthr,
lpEventAttributes,
bManualReset,
bInitialState,
lpName,
&hEvent
);
//
// We always need to set last error, even on success:
// we need to protect ourselves from the situation
// where last error is set to ERROR_ALREADY_EXISTS on
// entry to the function
//
pthr->SetLastError(palError);
LOGEXIT("CreateEventW returns HANDLE %p\n", hEvent);
PERF_EXIT(CreateEventW);
return hEvent;
}
/*++
Function:
InternalCreateEvent
Note:
lpEventAttributes currentely ignored:
-- Win32 object security not supported
-- handles to event objects are not inheritable
Parameters:
pthr -- thread data for calling thread
phEvent -- on success, receives the allocated event handle
See MSDN docs on CreateEvent for all other parameters
--*/
PAL_ERROR
CorUnix::InternalCreateEvent(
CPalThread *pthr,
LPSECURITY_ATTRIBUTES lpEventAttributes,
BOOL bManualReset,
BOOL bInitialState,
LPCWSTR lpName,
HANDLE *phEvent
)
{
CObjectAttributes oa(lpName, lpEventAttributes);
PAL_ERROR palError = NO_ERROR;
IPalObject *pobjEvent = NULL;
IPalObject *pobjRegisteredEvent = NULL;
_ASSERTE(NULL != pthr);
_ASSERTE(NULL != phEvent);
ENTRY("InternalCreateEvent(pthr=%p, lpEventAttributes=%p, bManualReset=%i, "
"bInitialState=%i, lpName=%p, phEvent=%p)\n",
pthr,
lpEventAttributes,
bManualReset,
bInitialState,
lpName,
phEvent
);
if (lpName != nullptr)
{
ASSERT("lpName: Cross-process named objects are not supported in PAL");
palError = ERROR_NOT_SUPPORTED;
goto InternalCreateEventExit;
}
palError = g_pObjectManager->AllocateObject(
pthr,
bManualReset ? &otManualResetEvent : &otAutoResetEvent,
&oa,
&pobjEvent
);
if (NO_ERROR != palError)
{
goto InternalCreateEventExit;
}
if (bInitialState)
{
ISynchStateController *pssc;
palError = pobjEvent->GetSynchStateController(
pthr,
&pssc
);
if (NO_ERROR == palError)
{
palError = pssc->SetSignalCount(1);
pssc->ReleaseController();
}
if (NO_ERROR != palError)
{
ASSERT("Unable to set new event state (%d)\n", palError);
goto InternalCreateEventExit;
}
}
palError = g_pObjectManager->RegisterObject(
pthr,
pobjEvent,
&aotEvent,
EVENT_ALL_ACCESS, // Currently ignored (no Win32 security)
phEvent,
&pobjRegisteredEvent
);
//
// pobjEvent is invalidated by the call to RegisterObject, so NULL it
// out here to ensure that we don't try to release a reference on
// it down the line.
//
pobjEvent = NULL;
InternalCreateEventExit:
if (NULL != pobjEvent)
{
pobjEvent->ReleaseReference(pthr);
}
if (NULL != pobjRegisteredEvent)
{
pobjRegisteredEvent->ReleaseReference(pthr);
}
LOGEXIT("InternalCreateEvent returns %i\n", palError);
return palError;
}
/*++
Function:
SetEvent
See MSDN doc.
--*/
BOOL
PALAPI
SetEvent(
IN HANDLE hEvent)
{
PAL_ERROR palError = NO_ERROR;
CPalThread *pthr = NULL;
PERF_ENTRY(SetEvent);
ENTRY("SetEvent(hEvent=%p)\n", hEvent);
pthr = InternalGetCurrentThread();
palError = InternalSetEvent(pthr, hEvent, TRUE);
if (NO_ERROR != palError)
{
pthr->SetLastError(palError);
}
LOGEXIT("SetEvent returns BOOL %d\n", (NO_ERROR == palError));
PERF_EXIT(SetEvent);
return (NO_ERROR == palError);
}
/*++
Function:
ResetEvent
See MSDN doc.
--*/
BOOL
PALAPI
ResetEvent(
IN HANDLE hEvent)
{
PAL_ERROR palError = NO_ERROR;
CPalThread *pthr = NULL;
PERF_ENTRY(ResetEvent);
ENTRY("ResetEvent(hEvent=%p)\n", hEvent);
pthr = InternalGetCurrentThread();
palError = InternalSetEvent(pthr, hEvent, FALSE);
if (NO_ERROR != palError)
{
pthr->SetLastError(palError);
}
LOGEXIT("ResetEvent returns BOOL %d\n", (NO_ERROR == palError));
PERF_EXIT(ResetEvent);
return (NO_ERROR == palError);
}
/*++
Function:
InternalCreateEvent
Parameters:
pthr -- thread data for calling thread
hEvent -- handle to the event to set
fSetEvent -- if TRUE, set the event; if FALSE, reset it
--*/
PAL_ERROR
CorUnix::InternalSetEvent(
CPalThread *pthr,
HANDLE hEvent,
BOOL fSetEvent
)
{
PAL_ERROR palError = NO_ERROR;
IPalObject *pobjEvent = NULL;
ISynchStateController *pssc = NULL;
_ASSERTE(NULL != pthr);
ENTRY("InternalSetEvent(pthr=%p, hEvent=%p, fSetEvent=%i\n",
pthr,
hEvent,
fSetEvent
);
palError = g_pObjectManager->ReferenceObjectByHandle(
pthr,
hEvent,
&aotEvent,
0, // Should be EVENT_MODIFY_STATE; currently ignored (no Win32 security)
&pobjEvent
);
if (NO_ERROR != palError)
{
ERROR("Unable to obtain object for handle %p (error %d)!\n", hEvent, palError);
goto InternalSetEventExit;
}
palError = pobjEvent->GetSynchStateController(
pthr,
&pssc
);
if (NO_ERROR != palError)
{
ASSERT("Error %d obtaining synch state controller\n", palError);
goto InternalSetEventExit;
}
palError = pssc->SetSignalCount(fSetEvent ? 1 : 0);
if (NO_ERROR != palError)
{
ASSERT("Error %d setting event state\n", palError);
goto InternalSetEventExit;
}
InternalSetEventExit:
if (NULL != pssc)
{
pssc->ReleaseController();
}
if (NULL != pobjEvent)
{
pobjEvent->ReleaseReference(pthr);
}
LOGEXIT("InternalSetEvent returns %d\n", palError);
return palError;
}
// TODO: Implementation of OpenEventA() doesn't exist, do we need it? More generally, do we need the A versions at all?
/*++
Function:
OpenEventW
Note:
dwDesiredAccess is currently ignored (no Win32 object security support)
bInheritHandle is currently ignored (handles to events are not inheritable)
Parameters:
See MSDN doc.
--*/
HANDLE
PALAPI
OpenEventW(
IN DWORD dwDesiredAccess,
IN BOOL bInheritHandle,
IN LPCWSTR lpName)
{
HANDLE hEvent = NULL;
PAL_ERROR palError = NO_ERROR;
CPalThread *pthr = NULL;
PERF_ENTRY(OpenEventW);
ENTRY("OpenEventW(dwDesiredAccess=%#x, bInheritHandle=%d, lpName=%p (%S))\n",
dwDesiredAccess, bInheritHandle, lpName, lpName?lpName:W16_NULLSTRING);
pthr = InternalGetCurrentThread();
/* validate parameters */
if (lpName == nullptr)
{
ERROR("name is NULL\n");
palError = ERROR_INVALID_PARAMETER;
goto OpenEventWExit;
}
else
{
ASSERT("lpName: Cross-process named objects are not supported in PAL");
palError = ERROR_NOT_SUPPORTED;
}
OpenEventWExit:
if (NO_ERROR != palError)
{
pthr->SetLastError(palError);
}
LOGEXIT("OpenEventW returns HANDLE %p\n", hEvent);
PERF_EXIT(OpenEventW);
return hEvent;
}
/*++
Function:
InternalOpenEvent
Note:
dwDesiredAccess is currently ignored (no Win32 object security support)
bInheritHandle is currently ignored (handles to events are not inheritable)
Parameters:
pthr -- thread data for calling thread
phEvent -- on success, receives the allocated event handle
See MSDN docs on OpenEvent for all other parameters.
--*/
PAL_ERROR
CorUnix::InternalOpenEvent(
CPalThread *pthr,
DWORD dwDesiredAccess,
BOOL bInheritHandle,
LPCWSTR lpName,
HANDLE *phEvent
)
{
PAL_ERROR palError = NO_ERROR;
IPalObject *pobjEvent = NULL;
CPalString sObjectName(lpName);
_ASSERTE(NULL != pthr);
_ASSERTE(NULL != lpName);
_ASSERTE(NULL != phEvent);
ENTRY("InternalOpenEvent(pthr=%p, dwDesiredAccess=%#x, bInheritHandle=%d, "
"lpName=%p, phEvent=%p)\n",
pthr,
dwDesiredAccess,
bInheritHandle,
lpName,
phEvent
);
palError = g_pObjectManager->LocateObject(
pthr,
&sObjectName,
&aotEvent,
&pobjEvent
);
if (NO_ERROR != palError)
{
goto InternalOpenEventExit;
}
palError = g_pObjectManager->ObtainHandleForObject(
pthr,
pobjEvent,
dwDesiredAccess,
bInheritHandle,
NULL,
phEvent
);
if (NO_ERROR != palError)
{
goto InternalOpenEventExit;
}
InternalOpenEventExit:
if (NULL != pobjEvent)
{
pobjEvent->ReleaseReference(pthr);
}
LOGEXIT("InternalOpenEvent returns %d\n", palError);
return palError;
}