blob: bfe117f96dac18ec57b2e913bebb46a8d637340d [file] [log] [blame]
//
// EventClass.cpp: implementation file
//
// Copyright (C) Walter E. Capers. All rights reserved
//
// This source is free to use as you like. If you make
// any changes please keep me in the loop. Email them to
// walt.capers@comcast.net.
//
// PURPOSE:
//
// To implement event signals as a C++ object
//
// REVISIONS
// =======================================================
// Date: 10.25.07
// Name: Walter E. Capers
// Description: File creation
//
// Date: 11/02/07
// Name: Walter E. Capers
// Description: removed unnessary code identified by On Freund from Code Project
//
//
#include "Thread.h"
#ifndef WINDOWS
#include <sys/time.h>
#endif
#include <iostream>
using namespace std;
CEventClass::CEventClass(void)
:m_bCreated(TRUE)
{
memset(&m_owner,0,sizeof(ThreadId_t));
#ifdef WINDOWS
m_event = CreateEvent(NULL,FALSE,FALSE,NULL);
if( !m_event )
{
m_bCreated = FALSE;
}
#else
pthread_mutexattr_t mattr;
pthread_mutexattr_init(&mattr);
pthread_mutex_init(&m_lock,&mattr);
pthread_cond_init(&m_ready,NULL);
#endif
}
CEventClass::~CEventClass(void)
{
#ifdef WINDOWS
CloseHandle(m_event);
#else
pthread_cond_destroy(&m_ready);
pthread_mutex_destroy(&m_lock);
#endif
}
/**
*
* Set
* set an event to signaled
*
**/
void
CEventClass::Set()
{
#ifdef WINDOWS
SetEvent(m_event);
#else
pthread_cond_signal(&m_ready);
#endif
}
/**
*
* Wait
* wait for an event -- wait for an event object
* to be set to signaled. must be paired with a
* call to reset within the same thread.
*
**/
BOOL
CEventClass::Wait(DWORD tmout)
{
try
{
ThreadId_t id = CThread::ThreadId();
if( CThread::ThreadIdsEqual(&id,&m_owner) )
{
throw "\n\tinvalid Wait call, Wait can not be called more than once"
"\n\twithout a corresponding call to Reset!\n";
}
ThreadId_t zero;
memset(&zero,0,sizeof(ThreadId_t));
if( memcmp(&zero,&m_owner,sizeof(ThreadId_t)) != 0 )
{
throw "\n\tanother thread is already waiting on this event!\n";
}
m_owner = CThread::ThreadId();
#ifdef WINDOWS
tmout = tmout == 0 ? INFINITE : tmout;
DWORD rc = WaitForSingleObject(m_event, tmout);
e_timeout = FALSE;
if (rc == WAIT_OBJECT_0) {
return TRUE;
}
else if (rc == WAIT_TIMEOUT) {
e_timeout = TRUE;
return TRUE;
}
else
return FALSE;
#else
pthread_mutex_lock(&m_lock);
e_timeout = FALSE;
if (tmout == 0) {
pthread_cond_wait(&m_ready,&m_lock);
return TRUE;
}
struct timespec ts;
timeval tv;
gettimeofday(&tv, NULL);
ts.tv_sec = tv.tv_sec;
ts.tv_nsec = tv.tv_usec * 1000l;
ts.tv_sec += tmout / 1000;
ts.tv_nsec += (tmout % 1000) * 1000000l;
while(ts.tv_nsec > 1000000000l) {
++ts.tv_sec;
ts.tv_nsec -= 1000000000l;
}
int rc = pthread_cond_timedwait(&m_ready, &m_lock, &ts);
if (rc == ETIMEDOUT)
e_timeout = TRUE;
return TRUE;
#endif
}
catch( char *psz )
{
#ifdef WINDOWS
MessageBoxA(NULL,&psz[2],"Fatal exception CEventClass::Wait",MB_ICONHAND);
exit(-1);
#else
cerr << "Fatal exception CEventClass::Wait: " << psz;
#endif
}
return TRUE;
}
/**
*
* Reset
* reset an event flag to unsignaled
* wait must be paired with reset within the same thread.
*
**/
void
CEventClass::Reset()
{
try
{
ThreadId_t id = CThread::ThreadId();
if( !CThread::ThreadIdsEqual(&id,&m_owner) )
{
throw "\n\tunbalanced call to Reset, Reset must be called from\n"
"\n\tthe same Wait-Reset pair!\n";
}
memset(&m_owner,0,sizeof(ThreadId_t));
#ifndef WINDOWS
pthread_mutex_unlock(&m_lock);
#endif
}
catch( char *psz )
{
#ifdef WINDOWS
MessageBoxA(NULL,&psz[2],"Fatal exception CEventClass::Reset",MB_ICONHAND);
exit(-1);
#else
cerr << "Fatal exception CEventClass::Reset: " << psz;
#endif
}
}