Rewrite and activate message passing by area. Passing by area works now with

the new sematic of transfer_area so a message area is transfered into the right
teams' address space and it does not need to be cloned there anymore. Passing
by area is only used for messages bigger than a certain size (currently
hardcoded to 40KB) which should be somehow bound to the max port message size.
This makes passing large messages (i.e. > the port limit) possible, so for
example copy&paste of long text, image data, etc. should now work.
Got rid of the fClonedArea member as it is not necessary with the new design,
renamed shared_area to message_area in the private message_header, avoid
an unnecessary allocation of the header for the copy constructors, check
allocations in a few more places and some minor cleanup.

git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@24321 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
Michael Lotz
2008-03-09 13:35:41 +00:00
parent d1189f0b05
commit a433b9febf
3 changed files with 118 additions and 70 deletions
+2 -3
View File
@@ -257,7 +257,7 @@ class BMessage {
friend class Private;
friend class BMessageQueue;
status_t _InitCommon();
status_t _InitCommon(bool initHeader);
status_t _InitHeader();
status_t _Clear();
@@ -284,14 +284,13 @@ class BMessage {
message_header* fHeader;
field_header* fFields;
uint8* fData;
area_id fClonedArea;
mutable BMessage* fOriginal;
BMessage* fQueueLink;
// fQueueLink is used by BMessageQueue to build a linked list
uint32 fReserved[10];
uint32 fReserved[11];
// deprecated
BMessage(BMessage *message);
+1 -1
View File
@@ -68,7 +68,7 @@ struct BMessage::message_header {
int32 target;
int32 current_specifier;
area_id shared_area;
area_id message_area;
// reply info
port_id reply_port;
+115 -66
View File
@@ -100,6 +100,9 @@ handle_reply(port_id replyPort, int32 *_code, bigtime_t timeout,
status_t result;
char *buffer = (char *)malloc(size);
if (buffer == NULL)
return B_NO_MEMORY;
do {
result = read_port(replyPort, _code, buffer, size);
} while (result == B_INTERRUPTED);
@@ -121,14 +124,14 @@ handle_reply(port_id replyPort, int32 *_code, bigtime_t timeout,
BMessage::BMessage()
{
DEBUG_FUNCTION_ENTER;
_InitCommon();
_InitCommon(true);
}
BMessage::BMessage(BMessage *other)
{
DEBUG_FUNCTION_ENTER;
_InitCommon();
_InitCommon(false);
*this = *other;
}
@@ -136,7 +139,7 @@ BMessage::BMessage(BMessage *other)
BMessage::BMessage(uint32 _what)
{
DEBUG_FUNCTION_ENTER;
_InitCommon();
_InitCommon(true);
fHeader->what = what = _what;
}
@@ -144,7 +147,7 @@ BMessage::BMessage(uint32 _what)
BMessage::BMessage(const BMessage &other)
{
DEBUG_FUNCTION_ENTER;
_InitCommon();
_InitCommon(false);
*this = other;
}
@@ -152,7 +155,6 @@ BMessage::BMessage(const BMessage &other)
BMessage::~BMessage()
{
DEBUG_FUNCTION_ENTER;
_Clear();
}
@@ -184,7 +186,7 @@ BMessage::operator=(const BMessage &other)
memcpy(fData, other.fData, fHeader->data_size);
}
fHeader->shared_area = -1;
fHeader->message_area = -1;
fHeader->fields_available = 0;
fHeader->data_available = 0;
fHeader->what = what = other.what;
@@ -219,7 +221,7 @@ BMessage::operator delete(void *pointer, size_t size)
status_t
BMessage::_InitCommon()
BMessage::_InitCommon(bool initHeader)
{
DEBUG_FUNCTION_ENTER;
what = 0;
@@ -228,12 +230,14 @@ BMessage::_InitCommon()
fFields = NULL;
fData = NULL;
fClonedArea = -1;
fOriginal = NULL;
fQueueLink = NULL;
return _InitHeader();
if (initHeader)
return _InitHeader();
fHeader = NULL;
return B_OK;
}
@@ -248,7 +252,7 @@ BMessage::_InitHeader()
fHeader->flags = MESSAGE_FLAG_VALID;
fHeader->what = what;
fHeader->current_specifier = -1;
fHeader->shared_area = -1;
fHeader->message_area = -1;
fHeader->target = B_NULL_TOKEN;
fHeader->reply_target = B_NULL_TOKEN;
@@ -266,17 +270,20 @@ status_t
BMessage::_Clear()
{
DEBUG_FUNCTION_ENTER;
// We're going to destroy all information of this message. If there's
// still someone waiting for a reply to this message, we have to send
// one now.
if (IsSourceWaiting())
SendReply(B_NO_REPLY);
if (fHeader) {
// We're going to destroy all information of this message. If there's
// still someone waiting for a reply to this message, we have to send
// one now.
if (IsSourceWaiting())
SendReply(B_NO_REPLY);
if (fClonedArea >= B_OK)
_Dereference();
if (fHeader->message_area >= 0)
_Dereference();
free(fHeader);
fHeader = NULL;
}
free(fHeader);
fHeader = NULL;
free(fFields);
fFields = NULL;
free(fData);
@@ -561,7 +568,7 @@ BMessage::Rename(const char *oldEntry, const char *newEntry)
if (!oldEntry || !newEntry)
return B_BAD_VALUE;
if (fClonedArea >= B_OK)
if (fHeader->message_area >= 0)
_CopyForWrite();
uint32 hash = _HashName(oldEntry) % fHeader->hash_table_size;
@@ -926,6 +933,9 @@ BMessage::_FlattenToArea(message_header **_header) const
{
DEBUG_FUNCTION_ENTER;
message_header *header = (message_header *)malloc(sizeof(message_header));
if (header == NULL)
return B_NO_MEMORY;
memcpy(header, fHeader, sizeof(message_header));
header->what = what;
@@ -934,7 +944,7 @@ BMessage::_FlattenToArea(message_header **_header) const
header->flags |= MESSAGE_FLAG_PASS_BY_AREA;
*_header = header;
if (header->shared_area >= B_OK)
if (header->message_area >= 0)
return B_OK;
if (header->fields_size == 0 && header->data_size == 0)
@@ -943,7 +953,7 @@ BMessage::_FlattenToArea(message_header **_header) const
uint8 *address = NULL;
ssize_t size = header->fields_size + header->data_size;
size = (size + B_PAGE_SIZE) & ~(B_PAGE_SIZE - 1);
area_id area = create_area("Shared BMessage data", (void **)&address,
area_id area = create_area("BMessage data", (void **)&address,
B_ANY_ADDRESS, size, B_NO_LOCK, B_READ_AREA | B_WRITE_AREA);
if (area < B_OK) {
@@ -963,7 +973,7 @@ BMessage::_FlattenToArea(message_header **_header) const
header->data_checksum = BPrivate::CalculateChecksum((uint8 *)address, header->data_size);
}
header->shared_area = area;
header->message_area = area;
return B_OK;
}
@@ -979,25 +989,37 @@ BMessage::_Reference(message_header *header)
if (fHeader->fields_size == 0 && header->data_size == 0)
return B_OK;
area_info areaInfo;
status_t result = get_area_info(fHeader->message_area, &areaInfo);
if (result < B_OK)
return result;
uint8 *address = NULL;
area_id clone = clone_area("Cloned BMessage data", (void **)&address,
B_ANY_ADDRESS, B_READ_AREA, fHeader->shared_area);
thread_info threadInfo;
get_thread_info(find_thread(NULL), &threadInfo);
if (areaInfo.team != threadInfo.team) {
#ifndef HAIKU_TARGET_PLATFORM_LIBBE_TEST
// we are accessing a message from a port not owned by us
area_id transfered = _kern_transfer_area(fHeader->message_area,
(void **)&address, B_ANY_ADDRESS, threadInfo.team);
if (transfered < 0) {
debug_printf("BMessage: failed to transfer area into current team\n");
return transfered;
}
if (clone < B_OK) {
free(fHeader);
fHeader = NULL;
_InitHeader();
return clone;
}
fHeader->message_area = transfered;
#endif
} else
address = (uint8 *)areaInfo.address;
fClonedArea = clone;
fFields = (field_header *)address;
address += fHeader->fields_size;
fData = address;
// ToDo: once we fully trust this mechanism we might want to remove this
if (fHeader->fields_checksum != BPrivate::CalculateChecksum((uint8 *)fFields, fHeader->fields_size)
|| fHeader->data_checksum != BPrivate::CalculateChecksum((uint8 *)fData, fHeader->data_size)) {
debug_printf("checksum mismatch\n");
debug_printf("BMessage: checksum mismatch in message passed by area!\n");
_Clear();
_InitHeader();
return B_BAD_VALUE;
@@ -1011,8 +1033,8 @@ status_t
BMessage::_Dereference()
{
DEBUG_FUNCTION_ENTER;
delete_area(fClonedArea);
fClonedArea = -1;
delete_area(fHeader->message_area);
fHeader->message_area = -1;
fFields = NULL;
fData = NULL;
return B_OK;
@@ -1023,19 +1045,25 @@ status_t
BMessage::_CopyForWrite()
{
DEBUG_FUNCTION_ENTER;
if (fClonedArea < B_OK)
return B_OK;
field_header *newFields = NULL;
uint8 *newData = NULL;
if (fHeader->fields_size > 0) {
newFields = (field_header *)malloc(fHeader->fields_size);
if (newFields == NULL)
return B_NO_MEMORY;
memcpy(newFields, fFields, fHeader->fields_size);
}
if (fHeader->data_size > 0) {
newData = (uint8 *)malloc(fHeader->data_size);
if (newData == NULL) {
free(newFields);
return B_NO_MEMORY;
}
memcpy(newData, fData, fHeader->data_size);
}
@@ -1089,7 +1117,7 @@ BMessage::Unflatten(const char *flatBuffer)
if (result < B_OK)
return result;
} else {
fHeader->shared_area = -1;
fHeader->message_area = -1;
if (fHeader->fields_size > 0) {
fFields = (field_header *)malloc(fHeader->fields_size);
@@ -1102,8 +1130,11 @@ BMessage::Unflatten(const char *flatBuffer)
if (fHeader->data_size > 0) {
fData = (uint8 *)malloc(fHeader->data_size);
if (!fData)
if (!fData) {
free(fFields);
fFields = NULL;
return B_NO_MEMORY;
}
memcpy(fData, flatBuffer, fHeader->data_size);
}
@@ -1156,7 +1187,7 @@ BMessage::Unflatten(BDataIO *stream)
if (result < B_OK)
return result;
} else {
fHeader->shared_area = -1;
fHeader->message_area = -1;
if (result == B_OK && fHeader->fields_size > 0) {
fFields = (field_header *)malloc(fHeader->fields_size);
@@ -1571,7 +1602,7 @@ BMessage::AddData(const char *name, type_code type, const void *data,
if (numBytes <= 0 || !data)
return B_BAD_VALUE;
if (fClonedArea >= B_OK)
if (fHeader->message_area >= 0)
_CopyForWrite();
field_header *field = NULL;
@@ -1628,7 +1659,7 @@ BMessage::RemoveData(const char *name, int32 index)
if (index < 0)
return B_BAD_VALUE;
if (fClonedArea >= B_OK)
if (fHeader->message_area >= 0)
_CopyForWrite();
field_header *field = NULL;
@@ -1679,7 +1710,7 @@ status_t
BMessage::RemoveName(const char *name)
{
DEBUG_FUNCTION_ENTER;
if (fClonedArea >= B_OK)
if (fHeader->message_area >= 0)
_CopyForWrite();
field_header *field = NULL;
@@ -1751,9 +1782,6 @@ BMessage::ReplaceData(const char *name, type_code type, int32 index,
if (numBytes <= 0 || !data)
return B_BAD_VALUE;
if (fClonedArea >= B_OK)
_CopyForWrite();
field_header *field = NULL;
status_t result = _FindField(name, type, &field);
@@ -1766,6 +1794,9 @@ BMessage::ReplaceData(const char *name, type_code type, int32 index,
if (index >= field->count)
return B_BAD_INDEX;
if (fHeader->message_area >= 0)
_CopyForWrite();
if (field->flags & FIELD_FLAG_FIXED_SIZE) {
ssize_t size = field->data_size / field->count;
if (size != numBytes)
@@ -1885,7 +1916,7 @@ BMessage::_SendMessage(port_id port, team_id portOwner, int32 token,
ssize_t size = 0;
char *buffer = NULL;
message_header *header = NULL;
status_t result;
status_t result = B_OK;
BPrivate::BDirectMessageTarget* direct = NULL;
BMessage* copy = NULL;
@@ -1900,37 +1931,55 @@ BMessage::_SendMessage(port_id port, team_id portOwner, int32 token,
if (copy != NULL) {
header = copy->fHeader;
header->flags = fHeader->flags;
result = B_OK;
} else {
direct->Release();
result = B_NO_MEMORY;
return B_NO_MEMORY;
}
} else if (/*fHeader->fields_size + fHeader->data_size > B_PAGE_SIZE*/false) {
#ifndef HAIKU_TARGET_PLATFORM_LIBBE_TEST
} else if (fHeader->fields_size + fHeader->data_size > B_PAGE_SIZE * 10) {
// ToDo: bind the above size to the max port message size
// use message passing by area for such a large message
result = _FlattenToArea(&header);
if (result < B_OK)
return result;
buffer = (char *)header;
size = sizeof(message_header);
#ifndef HAIKU_TARGET_PLATFORM_LIBBE_TEST
// TODO: this is not yet finished - the target needs to get the
// address (and ID) of the area
port_info info;
get_port_info(port, &info);
team_id target = portOwner;
if (target < 0) {
port_info info;
result = get_port_info(port, &info);
if (result < B_OK)
return result;
target = info.team;
}
void *address = NULL;
_kern_transfer_area(header->shared_area, &address, B_ANY_ADDRESS,
info.team);
area_id transfered = _kern_transfer_area(header->message_area,
&address, B_ANY_ADDRESS, target);
if (transfered < B_OK) {
delete_area(header->message_area);
free(header);
return transfered;
}
header->message_area = transfered;
#endif
} else {
size = _NativeFlattenedSize();
buffer = (char *)malloc(size);
if (buffer != NULL) {
result = _NativeFlatten(buffer, size);
header = (message_header *)buffer;
} else
result = B_NO_MEMORY;
}
if (buffer == NULL)
return B_NO_MEMORY;
if (result < B_OK)
return result;
result = _NativeFlatten(buffer, size);
if (result < B_OK) {
free(buffer);
return result;
}
header = (message_header *)buffer;
}
if (!replyTo.IsValid()) {
BMessenger::Private(replyTo).SetTo(fHeader->reply_team,