Implemented direct message passing for local targets; this fixes a deadlock

with PostMessage() in case the message queue is full.
Some notes:
* for synchronous replies, we don't use this mechanism yet, but it could be
  extended to do that as well.
* the code looks so complicated because we need a way to access the looper's
  queue without locking it (to prevent deadlocks); like Dano's solution, I've
  abused BTokenSpace to store a BDirectMessageTarget with a BHandler.
* we also need to decouple the lifetime of a looper's queue from its target,
  as we cannot lock the looper, and therefore, can't guarantee it stays valid
  as long as we're accessing it outside of BLooper.
* init_clipboard() now needs to be done after the global constructors have
  been called - since sending messages now needs gDefaultTokens to be initialized.
  Since this is done per image, it shouldn't cause any troubles, though.
* some minor cleanup, removed unused _msg_cache_cleanup_() and friends.


git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@19968 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
Axel Dörfler
2007-01-26 13:59:56 +00:00
parent caa76e0da1
commit 9dbe170a69
14 changed files with 264 additions and 65 deletions
+49 -12
View File
@@ -1,5 +1,5 @@
/*
* Copyright 2005-2006, Haiku Inc. All rights reserved.
* Copyright 2005-2007, Haiku Inc. All rights reserved.
* Distributed under the terms of the MIT License.
*
* Authors:
@@ -14,18 +14,21 @@
#include <MessagePrivate.h>
#include <MessageUtils.h>
#include <DirectMessageTarget.h>
#include <MessengerPrivate.h>
#include <TokenSpace.h>
#include <util/KMessage.h>
#include <Application.h>
#include <AppMisc.h>
#include <BlockCache.h>
#include <Entry.h>
#include <MessageQueue.h>
#include <Messenger.h>
#include <MessengerPrivate.h>
#include <Path.h>
#include <Point.h>
#include <Rect.h>
#include <String.h>
#include <TokenSpace.h>
#include <util/KMessage.h>
#include <ctype.h>
#include <malloc.h>
@@ -1837,8 +1840,8 @@ BMessage::_StaticGetCachedReplyPort()
status_t
BMessage::_SendMessage(port_id port, int32 token, bigtime_t timeout,
bool replyRequired, BMessenger &replyTo) const
BMessage::_SendMessage(port_id port, team_id portOwner, int32 token,
bigtime_t timeout, bool replyRequired, BMessenger &replyTo) const
{
DEBUG_FUNCTION_ENTER;
ssize_t size = 0;
@@ -1846,7 +1849,24 @@ BMessage::_SendMessage(port_id port, int32 token, bigtime_t timeout,
message_header *header = NULL;
status_t result;
if (/*fHeader->fields_size + fHeader->data_size > B_PAGE_SIZE*/false) {
BPrivate::BDirectMessageTarget* direct = NULL;
BMessage* copy = NULL;
if (portOwner == BPrivate::current_team())
BPrivate::gDefaultTokens.AcquireHandlerTarget(token, &direct);
if (direct != NULL) {
// We have a direct local message target - we can just enqueue the message
// in its message queue. This will also prevent possible deadlocks when the
// queue is full.
copy = new BMessage(*this);
if (copy != NULL) {
header = copy->fHeader;
result = B_OK;
} else {
direct->Release();
result = B_NO_MEMORY;
}
} else if (/*fHeader->fields_size + fHeader->data_size > B_PAGE_SIZE*/false) {
result = _FlattenToArea(&header);
buffer = (char *)header;
size = sizeof(message_header);
@@ -1892,10 +1912,22 @@ BMessage::_SendMessage(port_id port, int32 token, bigtime_t timeout,
header->reply_target = replyToPrivate.Token();
header->flags |= MESSAGE_FLAG_WAS_DELIVERED;
do {
result = write_port_etc(port, kPortMessageCode, (void *)buffer, size,
B_RELATIVE_TIMEOUT, timeout);
} while (result == B_INTERRUPTED);
if (direct != NULL) {
// this is a local message transmission
direct->AddMessage(copy);
if (direct->Queue()->IsNextMessage(copy) && port_count(port) <= 0) {
// there is currently no message waiting, and we need to wakeup the looper
write_port_etc(port, 0, NULL, 0, B_RELATIVE_TIMEOUT, 0);
}
direct->Release();
} else {
do {
result = write_port_etc(port, kPortMessageCode, (void *)buffer, size,
B_RELATIVE_TIMEOUT, timeout);
} while (result == B_INTERRUPTED);
}
if (result == B_OK && IsSourceWaiting()) {
// the forwarded message will handle the reply - we must not do
@@ -1908,6 +1940,9 @@ BMessage::_SendMessage(port_id port, int32 token, bigtime_t timeout,
}
/*!
Sends a message and waits synchronously for a reply.
*/
status_t
BMessage::_SendMessage(port_id port, team_id portOwner, int32 token,
BMessage *reply, bigtime_t sendTimeout, bigtime_t replyTimeout) const
@@ -1961,7 +1996,9 @@ BMessage::_SendMessage(port_id port, team_id portOwner, int32 token,
BMessenger replyTarget;
BMessenger::Private(replyTarget).SetTo(team, replyPort,
B_PREFERRED_TOKEN);
result = _SendMessage(port, token, sendTimeout, true, replyTarget);
// TODO: replying could also use a BDirectMessageTarget like mechanism for local targets
result = _SendMessage(port, -1, token, sendTimeout, true,
replyTarget);
}
if (result < B_OK)