* Fixed some more bugs in the message passing by area
* Reordered some functions * Area messages can now be unflattened instead of using the private _Reference and a special port code Passing by area is now mostly working but it's not yet enabled. I will have to conduct performance tests first to see if and starting at what messagesize the overhead is reasonable. git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@16500 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
@@ -291,13 +291,14 @@ class BMessage {
|
|||||||
message_header* fHeader;
|
message_header* fHeader;
|
||||||
field_header* fFields;
|
field_header* fFields;
|
||||||
uint8* fData;
|
uint8* fData;
|
||||||
|
area_id fClonedArea;
|
||||||
|
|
||||||
mutable BMessage* fOriginal;
|
mutable BMessage* fOriginal;
|
||||||
|
|
||||||
BMessage* fQueueLink;
|
BMessage* fQueueLink;
|
||||||
// fQueueLink is used by BMessageQueue to build a linked list
|
// fQueueLink is used by BMessageQueue to build a linked list
|
||||||
|
|
||||||
uint32 fReserved[11];
|
uint32 fReserved[10];
|
||||||
|
|
||||||
// deprecated
|
// deprecated
|
||||||
BMessage(BMessage *message);
|
BMessage(BMessage *message);
|
||||||
|
|||||||
@@ -20,8 +20,7 @@
|
|||||||
#define MAX_ITEM_PREALLOCATION B_PAGE_SIZE
|
#define MAX_ITEM_PREALLOCATION B_PAGE_SIZE
|
||||||
|
|
||||||
|
|
||||||
static const int32 kPortMessageCodeDirect = 'pjpp';
|
static const int32 kPortMessageCode = 'pjpp';
|
||||||
static const int32 kPortMessageCodeByArea = 'pjp2';
|
|
||||||
|
|
||||||
|
|
||||||
enum {
|
enum {
|
||||||
@@ -31,7 +30,8 @@ enum {
|
|||||||
MESSAGE_FLAG_IS_REPLY = 0x0008,
|
MESSAGE_FLAG_IS_REPLY = 0x0008,
|
||||||
MESSAGE_FLAG_WAS_DELIVERED = 0x0010,
|
MESSAGE_FLAG_WAS_DELIVERED = 0x0010,
|
||||||
MESSAGE_FLAG_HAS_SPECIFIERS = 0x0020,
|
MESSAGE_FLAG_HAS_SPECIFIERS = 0x0020,
|
||||||
MESSAGE_FLAG_WAS_DROPPED = 0x0080
|
MESSAGE_FLAG_WAS_DROPPED = 0x0080,
|
||||||
|
MESSAGE_FLAG_PASS_BY_AREA = 0x0100
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
@@ -182,12 +182,6 @@ class BMessage::Private {
|
|||||||
return fMessage->_FlattenToArea(header);
|
return fMessage->_FlattenToArea(header);
|
||||||
}
|
}
|
||||||
|
|
||||||
status_t
|
|
||||||
Reference(message_header *header)
|
|
||||||
{
|
|
||||||
return fMessage->_Reference(header);
|
|
||||||
}
|
|
||||||
|
|
||||||
status_t
|
status_t
|
||||||
SendMessage(port_id port, int32 token, bigtime_t timeout,
|
SendMessage(port_id port, int32 token, bigtime_t timeout,
|
||||||
bool replyRequired, BMessenger &replyTo) const
|
bool replyRequired, BMessenger &replyTo) const
|
||||||
|
|||||||
@@ -1171,19 +1171,6 @@ BLooper::ConvertToMessage(void *buffer, int32 code)
|
|||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
BMessage *message = new BMessage();
|
BMessage *message = new BMessage();
|
||||||
#ifdef USING_MESSAGE4
|
|
||||||
if (code == kPortMessageCodeByArea) {
|
|
||||||
BMessage::Private messagePrivate(message);
|
|
||||||
if (messagePrivate.Reference((BMessage::message_header *)buffer) != B_OK) {
|
|
||||||
PRINT(("BLooper::ConvertToMessage(): referencing message failed\n"));
|
|
||||||
delete message;
|
|
||||||
message = NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
return message;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
if (message->Unflatten((const char *)buffer) != B_OK) {
|
if (message->Unflatten((const char *)buffer) != B_OK) {
|
||||||
PRINT(("BLooper::ConvertToMessage(): unflattening message failed\n"));
|
PRINT(("BLooper::ConvertToMessage(): unflattening message failed\n"));
|
||||||
delete message;
|
delete message;
|
||||||
|
|||||||
+230
-239
@@ -161,6 +161,8 @@ BMessage::_InitCommon()
|
|||||||
fFields = NULL;
|
fFields = NULL;
|
||||||
fData = NULL;
|
fData = NULL;
|
||||||
|
|
||||||
|
fClonedArea = -1;
|
||||||
|
|
||||||
fOriginal = NULL;
|
fOriginal = NULL;
|
||||||
fQueueLink = NULL;
|
fQueueLink = NULL;
|
||||||
return B_OK;
|
return B_OK;
|
||||||
@@ -196,7 +198,7 @@ status_t
|
|||||||
BMessage::_Clear()
|
BMessage::_Clear()
|
||||||
{
|
{
|
||||||
DEBUG_FUNCTION_ENTER;
|
DEBUG_FUNCTION_ENTER;
|
||||||
if (fHeader && fHeader->shared_area >= B_OK)
|
if (fClonedArea >= B_OK)
|
||||||
_Dereference();
|
_Dereference();
|
||||||
|
|
||||||
free(fHeader);
|
free(fHeader);
|
||||||
@@ -532,7 +534,7 @@ BMessage::Rename(const char *oldEntry, const char *newEntry)
|
|||||||
if (!oldEntry || !newEntry)
|
if (!oldEntry || !newEntry)
|
||||||
return B_BAD_VALUE;
|
return B_BAD_VALUE;
|
||||||
|
|
||||||
if (fHeader->shared_area >= B_OK)
|
if (fClonedArea >= B_OK)
|
||||||
_CopyForWrite();
|
_CopyForWrite();
|
||||||
|
|
||||||
uint32 hash = _HashName(oldEntry) % fHeader->hash_table_size;
|
uint32 hash = _HashName(oldEntry) % fHeader->hash_table_size;
|
||||||
@@ -861,6 +863,155 @@ BMessage::_NativeFlatten(BDataIO *stream, ssize_t *size) const
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* The concept of message sending by area:
|
||||||
|
|
||||||
|
The traditional way of sending a message is to send it by flattening it to
|
||||||
|
a buffer, pushing it through a port, reading it into the outputbuffer and
|
||||||
|
unflattening it from there (copying the data again). While this works ok
|
||||||
|
for small messages it does not make any sense for larger ones and may even
|
||||||
|
hit some port capacity limit.
|
||||||
|
Often in the life of a BMessage, it will be sent to someone. Almost as
|
||||||
|
often the one receiving the message will not need to change the message
|
||||||
|
in any way, but uses it "read only" to get information from it. This means
|
||||||
|
that all that copying is pretty pointless in the first place since we
|
||||||
|
could simply pass the original buffers on.
|
||||||
|
It's obviously not exactly as simple as this, since we cannot just use the
|
||||||
|
memory of one application in another - but we can share areas with
|
||||||
|
eachother.
|
||||||
|
Therefore instead of flattening into a buffer, we copy the message data
|
||||||
|
into an area, put this information into the message header and only push
|
||||||
|
this through the port. The receiving looper then builds a BMessage from
|
||||||
|
the header, that only references the data in the area (not copying it),
|
||||||
|
allowing read only access to it.
|
||||||
|
Only if write access is necessary the message will be copyed from the area
|
||||||
|
to its own buffers (like in the unflatten step before).
|
||||||
|
The double copying is reduced to a single copy in most cases and we safe
|
||||||
|
the slower route of moving the data through a port.
|
||||||
|
Additionally we save us the reference counting with the use of areas that
|
||||||
|
are reference counted internally. So we don't have to worry about leaving
|
||||||
|
an area behind or deleting one that is still in use.
|
||||||
|
*/
|
||||||
|
|
||||||
|
status_t
|
||||||
|
BMessage::_FlattenToArea(message_header **_header) const
|
||||||
|
{
|
||||||
|
DEBUG_FUNCTION_ENTER;
|
||||||
|
message_header *header = (message_header *)malloc(sizeof(message_header));
|
||||||
|
memcpy(header, fHeader, sizeof(message_header));
|
||||||
|
|
||||||
|
header->what = what;
|
||||||
|
header->fields_available = 0;
|
||||||
|
header->data_available = 0;
|
||||||
|
header->flags |= MESSAGE_FLAG_PASS_BY_AREA;
|
||||||
|
*_header = header;
|
||||||
|
|
||||||
|
if (header->shared_area >= B_OK)
|
||||||
|
return B_OK;
|
||||||
|
|
||||||
|
if (header->fields_size == 0 && header->data_size == 0)
|
||||||
|
return B_OK;
|
||||||
|
|
||||||
|
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,
|
||||||
|
B_ANY_ADDRESS, size, B_NO_LOCK, B_READ_AREA | B_WRITE_AREA);
|
||||||
|
|
||||||
|
if (area < B_OK) {
|
||||||
|
free(header);
|
||||||
|
*_header = NULL;
|
||||||
|
return area;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (header->fields_size > 0) {
|
||||||
|
memcpy(address, fFields, header->fields_size);
|
||||||
|
header->fields_checksum = BPrivate::CalculateChecksum((uint8 *)address, header->fields_size);
|
||||||
|
address += header->fields_size;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (header->data_size > 0) {
|
||||||
|
memcpy(address, fData, header->data_size);
|
||||||
|
header->data_checksum = BPrivate::CalculateChecksum((uint8 *)address, header->data_size);
|
||||||
|
}
|
||||||
|
|
||||||
|
header->shared_area = area;
|
||||||
|
return B_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
status_t
|
||||||
|
BMessage::_Reference(message_header *header)
|
||||||
|
{
|
||||||
|
DEBUG_FUNCTION_ENTER;
|
||||||
|
fHeader = header;
|
||||||
|
fHeader->flags &= ~MESSAGE_FLAG_PASS_BY_AREA;
|
||||||
|
|
||||||
|
/* if there is no data at all we don't need the area */
|
||||||
|
if (fHeader->fields_size == 0 && header->data_size == 0)
|
||||||
|
return B_OK;
|
||||||
|
|
||||||
|
uint8 *address = NULL;
|
||||||
|
area_id clone = clone_area("Cloned BMessage data", (void **)&address,
|
||||||
|
B_ANY_ADDRESS, B_READ_AREA, fHeader->shared_area);
|
||||||
|
|
||||||
|
if (clone < B_OK) {
|
||||||
|
free(fHeader);
|
||||||
|
fHeader = NULL;
|
||||||
|
_InitHeader();
|
||||||
|
return clone;
|
||||||
|
}
|
||||||
|
|
||||||
|
fClonedArea = clone;
|
||||||
|
fFields = (field_header *)address;
|
||||||
|
address += fHeader->fields_size;
|
||||||
|
fData = address;
|
||||||
|
return B_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
status_t
|
||||||
|
BMessage::_Dereference()
|
||||||
|
{
|
||||||
|
DEBUG_FUNCTION_ENTER;
|
||||||
|
delete_area(fClonedArea);
|
||||||
|
fClonedArea = -1;
|
||||||
|
fFields = NULL;
|
||||||
|
fData = NULL;
|
||||||
|
return B_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
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);
|
||||||
|
memcpy(newFields, fFields, fHeader->fields_size);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (fHeader->data_size > 0) {
|
||||||
|
newData = (uint8 *)malloc(fHeader->data_size);
|
||||||
|
memcpy(newData, fData, fHeader->data_size);
|
||||||
|
}
|
||||||
|
|
||||||
|
_Dereference();
|
||||||
|
|
||||||
|
fHeader->fields_available = 0;
|
||||||
|
fHeader->data_available = 0;
|
||||||
|
|
||||||
|
fFields = newFields;
|
||||||
|
fData = newData;
|
||||||
|
return B_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
status_t
|
status_t
|
||||||
BMessage::Unflatten(const char *flatBuffer)
|
BMessage::Unflatten(const char *flatBuffer)
|
||||||
{
|
{
|
||||||
@@ -903,38 +1054,46 @@ BMessage::Unflatten(const char *flatBuffer)
|
|||||||
memcpy(fHeader, flatBuffer, sizeof(message_header));
|
memcpy(fHeader, flatBuffer, sizeof(message_header));
|
||||||
flatBuffer += sizeof(message_header);
|
flatBuffer += sizeof(message_header);
|
||||||
|
|
||||||
fHeader->shared_area = -1;
|
if (fHeader->format != kMessageMagic4
|
||||||
fHeader->fields_available = 0;
|
|| !(fHeader->flags & MESSAGE_FLAG_VALID)) {
|
||||||
fHeader->data_available = 0;
|
free(fHeader);
|
||||||
what = fHeader->what;
|
fHeader = NULL;
|
||||||
|
|
||||||
if (fHeader->format != kMessageMagic4 ||
|
|
||||||
!(fHeader->flags & MESSAGE_FLAG_VALID)) {
|
|
||||||
_Clear();
|
|
||||||
_InitHeader();
|
_InitHeader();
|
||||||
return B_BAD_VALUE;
|
return B_BAD_VALUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (fHeader->fields_size > 0) {
|
fHeader->fields_available = 0;
|
||||||
fFields = (field_header *)malloc(fHeader->fields_size);
|
fHeader->data_available = 0;
|
||||||
if (!fFields)
|
what = fHeader->what;
|
||||||
return B_NO_MEMORY;
|
|
||||||
|
|
||||||
memcpy(fFields, flatBuffer, fHeader->fields_size);
|
if (fHeader->flags & MESSAGE_FLAG_PASS_BY_AREA) {
|
||||||
flatBuffer += fHeader->fields_size;
|
status_t result = _Reference(fHeader);
|
||||||
}
|
if (result < B_OK)
|
||||||
|
return result;
|
||||||
|
} else {
|
||||||
|
fHeader->shared_area = -1;
|
||||||
|
|
||||||
if (fHeader->data_size > 0) {
|
if (fHeader->fields_size > 0) {
|
||||||
fData = (uint8 *)malloc(fHeader->data_size);
|
fFields = (field_header *)malloc(fHeader->fields_size);
|
||||||
if (!fData)
|
if (!fFields)
|
||||||
return B_NO_MEMORY;
|
return B_NO_MEMORY;
|
||||||
|
|
||||||
memcpy(fData, flatBuffer, fHeader->data_size);
|
memcpy(fFields, flatBuffer, fHeader->fields_size);
|
||||||
|
flatBuffer += fHeader->fields_size;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (fHeader->data_size > 0) {
|
||||||
|
fData = (uint8 *)malloc(fHeader->data_size);
|
||||||
|
if (!fData)
|
||||||
|
return B_NO_MEMORY;
|
||||||
|
|
||||||
|
memcpy(fData, flatBuffer, fHeader->data_size);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (fHeader->fields_checksum != BPrivate::CalculateChecksum((uint8 *)fFields, fHeader->fields_size)
|
if (fHeader->fields_checksum != BPrivate::CalculateChecksum((uint8 *)fFields, fHeader->fields_size)
|
||||||
|| fHeader->data_checksum != BPrivate::CalculateChecksum((uint8 *)fData, fHeader->data_size)) {
|
|| fHeader->data_checksum != BPrivate::CalculateChecksum((uint8 *)fData, fHeader->data_size)) {
|
||||||
debug_printf("checksum mismatch\n");
|
debug_printf("checksum mismatch 2\n");
|
||||||
_Clear();
|
_Clear();
|
||||||
_InitHeader();
|
_InitHeader();
|
||||||
return B_BAD_VALUE;
|
return B_BAD_VALUE;
|
||||||
@@ -975,54 +1134,52 @@ BMessage::Unflatten(BDataIO *stream)
|
|||||||
uint8 *header = (uint8 *)fHeader;
|
uint8 *header = (uint8 *)fHeader;
|
||||||
ssize_t result = stream->Read(header + sizeof(uint32),
|
ssize_t result = stream->Read(header + sizeof(uint32),
|
||||||
sizeof(message_header) - sizeof(uint32));
|
sizeof(message_header) - sizeof(uint32));
|
||||||
|
result -= sizeof(message_header) - sizeof(uint32);
|
||||||
|
|
||||||
fHeader->shared_area = -1;
|
if (result != B_OK || fHeader->format != kMessageMagic4
|
||||||
fHeader->fields_available = 0;
|
|| !(fHeader->flags & MESSAGE_FLAG_VALID)) {
|
||||||
fHeader->data_available = 0;
|
free(fHeader);
|
||||||
what = fHeader->what;
|
fHeader = NULL;
|
||||||
|
|
||||||
if (result != sizeof(message_header) - sizeof(uint32)) {
|
|
||||||
_Clear();
|
|
||||||
_InitHeader();
|
|
||||||
return (result >= 0 ? B_ERROR : result);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (fHeader->format != kMessageMagic4 ||
|
|
||||||
!(fHeader->flags & MESSAGE_FLAG_VALID)) {
|
|
||||||
_Clear();
|
|
||||||
_InitHeader();
|
_InitHeader();
|
||||||
return B_BAD_VALUE;
|
return B_BAD_VALUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (fHeader->fields_size > 0) {
|
fHeader->fields_available = 0;
|
||||||
fFields = (field_header *)malloc(fHeader->fields_size);
|
fHeader->data_available = 0;
|
||||||
if (!fFields)
|
what = fHeader->what;
|
||||||
return B_NO_MEMORY;
|
|
||||||
|
|
||||||
result = stream->Read(fFields, fHeader->fields_size);
|
if (fHeader->flags & MESSAGE_FLAG_PASS_BY_AREA) {
|
||||||
if (result != fHeader->fields_size) {
|
result = _Reference(fHeader);
|
||||||
_Clear();
|
if (result < B_OK)
|
||||||
_InitHeader();
|
return result;
|
||||||
return (result >= 0 ? B_ERROR : result);
|
} else {
|
||||||
|
fHeader->shared_area = -1;
|
||||||
|
|
||||||
|
if (result == B_OK && fHeader->fields_size > 0) {
|
||||||
|
fFields = (field_header *)malloc(fHeader->fields_size);
|
||||||
|
if (!fFields)
|
||||||
|
return B_NO_MEMORY;
|
||||||
|
|
||||||
|
result = stream->Read(fFields, fHeader->fields_size);
|
||||||
|
result -= fHeader->fields_size;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
if (fHeader->data_size > 0) {
|
if (result == B_OK && fHeader->data_size > 0) {
|
||||||
fData = (uint8 *)malloc(fHeader->data_size);
|
fData = (uint8 *)malloc(fHeader->data_size);
|
||||||
if (!fData)
|
if (!fData)
|
||||||
return B_NO_MEMORY;
|
return B_NO_MEMORY;
|
||||||
|
|
||||||
result = stream->Read(fData, fHeader->data_size);
|
result = stream->Read(fData, fHeader->data_size);
|
||||||
if (result != fHeader->data_size) {
|
result -= fHeader->data_size;
|
||||||
_Clear();
|
|
||||||
_InitHeader();
|
|
||||||
return (result >= 0 ? B_ERROR : result);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (result < B_OK)
|
||||||
|
return B_BAD_VALUE;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (fHeader->fields_checksum != BPrivate::CalculateChecksum((uint8 *)fFields, fHeader->fields_size)
|
if (fHeader->fields_checksum != BPrivate::CalculateChecksum((uint8 *)fFields, fHeader->fields_size)
|
||||||
|| fHeader->data_checksum != BPrivate::CalculateChecksum((uint8 *)fData, fHeader->data_size)) {
|
|| fHeader->data_checksum != BPrivate::CalculateChecksum((uint8 *)fData, fHeader->data_size)) {
|
||||||
debug_printf("checksum mismatch\n");
|
debug_printf("checksum mismatch 2\n");
|
||||||
_Clear();
|
_Clear();
|
||||||
_InitHeader();
|
_InitHeader();
|
||||||
return B_BAD_VALUE;
|
return B_BAD_VALUE;
|
||||||
@@ -1191,162 +1348,6 @@ BMessage::PopSpecifier()
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* The concept of message sending by area:
|
|
||||||
|
|
||||||
The traditional way of sending a message is to send it by flattening it to
|
|
||||||
a buffer, pushing it through a port, reading it into the outputbuffer and
|
|
||||||
unflattening it from there (copying the data again). While this works ok
|
|
||||||
for small messages it does not make any sense for larger ones and may even
|
|
||||||
hit some port capacity limit.
|
|
||||||
Often in the life of a BMessage, it will be sent to someone. Almost as
|
|
||||||
often the one receiving the message will not need to change the message
|
|
||||||
in any way, but uses it "read only" to get information from it. This means
|
|
||||||
that all that copying is pretty pointless in the first place since we
|
|
||||||
could simply pass the original buffers on.
|
|
||||||
It's obviously not exactly as simple as this, since we cannot just use the
|
|
||||||
memory of one application in another - but we can share areas with
|
|
||||||
eachother.
|
|
||||||
Therefore instead of flattening into a buffer, we copy the message data
|
|
||||||
into an area, put this information into the message header and only push
|
|
||||||
this through the port. The receiving looper then builds a BMessage from
|
|
||||||
the header, that only references the data in the area (not copying it),
|
|
||||||
allowing read only access to it.
|
|
||||||
Only if write access is necessary the message will be copyed from the area
|
|
||||||
to its own buffers (like in the unflatten step before).
|
|
||||||
The double copying is reduced to a single copy in most cases and we safe
|
|
||||||
the slower route of moving the data through a port.
|
|
||||||
Additionally we save us the reference counting with the use of areas that
|
|
||||||
are reference counted internally. So we don't have to worry about leaving
|
|
||||||
an area behind or deleting one that is still in use.
|
|
||||||
*/
|
|
||||||
|
|
||||||
status_t
|
|
||||||
BMessage::_FlattenToArea(message_header **_header) const
|
|
||||||
{
|
|
||||||
DEBUG_FUNCTION_ENTER;
|
|
||||||
message_header *header = (message_header *)malloc(sizeof(message_header));
|
|
||||||
memcpy(header, fHeader, sizeof(message_header));
|
|
||||||
|
|
||||||
header->what = what;
|
|
||||||
header->fields_available = 0;
|
|
||||||
header->data_available = 0;
|
|
||||||
*_header = header;
|
|
||||||
|
|
||||||
if (header->shared_area >= B_OK)
|
|
||||||
return B_OK;
|
|
||||||
|
|
||||||
if (header->fields_size == 0 && header->data_size == 0)
|
|
||||||
return B_OK;
|
|
||||||
|
|
||||||
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,
|
|
||||||
B_ANY_ADDRESS, size, B_NO_LOCK, B_READ_AREA | B_WRITE_AREA);
|
|
||||||
|
|
||||||
if (area < B_OK) {
|
|
||||||
free(header);
|
|
||||||
*_header = NULL;
|
|
||||||
return area;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (header->fields_size > 0) {
|
|
||||||
memcpy(address, fFields, header->fields_size);
|
|
||||||
header->fields_checksum = BPrivate::CalculateChecksum((uint8 *)address, header->fields_size);
|
|
||||||
address += header->fields_size;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (header->data_size > 0) {
|
|
||||||
memcpy(address, fData, header->data_size);
|
|
||||||
header->data_checksum = BPrivate::CalculateChecksum((uint8 *)address, header->data_size);
|
|
||||||
}
|
|
||||||
|
|
||||||
header->shared_area = area;
|
|
||||||
return B_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
status_t
|
|
||||||
BMessage::_CopyForWrite()
|
|
||||||
{
|
|
||||||
DEBUG_FUNCTION_ENTER;
|
|
||||||
if (fHeader->shared_area < B_OK)
|
|
||||||
return B_OK;
|
|
||||||
|
|
||||||
field_header *newFields = NULL;
|
|
||||||
uint8 *newData = NULL;
|
|
||||||
|
|
||||||
if (fHeader->fields_size > 0) {
|
|
||||||
newFields = (field_header *)malloc(fHeader->fields_size);
|
|
||||||
memcpy(newFields, fFields, fHeader->fields_size);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (fHeader->data_size > 0) {
|
|
||||||
newData = (uint8 *)malloc(fHeader->data_size);
|
|
||||||
memcpy(newData, fData, fHeader->data_size);
|
|
||||||
}
|
|
||||||
|
|
||||||
_Dereference();
|
|
||||||
|
|
||||||
fHeader->fields_available = 0;
|
|
||||||
fHeader->data_available = 0;
|
|
||||||
|
|
||||||
fFields = newFields;
|
|
||||||
fData = newData;
|
|
||||||
return B_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
status_t
|
|
||||||
BMessage::_Reference(message_header *header)
|
|
||||||
{
|
|
||||||
DEBUG_FUNCTION_ENTER;
|
|
||||||
_Clear();
|
|
||||||
|
|
||||||
fHeader = (message_header *)malloc(sizeof(message_header));
|
|
||||||
memcpy(fHeader, header, sizeof(message_header));
|
|
||||||
fHeader->fields_available = 0;
|
|
||||||
fHeader->data_available = 0;
|
|
||||||
what = fHeader->what;
|
|
||||||
|
|
||||||
if (fHeader->shared_area < B_OK) {
|
|
||||||
/* if there is no data at all we don't need the area */
|
|
||||||
if (fHeader->fields_size == 0 && header->data_size == 0)
|
|
||||||
return B_OK;
|
|
||||||
|
|
||||||
_InitHeader();
|
|
||||||
return B_BAD_DATA;
|
|
||||||
}
|
|
||||||
|
|
||||||
uint8 *address = NULL;
|
|
||||||
area_id clone = clone_area("Cloned BMessage data", (void **)&address,
|
|
||||||
B_ANY_ADDRESS, B_READ_AREA, fHeader->shared_area);
|
|
||||||
|
|
||||||
if (clone < B_OK) {
|
|
||||||
_InitHeader();
|
|
||||||
return clone;
|
|
||||||
}
|
|
||||||
|
|
||||||
fHeader->shared_area = clone;
|
|
||||||
fFields = (field_header *)address;
|
|
||||||
address += fHeader->fields_size;
|
|
||||||
fData = address;
|
|
||||||
return B_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
status_t
|
|
||||||
BMessage::_Dereference()
|
|
||||||
{
|
|
||||||
DEBUG_FUNCTION_ENTER;
|
|
||||||
delete_area(fHeader->shared_area);
|
|
||||||
fHeader->shared_area = -1;
|
|
||||||
fFields = NULL;
|
|
||||||
fData = NULL;
|
|
||||||
return B_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
status_t
|
status_t
|
||||||
BMessage::_ResizeData(int32 offset, int32 change)
|
BMessage::_ResizeData(int32 offset, int32 change)
|
||||||
{
|
{
|
||||||
@@ -1558,7 +1559,7 @@ BMessage::AddData(const char *name, type_code type, const void *data,
|
|||||||
if (numBytes <= 0 || !data)
|
if (numBytes <= 0 || !data)
|
||||||
return B_BAD_VALUE;
|
return B_BAD_VALUE;
|
||||||
|
|
||||||
if (fHeader->shared_area >= B_OK)
|
if (fClonedArea >= B_OK)
|
||||||
_CopyForWrite();
|
_CopyForWrite();
|
||||||
|
|
||||||
field_header *field = NULL;
|
field_header *field = NULL;
|
||||||
@@ -1600,6 +1601,9 @@ BMessage::RemoveData(const char *name, int32 index)
|
|||||||
if (index < 0)
|
if (index < 0)
|
||||||
return B_BAD_VALUE;
|
return B_BAD_VALUE;
|
||||||
|
|
||||||
|
if (fClonedArea >= B_OK)
|
||||||
|
_CopyForWrite();
|
||||||
|
|
||||||
field_header *field = NULL;
|
field_header *field = NULL;
|
||||||
status_t result = _FindField(name, B_ANY_TYPE, &field);
|
status_t result = _FindField(name, B_ANY_TYPE, &field);
|
||||||
|
|
||||||
@@ -1612,9 +1616,6 @@ BMessage::RemoveData(const char *name, int32 index)
|
|||||||
if (index >= field->count)
|
if (index >= field->count)
|
||||||
return B_BAD_INDEX;
|
return B_BAD_INDEX;
|
||||||
|
|
||||||
if (fHeader->shared_area >= B_OK)
|
|
||||||
_CopyForWrite();
|
|
||||||
|
|
||||||
if (field->count == 1)
|
if (field->count == 1)
|
||||||
return _RemoveField(field);
|
return _RemoveField(field);
|
||||||
|
|
||||||
@@ -1645,6 +1646,9 @@ status_t
|
|||||||
BMessage::RemoveName(const char *name)
|
BMessage::RemoveName(const char *name)
|
||||||
{
|
{
|
||||||
DEBUG_FUNCTION_ENTER;
|
DEBUG_FUNCTION_ENTER;
|
||||||
|
if (fClonedArea >= B_OK)
|
||||||
|
_CopyForWrite();
|
||||||
|
|
||||||
field_header *field = NULL;
|
field_header *field = NULL;
|
||||||
status_t result = _FindField(name, B_ANY_TYPE, &field);
|
status_t result = _FindField(name, B_ANY_TYPE, &field);
|
||||||
|
|
||||||
@@ -1654,9 +1658,6 @@ BMessage::RemoveName(const char *name)
|
|||||||
if (!field)
|
if (!field)
|
||||||
return B_ERROR;
|
return B_ERROR;
|
||||||
|
|
||||||
if (fHeader->shared_area >= B_OK)
|
|
||||||
_CopyForWrite();
|
|
||||||
|
|
||||||
return _RemoveField(field);
|
return _RemoveField(field);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1717,6 +1718,9 @@ BMessage::ReplaceData(const char *name, type_code type, int32 index,
|
|||||||
if (numBytes <= 0 || !data)
|
if (numBytes <= 0 || !data)
|
||||||
return B_BAD_VALUE;
|
return B_BAD_VALUE;
|
||||||
|
|
||||||
|
if (fClonedArea >= B_OK)
|
||||||
|
_CopyForWrite();
|
||||||
|
|
||||||
field_header *field = NULL;
|
field_header *field = NULL;
|
||||||
status_t result = _FindField(name, type, &field);
|
status_t result = _FindField(name, type, &field);
|
||||||
|
|
||||||
@@ -1729,9 +1733,6 @@ BMessage::ReplaceData(const char *name, type_code type, int32 index,
|
|||||||
if (index >= field->count)
|
if (index >= field->count)
|
||||||
return B_BAD_INDEX;
|
return B_BAD_INDEX;
|
||||||
|
|
||||||
if (fHeader->shared_area >= B_OK)
|
|
||||||
_CopyForWrite();
|
|
||||||
|
|
||||||
if (field->flags & FIELD_FLAG_FIXED_SIZE) {
|
if (field->flags & FIELD_FLAG_FIXED_SIZE) {
|
||||||
ssize_t size = field->data_size / field->count;
|
ssize_t size = field->data_size / field->count;
|
||||||
if (size != numBytes)
|
if (size != numBytes)
|
||||||
@@ -1849,27 +1850,24 @@ BMessage::_SendMessage(port_id port, int32 token, bigtime_t timeout,
|
|||||||
char *buffer = NULL;
|
char *buffer = NULL;
|
||||||
message_header *header = NULL;
|
message_header *header = NULL;
|
||||||
status_t result;
|
status_t result;
|
||||||
int32 code;
|
|
||||||
|
|
||||||
if (/*fHeader->fields_size + fHeader->data_size > B_PAGE_SIZE*/false) {
|
if (/*fHeader->fields_size + fHeader->data_size > B_PAGE_SIZE*/false) {
|
||||||
result = _FlattenToArea(&header);
|
result = _FlattenToArea(&header);
|
||||||
buffer = (char *)header;
|
buffer = (char *)header;
|
||||||
size = sizeof(message_header);
|
size = sizeof(message_header);
|
||||||
code = kPortMessageCodeByArea;
|
|
||||||
} else {
|
} else {
|
||||||
size = _NativeFlattenedSize();
|
size = _NativeFlattenedSize();
|
||||||
buffer = (char *)malloc(size);
|
buffer = (char *)malloc(size);
|
||||||
result = _NativeFlatten(buffer, size);
|
result = _NativeFlatten(buffer, size);
|
||||||
header = (message_header *)buffer;
|
header = (message_header *)buffer;
|
||||||
code = kPortMessageCodeDirect;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (result < B_OK)
|
if (result < B_OK)
|
||||||
return result;
|
return result;
|
||||||
|
|
||||||
if (!replyTo.IsValid()) {
|
if (!replyTo.IsValid()) {
|
||||||
BMessenger::Private(replyTo).SetTo(fHeader->reply_team,
|
BMessenger::Private(replyTo).SetTo(header->reply_team,
|
||||||
fHeader->reply_port, fHeader->reply_target);
|
header->reply_port, header->reply_target);
|
||||||
|
|
||||||
if (!replyTo.IsValid())
|
if (!replyTo.IsValid())
|
||||||
replyTo = be_app_messenger;
|
replyTo = be_app_messenger;
|
||||||
@@ -1889,7 +1887,7 @@ BMessage::_SendMessage(port_id port, int32 token, bigtime_t timeout,
|
|||||||
header->flags |= MESSAGE_FLAG_WAS_DELIVERED;
|
header->flags |= MESSAGE_FLAG_WAS_DELIVERED;
|
||||||
|
|
||||||
do {
|
do {
|
||||||
result = write_port_etc(port, code, (void *)buffer, size,
|
result = write_port_etc(port, kPortMessageCode, (void *)buffer, size,
|
||||||
B_RELATIVE_TIMEOUT, timeout);
|
B_RELATIVE_TIMEOUT, timeout);
|
||||||
} while (result == B_INTERRUPTED);
|
} while (result == B_INTERRUPTED);
|
||||||
|
|
||||||
@@ -1995,7 +1993,7 @@ BMessage::_SendFlattenedMessage(void *data, int32 size, port_id port,
|
|||||||
status_t result;
|
status_t result;
|
||||||
|
|
||||||
do {
|
do {
|
||||||
result = write_port_etc(port, kPortMessageCodeDirect, data, size,
|
result = write_port_etc(port, kPortMessageCode, data, size,
|
||||||
B_RELATIVE_TIMEOUT, timeout);
|
B_RELATIVE_TIMEOUT, timeout);
|
||||||
} while (result == B_INTERRUPTED);
|
} while (result == B_INTERRUPTED);
|
||||||
|
|
||||||
@@ -2022,19 +2020,12 @@ handle_reply(port_id replyPort, int32 *pCode, bigtime_t timeout,
|
|||||||
result = read_port(replyPort, pCode, buffer, size);
|
result = read_port(replyPort, pCode, buffer, size);
|
||||||
} while (result == B_INTERRUPTED);
|
} while (result == B_INTERRUPTED);
|
||||||
|
|
||||||
if (result < B_OK || (*pCode != kPortMessageCodeDirect
|
if (result < B_OK || *pCode != kPortMessageCode) {
|
||||||
&& *pCode != kPortMessageCodeByArea)) {
|
|
||||||
free(buffer);
|
free(buffer);
|
||||||
return (result < B_OK ? result : B_ERROR);
|
return (result < B_OK ? result : B_ERROR);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (*pCode == kPortMessageCodeDirect) {
|
result = reply->Unflatten(buffer);
|
||||||
result = reply->Unflatten(buffer);
|
|
||||||
} else if (*pCode == kPortMessageCodeByArea) {
|
|
||||||
BMessage::Private messagePrivate(reply);
|
|
||||||
result = messagePrivate.Reference((BMessage::message_header *)buffer);
|
|
||||||
}
|
|
||||||
|
|
||||||
free(buffer);
|
free(buffer);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user