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 namespace OpenZWave
43 {
44 	namespace Internal
45 	{
46 		namespace Platform
47 		{
48 
49 			void WaitMultipleCallback(void* _context);
50 
51 //-----------------------------------------------------------------------------
52 //	<Wait::Wait>
53 //	Constructor
54 //-----------------------------------------------------------------------------
Wait()55 			Wait::Wait()
56 			{
57 				m_pImpl = new WaitImpl(this);
58 			}
59 
60 //-----------------------------------------------------------------------------
61 //	<Wait::~Wait>
62 //	Destructor
63 //-----------------------------------------------------------------------------
~Wait()64 			Wait::~Wait()
65 			{
66 				delete m_pImpl;
67 			}
68 
69 //-----------------------------------------------------------------------------
70 //	<Wait::AddWatcher>
71 //	Add a watcher to our object.
72 //-----------------------------------------------------------------------------
AddWatcher(pfnWaitNotification_t _callback,void * _context)73 			void Wait::AddWatcher(pfnWaitNotification_t _callback, void* _context)
74 			{
75 				if (!_callback)
76 				{
77 					assert(0);
78 					return;
79 				}
80 
81 				// Add a ref so our object cannot disappear while being watched
82 				AddRef();
83 
84 				// Add the watcher (platform specific code required here for thread safety)
85 				m_pImpl->AddWatcher(_callback, _context);
86 			}
87 
88 //-----------------------------------------------------------------------------
89 //	<Wait::RemoveWatcher>
90 //	Remove a watcher from our object.
91 //-----------------------------------------------------------------------------
RemoveWatcher(pfnWaitNotification_t _callback,void * _context)92 			void Wait::RemoveWatcher(pfnWaitNotification_t _callback, void* _context)
93 			{
94 				if (m_pImpl->RemoveWatcher(_callback, _context))
95 				{
96 					Release();
97 				}
98 			}
99 
100 //-----------------------------------------------------------------------------
101 //	<Wait::Notify>
102 //	Notify all the watchers that the object has become signalled
103 //-----------------------------------------------------------------------------
Notify()104 			void Wait::Notify()
105 			{
106 				m_pImpl->Notify();
107 			}
108 
109 //-----------------------------------------------------------------------------
110 //	<Wait::Multiple>
111 //	Wait for one of multiple objects to become signalled.
112 //-----------------------------------------------------------------------------
Multiple(Wait ** _objects,uint32 _numObjects,int32 _timeout)113 			int32 Wait::Multiple(Wait** _objects, uint32 _numObjects, int32 _timeout // = -1
114 					)
115 			{
116 				uint32 i;
117 
118 				// Create an event that will be set when any of the objects in the list becomes signalled.
119 				Event* waitEvent = new Event();
120 
121 				// Add a watcher to each object in the list, passing in the event as the context.
122 				for (i = 0; i < _numObjects; ++i)
123 				{
124 //		Log::Write( LogLevel_Info, "Wait::Multiple - Object %p %d", _objects[i], _objects[i]->IsSignalled());
125 					_objects[i]->AddWatcher(WaitMultipleCallback, waitEvent);
126 				}
127 
128 				int32 res = -1;	// Default to timeout result
129 				string str = "";
130 				if (waitEvent->Wait(_timeout))
131 				{
132 					// An object was signalled.  Run through the list
133 					// and see which one it was.
134 					for (i = 0; i < _numObjects; ++i)
135 					{
136 						if (_objects[i]->IsSignalled())
137 						{
138 							if (res == -1)
139 								res = (int32) i;
140 							char buf[15];
141 							snprintf(buf, sizeof(buf), "%d, ", i);
142 							str += buf;
143 						}
144 					}
145 				}
146 //	Log::Write( LogLevel_Debug, "Wait::Multiple res=%d num=%d >%s", res, _numObjects, str.c_str() );
147 
148 				// Remove the watchers
149 				for (i = 0; i < _numObjects; ++i)
150 				{
151 					_objects[i]->RemoveWatcher(WaitMultipleCallback, waitEvent);
152 				}
153 
154 				// We're done with the event now
155 				waitEvent->Release();
156 				return res;
157 			}
158 
159 //-----------------------------------------------------------------------------
160 //	<WaitMultipleCallback>
161 //	Callback handler for the watchers added during WaitImpl::Multiple
162 //-----------------------------------------------------------------------------
WaitMultipleCallback(void * _context)163 			void WaitMultipleCallback(void* _context)
164 			{
165 				Event* waitEvent = (Event*) _context;
166 				waitEvent->Set();
167 			}
168 		} // namespace Platform
169 	} // namespace Internal
170 } // namespace OpenZWave
171