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