1 //-----------------------------------------------------------------------------
2 //
3 //	Wait.cpp
4 //
5 //	Base class for objects we want to be able to wait for.
6 //
7 //	Copyright (c) 2010 Mal Lansell <mal@lansell.org>
8 //	All rights reserved.
9 //
10 //	SOFTWARE NOTICE AND LICENSE
11 //
12 //	This file is part of OpenZWave.
13 //
14 //	OpenZWave is free software: you can redistribute it and/or modify
15 //	it under the terms of the GNU Lesser General Public License as published
16 //	by the Free Software Foundation, either version 3 of the License,
17 //	or (at your option) any later version.
18 //
19 //	OpenZWave is distributed in the hope that it will be useful,
20 //	but WITHOUT ANY WARRANTY; without even the implied warranty of
21 //	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
22 //	GNU Lesser General Public License for more details.
23 //
24 //	You should have received a copy of the GNU Lesser General Public License
25 //	along with OpenZWave.  If not, see <http://www.gnu.org/licenses/>.
26 //
27 //-----------------------------------------------------------------------------
28 #include <stdio.h>
29 #include "Defs.h"
30 #include "platform/Wait.h"
31 #include "platform/Event.h"
32 #include "platform/Log.h"
33 
34 #ifdef WIN32
35 #include "platform/windows/WaitImpl.h"	// Platform-specific implementation of a Wait object
36 #elif defined WINRT
37 #include "platform/winRT/WaitImpl.h"	// Platform-specific implementation of a Wait object
38 #else
39 #include "platform/unix/WaitImpl.h"	// Platform-specific implementation of a Wait object
40 #endif
41 
42 using namespace OpenZWave;
43 
44 void WaitMultipleCallback( void* _context );
45 
46 //-----------------------------------------------------------------------------
47 //	<Wait::Wait>
48 //	Constructor
49 //-----------------------------------------------------------------------------
Wait()50 Wait::Wait
51 (
52 )
53 {
54 	m_pImpl = new WaitImpl( this );
55 }
56 
57 //-----------------------------------------------------------------------------
58 //	<Wait::~Wait>
59 //	Destructor
60 //-----------------------------------------------------------------------------
~Wait()61 Wait::~Wait
62 (
63 )
64 {
65 	delete m_pImpl;
66 }
67 
68 //-----------------------------------------------------------------------------
69 //	<Wait::AddWatcher>
70 //	Add a watcher to our object.
71 //-----------------------------------------------------------------------------
AddWatcher(pfnWaitNotification_t _callback,void * _context)72 void Wait::AddWatcher
73 (
74 	pfnWaitNotification_t _callback,
75 	void* _context
76 )
77 {
78 	if( !_callback )
79 	{
80 		assert(0);
81 		return;
82 	}
83 
84 	// Add a ref so our object cannot disappear while being watched
85 	AddRef();
86 
87 	// Add the watcher (platform specific code required here for thread safety)
88 	m_pImpl->AddWatcher( _callback, _context );
89 }
90 
91 //-----------------------------------------------------------------------------
92 //	<Wait::RemoveWatcher>
93 //	Remove a watcher from our object.
94 //-----------------------------------------------------------------------------
RemoveWatcher(pfnWaitNotification_t _callback,void * _context)95 void Wait::RemoveWatcher
96 (
97 	pfnWaitNotification_t _callback,
98 	void* _context
99 )
100 {
101 	if( m_pImpl->RemoveWatcher( _callback, _context ) )
102 	{
103 		Release();
104 	}
105 }
106 
107 //-----------------------------------------------------------------------------
108 //	<Wait::Notify>
109 //	Notify all the watchers that the object has become signalled
110 //-----------------------------------------------------------------------------
Notify()111 void Wait::Notify
112 (
113 )
114 {
115 	m_pImpl->Notify();
116 }
117 
118 //-----------------------------------------------------------------------------
119 //	<Wait::Multiple>
120 //	Wait for one of multiple objects to become signalled.
121 //-----------------------------------------------------------------------------
Multiple(Wait ** _objects,uint32 _numObjects,int32 _timeout)122 int32 Wait::Multiple
123 (
124 	Wait** _objects,
125 	uint32 _numObjects,
126 	int32 _timeout // = -1
127 )
128 {
129 	uint32 i;
130 
131 	// Create an event that will be set when any of the objects in the list becomes signalled.
132 	Event* waitEvent = new Event();
133 
134 	// Add a watcher to each object in the list, passing in the event as the context.
135 	for( i=0; i<_numObjects; ++i )
136 	{
137 		_objects[i]->AddWatcher( WaitMultipleCallback, waitEvent );
138 	}
139 
140 	int32 res = -1;	// Default to timeout result
141 	string str = "";
142 	if( waitEvent->Wait( _timeout ) )
143 	{
144 		// An object was signalled.  Run through the list
145 		// and see which one it was.
146 		for( i=0; i<_numObjects; ++i )
147 		{
148 			if( _objects[i]->IsSignalled() )
149 			{
150 				if( res == -1 )
151 					res = (int32)i;
152 				char buf[15];
153 				snprintf(buf, sizeof(buf), "%d, ", i);
154 				str += buf;
155 			}
156 		}
157 	}
158 	//Log::Write( LogLevel_Debug, "Wait::Multiple res=%d num=%d >%s", res, _numObjects, str.c_str() );
159 
160 	// Remove the watchers
161 	for( i=0; i<_numObjects; ++i )
162 	{
163 		_objects[i]->RemoveWatcher( WaitMultipleCallback, waitEvent );
164 	}
165 
166 	// We're done with the event now
167 	waitEvent->Release();
168 	return res;
169 }
170 
171 
172 //-----------------------------------------------------------------------------
173 //	<WaitMultipleCallback>
174 //	Callback handler for the watchers added during WaitImpl::Multiple
175 //-----------------------------------------------------------------------------
WaitMultipleCallback(void * _context)176 void WaitMultipleCallback
177 (
178 	void* _context
179 )
180 {
181 	Event* waitEvent = (Event*)_context;
182 	waitEvent->Set();
183 }
184 
185