1 /* 2 * Copyright (c) 1999-2000, Eric Moon. 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 9 * 1. Redistributions of source code must retain the above copyright 10 * notice, this list of conditions, and the following disclaimer. 11 * 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions, and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 16 * 3. The name of the author may not be used to endorse or promote products 17 * derived from this software without specific prior written permission. 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR "AS IS" AND ANY EXPRESS OR 20 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 21 * OF TITLE, NON-INFRINGEMENT, MERCHANTABILITY AND FITNESS FOR A PARTICULAR 22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY 23 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 24 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 25 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 26 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR 27 * TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 28 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 29 */ 30 31 32 // ObservableLooper.cpp 33 34 #include "ObservableLooper.h" 35 36 #include <Debug.h> 37 #include <MessageRunner.h> 38 39 __USE_CORTEX_NAMESPACE 40 41 42 // ---------------------------------------------------------------- // 43 // *** deletion 44 // ---------------------------------------------------------------- // 45 46 // clients must call release() rather than deleting, 47 // to ensure that all observers are notified of the 48 // object's demise. if the object has already been 49 // released, return an error. 50 51 status_t ObservableLooper::release() { 52 53 // +++++ what if I'm not running? 54 // +++++ is a lock necessary? 55 56 if(isReleased()) 57 return B_NOT_ALLOWED; 58 59 // send request through proper channels 60 BMessenger(this).SendMessage(B_QUIT_REQUESTED); 61 62 return B_OK; 63 } 64 65 // ---------------------------------------------------------------- // 66 // *** ctor/dtor 67 // ---------------------------------------------------------------- // 68 69 ObservableLooper::~ObservableLooper() { 70 if(CountTargets()) { 71 PRINT(( 72 "*** ~ObservableLooper() '%s': %" B_PRId32 " observers remain\n", 73 Name(), CountTargets())); 74 } 75 if(m_executioner) 76 delete m_executioner; 77 } 78 79 ObservableLooper::ObservableLooper( 80 const char* name, 81 int32 priority, 82 int32 portCapacity, 83 bigtime_t quitTimeout) : 84 BLooper(name, priority, portCapacity), 85 m_quitTimeout(quitTimeout), 86 m_executioner(0), 87 m_quitting(false) {} 88 89 ObservableLooper::ObservableLooper( 90 BMessage* archive) : 91 BLooper(archive), 92 m_quitTimeout(B_INFINITE_TIMEOUT), 93 m_executioner(0), 94 m_quitting(false) { 95 96 archive->FindInt64("quitTimeout", (int64*)&m_quitTimeout); 97 } 98 99 // ---------------------------------------------------------------- // 100 // *** accessors 101 // ---------------------------------------------------------------- // 102 103 bool ObservableLooper::isReleased() const { 104 return m_quitting; 105 } 106 107 // ---------------------------------------------------------------- // 108 // *** hooks 109 // ---------------------------------------------------------------- // 110 111 // sends M_OBSERVER_ADDED to the newly-added observer 112 void ObservableLooper::observerAdded( 113 const BMessenger& observer) { 114 115 BMessage m(M_OBSERVER_ADDED); 116 m.AddMessenger("target", BMessenger(this)); 117 observer.SendMessage(&m); 118 } 119 120 // sends M_OBSERVER_REMOVED to the newly-removed observer 121 void ObservableLooper::observerRemoved( 122 const BMessenger& observer) { 123 124 BMessage m(M_OBSERVER_REMOVED); 125 m.AddMessenger("target", BMessenger(this)); 126 observer.SendMessage(&m); 127 } 128 129 // ---------------------------------------------------------------- // 130 // *** internal operations 131 // ---------------------------------------------------------------- // 132 133 status_t ObservableLooper::notify( 134 BMessage* message) { 135 ASSERT(IsLocked()); 136 137 return Invoke(message); 138 } 139 140 // sends M_RELEASE_OBSERVABLE 141 void ObservableLooper::notifyRelease() { 142 BMessage m(M_RELEASE_OBSERVABLE); 143 m.AddMessenger("target", BMessenger(this)); 144 notify(&m); 145 } 146 147 // ---------------------------------------------------------------- // 148 // *** BLooper 149 // ---------------------------------------------------------------- // 150 151 void ObservableLooper::Quit() { 152 ASSERT(IsLocked()); 153 154 if(QuitRequested()) { 155 releaseComplete(); 156 _inherited::Quit(); 157 } 158 else 159 Unlock(); 160 } 161 162 bool ObservableLooper::QuitRequested() { 163 164 if(CountTargets()) { 165 if(!m_quitting) { 166 m_quitting = true; 167 168 // no release request yet sent 169 notifyRelease(); 170 171 if(m_quitTimeout != B_INFINITE_TIMEOUT) { 172 // Initiate a timer to force quit -- if an observer 173 // has died, it shouldn't take me down with it. 174 ASSERT(!m_executioner); 175 m_executioner = new BMessageRunner( 176 BMessenger(this), 177 new BMessage(M_KILL_OBSERVABLE), 178 m_quitTimeout, 179 1); 180 } 181 } 182 183 // targets remain, so don't quit. 184 return false; 185 } 186 187 // okay to quit 188 return true; 189 } 190 191 // ---------------------------------------------------------------- // 192 // *** BHandler 193 // ---------------------------------------------------------------- // 194 195 void ObservableLooper::MessageReceived( 196 BMessage* message) { 197 198 // PRINT(( 199 // "### ObservableLooper::MessageReceived()\n")); 200 // message->PrintToStream(); 201 202 switch(message->what) { 203 case M_ADD_OBSERVER: 204 _handleAddObserver(message); 205 break; 206 207 case M_REMOVE_OBSERVER: 208 _handleRemoveObserver(message); 209 break; 210 211 case M_KILL_OBSERVABLE: 212 releaseComplete(); 213 BLooper::Quit(); 214 break; 215 216 default: 217 _inherited::MessageReceived(message); 218 } 219 } 220 221 // ---------------------------------------------------------------- // 222 // *** BArchivable 223 // ---------------------------------------------------------------- // 224 225 status_t ObservableLooper::Archive( 226 BMessage* archive, 227 bool deep) const { 228 229 ASSERT(IsLocked()); 230 231 // can't archive an object in limbo 232 if(m_quitting) 233 return B_NOT_ALLOWED; 234 235 status_t err = _inherited::Archive(archive, deep); 236 if(err < B_OK) 237 return err; 238 239 archive->AddInt64("quitTimeout", m_quitTimeout); 240 return B_OK; 241 } 242 243 // ---------------------------------------------------------------- // 244 // implementation 245 // ---------------------------------------------------------------- // 246 247 void ObservableLooper::_handleAddObserver( 248 BMessage* message) { 249 250 BMessage reply; 251 252 BMessenger observer; 253 status_t err = message->FindMessenger( 254 "observer", &observer); 255 if(err < B_OK) { 256 PRINT(( 257 "* ObservableLooper::_handleAddObserver(): no observer specified!\n")); 258 // send reply? +++++ 259 return; 260 } 261 262 // at this point, a reply of some sort will be sent 263 reply.AddMessenger("target", BMessenger(this)); 264 reply.AddMessenger("observer", observer); 265 266 if(m_quitting) { 267 // already quitting 268 reply.what = M_BAD_TARGET; 269 } 270 else if(IndexOfTarget(observer.Target(0)) != -1) { 271 // observer already added 272 reply.what = M_BAD_OBSERVER; 273 } 274 else { 275 // add it 276 err = AddTarget(observer.Target(0)); 277 ASSERT(err == B_OK); 278 reply.what = M_OBSERVER_ADDED; 279 } 280 281 // send reply 282 message->SendReply(&reply); 283 284 // call hook 285 observerAdded(observer); 286 } 287 288 void ObservableLooper::_handleRemoveObserver( 289 BMessage* message) { 290 291 // PRINT(("ObservableLooper::_handleRemoveObserver():\n" 292 // " %ld targets\n", CountTargets())); 293 BMessage reply; 294 295 BMessenger observer; 296 status_t err = message->FindMessenger( 297 "observer", &observer); 298 if(err < B_OK) { 299 PRINT(( 300 "* ObservableLooper::_handleRemoveObserver(): no observer specified!\n")); 301 // send reply? +++++ 302 return; 303 } 304 305 // at this point, a reply of some sort will be sent 306 reply.AddMessenger("target", BMessenger(this)); 307 reply.AddMessenger("observer", observer); 308 309 int32 index = IndexOfTarget(observer.Target(0)); 310 if(index == -1) { 311 reply.what = M_BAD_OBSERVER; 312 } 313 else { 314 RemoveTarget(index); 315 reply.what = M_OBSERVER_REMOVED; 316 } 317 318 message->SendReply(&reply); 319 320 // call hook 321 observerRemoved(observer); 322 323 // time to shut down? 324 if(m_quitting && !CountTargets()) { 325 releaseComplete(); 326 BLooper::Quit(); 327 } 328 } 329 330 // END -- ObservableLooper.cpp -- 331