summaryrefslogtreecommitdiffstats
path: root/chrome/common
diff options
context:
space:
mode:
authorjeremy@chromium.org <jeremy@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2008-11-20 21:11:20 +0000
committerjeremy@chromium.org <jeremy@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2008-11-20 21:11:20 +0000
commit5062bb007d3c87994023538401ae7bbedfaadf3f (patch)
tree9dce5c15ac1029747888e7074abbe664cf3af969 /chrome/common
parent57682ce7b6a6199861e8bf59796214a42bdb16e4 (diff)
downloadchromium_src-5062bb007d3c87994023538401ae7bbedfaadf3f.zip
chromium_src-5062bb007d3c87994023538401ae7bbedfaadf3f.tar.gz
chromium_src-5062bb007d3c87994023538401ae7bbedfaadf3f.tar.bz2
Mach msg class can use an externally allocated buffer rather than an internal
fixed size buffer. Replace deprecated bootstrap functions with Cocoa equivalents. Review URL: http://codereview.chromium.org/11486 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@5786 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chrome/common')
-rw-r--r--chrome/common/mach_ipc_mac.h128
-rw-r--r--chrome/common/mach_ipc_mac.mm145
2 files changed, 178 insertions, 95 deletions
diff --git a/chrome/common/mach_ipc_mac.h b/chrome/common/mach_ipc_mac.h
index 58fdc9f..74b84cf 100644
--- a/chrome/common/mach_ipc_mac.h
+++ b/chrome/common/mach_ipc_mac.h
@@ -5,12 +5,14 @@
#ifndef BASE_MACH_IPC_MAC_H_
#define BASE_MACH_IPC_MAC_H_
-#import <mach/mach.h>
-#import <mach/message.h>
-#import <servers/bootstrap.h>
-#import <sys/types.h>
+#include <mach/mach.h>
+#include <mach/message.h>
+#include <servers/bootstrap.h>
+#include <sys/types.h>
-#import <CoreServices/CoreServices.h>
+#include <CoreServices/CoreServices.h>
+
+#include "base/basictypes.h"
//==============================================================================
// DISCUSSION:
@@ -39,13 +41,13 @@
//
// MachReceiveMessage message;
// kern_return_t result = receivePort.WaitForMessage(&message, 0);
-//
+//
// if (result == KERN_SUCCESS && message.GetMessageID() == 57) {
// mach_port_t task = message.GetTranslatedPort(0);
// mach_port_t thread = message.GetTranslatedPort(1);
//
// char *messageString = message.GetData();
-//
+//
// printf("message string = %s\n", messageString);
// }
//
@@ -58,7 +60,7 @@
// // add some ports to be translated for us
// message.AddDescriptor(mach_task_self()); // our task
// message.AddDescriptor(mach_thread_self()); // this thread
-//
+//
// char messageString[] = "Hello server!\n";
// message.SetData(messageString, strlen(messageString)+1);
//
@@ -82,7 +84,7 @@ class MachMsgPortDescriptor : public mach_msg_port_descriptor_t {
disposition = in_disposition;
type = MACH_MSG_PORT_DESCRIPTOR;
}
-
+
// For passing send rights to a port
MachMsgPortDescriptor(mach_port_t in_name) {
name = in_name;
@@ -104,11 +106,11 @@ class MachMsgPortDescriptor : public mach_msg_port_descriptor_t {
mach_port_t GetMachPort() const {
return name;
}
-
+
mach_msg_type_name_t GetDisposition() const {
return disposition;
}
-
+
// We're just a simple wrapper for mach_msg_port_descriptor_t
// and have the same memory layout
operator mach_msg_port_descriptor_t&() {
@@ -128,10 +130,13 @@ class MachMsgPortDescriptor : public mach_msg_port_descriptor_t {
// This considerably simplifies the construction of a message for sending
// and the getting at relevant data and descriptors for the receiver.
//
-// Currently the combined size of the descriptors plus data must be
-// less than 1024. But as a benefit no memory allocation is necessary.
-//
-// TODO: could consider adding malloc() support for very large messages
+// This class can be initialized using external storage of an arbitrary size
+// or it can manage storage internally.
+// 1. If storage is allocated internally, the combined size of the descriptors
+// plus data must be less than 1024. But as a benefit no memory allocation is
+// necessary.
+// 2. For external storage, a buffer of at least EmptyMessageSize() must be
+// provided.
//
// A MachMessage object is used by ReceivePort::WaitForMessage
// and MachPortSender::SendMessage
@@ -139,11 +144,13 @@ class MachMsgPortDescriptor : public mach_msg_port_descriptor_t {
class MachMessage {
public:
+ virtual ~MachMessage();
+
// The receiver of the message can retrieve the raw data this way
u_int8_t *GetData() {
return GetDataLength() > 0 ? GetDataPacket()->data : NULL;
}
-
+
u_int32_t GetDataLength() {
return EndianU32_LtoN(GetDataPacket()->data_length);
}
@@ -152,14 +159,16 @@ class MachMessage {
void SetMessageID(int32_t message_id) {
GetDataPacket()->id = EndianU32_NtoL(message_id);
}
-
+
int32_t GetMessageID() { return EndianU32_LtoN(GetDataPacket()->id); }
// Adds a descriptor (typically a mach port) to be translated
// returns true if successful, otherwise not enough space
- bool AddDescriptor(const MachMsgPortDescriptor &desc);
+ bool AddDescriptor(const MachMsgPortDescriptor &desc);
- int GetDescriptorCount() const { return body.msgh_descriptor_count; }
+ int GetDescriptorCount() const {
+ return storage_->body.msgh_descriptor_count;
+ }
MachMsgPortDescriptor *GetDescriptor(int n);
// Convenience method which gets the mach port described by the descriptor
@@ -169,15 +178,16 @@ class MachMessage {
bool IsSimpleMessage() const { return GetDescriptorCount() == 0; }
// Sets raw data for the message (returns false if not enough space)
- bool SetData(void *data, int32_t data_length);
+ bool SetData(const void* data, int32_t data_length);
protected:
// Consider this an abstract base class - must create an actual instance
// of MachReceiveMessage or MachSendMessage
-
- MachMessage() {
- memset(this, 0, sizeof(MachMessage));
- }
+ MachMessage();
+
+ // Constructor for use with preallocate storage.
+ // storage_length must be >= EmptyMessageSize()
+ MachMessage(void *storage, size_t storage_length);
friend class ReceivePort;
friend class MachPortSender;
@@ -186,39 +196,73 @@ class MachMessage {
struct MessageDataPacket {
int32_t id; // little-endian
int32_t data_length; // little-endian
- u_int8_t data[1]; // actual size limited by sizeof(MachMessage)
+ u_int8_t data[1]; // actual size limited by storage_length_bytes_
};
MessageDataPacket* GetDataPacket();
void SetDescriptorCount(int n);
- void SetDescriptor(int n, const MachMsgPortDescriptor &desc);
+ void SetDescriptor(int n, const MachMsgPortDescriptor &desc);
- // Returns total message size setting msgh_size in the header to this value
+ // Returns total message size setting msgh_size in the header to this value
int CalculateSize();
- mach_msg_header_t head;
- mach_msg_body_t body;
- u_int8_t padding[1024]; // descriptors and data may be embedded here
+ // Returns total storage size that this object can grow to, this is inclusive
+ // of the mach header.
+ size_t MaxSize() const { return storage_length_bytes_; }
+
+ protected:
+ mach_msg_header_t *Head() { return &(storage_->head); }
+
+ private:
+ struct MachMessageData {
+ mach_msg_header_t head;
+ mach_msg_body_t body;
+ // descriptors and data may be embedded here.
+ u_int8_t padding[1024];
+ };
+
+ // kEmptyMessageSize needs to have the definition of MachMessageData before it.NNN
+ public:
+ // The size of an empty message with no data.
+ static const size_t kEmptyMessageSize = sizeof(mach_msg_header_t) +
+ sizeof(mach_msg_body_t) +
+ sizeof(MessageDataPacket);
+
+ private:
+ MachMessageData *storage_;
+ size_t storage_length_bytes_;
+ bool own_storage_; // Is storage owned by this object?
};
//==============================================================================
// MachReceiveMessage and MachSendMessage are useful to separate the idea
// of a mach message being sent and being received, and adds increased type
// safety:
-// ReceivePort::WaitForMessage() only accepts a MachReceiveMessage
-// MachPortSender::SendMessage() only accepts a MachSendMessage
+// ReceivePort::WaitForMessage() only accepts a MachReceiveMessage
+// MachPortSender::SendMessage() only accepts a MachSendMessage
//==============================================================================
class MachReceiveMessage : public MachMessage {
public:
- MachReceiveMessage() : MachMessage() {};
+ MachReceiveMessage() : MachMessage() {}
+ MachReceiveMessage(void *storage, size_t storage_length)
+ : MachMessage(storage, storage_length) {}
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(MachReceiveMessage);
};
//==============================================================================
class MachSendMessage : public MachMessage {
public:
MachSendMessage(int32_t message_id);
+ MachSendMessage(void *storage, size_t storage_length, int32_t message_id);
+
+ private:
+ void Initialize(int32_t message_id);
+
+ DISALLOW_COPY_AND_ASSIGN(MachSendMessage);
};
//==============================================================================
@@ -236,19 +280,19 @@ class ReceivePort {
ReceivePort();
~ReceivePort();
-
+
// Waits on the mach port until message received or timeout
kern_return_t WaitForMessage(MachReceiveMessage *out_message,
mach_msg_timeout_t timeout);
-
+
// The underlying mach port that we wrap
mach_port_t GetPort() const { return port_; }
private:
- ReceivePort(const ReceivePort&); // disable copy c-tor
-
mach_port_t port_;
kern_return_t init_result_;
+
+ DISALLOW_COPY_AND_ASSIGN(ReceivePort);
};
//==============================================================================
@@ -258,18 +302,18 @@ class MachPortSender {
// get a port with send rights corresponding to a named registered service
MachPortSender(const char *receive_port_name);
-
+
// Given an already existing mach port, use it.
MachPortSender(mach_port_t send_port);
-
+
kern_return_t SendMessage(MachSendMessage &message,
mach_msg_timeout_t timeout);
-
+
private:
- MachPortSender(const MachPortSender&); // disable copy c-tor
-
mach_port_t send_port_;
kern_return_t init_result_;
+
+ DISALLOW_COPY_AND_ASSIGN(MachPortSender);
};
#endif // BASE_MACH_IPC_MAC_H_
diff --git a/chrome/common/mach_ipc_mac.mm b/chrome/common/mach_ipc_mac.mm
index 96786d0..3c95ef6 100644
--- a/chrome/common/mach_ipc_mac.mm
+++ b/chrome/common/mach_ipc_mac.mm
@@ -2,17 +2,31 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#import <stdio.h>
-#import "chrome/common/mach_ipc_mac.h"
+#include "chrome/common/mach_ipc_mac.h"
+
+#import <Foundation/Foundation.h>
+
+#include <stdio.h>
+#include "base/logging.h"
//==============================================================================
MachSendMessage::MachSendMessage(int32_t message_id) : MachMessage() {
- head.msgh_bits = MACH_MSGH_BITS(MACH_MSG_TYPE_COPY_SEND, 0);
+ Initialize(message_id);
+}
+
+MachSendMessage::MachSendMessage(void *storage, size_t storage_length,
+ int32_t message_id)
+ : MachMessage(storage, storage_length) {
+ Initialize(message_id);
+}
+
+void MachSendMessage::Initialize(int32_t message_id) {
+ Head()->msgh_bits = MACH_MSGH_BITS(MACH_MSG_TYPE_COPY_SEND, 0);
// head.msgh_remote_port = ...; // filled out in MachPortSender::SendMessage()
- head.msgh_local_port = MACH_PORT_NULL;
- head.msgh_reserved = 0;
- head.msgh_id = 0;
+ Head()->msgh_local_port = MACH_PORT_NULL;
+ Head()->msgh_reserved = 0;
+ Head()->msgh_id = 0;
SetDescriptorCount(0); // start out with no descriptors
@@ -21,20 +35,50 @@ MachSendMessage::MachSendMessage(int32_t message_id) : MachMessage() {
}
//==============================================================================
+MachMessage::MachMessage()
+ : storage_(new MachMessageData), // Allocate storage_ ourselves
+ storage_length_bytes_(sizeof(MachMessageData)),
+ own_storage_(true) {
+ memset(storage_, 0, storage_length_bytes_);
+}
+
+//==============================================================================
+MachMessage::MachMessage(void *storage, size_t storage_length)
+ : storage_(static_cast<MachMessageData*>(storage)),
+ storage_length_bytes_(storage_length),
+ own_storage_(false) {
+ DCHECK(storage);
+ DCHECK(storage_length >= kEmptyMessageSize);
+}
+
+//==============================================================================
+MachMessage::~MachMessage() {
+ if (own_storage_) {
+ delete storage_;
+ storage_ = NULL;
+ }
+}
+
+//==============================================================================
// returns true if successful
-bool MachMessage::SetData(void *data,
+bool MachMessage::SetData(const void* data,
int32_t data_length) {
+ // Enforce the fact that it's only safe to call this method once on a
+ // message.
+ DCHECK(GetDataPacket()->data_length == 0);
+
// first check to make sure we have enough space
int size = CalculateSize();
int new_size = size + data_length;
-
- if ((unsigned)new_size > sizeof(MachMessage)) {
+
+ if ((unsigned)new_size > storage_length_bytes_) {
return false; // not enough space
}
GetDataPacket()->data_length = EndianU32_NtoL(data_length);
if (data) memcpy(GetDataPacket()->data, data, data_length);
+ // Update the Mach header with the new aligned size of the message.
CalculateSize();
return true;
@@ -43,19 +87,19 @@ bool MachMessage::SetData(void *data,
//==============================================================================
// calculates and returns the total size of the message
// Currently, the entire message MUST fit inside of the MachMessage
-// messsage size <= sizeof(MachMessage)
+// messsage size <= EmptyMessageSize()
int MachMessage::CalculateSize() {
int size = sizeof(mach_msg_header_t) + sizeof(mach_msg_body_t);
-
+
// add space for MessageDataPacket
int32_t alignedDataLength = (GetDataLength() + 3) & ~0x3;
size += 2*sizeof(int32_t) + alignedDataLength;
-
+
// add space for descriptors
size += GetDescriptorCount() * sizeof(MachMsgPortDescriptor);
-
- head.msgh_size = size;
-
+
+ Head()->msgh_size = size;
+
return size;
}
@@ -63,7 +107,7 @@ int MachMessage::CalculateSize() {
MachMessage::MessageDataPacket *MachMessage::GetDataPacket() {
int desc_size = sizeof(MachMsgPortDescriptor)*GetDescriptorCount();
MessageDataPacket *packet =
- reinterpret_cast<MessageDataPacket*>(padding + desc_size);
+ reinterpret_cast<MessageDataPacket*>(storage_->padding + desc_size);
return packet;
}
@@ -72,7 +116,7 @@ MachMessage::MessageDataPacket *MachMessage::GetDataPacket() {
void MachMessage::SetDescriptor(int n,
const MachMsgPortDescriptor &desc) {
MachMsgPortDescriptor *desc_array =
- reinterpret_cast<MachMsgPortDescriptor*>(padding);
+ reinterpret_cast<MachMsgPortDescriptor*>(storage_->padding);
desc_array[n] = desc;
}
@@ -82,8 +126,8 @@ bool MachMessage::AddDescriptor(const MachMsgPortDescriptor &desc) {
// first check to make sure we have enough space
int size = CalculateSize();
int new_size = size + sizeof(MachMsgPortDescriptor);
-
- if ((unsigned)new_size > sizeof(MachMessage)) {
+
+ if ((unsigned)new_size > storage_length_bytes_) {
return false; // not enough space
}
@@ -91,23 +135,23 @@ bool MachMessage::AddDescriptor(const MachMsgPortDescriptor &desc) {
// new descriptor
u_int8_t *p = reinterpret_cast<u_int8_t*>(GetDataPacket());
bcopy(p, p+sizeof(MachMsgPortDescriptor), GetDataLength()+2*sizeof(int32_t));
-
+
SetDescriptor(GetDescriptorCount(), desc);
SetDescriptorCount(GetDescriptorCount() + 1);
CalculateSize();
-
+
return true;
}
//==============================================================================
void MachMessage::SetDescriptorCount(int n) {
- body.msgh_descriptor_count = n;
+ storage_->body.msgh_descriptor_count = n;
if (n > 0) {
- head.msgh_bits |= MACH_MSGH_BITS_COMPLEX;
+ Head()->msgh_bits |= MACH_MSGH_BITS_COMPLEX;
} else {
- head.msgh_bits &= ~MACH_MSGH_BITS_COMPLEX;
+ Head()->msgh_bits &= ~MACH_MSGH_BITS_COMPLEX;
}
}
@@ -115,10 +159,10 @@ void MachMessage::SetDescriptorCount(int n) {
MachMsgPortDescriptor *MachMessage::GetDescriptor(int n) {
if (n < GetDescriptorCount()) {
MachMsgPortDescriptor *desc =
- reinterpret_cast<MachMsgPortDescriptor*>(padding);
+ reinterpret_cast<MachMsgPortDescriptor*>(storage_->padding);
return desc + n;
}
-
+
return nil;
}
@@ -143,7 +187,7 @@ ReceivePort::ReceivePort(const char *receive_port_name) {
if (init_result_ != KERN_SUCCESS)
return;
-
+
init_result_ = mach_port_insert_right(current_task,
port_,
port_,
@@ -152,15 +196,9 @@ ReceivePort::ReceivePort(const char *receive_port_name) {
if (init_result_ != KERN_SUCCESS)
return;
- mach_port_t bootstrap_port = 0;
- init_result_ = task_get_bootstrap_port(current_task, &bootstrap_port);
-
- if (init_result_ != KERN_SUCCESS)
- return;
-
- init_result_ = bootstrap_register(bootstrap_port,
- const_cast<char*>(receive_port_name),
- port_);
+ NSPort *ns_port = [NSMachPort portWithMachPort:port_];
+ NSString *port_name = [NSString stringWithUTF8String:receive_port_name];
+ [[NSMachBootstrapServer sharedInstance] registerPort:ns_port name:port_name];
}
//==============================================================================
@@ -205,17 +243,17 @@ kern_return_t ReceivePort::WaitForMessage(MachReceiveMessage *out_message,
// return any error condition encountered in constructor
if (init_result_ != KERN_SUCCESS)
return init_result_;
-
- out_message->head.msgh_bits = 0;
- out_message->head.msgh_local_port = port_;
- out_message->head.msgh_remote_port = MACH_PORT_NULL;
- out_message->head.msgh_reserved = 0;
- out_message->head.msgh_id = 0;
-
- kern_return_t result = mach_msg(&out_message->head,
+
+ out_message->Head()->msgh_bits = 0;
+ out_message->Head()->msgh_local_port = port_;
+ out_message->Head()->msgh_remote_port = MACH_PORT_NULL;
+ out_message->Head()->msgh_reserved = 0;
+ out_message->Head()->msgh_id = 0;
+
+ kern_return_t result = mach_msg(out_message->Head(),
MACH_RCV_MSG | MACH_RCV_TIMEOUT,
0,
- sizeof(MachMessage),
+ out_message->MaxSize(),
port_,
timeout, // timeout in ms
MACH_PORT_NULL);
@@ -230,7 +268,7 @@ kern_return_t ReceivePort::WaitForMessage(MachReceiveMessage *out_message,
MachPortSender::MachPortSender(const char *receive_port_name) {
mach_port_t bootstrap_port = 0;
init_result_ = task_get_bootstrap_port(mach_task_self(), &bootstrap_port);
-
+
if (init_result_ != KERN_SUCCESS)
return;
@@ -240,7 +278,7 @@ MachPortSender::MachPortSender(const char *receive_port_name) {
}
//==============================================================================
-MachPortSender::MachPortSender(mach_port_t send_port)
+MachPortSender::MachPortSender(mach_port_t send_port)
: send_port_(send_port),
init_result_(KERN_SUCCESS) {
}
@@ -248,18 +286,19 @@ MachPortSender::MachPortSender(mach_port_t send_port)
//==============================================================================
kern_return_t MachPortSender::SendMessage(MachSendMessage &message,
mach_msg_timeout_t timeout) {
- if (message.head.msgh_size == 0) {
+ if (message.Head()->msgh_size == 0) {
+ NOTREACHED();
return KERN_INVALID_VALUE; // just for safety -- never should occur
};
-
+
if (init_result_ != KERN_SUCCESS)
return init_result_;
-
- message.head.msgh_remote_port = send_port_;
- kern_return_t result = mach_msg(&message.head,
+ message.Head()->msgh_remote_port = send_port_;
+
+ kern_return_t result = mach_msg(message.Head(),
MACH_SEND_MSG | MACH_SEND_TIMEOUT,
- message.head.msgh_size,
+ message.Head()->msgh_size,
0,
MACH_PORT_NULL,
timeout, // timeout in ms