From 5062bb007d3c87994023538401ae7bbedfaadf3f Mon Sep 17 00:00:00 2001 From: "jeremy@chromium.org" Date: Thu, 20 Nov 2008 21:11:20 +0000 Subject: 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 --- chrome/chrome.xcodeproj/project.pbxproj | 6 ++ chrome/common/mach_ipc_mac.h | 128 +++++++++++++++++++--------- chrome/common/mach_ipc_mac.mm | 145 ++++++++++++++++++++------------ 3 files changed, 184 insertions(+), 95 deletions(-) diff --git a/chrome/chrome.xcodeproj/project.pbxproj b/chrome/chrome.xcodeproj/project.pbxproj index f018d27..e143d70 100644 --- a/chrome/chrome.xcodeproj/project.pbxproj +++ b/chrome/chrome.xcodeproj/project.pbxproj @@ -138,6 +138,7 @@ 4DDC63E70EAE344300FB5EBE /* metrics_response_unittest.cc in Sources */ = {isa = PBXBuildFile; fileRef = 4D7BF8B60E9D4839009A6919 /* metrics_response_unittest.cc */; }; 4DDC644B0EAE390800FB5EBE /* libxml.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 4D7BFB230E9D4BBF009A6919 /* libxml.a */; }; 4DDC64580EAE394200FB5EBE /* libzlib.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 4DDC64550EAE392400FB5EBE /* libzlib.a */; }; + B562C8430ED49C830077A23F /* mach_ipc_mac.mm in Sources */ = {isa = PBXBuildFile; fileRef = B562C8420ED49C830077A23F /* mach_ipc_mac.mm */; }; E48FB9590EC4E9C10052B72B /* safe_browsing_database_bloom.cc in Sources */ = {isa = PBXBuildFile; fileRef = 4D7BFADF0E9D49DE009A6919 /* safe_browsing_database_bloom.cc */; }; E48FB95C0EC4E9DD0052B72B /* safe_browsing_database_impl.cc in Sources */ = {isa = PBXBuildFile; fileRef = 4D7BFAE10E9D49DE009A6919 /* safe_browsing_database_impl.cc */; }; E48FB9760EC4EA320052B72B /* url_request_failed_dns_job.cc in Sources */ = {isa = PBXBuildFile; fileRef = E48FB96E0EC4EA270052B72B /* url_request_failed_dns_job.cc */; }; @@ -1230,6 +1231,8 @@ 4D7BFF7A0E9D5449009A6919 /* AppKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AppKit.framework; path = System/Library/Frameworks/AppKit.framework; sourceTree = ""; }; 4DC6498E0EA92BF90017C876 /* platform_test_mac.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = platform_test_mac.mm; sourceTree = ""; }; 4DDC64500EAE392400FB5EBE /* zlib.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = zlib.xcodeproj; path = third_party/zlib/zlib.xcodeproj; sourceTree = ""; }; + B562C8410ED49C830077A23F /* mach_ipc_mac.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = mach_ipc_mac.h; sourceTree = ""; }; + B562C8420ED49C830077A23F /* mach_ipc_mac.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = mach_ipc_mac.mm; sourceTree = ""; }; E48FB9610EC4EA270052B72B /* automation_autocomplete_edit_tracker.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = automation_autocomplete_edit_tracker.h; sourceTree = ""; }; E48FB9620EC4EA270052B72B /* automation_browser_tracker.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = automation_browser_tracker.h; sourceTree = ""; }; E48FB9630EC4EA270052B72B /* automation_constrained_window_tracker.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = automation_constrained_window_tracker.h; sourceTree = ""; }; @@ -2089,6 +2092,8 @@ 4D7BFBCE0E9D4C9F009A6919 /* logging_chrome.cc */, 4D7BFBCF0E9D4C9F009A6919 /* logging_chrome.h */, 4D7BFBD00E9D4C9F009A6919 /* logging_chrome_uitest.cc */, + B562C8410ED49C830077A23F /* mach_ipc_mac.h */, + B562C8420ED49C830077A23F /* mach_ipc_mac.mm */, 4D7BFBD10E9D4C9F009A6919 /* message_router.cc */, 4D7BFBD20E9D4C9F009A6919 /* message_router.h */, 4D7BFBD30E9D4C9F009A6919 /* mru_cache.h */, @@ -2831,6 +2836,7 @@ 4D7BFC580E9D4D0E009A6919 /* jpeg_codec.cc in Sources */, 4D7BFC4B0E9D4D06009A6919 /* json_value_serializer.cc in Sources */, 4D7BFC540E9D4D09009A6919 /* libxml_utils.cc in Sources */, + B562C8430ED49C830077A23F /* mach_ipc_mac.mm in Sources */, 4D7BFC5C0E9D4D24009A6919 /* notification_service.cc in Sources */, 4D7BFC710E9D4D28009A6919 /* pref_member.cc in Sources */, 4D7BFC7A0E9D4D2B009A6919 /* pref_names.cc in Sources */, 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 -#import -#import -#import +#include +#include +#include +#include -#import +#include + +#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 -#import "chrome/common/mach_ipc_mac.h" +#include "chrome/common/mach_ipc_mac.h" + +#import + +#include +#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(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(padding + desc_size); + reinterpret_cast(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(padding); + reinterpret_cast(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(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(padding); + reinterpret_cast(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(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 -- cgit v1.1