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 51status_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 69ObservableLooper::~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 79ObservableLooper::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 89ObservableLooper::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 103bool ObservableLooper::isReleased() const { 104 return m_quitting; 105} 106 107// ---------------------------------------------------------------- // 108// *** hooks 109// ---------------------------------------------------------------- // 110 111// sends M_OBSERVER_ADDED to the newly-added observer 112void 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 121void 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 133status_t ObservableLooper::notify( 134 BMessage* message) { 135 ASSERT(IsLocked()); 136 137 return Invoke(message); 138} 139 140// sends M_RELEASE_OBSERVABLE 141void ObservableLooper::notifyRelease() { 142 BMessage m(M_RELEASE_OBSERVABLE); 143 m.AddMessenger("target", BMessenger(this)); 144 notify(&m); 145} 146 147// ---------------------------------------------------------------- // 148// *** BLooper 149// ---------------------------------------------------------------- // 150 151void ObservableLooper::Quit() { 152 ASSERT(IsLocked()); 153 154 if(QuitRequested()) { 155 releaseComplete(); 156 _inherited::Quit(); 157 } 158 else 159 Unlock(); 160} 161 162bool 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 195void 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 225status_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 247void 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 288void 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