Started implementing message passing by area. This will be needed for drag & drop messages and will probably be used for large messages instead of sending them through a port. Not yet finished and not enabled. Cleaned up a part of BLooper - this class should probably be cleaned up completely.
git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@16459 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
parent
7938b1158e
commit
721a0fe3e4
@ -269,6 +269,11 @@ class BMessage {
|
||||
status_t _InitHeader();
|
||||
status_t _Clear();
|
||||
|
||||
status_t _FlattenToArea(message_header **_header) const;
|
||||
status_t _CopyForWrite();
|
||||
status_t _Reference(message_header *header);
|
||||
status_t _Dereference();
|
||||
|
||||
status_t _ResizeData(int32 offset, int32 change);
|
||||
|
||||
uint32 _HashName(const char* name) const;
|
||||
|
@ -20,6 +20,10 @@
|
||||
#define MAX_ITEM_PREALLOCATION B_PAGE_SIZE
|
||||
|
||||
|
||||
static const int32 kPortMessageCodeDirect = 'pjpp';
|
||||
static const int32 kPortMessageCodeByArea = 'pjp2';
|
||||
|
||||
|
||||
enum {
|
||||
MESSAGE_FLAG_VALID = 0x0001,
|
||||
MESSAGE_FLAG_REPLY_REQUIRED = 0x0002,
|
||||
@ -27,7 +31,7 @@ enum {
|
||||
MESSAGE_FLAG_IS_REPLY = 0x0008,
|
||||
MESSAGE_FLAG_WAS_DELIVERED = 0x0010,
|
||||
MESSAGE_FLAG_HAS_SPECIFIERS = 0x0020,
|
||||
MESSAGE_FLAG_READ_ONLY = 0x0040
|
||||
MESSAGE_FLAG_WAS_DROPPED = 0x0080
|
||||
};
|
||||
|
||||
|
||||
@ -61,6 +65,7 @@ struct BMessage::message_header {
|
||||
|
||||
int32 target;
|
||||
int32 current_specifier;
|
||||
area_id shared_area;
|
||||
|
||||
// reply info
|
||||
port_id reply_port;
|
||||
@ -168,6 +173,18 @@ class BMessage::Private {
|
||||
return fMessage->_NativeFlatten(stream, size);
|
||||
}
|
||||
|
||||
status_t
|
||||
FlattenToArea(message_header **header) const
|
||||
{
|
||||
return fMessage->_FlattenToArea(header);
|
||||
}
|
||||
|
||||
status_t
|
||||
Reference(message_header *header)
|
||||
{
|
||||
return fMessage->_Reference(header);
|
||||
}
|
||||
|
||||
status_t
|
||||
SendMessage(port_id port, int32 token, bigtime_t timeout,
|
||||
bool replyRequired, BMessenger &replyTo) const
|
||||
|
@ -1112,7 +1112,7 @@ void *
|
||||
BLooper::ReadRawFromPort(int32 *msgCode, bigtime_t timeout)
|
||||
{
|
||||
PRINT(("BLooper::ReadRawFromPort()\n"));
|
||||
int8 *msgBuffer = NULL;
|
||||
uint8 *buffer = NULL;
|
||||
ssize_t bufferSize;
|
||||
|
||||
do {
|
||||
@ -1125,60 +1125,69 @@ BLooper::ReadRawFromPort(int32 *msgCode, bigtime_t timeout)
|
||||
}
|
||||
|
||||
if (bufferSize > 0)
|
||||
msgBuffer = new int8[bufferSize];
|
||||
buffer = (uint8 *)malloc(bufferSize);
|
||||
|
||||
// we don't want to wait again here, since that can only mean
|
||||
// that someone else has read our message and our bufferSize
|
||||
// is now probably wrong
|
||||
PRINT(("read_port()...\n"));
|
||||
bufferSize = read_port_etc(fMsgPort, msgCode, msgBuffer, bufferSize,
|
||||
B_RELATIVE_TIMEOUT, 0);
|
||||
bufferSize = read_port_etc(fMsgPort, msgCode, buffer, bufferSize,
|
||||
B_RELATIVE_TIMEOUT, 0);
|
||||
|
||||
if (bufferSize < B_OK) {
|
||||
delete[] msgBuffer;
|
||||
free(buffer);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
PRINT(("BLooper::ReadRawFromPort() read: %.4s, %p\n", (char *)msgCode, msgBuffer));
|
||||
return msgBuffer;
|
||||
PRINT(("BLooper::ReadRawFromPort() read: %.4s, %p (%d bytes)\n", (char *)msgCode, buffer, bufferSize));
|
||||
return buffer;
|
||||
}
|
||||
|
||||
|
||||
BMessage *
|
||||
BLooper::ReadMessageFromPort(bigtime_t tout)
|
||||
BLooper::ReadMessageFromPort(bigtime_t timeout)
|
||||
{
|
||||
PRINT(("BLooper::ReadMessageFromPort()\n"));
|
||||
int32 msgcode;
|
||||
BMessage* bmsg;
|
||||
int32 msgCode;
|
||||
BMessage *message = NULL;
|
||||
|
||||
void* msgbuffer = ReadRawFromPort(&msgcode, tout);
|
||||
if (!msgbuffer)
|
||||
void *buffer = ReadRawFromPort(&msgCode, timeout);
|
||||
if (!buffer)
|
||||
return NULL;
|
||||
|
||||
bmsg = ConvertToMessage(msgbuffer, msgcode);
|
||||
message = ConvertToMessage(buffer, msgCode);
|
||||
free(buffer);
|
||||
|
||||
delete[] (int8*)msgbuffer;
|
||||
|
||||
PRINT(("BLooper::ReadMessageFromPort() done: %p\n", bmsg));
|
||||
return bmsg;
|
||||
PRINT(("BLooper::ReadMessageFromPort() done: %p\n", message));
|
||||
return message;
|
||||
}
|
||||
|
||||
|
||||
BMessage*
|
||||
BLooper::ConvertToMessage(void* raw, int32 code)
|
||||
BMessage *
|
||||
BLooper::ConvertToMessage(void *buffer, int32 code)
|
||||
{
|
||||
PRINT(("BLooper::ConvertToMessage()\n"));
|
||||
BMessage* bmsg = new BMessage(code);
|
||||
if (!buffer)
|
||||
return NULL;
|
||||
|
||||
if (raw != NULL) {
|
||||
if (bmsg->Unflatten((const char*)raw) != B_OK) {
|
||||
BMessage *message = new BMessage();
|
||||
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;
|
||||
}
|
||||
} else {
|
||||
if (message->Unflatten((const char *)buffer) != B_OK) {
|
||||
PRINT(("BLooper::ConvertToMessage(): unflattening message failed\n"));
|
||||
delete bmsg;
|
||||
bmsg = NULL;
|
||||
delete message;
|
||||
message = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
PRINT(("BLooper::ConvertToMessage(): %p\n", bmsg));
|
||||
return bmsg;
|
||||
PRINT(("BLooper::ConvertToMessage(): %p\n", message));
|
||||
return message;
|
||||
}
|
||||
|
||||
|
||||
|
@ -33,7 +33,8 @@
|
||||
#include <string.h>
|
||||
|
||||
|
||||
#define DEBUG_FUNCTION_ENTER //debug_printf("%ld: %s\n", __LINE__, __PRETTY_FUNCTION__);
|
||||
#define DEBUG_FUNCTION_ENTER //debug_printf("thread: 0x%x; this: 0x%08x; header: 0x%08x; fields: 0x%08x; data: 0x%08x; line: %04ld; func: %s\n", find_thread(NULL), this, fHeader, fFields, fData, __LINE__, __PRETTY_FUNCTION__);
|
||||
#define DEBUG_FUNCTION_ENTER2 //debug_printf("thread: 0x%x; line: %04ld: func: %s\n", find_thread(NULL), __LINE__, __PRETTY_FUNCTION__);
|
||||
|
||||
|
||||
static const uint32 kMessageMagicR5 = 'FOB1';
|
||||
@ -81,6 +82,7 @@ BMessage::BMessage(const BMessage &other)
|
||||
{
|
||||
DEBUG_FUNCTION_ENTER;
|
||||
_InitCommon();
|
||||
_InitHeader();
|
||||
*this = other;
|
||||
}
|
||||
|
||||
@ -99,6 +101,7 @@ BMessage &
|
||||
BMessage::operator=(const BMessage &other)
|
||||
{
|
||||
DEBUG_FUNCTION_ENTER;
|
||||
|
||||
_Clear();
|
||||
|
||||
fHeader = (message_header *)malloc(sizeof(message_header));
|
||||
@ -110,10 +113,11 @@ BMessage::operator=(const BMessage &other)
|
||||
}
|
||||
|
||||
if (fHeader->data_size > 0) {
|
||||
fData = (uint8 *)malloc(other.fHeader->data_size);
|
||||
memcpy(fData, other.fData, other.fHeader->data_size);
|
||||
fData = (uint8 *)malloc(fHeader->data_size);
|
||||
memcpy(fData, other.fData, fHeader->data_size);
|
||||
}
|
||||
|
||||
fHeader->shared_area = -1;
|
||||
fHeader->fields_available = 0;
|
||||
fHeader->data_available = 0;
|
||||
what = fHeader->what;
|
||||
@ -125,18 +129,19 @@ BMessage::operator=(const BMessage &other)
|
||||
void *
|
||||
BMessage::operator new(size_t size)
|
||||
{
|
||||
DEBUG_FUNCTION_ENTER;
|
||||
DEBUG_FUNCTION_ENTER2;
|
||||
if (!sMsgCache)
|
||||
sMsgCache = new BBlockCache(10, size, B_OBJECT_CACHE);
|
||||
|
||||
return sMsgCache->Get(size);
|
||||
void *pointer = sMsgCache->Get(size);
|
||||
return pointer;
|
||||
}
|
||||
|
||||
|
||||
void *
|
||||
BMessage::operator new(size_t, void *pointer)
|
||||
{
|
||||
DEBUG_FUNCTION_ENTER;
|
||||
DEBUG_FUNCTION_ENTER2;
|
||||
return pointer;
|
||||
}
|
||||
|
||||
@ -144,7 +149,7 @@ BMessage::operator new(size_t, void *pointer)
|
||||
void
|
||||
BMessage::operator delete(void *pointer, size_t size)
|
||||
{
|
||||
DEBUG_FUNCTION_ENTER;
|
||||
DEBUG_FUNCTION_ENTER2;
|
||||
sMsgCache->Save(pointer, size);
|
||||
}
|
||||
|
||||
@ -175,6 +180,7 @@ BMessage::_InitHeader()
|
||||
fHeader->format = kMessageMagic4;
|
||||
fHeader->flags = MESSAGE_FLAG_VALID;
|
||||
fHeader->current_specifier = -1;
|
||||
fHeader->shared_area = -1;
|
||||
|
||||
fHeader->target = B_NULL_TOKEN;
|
||||
fHeader->reply_target = B_NULL_TOKEN;
|
||||
@ -191,9 +197,9 @@ BMessage::_InitHeader()
|
||||
status_t
|
||||
BMessage::_Clear()
|
||||
{
|
||||
delete fOriginal;
|
||||
fOriginal = NULL;
|
||||
fQueueLink = NULL;
|
||||
DEBUG_FUNCTION_ENTER;
|
||||
if (fHeader && fHeader->shared_area >= B_OK)
|
||||
_Dereference();
|
||||
|
||||
free(fHeader);
|
||||
fHeader = NULL;
|
||||
@ -202,6 +208,10 @@ BMessage::_Clear()
|
||||
free(fData);
|
||||
fData = NULL;
|
||||
|
||||
delete fOriginal;
|
||||
fOriginal = NULL;
|
||||
fQueueLink = NULL;
|
||||
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
@ -524,6 +534,9 @@ BMessage::Rename(const char *oldEntry, const char *newEntry)
|
||||
if (!oldEntry || !newEntry)
|
||||
return B_BAD_VALUE;
|
||||
|
||||
if (fHeader->shared_area >= B_OK)
|
||||
_CopyForWrite();
|
||||
|
||||
uint32 hash = _HashName(oldEntry) % fHeader->hash_table_size;
|
||||
int32 *nextField = &fHeader->hash_table[hash];
|
||||
|
||||
@ -604,8 +617,7 @@ BMessage::Previous() const
|
||||
DEBUG_FUNCTION_ENTER;
|
||||
/* ToDo: test if the "_previous_" field is used in R5 */
|
||||
if (!fOriginal) {
|
||||
delete fOriginal;
|
||||
fOriginal = new BMessage;
|
||||
fOriginal = new BMessage();
|
||||
|
||||
if (FindMessage("_previous_", fOriginal) != B_OK) {
|
||||
delete fOriginal;
|
||||
@ -621,7 +633,7 @@ bool
|
||||
BMessage::WasDropped() const
|
||||
{
|
||||
DEBUG_FUNCTION_ENTER;
|
||||
return fHeader->flags & MESSAGE_FLAG_READ_ONLY;
|
||||
return fHeader->flags & MESSAGE_FLAG_WAS_DROPPED;
|
||||
}
|
||||
|
||||
|
||||
@ -752,7 +764,6 @@ ssize_t
|
||||
BMessage::FlattenedSize() const
|
||||
{
|
||||
DEBUG_FUNCTION_ENTER;
|
||||
//return _NativeFlattenedSize();
|
||||
return BPrivate::r5_message_flattened_size(this);
|
||||
}
|
||||
|
||||
@ -761,7 +772,6 @@ status_t
|
||||
BMessage::Flatten(char *buffer, ssize_t size) const
|
||||
{
|
||||
DEBUG_FUNCTION_ENTER;
|
||||
//return _NativeFlatten(buffer, size);
|
||||
return BPrivate::flatten_r5_message(this, buffer, size);
|
||||
}
|
||||
|
||||
@ -770,7 +780,6 @@ status_t
|
||||
BMessage::Flatten(BDataIO *stream, ssize_t *size) const
|
||||
{
|
||||
DEBUG_FUNCTION_ENTER;
|
||||
//return _NativeFlatten(stream, size);
|
||||
return BPrivate::flatten_r5_message(this, stream, size);
|
||||
}
|
||||
|
||||
@ -883,7 +892,8 @@ BMessage::Unflatten(const char *flatBuffer)
|
||||
|
||||
// native message unflattening
|
||||
|
||||
free(fHeader);
|
||||
_Clear();
|
||||
|
||||
fHeader = (message_header *)malloc(sizeof(message_header));
|
||||
if (!fHeader)
|
||||
return B_NO_MEMORY;
|
||||
@ -891,6 +901,11 @@ BMessage::Unflatten(const char *flatBuffer)
|
||||
memcpy(fHeader, flatBuffer, sizeof(message_header));
|
||||
flatBuffer += sizeof(message_header);
|
||||
|
||||
fHeader->shared_area = -1;
|
||||
fHeader->fields_available = 0;
|
||||
fHeader->data_available = 0;
|
||||
what = fHeader->what;
|
||||
|
||||
/* ToDo: better message validation (checksum) */
|
||||
if (fHeader->format != kMessageMagic4 ||
|
||||
!(fHeader->flags & MESSAGE_FLAG_VALID)) {
|
||||
@ -899,8 +914,6 @@ BMessage::Unflatten(const char *flatBuffer)
|
||||
return B_BAD_VALUE;
|
||||
}
|
||||
|
||||
free(fFields);
|
||||
fFields = NULL;
|
||||
if (fHeader->fields_size > 0) {
|
||||
fFields = (field_header *)malloc(fHeader->fields_size);
|
||||
if (!fFields)
|
||||
@ -910,8 +923,6 @@ BMessage::Unflatten(const char *flatBuffer)
|
||||
flatBuffer += fHeader->fields_size;
|
||||
}
|
||||
|
||||
free(fData);
|
||||
fData = NULL;
|
||||
if (fHeader->data_size > 0) {
|
||||
fData = (uint8 *)malloc(fHeader->data_size);
|
||||
if (!fData)
|
||||
@ -920,9 +931,6 @@ BMessage::Unflatten(const char *flatBuffer)
|
||||
memcpy(fData, flatBuffer, fHeader->data_size);
|
||||
}
|
||||
|
||||
fHeader->fields_available = 0;
|
||||
fHeader->data_available = 0;
|
||||
what = fHeader->what;
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
@ -948,7 +956,8 @@ BMessage::Unflatten(BDataIO *stream)
|
||||
|
||||
// native message unflattening
|
||||
|
||||
free(fHeader);
|
||||
_Clear();
|
||||
|
||||
fHeader = (message_header *)malloc(sizeof(message_header));
|
||||
if (!fHeader)
|
||||
return B_NO_MEMORY;
|
||||
@ -957,6 +966,12 @@ BMessage::Unflatten(BDataIO *stream)
|
||||
uint8 *header = (uint8 *)fHeader;
|
||||
ssize_t result = stream->Read(header + sizeof(uint32),
|
||||
sizeof(message_header) - sizeof(uint32));
|
||||
|
||||
fHeader->shared_area = -1;
|
||||
fHeader->fields_available = 0;
|
||||
fHeader->data_available = 0;
|
||||
what = fHeader->what;
|
||||
|
||||
if (result != sizeof(message_header) - sizeof(uint32)) {
|
||||
_Clear();
|
||||
_InitHeader();
|
||||
@ -971,8 +986,6 @@ BMessage::Unflatten(BDataIO *stream)
|
||||
return B_BAD_VALUE;
|
||||
}
|
||||
|
||||
free(fFields);
|
||||
fFields = NULL;
|
||||
if (fHeader->fields_size > 0) {
|
||||
fFields = (field_header *)malloc(fHeader->fields_size);
|
||||
if (!fFields)
|
||||
@ -986,8 +999,6 @@ BMessage::Unflatten(BDataIO *stream)
|
||||
}
|
||||
}
|
||||
|
||||
free(fData);
|
||||
fData = NULL;
|
||||
if (fHeader->data_size > 0) {
|
||||
fData = (uint8 *)malloc(fHeader->data_size);
|
||||
if (!fData)
|
||||
@ -1001,9 +1012,6 @@ BMessage::Unflatten(BDataIO *stream)
|
||||
}
|
||||
}
|
||||
|
||||
fHeader->fields_available = 0;
|
||||
fHeader->data_available = 0;
|
||||
what = fHeader->what;
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
@ -1166,6 +1174,157 @@ 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 possibly dangerous and 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 = 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 = sizeof(int32) + header->fields_size + header->data_size;
|
||||
size = ((size + B_PAGE_SIZE) & ~(B_PAGE_SIZE - 1)) + B_PAGE_SIZE;
|
||||
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);
|
||||
address += header->fields_size;
|
||||
}
|
||||
|
||||
if (header->data_size > 0)
|
||||
memcpy(address, fData, header->data_size);
|
||||
|
||||
header->shared_area = area;
|
||||
header->fields_available = 0;
|
||||
header->data_available = 0;
|
||||
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 (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
|
||||
BMessage::_ResizeData(int32 offset, int32 change)
|
||||
{
|
||||
@ -1377,6 +1536,9 @@ BMessage::AddData(const char *name, type_code type, const void *data,
|
||||
if (numBytes <= 0 || !data)
|
||||
return B_BAD_VALUE;
|
||||
|
||||
if (fHeader->shared_area >= B_OK)
|
||||
_CopyForWrite();
|
||||
|
||||
field_header *field = NULL;
|
||||
status_t result = _FindField(name, type, &field);
|
||||
if (result == B_NAME_NOT_FOUND)
|
||||
@ -1428,6 +1590,9 @@ BMessage::RemoveData(const char *name, int32 index)
|
||||
if (index >= field->count)
|
||||
return B_BAD_INDEX;
|
||||
|
||||
if (fHeader->shared_area >= B_OK)
|
||||
_CopyForWrite();
|
||||
|
||||
if (field->count == 1)
|
||||
return _RemoveField(field);
|
||||
|
||||
@ -1467,6 +1632,9 @@ BMessage::RemoveName(const char *name)
|
||||
if (!field)
|
||||
return B_ERROR;
|
||||
|
||||
if (fHeader->shared_area >= B_OK)
|
||||
_CopyForWrite();
|
||||
|
||||
return _RemoveField(field);
|
||||
}
|
||||
|
||||
@ -1475,23 +1643,8 @@ status_t
|
||||
BMessage::MakeEmpty()
|
||||
{
|
||||
DEBUG_FUNCTION_ENTER;
|
||||
|
||||
free(fFields);
|
||||
fFields = NULL;
|
||||
free(fData);
|
||||
fData = NULL;
|
||||
|
||||
fHeader->fields_size = 0;
|
||||
fHeader->data_size = 0;
|
||||
fHeader->fields_available = 0;
|
||||
fHeader->data_available = 0;
|
||||
fHeader->current_specifier = -1;
|
||||
fHeader->field_count = 0;
|
||||
|
||||
fHeader->flags &= ~MESSAGE_FLAG_HAS_SPECIFIERS;
|
||||
|
||||
// initializing the hash table to -1 because 0 is a valid index
|
||||
memset(&fHeader->hash_table, 255, sizeof(fHeader->hash_table));
|
||||
_Clear();
|
||||
_InitHeader();
|
||||
return B_OK;
|
||||
}
|
||||
|
||||
@ -1554,6 +1707,9 @@ BMessage::ReplaceData(const char *name, type_code type, int32 index,
|
||||
if (index >= field->count)
|
||||
return B_BAD_INDEX;
|
||||
|
||||
if (fHeader->shared_area >= B_OK)
|
||||
_CopyForWrite();
|
||||
|
||||
if (field->flags & FIELD_FLAG_FIXED_SIZE) {
|
||||
ssize_t size = field->data_size / field->count;
|
||||
if (size != numBytes)
|
||||
@ -1606,7 +1762,7 @@ BMessage::HasData(const char *name, type_code type, int32 index) const
|
||||
void
|
||||
BMessage::_StaticInit()
|
||||
{
|
||||
DEBUG_FUNCTION_ENTER;
|
||||
DEBUG_FUNCTION_ENTER2;
|
||||
sReplyPorts[0] = create_port(1, "tmp_rport0");
|
||||
sReplyPorts[1] = create_port(1, "tmp_rport1");
|
||||
sReplyPorts[2] = create_port(1, "tmp_rport2");
|
||||
@ -1622,7 +1778,7 @@ BMessage::_StaticInit()
|
||||
void
|
||||
BMessage::_StaticCleanup()
|
||||
{
|
||||
DEBUG_FUNCTION_ENTER;
|
||||
DEBUG_FUNCTION_ENTER2;
|
||||
delete_port(sReplyPorts[0]);
|
||||
sReplyPorts[0] = -1;
|
||||
delete_port(sReplyPorts[1]);
|
||||
@ -1635,7 +1791,7 @@ BMessage::_StaticCleanup()
|
||||
void
|
||||
BMessage::_StaticCacheCleanup()
|
||||
{
|
||||
DEBUG_FUNCTION_ENTER;
|
||||
DEBUG_FUNCTION_ENTER2;
|
||||
delete sMsgCache;
|
||||
sMsgCache = NULL;
|
||||
}
|
||||
@ -1644,7 +1800,7 @@ BMessage::_StaticCacheCleanup()
|
||||
int32
|
||||
BMessage::_StaticGetCachedReplyPort()
|
||||
{
|
||||
DEBUG_FUNCTION_ENTER;
|
||||
DEBUG_FUNCTION_ENTER2;
|
||||
int index = -1;
|
||||
for (int32 i = 0; i < sNumReplyPorts; i++) {
|
||||
int32 old = atomic_add(&(sReplyPortInUse[i]), 1);
|
||||
@ -1667,11 +1823,27 @@ BMessage::_SendMessage(port_id port, int32 token, bigtime_t timeout,
|
||||
bool replyRequired, BMessenger &replyTo) const
|
||||
{
|
||||
DEBUG_FUNCTION_ENTER;
|
||||
uint32 oldFlags = fHeader->flags;
|
||||
int32 oldTarget = fHeader->target;
|
||||
port_id oldReplyPort = fHeader->reply_port;
|
||||
int32 oldReplyTarget = fHeader->reply_target;
|
||||
team_id oldReplyTeam = fHeader->reply_team;
|
||||
ssize_t size = 0;
|
||||
char *buffer = NULL;
|
||||
message_header *header = NULL;
|
||||
status_t result;
|
||||
int32 code;
|
||||
|
||||
if (/*fHeader->fields_size + fHeader->data_size > B_PAGE_SIZE*/false) {
|
||||
result = _FlattenToArea(&header);
|
||||
buffer = (char *)header;
|
||||
size = sizeof(message_header);
|
||||
code = kPortMessageCodeByArea;
|
||||
} else {
|
||||
size = _NativeFlattenedSize();
|
||||
buffer = (char *)malloc(size);
|
||||
result = _NativeFlatten(buffer, size);
|
||||
header = (message_header *)buffer;
|
||||
code = kPortMessageCodeDirect;
|
||||
}
|
||||
|
||||
if (result < B_OK)
|
||||
return result;
|
||||
|
||||
if (!replyTo.IsValid()) {
|
||||
BMessenger::Private(replyTo).SetTo(fHeader->reply_team,
|
||||
@ -1684,50 +1856,22 @@ BMessage::_SendMessage(port_id port, int32 token, bigtime_t timeout,
|
||||
BMessenger::Private replyToPrivate(replyTo);
|
||||
|
||||
if (replyRequired)
|
||||
fHeader->flags |= MESSAGE_FLAG_REPLY_REQUIRED;
|
||||
header->flags |= MESSAGE_FLAG_REPLY_REQUIRED;
|
||||
else
|
||||
fHeader->flags &= ~MESSAGE_FLAG_REPLY_REQUIRED;
|
||||
header->flags &= ~MESSAGE_FLAG_REPLY_REQUIRED;
|
||||
|
||||
fHeader->target = token;
|
||||
fHeader->reply_team = replyToPrivate.Team();
|
||||
fHeader->reply_port = replyToPrivate.Port();
|
||||
fHeader->reply_target = replyToPrivate.Token();
|
||||
fHeader->flags |= MESSAGE_FLAG_WAS_DELIVERED;
|
||||
|
||||
/* ToDo: we can use _kern_writev_port to send the three parts directly:
|
||||
iovec vectors[3];
|
||||
vectors[0].iov_base = fHeader;
|
||||
vectors[0].iov_len = sizeof(message_header);
|
||||
vectors[1].iov_base = fFields;
|
||||
vectors[1].iov_len = fHeader->fields_size;
|
||||
vectors[2].iov_base = fData;
|
||||
vectors[2].iov_len = fHeader->data_size;
|
||||
status_t result;
|
||||
|
||||
do {
|
||||
result = _kern_writev_port_etc(port, 'pjpp', vectors, 3,
|
||||
_NativeFlattenedSize(), B_RELATIVE_TIMEOUT, timeout);
|
||||
} while (result == B_INTERRUPTED);
|
||||
*/
|
||||
|
||||
ssize_t size = _NativeFlattenedSize();
|
||||
char *buffer = new char[size];
|
||||
status_t result = _NativeFlatten(buffer, size);
|
||||
if (result < B_OK)
|
||||
goto error;
|
||||
header->target = token;
|
||||
header->reply_team = replyToPrivate.Team();
|
||||
header->reply_port = replyToPrivate.Port();
|
||||
header->reply_target = replyToPrivate.Token();
|
||||
header->flags |= MESSAGE_FLAG_WAS_DELIVERED;
|
||||
|
||||
do {
|
||||
result = write_port_etc(port, 'pjpp', buffer, size,
|
||||
result = write_port_etc(port, code, (void *)buffer, size,
|
||||
B_RELATIVE_TIMEOUT, timeout);
|
||||
} while (result == B_INTERRUPTED);
|
||||
|
||||
error:
|
||||
fHeader->flags = oldFlags;
|
||||
fHeader->target = oldTarget;
|
||||
fHeader->reply_port = oldReplyPort;
|
||||
fHeader->reply_target = oldReplyTarget;
|
||||
fHeader->reply_team = oldReplyTeam;
|
||||
delete[] buffer;
|
||||
free(buffer);
|
||||
return result;
|
||||
}
|
||||
|
||||
@ -1803,11 +1947,11 @@ status_t
|
||||
BMessage::_SendFlattenedMessage(void *data, int32 size, port_id port,
|
||||
int32 token, bigtime_t timeout)
|
||||
{
|
||||
DEBUG_FUNCTION_ENTER;
|
||||
DEBUG_FUNCTION_ENTER2;
|
||||
if (!data)
|
||||
return B_BAD_VALUE;
|
||||
|
||||
uint32 magic = *(uint32*)data;
|
||||
uint32 magic = *(uint32 *)data;
|
||||
|
||||
if (magic == kMessageMagic4 || magic == kMessageMagic4Swapped) {
|
||||
message_header *header = (message_header *)data;
|
||||
@ -1829,8 +1973,8 @@ BMessage::_SendFlattenedMessage(void *data, int32 size, port_id port,
|
||||
status_t result;
|
||||
|
||||
do {
|
||||
result = write_port_etc(port, 'pjpp', data, size, B_RELATIVE_TIMEOUT,
|
||||
timeout);
|
||||
result = write_port_etc(port, kPortMessageCodeDirect, data, size,
|
||||
B_RELATIVE_TIMEOUT, timeout);
|
||||
} while (result == B_INTERRUPTED);
|
||||
|
||||
return result;
|
||||
@ -1841,7 +1985,7 @@ static status_t
|
||||
handle_reply(port_id replyPort, int32 *pCode, bigtime_t timeout,
|
||||
BMessage *reply)
|
||||
{
|
||||
DEBUG_FUNCTION_ENTER;
|
||||
DEBUG_FUNCTION_ENTER2;
|
||||
status_t result;
|
||||
do {
|
||||
result = port_buffer_size_etc(replyPort, B_RELATIVE_TIMEOUT, timeout);
|
||||
@ -1851,19 +1995,25 @@ handle_reply(port_id replyPort, int32 *pCode, bigtime_t timeout,
|
||||
return result;
|
||||
|
||||
// The API lied. It really isn't an error code, but the message size...
|
||||
char *buffer = new char[result];
|
||||
|
||||
char *buffer = (char *)malloc(result);
|
||||
do {
|
||||
result = read_port(replyPort, pCode, buffer, result);
|
||||
} while (result == B_INTERRUPTED);
|
||||
|
||||
if (result < B_OK || *pCode != 'pjpp') {
|
||||
delete[] buffer;
|
||||
if (result < B_OK || (*pCode != kPortMessageCodeDirect
|
||||
&& *pCode != kPortMessageCodeByArea)) {
|
||||
free(buffer);
|
||||
return (result < B_OK ? result : B_ERROR);
|
||||
}
|
||||
|
||||
result = reply->Unflatten(buffer);
|
||||
delete[] buffer;
|
||||
if (*pCode == kPortMessageCodeDirect) {
|
||||
result = reply->Unflatten(buffer);
|
||||
} else if (*pCode == kPortMessageCodeByArea) {
|
||||
BMessage::Private messagePrivate(reply);
|
||||
result = messagePrivate.Reference((BMessage::message_header *)buffer);
|
||||
}
|
||||
|
||||
free(buffer);
|
||||
return result;
|
||||
}
|
||||
|
||||
@ -1871,7 +2021,7 @@ handle_reply(port_id replyPort, int32 *pCode, bigtime_t timeout,
|
||||
static status_t
|
||||
convert_message(const KMessage *fromMessage, BMessage *toMessage)
|
||||
{
|
||||
DEBUG_FUNCTION_ENTER;
|
||||
DEBUG_FUNCTION_ENTER2;
|
||||
if (!fromMessage || !toMessage)
|
||||
return B_BAD_VALUE;
|
||||
|
||||
@ -2083,10 +2233,10 @@ BMessage::AddMessage(const char *name, const BMessage *message)
|
||||
copying an extra buffer. Functions can be added that return a direct
|
||||
pointer into the message. */
|
||||
|
||||
ssize_t size = message->FlattenedSize();
|
||||
ssize_t size = message->_NativeFlattenedSize();
|
||||
char buffer[size];
|
||||
|
||||
status_t error = message->Flatten(buffer, size);
|
||||
status_t error = message->_NativeFlatten(buffer, size);
|
||||
|
||||
if (error >= B_OK)
|
||||
error = AddData(name, B_MESSAGE_TYPE, &buffer, size, false);
|
||||
|
Loading…
Reference in New Issue
Block a user