btrfs: Attempt to fix GCC2 build.
[haiku.git] / src / apps / cortex / support / ObservableLooper.cpp
blobbe44fb67bac054e8d8e6d5c7e0ab63fe23499646
1 /*
2 * Copyright (c) 1999-2000, Eric Moon.
3 * All rights reserved.
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions, and the following disclaimer.
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.
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.
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.
32 // ObservableLooper.cpp
34 #include "ObservableLooper.h"
36 #include <Debug.h>
37 #include <MessageRunner.h>
39 __USE_CORTEX_NAMESPACE
42 // ---------------------------------------------------------------- //
43 // *** deletion
44 // ---------------------------------------------------------------- //
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.
51 status_t ObservableLooper::release() {
53 // +++++ what if I'm not running?
54 // +++++ is a lock necessary?
56 if(isReleased())
57 return B_NOT_ALLOWED;
59 // send request through proper channels
60 BMessenger(this).SendMessage(B_QUIT_REQUESTED);
62 return B_OK;
65 // ---------------------------------------------------------------- //
66 // *** ctor/dtor
67 // ---------------------------------------------------------------- //
69 ObservableLooper::~ObservableLooper() {
70 if(CountTargets()) {
71 PRINT((
72 "*** ~ObservableLooper() '%s': %" B_PRId32 " observers remain\n",
73 Name(), CountTargets()));
75 if(m_executioner)
76 delete m_executioner;
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) {}
89 ObservableLooper::ObservableLooper(
90 BMessage* archive) :
91 BLooper(archive),
92 m_quitTimeout(B_INFINITE_TIMEOUT),
93 m_executioner(0),
94 m_quitting(false) {
96 archive->FindInt64("quitTimeout", (int64*)&m_quitTimeout);
99 // ---------------------------------------------------------------- //
100 // *** accessors
101 // ---------------------------------------------------------------- //
103 bool ObservableLooper::isReleased() const {
104 return m_quitting;
107 // ---------------------------------------------------------------- //
108 // *** hooks
109 // ---------------------------------------------------------------- //
111 // sends M_OBSERVER_ADDED to the newly-added observer
112 void ObservableLooper::observerAdded(
113 const BMessenger& observer) {
115 BMessage m(M_OBSERVER_ADDED);
116 m.AddMessenger("target", BMessenger(this));
117 observer.SendMessage(&m);
120 // sends M_OBSERVER_REMOVED to the newly-removed observer
121 void ObservableLooper::observerRemoved(
122 const BMessenger& observer) {
124 BMessage m(M_OBSERVER_REMOVED);
125 m.AddMessenger("target", BMessenger(this));
126 observer.SendMessage(&m);
129 // ---------------------------------------------------------------- //
130 // *** internal operations
131 // ---------------------------------------------------------------- //
133 status_t ObservableLooper::notify(
134 BMessage* message) {
135 ASSERT(IsLocked());
137 return Invoke(message);
140 // sends M_RELEASE_OBSERVABLE
141 void ObservableLooper::notifyRelease() {
142 BMessage m(M_RELEASE_OBSERVABLE);
143 m.AddMessenger("target", BMessenger(this));
144 notify(&m);
147 // ---------------------------------------------------------------- //
148 // *** BLooper
149 // ---------------------------------------------------------------- //
151 void ObservableLooper::Quit() {
152 ASSERT(IsLocked());
154 if(QuitRequested()) {
155 releaseComplete();
156 _inherited::Quit();
158 else
159 Unlock();
162 bool ObservableLooper::QuitRequested() {
164 if(CountTargets()) {
165 if(!m_quitting) {
166 m_quitting = true;
168 // no release request yet sent
169 notifyRelease();
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,
183 // targets remain, so don't quit.
184 return false;
187 // okay to quit
188 return true;
191 // ---------------------------------------------------------------- //
192 // *** BHandler
193 // ---------------------------------------------------------------- //
195 void ObservableLooper::MessageReceived(
196 BMessage* message) {
198 // PRINT((
199 // "### ObservableLooper::MessageReceived()\n"));
200 // message->PrintToStream();
202 switch(message->what) {
203 case M_ADD_OBSERVER:
204 _handleAddObserver(message);
205 break;
207 case M_REMOVE_OBSERVER:
208 _handleRemoveObserver(message);
209 break;
211 case M_KILL_OBSERVABLE:
212 releaseComplete();
213 BLooper::Quit();
214 break;
216 default:
217 _inherited::MessageReceived(message);
221 // ---------------------------------------------------------------- //
222 // *** BArchivable
223 // ---------------------------------------------------------------- //
225 status_t ObservableLooper::Archive(
226 BMessage* archive,
227 bool deep) const {
229 ASSERT(IsLocked());
231 // can't archive an object in limbo
232 if(m_quitting)
233 return B_NOT_ALLOWED;
235 status_t err = _inherited::Archive(archive, deep);
236 if(err < B_OK)
237 return err;
239 archive->AddInt64("quitTimeout", m_quitTimeout);
240 return B_OK;
243 // ---------------------------------------------------------------- //
244 // implementation
245 // ---------------------------------------------------------------- //
247 void ObservableLooper::_handleAddObserver(
248 BMessage* message) {
250 BMessage reply;
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;
262 // at this point, a reply of some sort will be sent
263 reply.AddMessenger("target", BMessenger(this));
264 reply.AddMessenger("observer", observer);
266 if(m_quitting) {
267 // already quitting
268 reply.what = M_BAD_TARGET;
270 else if(IndexOfTarget(observer.Target(0)) != -1) {
271 // observer already added
272 reply.what = M_BAD_OBSERVER;
274 else {
275 // add it
276 err = AddTarget(observer.Target(0));
277 ASSERT(err == B_OK);
278 reply.what = M_OBSERVER_ADDED;
281 // send reply
282 message->SendReply(&reply);
284 // call hook
285 observerAdded(observer);
288 void ObservableLooper::_handleRemoveObserver(
289 BMessage* message) {
291 // PRINT(("ObservableLooper::_handleRemoveObserver():\n"
292 // " %ld targets\n", CountTargets()));
293 BMessage reply;
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;
305 // at this point, a reply of some sort will be sent
306 reply.AddMessenger("target", BMessenger(this));
307 reply.AddMessenger("observer", observer);
309 int32 index = IndexOfTarget(observer.Target(0));
310 if(index == -1) {
311 reply.what = M_BAD_OBSERVER;
313 else {
314 RemoveTarget(index);
315 reply.what = M_OBSERVER_REMOVED;
318 message->SendReply(&reply);
320 // call hook
321 observerRemoved(observer);
323 // time to shut down?
324 if(m_quitting && !CountTargets()) {
325 releaseComplete();
326 BLooper::Quit();
330 // END -- ObservableLooper.cpp --