1 //
2 // EventClass.cpp: implementation file
3 //
4 // Copyright (C) Walter E. Capers.  All rights reserved
5 //
6 // This source is free to use as you like.  If you make
7 // any changes please keep me in the loop.  Email them to
8 // walt.capers@comcast.net.
9 //
10 // PURPOSE:
11 //
12 //  To implement event signals as a C++ object
13 //
14 // REVISIONS
15 // =======================================================
16 // Date: 10.25.07
17 // Name: Walter E. Capers
18 // Description: File creation
19 //
20 // Date: 11/02/07
21 // Name: Walter E. Capers
22 // Description: removed unnessary code identified by On Freund from Code Project
23 //
24 //
25 #include "Thread.h"
26 
27 #ifndef WINDOWS
28 #include <sys/time.h>
29 #endif
30 
31 #include <iostream>
32 using namespace std;
33 
CEventClass(void)34 CEventClass::CEventClass(void)
35 :m_bCreated(TRUE)
36 {
37 	memset(&m_owner,0,sizeof(ThreadId_t));
38 #ifdef WINDOWS
39 	m_event = CreateEvent(NULL,FALSE,FALSE,NULL);
40 	if( !m_event )
41 	{
42 		m_bCreated = FALSE;
43 	}
44 #else
45 	pthread_mutexattr_t mattr;
46 
47 	pthread_mutexattr_init(&mattr);
48 	pthread_mutex_init(&m_lock,&mattr);
49 	pthread_cond_init(&m_ready,NULL);
50 
51 #endif
52 }
53 
~CEventClass(void)54 CEventClass::~CEventClass(void)
55 {
56 #ifdef WINDOWS
57 	CloseHandle(m_event);
58 #else
59 	pthread_cond_destroy(&m_ready);
60 	pthread_mutex_destroy(&m_lock);
61 #endif
62 }
63 
64 
65 /**
66  *
67  * Set
68  * set an event to signaled
69  *
70  **/
71 void
Set()72 CEventClass::Set()
73 {
74 #ifdef WINDOWS
75 	SetEvent(m_event);
76 #else
77 	pthread_cond_signal(&m_ready);
78 #endif
79 }
80 
81 /**
82  *
83  * Wait
84  * wait for an event -- wait for an event object
85  * to be set to signaled.  must be paired with a
86  * call to reset within the same thread.
87  *
88  **/
89 BOOL
Wait(DWORD tmout)90 CEventClass::Wait(DWORD tmout)
91 {
92 
93 	try
94 	{
95 		ThreadId_t id = CThread::ThreadId();
96 		if( CThread::ThreadIdsEqual(&id,&m_owner) )
97 		{
98 			throw "\n\tinvalid Wait call, Wait can not be called more than once"
99 				"\n\twithout a corresponding call to Reset!\n";
100 		}
101 		ThreadId_t zero;
102 		memset(&zero,0,sizeof(ThreadId_t));
103 
104 		if( memcmp(&zero,&m_owner,sizeof(ThreadId_t)) != 0 )
105 		{
106 			throw "\n\tanother thread is already waiting on this event!\n";
107 		}
108 
109 		m_owner = CThread::ThreadId();
110 #ifdef WINDOWS
111         tmout = tmout == 0 ? INFINITE : tmout;
112         DWORD rc = WaitForSingleObject(m_event, tmout);
113         e_timeout = FALSE;
114         if (rc ==  WAIT_OBJECT_0) {
115             return TRUE;
116         }
117         else if (rc == WAIT_TIMEOUT) {
118             e_timeout = TRUE;
119             return TRUE;
120         }
121         else
122             return FALSE;
123 #else
124 		pthread_mutex_lock(&m_lock);
125         e_timeout = FALSE;
126         if (tmout == 0) {
127             pthread_cond_wait(&m_ready,&m_lock);
128             return TRUE;
129         }
130         struct timespec ts;
131         timeval tv;
132         gettimeofday(&tv, NULL);
133         ts.tv_sec = tv.tv_sec;
134         ts.tv_nsec = tv.tv_usec * 1000l;
135         ts.tv_sec += tmout / 1000;
136         ts.tv_nsec += (tmout % 1000) * 1000000l;
137         while(ts.tv_nsec > 1000000000l) {
138             ++ts.tv_sec;
139             ts.tv_nsec -= 1000000000l;
140         }
141         int rc = pthread_cond_timedwait(&m_ready, &m_lock, &ts);
142         if (rc == ETIMEDOUT)
143             e_timeout = TRUE;
144         return TRUE;
145 #endif
146 	}
147 	catch( char *psz )
148 	{
149 #ifdef WINDOWS
150 		MessageBoxA(NULL,&psz[2],"Fatal exception CEventClass::Wait",MB_ICONHAND);
151 		exit(-1);
152 #else
153 		cerr << "Fatal exception CEventClass::Wait: " << psz;
154 #endif
155 
156 	}
157 	return TRUE;
158 }
159 
160 
161 /**
162  *
163  * Reset
164  * reset an event flag to unsignaled
165  * wait must be paired with reset within the same thread.
166  *
167  **/
168 void
Reset()169 CEventClass::Reset()
170 {
171 	try
172 	{
173 		ThreadId_t id = CThread::ThreadId();
174 		if( !CThread::ThreadIdsEqual(&id,&m_owner) )
175 		{
176 			throw "\n\tunbalanced call to Reset, Reset must be called from\n"
177 				  "\n\tthe same Wait-Reset pair!\n";
178 		}
179 
180 		memset(&m_owner,0,sizeof(ThreadId_t));
181 
182 #ifndef WINDOWS
183 		pthread_mutex_unlock(&m_lock);
184 #endif
185 	}
186 	catch( char *psz )
187 	{
188 #ifdef WINDOWS
189 		MessageBoxA(NULL,&psz[2],"Fatal exception CEventClass::Reset",MB_ICONHAND);
190 		exit(-1);
191 #else
192 		cerr << "Fatal exception CEventClass::Reset: " << psz;
193 #endif
194 
195 	}
196 }
197 
198