xref: /haiku/src/servers/registrar/MessageRunnerManager.cpp (revision 4f00613311d0bd6b70fa82ce19931c41f071ea4e)
1 //------------------------------------------------------------------------------
2 //	Copyright (c) 2001-2002, OpenBeOS
3 //
4 //	Permission is hereby granted, free of charge, to any person obtaining a
5 //	copy of this software and associated documentation files (the "Software"),
6 //	to deal in the Software without restriction, including without limitation
7 //	the rights to use, copy, modify, merge, publish, distribute, sublicense,
8 //	and/or sell copies of the Software, and to permit persons to whom the
9 //	Software is furnished to do so, subject to the following conditions:
10 //
11 //	The above copyright notice and this permission notice shall be included in
12 //	all copies or substantial portions of the Software.
13 //
14 //	THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 //	IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 //	FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 //	AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 //	LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
19 //	FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
20 //	DEALINGS IN THE SOFTWARE.
21 //
22 //	File Name:		MessageRunnerManager.cpp
23 //	Author:			Ingo Weinhold (bonefish@users.sf.net)
24 //	Description:	Manages the registrar side "shadows" of BMessageRunners.
25 //------------------------------------------------------------------------------
26 
27 #include <algorithm>
28 #include <new>
29 
30 #include <Autolock.h>
31 #include <Message.h>
32 #include <MessagePrivate.h>
33 #include <Messenger.h>
34 #include <OS.h>
35 #include <RegistrarDefs.h>
36 
37 #include "Debug.h"
38 #include "Event.h"
39 #include "EventQueue.h"
40 #include "MessageDeliverer.h"
41 #include "MessageRunnerManager.h"
42 
43 using std::max;
44 using std::nothrow;
45 
46 /*!	\class MessageRunnerManager
47 	\brief Manages the registrar side "shadows" of BMessageRunners.
48 
49 	The class features four methods to which the registrar application
50 	dispatches the message runner specific request messages.
51 
52 	Each active message runner (i.e. one that still has messages to be sent)
53 	is represented by a RunnerInfo that comprises all necessary information,
54 	among these a RunnerEvent added to the event queue. When the event is
55 	executed, it calls the _DoEvent() method, which in turn sends the message
56 	runner message to the respective target and schedules the event for the
57 	next time the message has to be sent (_ScheduleEvent()).
58 
59 	A couple of helper methods provide convenient access to the RunnerInfo
60 	list (\a fRunnerInfos). A BLocker (\a fLock) and respective locking
61 	methods are used to serialize the access to the member variables.
62 */
63 
64 /*! \var BList MessageRunnerManager::fRunnerInfos
65 	\brief The list of RunnerInfos.
66 */
67 
68 /*! \var BLocker MessageRunnerManager::fLock
69 	\brief A locker used to serialize the access to the object's variable
70 		   members.
71 */
72 
73 /*! \var EventQueue *MessageRunnerManager::fEventQueue
74 	\brief Event queue used by the manager.
75 */
76 
77 /*! \var int32 MessageRunnerManager::fNextToken
78 	\brief Next unused token for message runners.
79 */
80 
81 
82 using namespace BPrivate;
83 
84 //! The minimal time interval for message runners (50 ms).
85 static const bigtime_t kMininalTimeInterval = 50000LL;
86 
87 // RunnerEvent
88 /*!	\brief Event class used to by the message runner manager.
89 
90 	For each active message runner such an event is used. It invokes
91 	MessageRunnerManager::_DoEvent() on execution.
92 */
93 class MessageRunnerManager::RunnerEvent : public Event {
94 public:
95 	/*!	\brief Creates a new RunnerEvent.
96 		\param manager The message runner manager.
97 		\param info The RunnerInfo for the message runner.
98 	*/
99 	RunnerEvent(MessageRunnerManager *manager, RunnerInfo *info)
100 		: Event(false),
101 		  fManager(manager),
102 		  fInfo(info)
103 	{
104 	}
105 
106 	/*!	\brief Hook method invoked when the event is executed.
107 
108 		Implements Event. Calls MessageRunnerManager::_DoEvent().
109 
110 		\param queue The event queue executing the event.
111 		\return \c true, if the object shall be deleted, \c false otherwise.
112 	*/
113 	virtual bool Do(EventQueue *queue)
114 	{
115 		return fManager->_DoEvent(fInfo);
116 	}
117 
118 private:
119 	MessageRunnerManager	*fManager;	//!< The message runner manager.
120 	RunnerInfo				*fInfo;		//!< The message runner info.
121 };
122 
123 
124 // RunnerInfo
125 /*!	\brief Contains all needed information about an active message runner.
126 */
127 struct MessageRunnerManager::RunnerInfo {
128 	/*!	\brief Creates a new RunnerInfo.
129 		\param team The team owning the message runner.
130 		\param token The unique token associated with the message runner.
131 		\param target The target the message shall be sent to.
132 		\param message The message to be sent to the target.
133 		\param interval The message runner's time interval.
134 		\param count The number of times the message shall be sent.
135 		\param replyTarget The reply target for the delivered message.
136 	*/
137 	RunnerInfo(team_id team, int32 token, BMessenger target, BMessage *message,
138 			   bigtime_t interval, int32 count, BMessenger replyTarget)
139 		: team(team),
140 		  token(token),
141 		  target(target),
142 		  message(message),
143 		  interval(interval),
144 		  count(count),
145 		  replyTarget(replyTarget),
146 		  time(0),
147 		  event(NULL),
148 		  rescheduled(false)
149 	{
150 	}
151 
152 	/*!	\brief Frees all resources associated with the object.
153 
154 		The message and the event are delete.
155 	*/
156 	~RunnerInfo()
157 	{
158 		delete message;
159 		delete event;
160 	}
161 
162 	/*!	\brief Delivers the message to the respective target.
163 		\return \c B_OK, if the message has successfully been delivered or
164 				the target does still exist and its message port is full,
165 				an error code otherwise.
166 	*/
167 	status_t DeliverMessage()
168 	{
169 		if (count > 0)
170 			count--;
171 
172 		// set the reply target
173 		BMessage::Private(message).SetReply(replyTarget);
174 
175 		// deliver the message: We use the MessageDeliverer to allow the
176 		// message to be delivered, even if the target port is temporarily
177 		// full. For periodic message runners, that have to deliver further
178 		// messages, we restrict the delivery timeout to the message interval.
179 		status_t error;
180 		if (count > 0) {
181 			error = MessageDeliverer::Default()->DeliverMessage(message, target,
182 				interval);
183 		} else {
184 			error = MessageDeliverer::Default()->DeliverMessage(message,
185 				target);
186 		}
187 
188 		// B_WOULD_BLOCK is as good as B_OK. We return an error only, if
189 		// there are serious problems with the target, i.e. if it doesn't
190 		// exist anymore for instance. A full message port is harmless.
191 		if (error == B_WOULD_BLOCK)
192 			error = B_OK;
193 		return error;
194 	}
195 
196 	team_id		team;			//!< The team owning the message runner.
197 	int32		token;			/*!< The unique token associated with the
198 									 message runner. */
199 	BMessenger	target;			//!< The target the message shall be sent to.
200 	BMessage	*message;		//!< The message to be sent to the target.
201 	bigtime_t	interval;		//!< The message runner's time interval.
202 	int32		count;			/*!< The number of times the message shall be
203 									 sent. */
204 	BMessenger	replyTarget;	/*!< The reply target for the delivered
205 									 message. */
206 	bigtime_t	time;			/*!< Time at which the next message will be
207 									 sent. */
208 	RunnerEvent	*event;			//!< Runner event for the message runner.
209 	bool		rescheduled;	/*!< Set to \c true when the event has been
210 									 started to be executed while it was
211 									 rescheduled. */
212 };
213 
214 
215 // constructor
216 /*!	\brief Creates a new MessageRunnerManager.
217 	\param eventQueue The EventQueue the manager shall use.
218 */
219 MessageRunnerManager::MessageRunnerManager(EventQueue *eventQueue)
220 	: fRunnerInfos(),
221 	  fLock(),
222 	  fEventQueue(eventQueue),
223 	  fNextToken(0)
224 {
225 }
226 
227 // destructor
228 /*!	\brief Frees all resources associated with the object.
229 
230 	The manager's event queue must already have been stopped
231 	(EventQueue::Die()).
232 */
233 MessageRunnerManager::~MessageRunnerManager()
234 {
235 	// The event queue should already be stopped, but must still exist.
236 	// If it is still running and an event gets executed after we've locked
237 	// ourselves, then it will access an already deleted manager.
238 	BAutolock _lock(fLock);
239 	for (int32 i = 0; RunnerInfo *info = _InfoAt(i); i++) {
240 		if (!fEventQueue->RemoveEvent(info->event))
241 			info->event = NULL;
242 		delete info;
243 	}
244 	fRunnerInfos.MakeEmpty();
245 }
246 
247 // HandleRegisterRunner
248 /*!	\brief Handles a registration request (BMessageRunner::InitData()).
249 	\param request The request message.
250 */
251 void
252 MessageRunnerManager::HandleRegisterRunner(BMessage *request)
253 {
254 	FUNCTION_START();
255 
256 	BAutolock _lock(fLock);
257 	status_t error = B_OK;
258 	// get the parameters
259 	team_id team;
260 	BMessenger target;
261 	// TODO: This should be a "new (nothrow)", but R5's BMessage doesn't
262 	// define that version.
263 	BMessage *message = new BMessage;
264 	bigtime_t interval;
265 	int32 count;
266 	BMessenger replyTarget;
267 	if (error == B_OK && message == NULL)
268 		error = B_NO_MEMORY;
269 	if (error == B_OK && request->FindInt32("team", &team) != B_OK)
270 		error = B_BAD_VALUE;
271 	if (error == B_OK && request->FindMessenger("target", &target) != B_OK)
272 		error = B_BAD_VALUE;
273 	if (error == B_OK && request->FindMessage("message", message) != B_OK)
274 		error = B_BAD_VALUE;
275 	if (error == B_OK && request->FindInt64("interval", &interval) != B_OK)
276 		error = B_BAD_VALUE;
277 	if (error == B_OK && request->FindInt32("count", &count) != B_OK)
278 		error = B_BAD_VALUE;
279 	if (error == B_OK
280 		&& request->FindMessenger("reply_target", &replyTarget) != B_OK) {
281 		error = B_BAD_VALUE;
282 	}
283 	// check the parameters
284 	if (error == B_OK && count == 0)
285 		error = B_BAD_VALUE;
286 	// add a new runner info
287 	RunnerInfo *info = NULL;
288 	if (error == B_OK) {
289 		interval = max(interval, kMininalTimeInterval);
290 		info = new(nothrow) RunnerInfo(team, _NextToken(), target, message,
291 									   interval, count, replyTarget);
292 		if (info) {
293 			info->time = system_time();
294 			if (!_AddInfo(info))
295 				error = B_NO_MEMORY;
296 		} else
297 			error = B_NO_MEMORY;
298 	}
299 	// create a new event
300 	RunnerEvent *event = NULL;
301 	if (error == B_OK) {
302 		event = new(nothrow) RunnerEvent(this, info);
303 		if (event) {
304 			info->event = event;
305 			if (!_ScheduleEvent(info))
306 				error = B_NO_MEMORY;	// TODO: The only possible reason?
307 		} else
308 			error = B_NO_MEMORY;
309 	}
310 	// cleanup on error
311 	if (error != B_OK) {
312 		if (info) {
313 			_RemoveInfo(info);
314 			delete info;
315 		}
316 		delete message;
317 	}
318 	// reply to the request
319 	if (error == B_OK) {
320 		BMessage reply(B_REG_SUCCESS);
321 		reply.AddInt32("token", info->token);
322 		request->SendReply(&reply);
323 	} else {
324 		BMessage reply(B_REG_ERROR);
325 		reply.AddInt32("error", error);
326 		request->SendReply(&reply);
327 	}
328 
329 	FUNCTION_END();
330 }
331 
332 // HandleUnregisterRunner
333 /*!	\brief Handles an unregistration request (BMessageRunner destructor).
334 	\param request The request message.
335 */
336 void
337 MessageRunnerManager::HandleUnregisterRunner(BMessage *request)
338 {
339 	FUNCTION_START();
340 
341 	BAutolock _lock(fLock);
342 	status_t error = B_OK;
343 	// get the parameters
344 	int32 token;
345 	if (error == B_OK && request->FindInt32("token", &token) != B_OK)
346 		error = B_BAD_VALUE;
347 	// find and delete the runner info
348 	if (error == B_OK) {
349 		if (RunnerInfo *info = _InfoForToken(token))
350 			_DeleteInfo(info, false);
351 		else
352 			error = B_BAD_VALUE;
353 	}
354 	// reply to the request
355 	if (error == B_OK) {
356 		BMessage reply(B_REG_SUCCESS);
357 		request->SendReply(&reply);
358 	} else {
359 		BMessage reply(B_REG_ERROR);
360 		reply.AddInt32("error", error);
361 		request->SendReply(&reply);
362 	}
363 
364 	FUNCTION_END();
365 }
366 
367 // HandleSetRunnerParams
368 /*!	\brief Handles an parameter change request (BMessageRunner::SetParams()).
369 	\param request The request message.
370 */
371 void
372 MessageRunnerManager::HandleSetRunnerParams(BMessage *request)
373 {
374 	FUNCTION_START();
375 
376 	BAutolock _lock(fLock);
377 	status_t error = B_OK;
378 	// get the parameters
379 	int32 token;
380 	bigtime_t interval;
381 	int32 count;
382 	bool setInterval = false;
383 	bool setCount = false;
384 	if (error == B_OK && request->FindInt32("token", &token) != B_OK)
385 		error = B_BAD_VALUE;
386 	if (error == B_OK && request->FindInt64("interval", &interval) == B_OK)
387 		setInterval = true;
388 	if (error == B_OK && request->FindInt32("count", &count) == B_OK)
389 		setCount = true;
390 	// find the runner info
391 	RunnerInfo *info = NULL;
392 	if (error == B_OK) {
393 		info = _InfoForToken(token);
394 		if (!info)
395 			error = B_BAD_VALUE;
396 	}
397 	// set the new values
398 	if (error == B_OK) {
399 		bool eventRemoved = false;
400 		bool deleteInfo = false;
401 		// count
402 		if (setCount) {
403 			if (count == 0)
404 				deleteInfo = true;
405 			else
406 				info->count = count;
407 		}
408 		// interval
409 		if (setInterval) {
410 			eventRemoved = fEventQueue->RemoveEvent(info->event);
411 			if (!eventRemoved)
412 				info->rescheduled = true;
413 			interval = max(interval, kMininalTimeInterval);
414 			info->interval = interval;
415 			info->time = system_time();
416 			if (!_ScheduleEvent(info))
417 				error = B_NO_MEMORY;	// TODO: The only possible reason?
418 		}
419 		// remove and delete the info on error
420 		if (error != B_OK || deleteInfo)
421 			_DeleteInfo(info, eventRemoved);
422 	}
423 	// reply to the request
424 	if (error == B_OK) {
425 		BMessage reply(B_REG_SUCCESS);
426 		request->SendReply(&reply);
427 	} else {
428 		BMessage reply(B_REG_ERROR);
429 		reply.AddInt32("error", error);
430 		request->SendReply(&reply);
431 	}
432 
433 	FUNCTION_END();
434 }
435 
436 // HandleGetRunnerInfo
437 /*!	\brief Handles an get info request (BMessageRunner::GetInfo()).
438 	\param request The request message.
439 */
440 void
441 MessageRunnerManager::HandleGetRunnerInfo(BMessage *request)
442 {
443 	FUNCTION_START();
444 
445 	BAutolock _lock(fLock);
446 	status_t error = B_OK;
447 	// get the parameters
448 	int32 token;
449 	if (error == B_OK && request->FindInt32("token", &token) != B_OK)
450 		error = B_BAD_VALUE;
451 	// find the runner info
452 	RunnerInfo *info = NULL;
453 	if (error == B_OK) {
454 		info = _InfoForToken(token);
455 		if (!info)
456 			error = B_BAD_VALUE;
457 	}
458 	// reply to the request
459 	if (error == B_OK) {
460 		BMessage reply(B_REG_SUCCESS);
461 		reply.AddInt64("interval", info->interval);
462 		reply.AddInt32("count", info->count);
463 		request->SendReply(&reply);
464 	} else {
465 		BMessage reply(B_REG_ERROR);
466 		reply.AddInt32("error", error);
467 		request->SendReply(&reply);
468 	}
469 
470 	FUNCTION_END();
471 }
472 
473 // Lock
474 /*!	\brief Locks the manager.
475 	\return \c true, if locked successfully, \c false otherwise.
476 */
477 bool
478 MessageRunnerManager::Lock()
479 {
480 	return fLock.Lock();
481 }
482 
483 // Unlock
484 /*!	\brief Unlocks the manager.
485 */
486 void
487 MessageRunnerManager::Unlock()
488 {
489 	fLock.Unlock();
490 }
491 
492 // _AddInfo
493 /*!	\brief Adds a RunnerInfo to the list of RunnerInfos.
494 
495 	\note The manager must be locked.
496 
497 	\param info The RunnerInfo to be added.
498 	\return \c true, if added successfully, \c false otherwise.
499 */
500 bool
501 MessageRunnerManager::_AddInfo(RunnerInfo *info)
502 {
503 	return fRunnerInfos.AddItem(info);
504 }
505 
506 // _RemoveInfo
507 /*!	\brief Removes a RunnerInfo from the list of RunnerInfos.
508 
509 	\note The manager must be locked.
510 
511 	\param info The RunnerInfo to be removed.
512 	\return \c true, if removed successfully, \c false, if the list doesn't
513 			contain the supplied info.
514 */
515 bool
516 MessageRunnerManager::_RemoveInfo(RunnerInfo *info)
517 {
518 	return fRunnerInfos.RemoveItem(info);
519 }
520 
521 // _RemoveInfo
522 /*!	\brief Removes a RunnerInfo at a given index from the list of RunnerInfos.
523 
524 	\note The manager must be locked.
525 
526 	\param index The index of the RunnerInfo to be removed.
527 	\return \c true, if removed successfully, \c false, if the supplied index
528 			is out of range.
529 */
530 MessageRunnerManager::RunnerInfo*
531 MessageRunnerManager::_RemoveInfo(int32 index)
532 {
533 	return (RunnerInfo*)fRunnerInfos.RemoveItem(index);
534 }
535 
536 // _RemoveInfoWithToken
537 /*!	\brief Removes a RunnerInfo with a specified token from the list of
538 		   RunnerInfos.
539 
540 	\note The manager must be locked.
541 
542 	\param token The token identifying the RunnerInfo to be removed.
543 	\return \c true, if removed successfully, \c false, if the list doesn't
544 			contain an info with the supplied token.
545 */
546 MessageRunnerManager::RunnerInfo*
547 MessageRunnerManager::_RemoveInfoWithToken(int32 token)
548 {
549 	RunnerInfo *info = NULL;
550 	int32 index = _IndexOfToken(token);
551 	if (index >= 0)
552 		info = _RemoveInfo(index);
553 	return info;
554 }
555 
556 // _DeleteInfo
557 /*!	\brief Removes a RunnerInfo from the list of RunnerInfos and deletes it.
558 
559 	\note The manager must be locked.
560 
561 	\param index The index of the RunnerInfo to be deleted.
562 	\return \c true, if removed and deleted successfully, \c false, if the
563 			list doesn't contain the supplied info.
564 */
565 bool
566 MessageRunnerManager::_DeleteInfo(RunnerInfo *info, bool eventRemoved)
567 {
568 	bool result = _RemoveInfo(info);
569 	if (result) {
570 		// If the event is not in the event queue and has not been removed
571 		// just before, then it is in progress. It will delete itself.
572 		if (!eventRemoved && !fEventQueue->RemoveEvent(info->event))
573 			info->event = NULL;
574 		delete info;
575 	}
576 	return result;
577 }
578 
579 // _CountInfos
580 /*!	\brief Returns the number of RunnerInfos in the list of RunnerInfos.
581 
582 	\note The manager must be locked.
583 
584 	\return Returns the number of RunnerInfos in the list of RunnerInfos.
585 */
586 int32
587 MessageRunnerManager::_CountInfos() const
588 {
589 	return fRunnerInfos.CountItems();
590 }
591 
592 // _InfoAt
593 /*!	\brief Returns the RunnerInfo at the specified index in the list of
594 		   RunnerInfos.
595 
596 	\note The manager must be locked.
597 
598 	\param index The index of the RunnerInfo to be returned.
599 	\return The runner info at the specified index, or \c NULL, if the index
600 			is out of range.
601 */
602 MessageRunnerManager::RunnerInfo*
603 MessageRunnerManager::_InfoAt(int32 index) const
604 {
605 	return (RunnerInfo*)fRunnerInfos.ItemAt(index);
606 }
607 
608 // _InfoForToken
609 /*!	\brief Returns the RunnerInfo with the specified index.
610 
611 	\note The manager must be locked.
612 
613 	\param token The token identifying the RunnerInfo to be returned.
614 	\return The runner info at the specified index, or \c NULL, if the list
615 			doesn't contain an info with the specified token.
616 */
617 MessageRunnerManager::RunnerInfo*
618 MessageRunnerManager::_InfoForToken(int32 token) const
619 {
620 	return _InfoAt(_IndexOfToken(token));
621 }
622 
623 // _IndexOf
624 /*!	\brief Returns the index of the supplied RunnerInfo in the list of
625 		   RunnerInfos.
626 
627 	\note The manager must be locked.
628 
629 	\param info The RunnerInfo whose index shall be returned.
630 	\return The index of the supplied RunnerInfo, or -1, if the list doesn't
631 			contain the supplied info.
632 */
633 int32
634 MessageRunnerManager::_IndexOf(RunnerInfo *info) const
635 {
636 	return fRunnerInfos.IndexOf(info);
637 }
638 
639 // _IndexOfToken
640 /*!	\brief Returns the index of the RunnerInfo identified by the supplied
641 		   token in the list of RunnerInfos.
642 
643 	\note The manager must be locked.
644 
645 	\param token The token identifying the RunnerInfo whose index shall be
646 		   returned.
647 	\return The index of the requested RunnerInfo, or -1, if the list doesn't
648 			contain an info with the supplied token.
649 */
650 int32
651 MessageRunnerManager::_IndexOfToken(int32 token) const
652 {
653 	for (int32 i = 0; RunnerInfo *info = _InfoAt(i); i++) {
654 		if (info->token == token)
655 			return i;
656 	}
657 	return -1;
658 }
659 
660 // _DoEvent
661 /*!	\brief Invoked when a message runner's event is executed.
662 
663 	If the message runner info is still valid and the event was not just
664 	rescheduled, the message is delivered to the message runner's target
665 	and the event is rescheduled.
666 
667 	\param info The message runner's info.
668 	\return \c true, if the event object shall be deleted, \c false otherwise.
669 */
670 bool
671 MessageRunnerManager::_DoEvent(RunnerInfo *info)
672 {
673 	FUNCTION_START();
674 
675 	BAutolock _lock(fLock);
676 	bool deleteEvent = false;
677 	// first check whether the info does still exist
678 	if (_lock.IsLocked() && _IndexOf(info) >= 0) {
679 		// If the event has been rescheduled after being removed from the
680 		// queue for execution, it needs to be ignored. This may happen, when
681 		// the interval is modified.
682 		if (info->rescheduled)
683 			info->rescheduled = false;
684 		else {
685 			// send the message
686 			bool success = (info->DeliverMessage() == B_OK);
687 			// reschedule the event
688 			if (success)
689 				success = _ScheduleEvent(info);
690 			// clean up, if the message delivery of the rescheduling failed
691 			if (!success) {
692 				deleteEvent = true;
693 				info->event = NULL;
694 				_RemoveInfo(info);
695 				delete info;
696 			}
697 		}
698 	} else {
699 		// The info is no more. That means it had been removed after the
700 		// event was removed from the event queue, but before we could acquire
701 		// the lock. Simply delete the event.
702 		deleteEvent = true;
703 	}
704 
705 	FUNCTION_END();
706 
707 	return deleteEvent;
708 }
709 
710 // _ScheduleEvent
711 /*!	\brief Schedules the event for a message runner for the next time a
712 		   message has to be sent.
713 
714 	\note The manager must be locked.
715 
716 	\param info The message runner's info.
717 	\return \c true, if the event successfully been rescheduled, \c false,
718 			if either all messages have already been sent or the event queue
719 			doesn't allow adding the event (e.g. due to insufficient memory).
720 */
721 bool
722 MessageRunnerManager::_ScheduleEvent(RunnerInfo *info)
723 {
724 	bool scheduled = false;
725 	// calculate next event time
726 	if (info->count != 0) {
727 		// avoid a bigtime_t overflow
728 		if (LONGLONG_MAX - info->interval < info->time)
729 			info->time = LONGLONG_MAX;
730 		else
731 			info->time += info->interval;
732 		info->event->SetTime(info->time);
733 		scheduled = fEventQueue->AddEvent(info->event);
734 PRINT(("runner %ld (%lld, %ld) rescheduled: %d, time: %lld, now: %lld\n",
735 info->token, info->interval, info->count, scheduled, info->time, system_time()));
736 	}
737 	return scheduled;
738 }
739 
740 // _NextToken
741 /*!	\brief Returns a new unused message runner token.
742 
743 	\note The manager must be locked.
744 
745 	\return A new unused message runner token.
746 */
747 int32
748 MessageRunnerManager::_NextToken()
749 {
750 	return fNextToken++;
751 }
752 
753