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