vfs: check userland buffers before reading them.
[haiku.git] / src / servers / registrar / MessageRunnerManager.cpp
blob2df05d914dc7881e169c19f80d7cf3af1a87a70e
1 /*
2 * Copyright 2001-2006, Haiku, Inc. All Rights Reserved.
3 * Distributed under the terms of the MIT License.
5 * Authors:
6 * Ingo Weinhold (bonefish@users.sf.net)
7 */
10 #include <algorithm>
11 #include <new>
13 #include <Autolock.h>
14 #include <Message.h>
15 #include <MessagePrivate.h>
16 #include <Messenger.h>
17 #include <OS.h>
18 #include <RegistrarDefs.h>
20 #include "Debug.h"
21 #include "Event.h"
22 #include "EventQueue.h"
23 #include "MessageDeliverer.h"
24 #include "MessageRunnerManager.h"
26 using std::max;
27 using std::nothrow;
29 /*! \class MessageRunnerManager
30 \brief Manages the registrar side "shadows" of BMessageRunners.
32 The class features four methods to which the registrar application
33 dispatches the message runner specific request messages.
35 Each active message runner (i.e. one that still has messages to be sent)
36 is represented by a RunnerInfo that comprises all necessary information,
37 among these a RunnerEvent added to the event queue. When the event is
38 executed, it calls the _DoEvent() method, which in turn sends the message
39 runner message to the respective target and schedules the event for the
40 next time the message has to be sent (_ScheduleEvent()).
42 A couple of helper methods provide convenient access to the RunnerInfo
43 list (\a fRunnerInfos). A BLocker (\a fLock) and respective locking
44 methods are used to serialize the access to the member variables.
47 /*! \var BList MessageRunnerManager::fRunnerInfos
48 \brief The list of RunnerInfos.
51 /*! \var BLocker MessageRunnerManager::fLock
52 \brief A locker used to serialize the access to the object's variable
53 members.
56 /*! \var EventQueue *MessageRunnerManager::fEventQueue
57 \brief Event queue used by the manager.
60 /*! \var int32 MessageRunnerManager::fNextToken
61 \brief Next unused token for message runners.
65 using namespace BPrivate;
67 //! The minimal time interval for message runners (50 ms).
68 static const bigtime_t kMininalTimeInterval = 50000LL;
71 static bigtime_t
72 add_time(bigtime_t a, bigtime_t b)
74 // avoid a bigtime_t overflow
75 if (LONGLONG_MAX - b < a)
76 return LONGLONG_MAX;
77 else
78 return a + b;
82 // RunnerEvent
83 /*! \brief Event class used to by the message runner manager.
85 For each active message runner such an event is used. It invokes
86 MessageRunnerManager::_DoEvent() on execution.
88 class MessageRunnerManager::RunnerEvent : public Event {
89 public:
90 /*! \brief Creates a new RunnerEvent.
91 \param manager The message runner manager.
92 \param info The RunnerInfo for the message runner.
94 RunnerEvent(MessageRunnerManager *manager, RunnerInfo *info)
95 : Event(false),
96 fManager(manager),
97 fInfo(info)
101 /*! \brief Hook method invoked when the event is executed.
103 Implements Event. Calls MessageRunnerManager::_DoEvent().
105 \param queue The event queue executing the event.
106 \return \c true, if the object shall be deleted, \c false otherwise.
108 virtual bool Do(EventQueue *queue)
110 return fManager->_DoEvent(fInfo);
113 private:
114 MessageRunnerManager *fManager; //!< The message runner manager.
115 RunnerInfo *fInfo; //!< The message runner info.
119 // RunnerInfo
120 /*! \brief Contains all needed information about an active message runner.
122 struct MessageRunnerManager::RunnerInfo {
123 /*! \brief Creates a new RunnerInfo.
124 \param team The team owning the message runner.
125 \param token The unique token associated with the message runner.
126 \param target The target the message shall be sent to.
127 \param message The message to be sent to the target.
128 \param interval The message runner's time interval.
129 \param count The number of times the message shall be sent.
130 \param replyTarget The reply target for the delivered message.
132 RunnerInfo(team_id team, int32 token, BMessenger target, BMessage *message,
133 bigtime_t interval, int32 count, BMessenger replyTarget)
134 : team(team),
135 token(token),
136 target(target),
137 message(message),
138 interval(interval),
139 count(count),
140 replyTarget(replyTarget),
141 time(0),
142 event(NULL),
143 rescheduled(false)
147 /*! \brief Frees all resources associated with the object.
149 The message and the event are delete.
151 ~RunnerInfo()
153 delete message;
154 delete event;
157 /*! \brief Delivers the message to the respective target.
158 \return \c B_OK, if the message has successfully been delivered or
159 the target does still exist and its message port is full,
160 an error code otherwise.
162 status_t DeliverMessage()
164 if (count > 0)
165 count--;
167 // set the reply target
168 BMessage::Private(message).SetReply(replyTarget);
170 // deliver the message: We use the MessageDeliverer to allow the
171 // message to be delivered, even if the target port is temporarily
172 // full. For periodic message runners, that have to deliver further
173 // messages, we restrict the delivery timeout to the message interval.
174 status_t error;
175 if (count > 0) {
176 error = MessageDeliverer::Default()->DeliverMessage(message, target,
177 interval);
178 } else {
179 error = MessageDeliverer::Default()->DeliverMessage(message,
180 target);
183 // B_WOULD_BLOCK is as good as B_OK. We return an error only, if
184 // there are serious problems with the target, i.e. if it doesn't
185 // exist anymore for instance. A full message port is harmless.
186 if (error == B_WOULD_BLOCK)
187 error = B_OK;
188 return error;
191 team_id team; //!< The team owning the message runner.
192 int32 token; /*!< The unique token associated with the
193 message runner. */
194 BMessenger target; //!< The target the message shall be sent to.
195 BMessage *message; //!< The message to be sent to the target.
196 bigtime_t interval; //!< The message runner's time interval.
197 int32 count; /*!< The number of times the message shall be
198 sent. */
199 BMessenger replyTarget; /*!< The reply target for the delivered
200 message. */
201 bigtime_t time; /*!< Time at which the next message will be
202 sent. */
203 RunnerEvent *event; //!< Runner event for the message runner.
204 bool rescheduled; /*!< Set to \c true when the event has been
205 started to be executed while it was
206 rescheduled. */
210 // constructor
211 /*! \brief Creates a new MessageRunnerManager.
212 \param eventQueue The EventQueue the manager shall use.
214 MessageRunnerManager::MessageRunnerManager(EventQueue *eventQueue)
215 : fRunnerInfos(),
216 fLock(),
217 fEventQueue(eventQueue),
218 fNextToken(0)
222 // destructor
223 /*! \brief Frees all resources associated with the object.
225 The manager's event queue must already have been stopped
226 (EventQueue::Die()).
228 MessageRunnerManager::~MessageRunnerManager()
230 // The event queue should already be stopped, but must still exist.
231 // If it is still running and an event gets executed after we've locked
232 // ourselves, then it will access an already deleted manager.
233 BAutolock _lock(fLock);
234 for (int32 i = 0; RunnerInfo *info = _InfoAt(i); i++) {
235 if (!fEventQueue->RemoveEvent(info->event))
236 info->event = NULL;
237 delete info;
239 fRunnerInfos.MakeEmpty();
242 // HandleRegisterRunner
243 /*! \brief Handles a registration request (BMessageRunner::InitData()).
244 \param request The request message.
246 void
247 MessageRunnerManager::HandleRegisterRunner(BMessage *request)
249 FUNCTION_START();
251 BAutolock _lock(fLock);
252 status_t error = B_OK;
253 // get the parameters
254 team_id team;
255 BMessenger target;
256 // TODO: This should be a "new (nothrow)", but R5's BMessage doesn't
257 // define that version.
258 BMessage *message = new BMessage;
259 bigtime_t interval;
260 int32 count;
261 BMessenger replyTarget;
262 if (error == B_OK && message == NULL)
263 error = B_NO_MEMORY;
264 if (error == B_OK && request->FindInt32("team", &team) != B_OK)
265 error = B_BAD_VALUE;
266 if (error == B_OK && request->FindMessenger("target", &target) != B_OK)
267 error = B_BAD_VALUE;
268 if (error == B_OK && request->FindMessage("message", message) != B_OK)
269 error = B_BAD_VALUE;
270 if (error == B_OK && request->FindInt64("interval", &interval) != B_OK)
271 error = B_BAD_VALUE;
272 if (error == B_OK && request->FindInt32("count", &count) != B_OK)
273 error = B_BAD_VALUE;
274 if (error == B_OK
275 && request->FindMessenger("reply_target", &replyTarget) != B_OK) {
276 error = B_BAD_VALUE;
279 // check the parameters
280 if (error == B_OK && count == 0)
281 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;
297 // create a new event
298 RunnerEvent *event = NULL;
299 if (error == B_OK) {
300 event = new(nothrow) RunnerEvent(this, info);
301 if (event) {
302 info->event = event;
303 if (!_ScheduleEvent(info))
304 error = B_NO_MEMORY; // TODO: The only possible reason?
305 } else
306 error = B_NO_MEMORY;
309 // cleanup on error
310 if (error != B_OK) {
311 if (info) {
312 _RemoveInfo(info);
313 delete info;
315 delete message;
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);
329 FUNCTION_END();
332 // HandleUnregisterRunner
333 /*! \brief Handles an unregistration request (BMessageRunner destructor).
334 \param request The request message.
336 void
337 MessageRunnerManager::HandleUnregisterRunner(BMessage *request)
339 FUNCTION_START();
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;
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);
364 FUNCTION_END();
367 // HandleSetRunnerParams
368 /*! \brief Handles an parameter change request (BMessageRunner::SetParams()).
369 \param request The request message.
371 void
372 MessageRunnerManager::HandleSetRunnerParams(BMessage *request)
374 FUNCTION_START();
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;
391 // find the runner info
392 RunnerInfo *info = NULL;
393 if (error == B_OK) {
394 info = _InfoForToken(token);
395 if (!info) {
396 // TODO: At this point, the runner could have been deleted already.
397 // Since setting its parameters at this point should still be
398 // valid, we'd have to recreate it.
399 // (Even though the documentation in *our* BMessageRunner
400 // implementation specifically denies the possibility of setting
401 // the runner's parameters at this point, it would still be nice
402 // to allow this.)
403 error = B_BAD_VALUE;
407 // set the new values
408 if (error == B_OK) {
409 bool eventRemoved = false;
410 bool deleteInfo = false;
411 // count
412 if (setCount) {
413 if (count == 0)
414 deleteInfo = true;
415 else
416 info->count = count;
418 // interval
419 if (setInterval) {
420 eventRemoved = fEventQueue->RemoveEvent(info->event);
421 if (!eventRemoved)
422 info->rescheduled = true;
423 interval = max(interval, kMininalTimeInterval);
424 info->interval = interval;
425 info->time = system_time();
426 if (!_ScheduleEvent(info))
427 error = B_NO_MEMORY; // TODO: The only possible reason?
429 // remove and delete the info on error
430 if (error != B_OK || deleteInfo)
431 _DeleteInfo(info, eventRemoved);
434 // reply to the request
435 if (error == B_OK) {
436 BMessage reply(B_REG_SUCCESS);
437 request->SendReply(&reply);
438 } else {
439 BMessage reply(B_REG_ERROR);
440 reply.AddInt32("error", error);
441 request->SendReply(&reply);
444 FUNCTION_END();
447 // HandleGetRunnerInfo
448 /*! \brief Handles an get info request (BMessageRunner::GetInfo()).
449 \param request The request message.
451 void
452 MessageRunnerManager::HandleGetRunnerInfo(BMessage *request)
454 FUNCTION_START();
456 BAutolock _lock(fLock);
457 status_t error = B_OK;
458 // get the parameters
459 int32 token;
460 if (error == B_OK && request->FindInt32("token", &token) != B_OK)
461 error = B_BAD_VALUE;
462 // find the runner info
463 RunnerInfo *info = NULL;
464 if (error == B_OK) {
465 info = _InfoForToken(token);
466 if (!info)
467 error = B_BAD_VALUE;
469 // reply to the request
470 if (error == B_OK) {
471 BMessage reply(B_REG_SUCCESS);
472 reply.AddInt64("interval", info->interval);
473 reply.AddInt32("count", info->count);
474 request->SendReply(&reply);
475 } else {
476 BMessage reply(B_REG_ERROR);
477 reply.AddInt32("error", error);
478 request->SendReply(&reply);
481 FUNCTION_END();
484 // Lock
485 /*! \brief Locks the manager.
486 \return \c true, if locked successfully, \c false otherwise.
488 bool
489 MessageRunnerManager::Lock()
491 return fLock.Lock();
494 // Unlock
495 /*! \brief Unlocks the manager.
497 void
498 MessageRunnerManager::Unlock()
500 fLock.Unlock();
503 // _AddInfo
504 /*! \brief Adds a RunnerInfo to the list of RunnerInfos.
506 \note The manager must be locked.
508 \param info The RunnerInfo to be added.
509 \return \c true, if added successfully, \c false otherwise.
511 bool
512 MessageRunnerManager::_AddInfo(RunnerInfo *info)
514 return fRunnerInfos.AddItem(info);
517 // _RemoveInfo
518 /*! \brief Removes a RunnerInfo from the list of RunnerInfos.
520 \note The manager must be locked.
522 \param info The RunnerInfo to be removed.
523 \return \c true, if removed successfully, \c false, if the list doesn't
524 contain the supplied info.
526 bool
527 MessageRunnerManager::_RemoveInfo(RunnerInfo *info)
529 return fRunnerInfos.RemoveItem(info);
532 // _RemoveInfo
533 /*! \brief Removes a RunnerInfo at a given index from the list of RunnerInfos.
535 \note The manager must be locked.
537 \param index The index of the RunnerInfo to be removed.
538 \return \c true, if removed successfully, \c false, if the supplied index
539 is out of range.
541 MessageRunnerManager::RunnerInfo*
542 MessageRunnerManager::_RemoveInfo(int32 index)
544 return (RunnerInfo*)fRunnerInfos.RemoveItem(index);
547 // _RemoveInfoWithToken
548 /*! \brief Removes a RunnerInfo with a specified token from the list of
549 RunnerInfos.
551 \note The manager must be locked.
553 \param token The token identifying the RunnerInfo to be removed.
554 \return \c true, if removed successfully, \c false, if the list doesn't
555 contain an info with the supplied token.
557 MessageRunnerManager::RunnerInfo*
558 MessageRunnerManager::_RemoveInfoWithToken(int32 token)
560 RunnerInfo *info = NULL;
561 int32 index = _IndexOfToken(token);
562 if (index >= 0)
563 info = _RemoveInfo(index);
564 return info;
567 // _DeleteInfo
568 /*! \brief Removes a RunnerInfo from the list of RunnerInfos and deletes it.
570 \note The manager must be locked.
572 \param index The index of the RunnerInfo to be deleted.
573 \return \c true, if removed and deleted successfully, \c false, if the
574 list doesn't contain the supplied info.
576 bool
577 MessageRunnerManager::_DeleteInfo(RunnerInfo *info, bool eventRemoved)
579 bool result = _RemoveInfo(info);
580 if (result) {
581 // If the event is not in the event queue and has not been removed
582 // just before, then it is in progress. It will delete itself.
583 if (!eventRemoved && !fEventQueue->RemoveEvent(info->event))
584 info->event = NULL;
585 delete info;
587 return result;
590 // _CountInfos
591 /*! \brief Returns the number of RunnerInfos in the list of RunnerInfos.
593 \note The manager must be locked.
595 \return Returns the number of RunnerInfos in the list of RunnerInfos.
597 int32
598 MessageRunnerManager::_CountInfos() const
600 return fRunnerInfos.CountItems();
603 // _InfoAt
604 /*! \brief Returns the RunnerInfo at the specified index in the list of
605 RunnerInfos.
607 \note The manager must be locked.
609 \param index The index of the RunnerInfo to be returned.
610 \return The runner info at the specified index, or \c NULL, if the index
611 is out of range.
613 MessageRunnerManager::RunnerInfo*
614 MessageRunnerManager::_InfoAt(int32 index) const
616 return (RunnerInfo*)fRunnerInfos.ItemAt(index);
619 // _InfoForToken
620 /*! \brief Returns the RunnerInfo with the specified index.
622 \note The manager must be locked.
624 \param token The token identifying the RunnerInfo to be returned.
625 \return The runner info at the specified index, or \c NULL, if the list
626 doesn't contain an info with the specified token.
628 MessageRunnerManager::RunnerInfo*
629 MessageRunnerManager::_InfoForToken(int32 token) const
631 return _InfoAt(_IndexOfToken(token));
634 // _IndexOf
635 /*! \brief Returns the index of the supplied RunnerInfo in the list of
636 RunnerInfos.
638 \note The manager must be locked.
640 \param info The RunnerInfo whose index shall be returned.
641 \return The index of the supplied RunnerInfo, or -1, if the list doesn't
642 contain the supplied info.
644 int32
645 MessageRunnerManager::_IndexOf(RunnerInfo *info) const
647 return fRunnerInfos.IndexOf(info);
650 // _IndexOfToken
651 /*! \brief Returns the index of the RunnerInfo identified by the supplied
652 token in the list of RunnerInfos.
654 \note The manager must be locked.
656 \param token The token identifying the RunnerInfo whose index shall be
657 returned.
658 \return The index of the requested RunnerInfo, or -1, if the list doesn't
659 contain an info with the supplied token.
661 int32
662 MessageRunnerManager::_IndexOfToken(int32 token) const
664 for (int32 i = 0; RunnerInfo *info = _InfoAt(i); i++) {
665 if (info->token == token)
666 return i;
668 return -1;
671 // _DoEvent
672 /*! \brief Invoked when a message runner's event is executed.
674 If the message runner info is still valid and the event was not just
675 rescheduled, the message is delivered to the message runner's target
676 and the event is rescheduled.
678 \param info The message runner's info.
679 \return \c true, if the event object shall be deleted, \c false otherwise.
681 bool
682 MessageRunnerManager::_DoEvent(RunnerInfo *info)
684 FUNCTION_START();
686 BAutolock _lock(fLock);
687 bool deleteEvent = false;
688 // first check whether the info does still exist
689 if (_lock.IsLocked() && _IndexOf(info) >= 0) {
690 // If the event has been rescheduled after being removed from the
691 // queue for execution, it needs to be ignored. This may happen, when
692 // the interval is modified.
693 if (info->rescheduled)
694 info->rescheduled = false;
695 else {
696 // send the message
697 bool success = (info->DeliverMessage() == B_OK);
698 // reschedule the event
699 if (success)
700 success = _ScheduleEvent(info);
702 // clean up, if the message delivery of the rescheduling failed
703 // (or the runner had already fulfilled its job)
704 if (!success) {
705 deleteEvent = true;
706 info->event = NULL;
707 _RemoveInfo(info);
708 delete info;
711 } else {
712 // The info is no more. That means it had been removed after the
713 // event was removed from the event queue, but before we could acquire
714 // the lock. Simply delete the event.
715 deleteEvent = true;
718 FUNCTION_END();
720 return deleteEvent;
723 // _ScheduleEvent
724 /*! \brief Schedules the event for a message runner for the next time a
725 message has to be sent.
727 \note The manager must be locked.
729 \param info The message runner's info.
730 \return \c true, if the event successfully been rescheduled, \c false,
731 if either all messages have already been sent or the event queue
732 doesn't allow adding the event (e.g. due to insufficient memory).
734 bool
735 MessageRunnerManager::_ScheduleEvent(RunnerInfo *info)
737 bool scheduled = false;
738 // calculate next event time
739 if (info->count != 0) {
740 info->time = add_time(info->time, info->interval);
742 // For runners without a count limit, we skip messages, if we're already
743 // late.
744 bigtime_t now = system_time();
745 if (info->time < now && info->count < 0) {
746 // keep the remainder modulo interval
747 info->time = add_time(now,
748 info->interval - (now - info->time) % info->interval);
751 info->event->SetTime(info->time);
752 scheduled = fEventQueue->AddEvent(info->event);
754 PRINT("runner %" B_PRId32 " (%" B_PRId64 ", %" B_PRId32 ") rescheduled: %d, "
755 "time: %" B_PRId64 ", now: %" B_PRId64 "\n", info->token, info->interval,
756 info->count, scheduled, info->time, system_time());
758 return scheduled;
761 // _NextToken
762 /*! \brief Returns a new unused message runner token.
764 \note The manager must be locked.
766 \return A new unused message runner token.
768 int32
769 MessageRunnerManager::_NextToken()
771 return fNextToken++;