437 lines
11 KiB
C++
437 lines
11 KiB
C++
/*===========================================================================
|
|
FILE:
|
|
Event.cpp
|
|
|
|
DESCRIPTION:
|
|
Implementation of cEvent class
|
|
|
|
PUBLIC CLASSES AND METHODS:
|
|
WaitOnMultipleEvents
|
|
cEvent
|
|
Functionality to mimic Windows events using UNIX pipes (enhanced
|
|
somewhat to allow one to specify a DWORD value to pass through
|
|
when signalling the event)
|
|
|
|
WARNING:
|
|
This class is not designed to be thread safe
|
|
|
|
Copyright (c) 2013, The Linux Foundation. All rights reserved.
|
|
|
|
Redistribution and use in source and binary forms, with or without
|
|
modification, are permitted provided that the following conditions are met:
|
|
* Redistributions of source code must retain the above copyright
|
|
notice, this list of conditions and the following disclaimer.
|
|
* Redistributions in binary form must reproduce the above copyright
|
|
notice, this list of conditions and the following disclaimer in the
|
|
documentation and/or other materials provided with the distribution.
|
|
* Neither the name of The Linux Foundation nor the names of its
|
|
contributors may be used to endorse or promote products derived from
|
|
this software without specific prior written permission.
|
|
|
|
|
|
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
|
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
|
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
|
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
|
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
|
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
|
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
|
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
|
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
|
POSSIBILITY OF SUCH DAMAGE.
|
|
===========================================================================*/
|
|
|
|
//---------------------------------------------------------------------------
|
|
// Include Files
|
|
//---------------------------------------------------------------------------
|
|
#include "StdAfx.h"
|
|
#include "Event.h"
|
|
|
|
/*===========================================================================
|
|
METHOD:
|
|
WaitOnMultipleEvents (Free Method)
|
|
|
|
DESCRIPTION:
|
|
Wait for any of the events to be set and return the value
|
|
|
|
Note: If multiple events are set, only the event specified by
|
|
eventIndex will be read from. Run this function again
|
|
to get the next event.
|
|
|
|
PARAMETERS:
|
|
events [ I ] - Vector of events which may be signaled
|
|
timeoutMS [ I ] - Relative timeout length (in milliseconds)
|
|
val [ O ] - Associated value upon success
|
|
eventIndex [ O ] - Index of event which was signaled
|
|
|
|
RETURN VALUE:
|
|
Return code
|
|
positive for number of events set
|
|
-ETIME on timeout
|
|
negative errno value on failure
|
|
===========================================================================*/
|
|
int WaitOnMultipleEvents(
|
|
std::vector <cEvent *> events,
|
|
DWORD timeoutMS,
|
|
DWORD & val,
|
|
DWORD & eventIndex )
|
|
{
|
|
// Check internal pipes' status
|
|
for (ULONG index = 0; index < events.size(); index++)
|
|
{
|
|
int error = events[index]->mError;
|
|
if (error != 0)
|
|
{
|
|
TRACE( "cEvent %lu has error %d\n", index, error );
|
|
return -error;
|
|
}
|
|
}
|
|
|
|
// Initialize the FD set
|
|
fd_set fds;
|
|
FD_ZERO( &fds );
|
|
|
|
// Add each item to the FD set, keeping track of the largest,
|
|
// which is used for select()
|
|
int largestFD = 0;
|
|
for (ULONG index = 0; index < events.size(); index++)
|
|
{
|
|
int pipe = events[index]->mPipes[READING];
|
|
FD_SET( pipe, &fds );
|
|
|
|
largestFD = std::max( pipe, largestFD );
|
|
}
|
|
|
|
struct timeval timeOut;
|
|
|
|
// Add avoiding an overflow on (long)usec
|
|
timeOut.tv_sec = timeoutMS / 1000l;
|
|
timeOut.tv_usec = ( timeoutMS % 1000l ) * 1000l;
|
|
|
|
// Wait for activity on the pipes for the specified amount of time
|
|
int rc = select( largestFD + 1, &fds, 0, 0, &timeOut );
|
|
if (rc == -1)
|
|
{
|
|
TRACE( "WaitOnMultipleEvents error %d\n", errno );
|
|
return -errno;
|
|
}
|
|
else if (rc == 0)
|
|
{
|
|
// No activity on the pipes
|
|
return -ETIME;
|
|
}
|
|
|
|
int numSignaled = rc;
|
|
|
|
// Only read from first pipe which was signaled
|
|
int signaled = -1;
|
|
for (ULONG index = 0; index < events.size(); index++)
|
|
{
|
|
int pipe = events[index]->mPipes[READING];
|
|
if (FD_ISSET( pipe, &fds ) != 0)
|
|
{
|
|
signaled = index;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (signaled == -1)
|
|
{
|
|
// Odd, no one was signaled
|
|
return -ENODATA;
|
|
}
|
|
|
|
DWORD tempVal = 0;
|
|
rc = events[signaled]->Read( tempVal );
|
|
if (rc == 0)
|
|
{
|
|
// Success
|
|
val = tempVal;
|
|
eventIndex = signaled;
|
|
return numSignaled;
|
|
}
|
|
else
|
|
{
|
|
// failure
|
|
return rc;
|
|
}
|
|
}
|
|
|
|
/*=========================================================================*/
|
|
// cEvent Methods
|
|
/*=========================================================================*/
|
|
|
|
/*===========================================================================
|
|
METHOD:
|
|
cEvent (Public Method)
|
|
|
|
DESCRIPTION:
|
|
Constructor
|
|
|
|
RETURN VALUE:
|
|
None
|
|
===========================================================================*/
|
|
cEvent::cEvent()
|
|
: mError( 0 )
|
|
{
|
|
int rc = pipe( mPipes );
|
|
if (rc != 0)
|
|
{
|
|
mError = errno;
|
|
TRACE( "cEvent - Error %d creating pipe, %s\n",
|
|
mError,
|
|
strerror( mError ) );
|
|
}
|
|
}
|
|
|
|
/*===========================================================================
|
|
METHOD:
|
|
~cEvent (Public Method)
|
|
|
|
DESCRIPTION:
|
|
Destructor
|
|
|
|
RETURN VALUE:
|
|
None
|
|
===========================================================================*/
|
|
cEvent::~cEvent()
|
|
{
|
|
// Check internal pipe status
|
|
if (mError == 0)
|
|
{
|
|
Close();
|
|
mError = EBADF;
|
|
}
|
|
}
|
|
|
|
/*===========================================================================
|
|
METHOD:
|
|
Close (Internal Method)
|
|
|
|
DESCRIPTION:
|
|
Close pipe
|
|
|
|
RETURN VALUE:
|
|
Return code
|
|
0 on success
|
|
errno value on failure
|
|
===========================================================================*/
|
|
int cEvent::Close()
|
|
{
|
|
int retCode = 0;
|
|
|
|
int rc = close( mPipes[READING] );
|
|
mPipes[READING] = -1;
|
|
|
|
if (rc != 0)
|
|
{
|
|
retCode = errno;
|
|
TRACE( "cEvent - Error %d deleting pipe[READING], %s\n",
|
|
retCode,
|
|
strerror( retCode ) );
|
|
}
|
|
|
|
rc = close( mPipes[WRITING] );
|
|
mPipes[WRITING] = -1;
|
|
|
|
if (rc != 0)
|
|
{
|
|
retCode = errno;
|
|
TRACE( "cEvent - Error %d deleting pipe[WRITING], %s\n",
|
|
retCode,
|
|
strerror( retCode ) );
|
|
}
|
|
|
|
return retCode;
|
|
}
|
|
|
|
/*===========================================================================
|
|
METHOD:
|
|
Set (Public Method)
|
|
|
|
DESCRIPTION:
|
|
Set/signal the event with the specified value
|
|
|
|
PARAMETERS:
|
|
val [ I ] - Value to pass through with signal
|
|
|
|
RETURN VALUE:
|
|
Return code
|
|
0 on success
|
|
errno value on failure
|
|
===========================================================================*/
|
|
int cEvent::Set( DWORD val )
|
|
{
|
|
// Check internal pipe status
|
|
if (mError != 0)
|
|
{
|
|
return mError;
|
|
}
|
|
|
|
PBYTE pWrite = (PBYTE)&val;
|
|
|
|
int writeSize = sizeof( DWORD );
|
|
while (writeSize > 0)
|
|
{
|
|
int bytesWritten = write( mPipes[WRITING], pWrite, writeSize );
|
|
if (bytesWritten == -1)
|
|
{
|
|
// Store error from write
|
|
int writeErr = errno;
|
|
|
|
// First error?
|
|
if (mError == 0)
|
|
{
|
|
// Yes, save the error
|
|
mError = writeErr;
|
|
}
|
|
|
|
// We cannot recover from this error
|
|
Close();
|
|
return writeErr;
|
|
}
|
|
|
|
pWrite += bytesWritten;
|
|
writeSize -= bytesWritten;
|
|
}
|
|
|
|
// Success
|
|
return 0;
|
|
}
|
|
|
|
/*===========================================================================
|
|
METHOD:
|
|
Wait (Free Method)
|
|
|
|
DESCRIPTION:
|
|
Wait for the event to be signalled and return the read in value
|
|
|
|
PARAMETERS:
|
|
timeoutMS [ I ] - Relative timeout length (in milliseconds)
|
|
val [ O ] - Associated value upon success
|
|
|
|
RETURN VALUE:
|
|
Return code
|
|
0 on success
|
|
ETIME on timeout
|
|
errno value on failure
|
|
===========================================================================*/
|
|
int cEvent::Wait(
|
|
DWORD timeoutMS,
|
|
DWORD & val )
|
|
{
|
|
// Check internal pipe status
|
|
if (mError != 0)
|
|
{
|
|
return mError;
|
|
}
|
|
|
|
fd_set fds;
|
|
FD_ZERO( &fds );
|
|
FD_SET( mPipes[READING], &fds );
|
|
|
|
struct timeval timeOut;
|
|
|
|
// Add avoiding an overflow on (long)usec
|
|
timeOut.tv_sec = timeoutMS / 1000l;
|
|
timeOut.tv_usec = ( timeoutMS % 1000l ) * 1000l;
|
|
|
|
// Wait for activity on the pipe for the specified amount of time
|
|
int rc = select( mPipes[READING] + 1, &fds, 0, 0, &timeOut );
|
|
if (rc == -1)
|
|
{
|
|
// Store error from select
|
|
int selectErr = errno;
|
|
|
|
// First error?
|
|
if (mError == 0)
|
|
{
|
|
// Yes, save the error
|
|
mError = selectErr;
|
|
}
|
|
|
|
// We cannot recover from this error
|
|
Close();
|
|
return selectErr;
|
|
}
|
|
else if (rc == 0)
|
|
{
|
|
// No activity on the pipe
|
|
return ETIME;
|
|
}
|
|
|
|
return Read( val );
|
|
}
|
|
|
|
/*===========================================================================
|
|
METHOD:
|
|
Clear (Free Method)
|
|
|
|
DESCRIPTION:
|
|
Read and discard all values currently in the pipe
|
|
===========================================================================*/
|
|
void cEvent::Clear()
|
|
{
|
|
DWORD unusedVal;
|
|
int rc = 0;
|
|
while (rc == 0)
|
|
{
|
|
rc = Wait( (DWORD)0, unusedVal );
|
|
}
|
|
}
|
|
|
|
|
|
/*===========================================================================
|
|
METHOD:
|
|
Read (Internal Method)
|
|
|
|
DESCRIPTION:
|
|
Read a DWORD from the pipe
|
|
|
|
RETURN VALUE:
|
|
Return code
|
|
0 on success
|
|
errno value on failure
|
|
===========================================================================*/
|
|
int cEvent::Read( DWORD & val )
|
|
{
|
|
DWORD tempVal;
|
|
PBYTE pRead = (PBYTE)&tempVal;
|
|
|
|
int readSize = sizeof( DWORD );
|
|
while (readSize > 0)
|
|
{
|
|
int bytesRead = read( mPipes[READING], pRead, readSize );
|
|
if (bytesRead <= 0)
|
|
{
|
|
// Store error from read
|
|
int readErr = errno;
|
|
if (readErr == 0)
|
|
{
|
|
// Hard error! This should NEVER happen for a pipe
|
|
ASSERT( 0 );
|
|
readErr = EBADF;
|
|
}
|
|
|
|
// First error?
|
|
if (mError == 0)
|
|
{
|
|
// Yes, store the error
|
|
mError = readErr;
|
|
}
|
|
|
|
// We cannot recover from this error
|
|
Close();
|
|
return readErr;
|
|
}
|
|
|
|
pRead += bytesRead;
|
|
readSize -= bytesRead;
|
|
}
|
|
|
|
val = tempVal;
|
|
|
|
return 0;
|
|
}
|