diff options
author | thakis@chromium.org <thakis@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2010-01-12 00:39:15 +0000 |
---|---|---|
committer | thakis@chromium.org <thakis@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2010-01-12 00:39:15 +0000 |
commit | c002879632b0e46b11e91e5595a83652f7cafd3c (patch) | |
tree | 87477d9e6b972292fbb98484ec3721f084ab41c4 /chrome | |
parent | 62ed4d36e4357deaf863711bdfd1f00b367c426a (diff) | |
download | chromium_src-c002879632b0e46b11e91e5595a83652f7cafd3c.zip chromium_src-c002879632b0e46b11e91e5595a83652f7cafd3c.tar.gz chromium_src-c002879632b0e46b11e91e5595a83652f7cafd3c.tar.bz2 |
Mac: Other approach for IPCing child task_ts.
Also move mach_ipc_mac to base, where it's now used.
Based on http://www.foldr.org/~michaelw/log/2009/03/13/ , but uses a named connection instead. Do the IPC right after fork-time, so that the sandbox is not yet in effect.
See the codereview comments for a benchmark that proves that this shouldn't be expensive, and for pros and cons for using a named connection vs temporarily switching out the bootstrap port.
Works for worker processes too and seems more reliable in general.
Measured perf impact in http://src.chromium.org/viewvc/chrome?view=rev&revision=35888 , it's negligible.
BUG=13156
TEST=(requires that one enables the task manager in browser.cc)
1.) Open one tab that plays a youtube video
2.) Open a second and visit http://www.whatwg.org/demos/workers/primes/page.html
3.) Install e.g. the gmail checker extension
4.) Open the task manager
It should report metrics for
* one browser process
* two renderer processes
* one plugin process
* one worker process
* one extension process
Check that %cpu etc more or less match what Activity Monitor displays if you filter for "Chromium".
Also choose "Open all bookmarks" on the bookmarks bar with the task manager open and check that metrics for all tabs appear immediately.
Review URL: http://codereview.chromium.org/549002
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@35977 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'chrome')
-rw-r--r-- | chrome/browser/child_process_launcher.cc | 22 | ||||
-rw-r--r-- | chrome/browser/mach_broker_mac.cc | 73 | ||||
-rw-r--r-- | chrome/browser/mach_broker_mac.h | 16 | ||||
-rw-r--r-- | chrome/common/mach_ipc_mac.h | 321 | ||||
-rw-r--r-- | chrome/common/mach_ipc_mac.mm | 308 |
5 files changed, 106 insertions, 634 deletions
diff --git a/chrome/browser/child_process_launcher.cc b/chrome/browser/child_process_launcher.cc index 1ab66c6..91bc2e6 100644 --- a/chrome/browser/child_process_launcher.cc +++ b/chrome/browser/child_process_launcher.cc @@ -23,6 +23,10 @@ #include "chrome/browser/renderer_host/render_sandbox_host_linux.h" #endif +#if defined(OS_MACOSX) +#include "chrome/browser/mach_broker_mac.h" +#endif + #if defined(OS_POSIX) #include "base/global_descriptors_posix.h" #endif @@ -161,10 +165,24 @@ class ChildProcessLauncher::Context #endif // defined(OS_LINUX) // Actually launch the app. - if (!base::LaunchApp(cmd_line->argv(), env, fds_to_map, false, &handle)) + bool launched; +#if defined(OS_MACOSX) + task_t child_task; + launched = base::LaunchAppAndGetTask( + cmd_line->argv(), env, fds_to_map, false, &child_task, &handle); + if (launched && child_task != MACH_PORT_NULL) { + MachBroker::instance()->RegisterPid( + handle, + MachBroker::MachInfo().SetTask(child_task)); + } +#else + launched = base::LaunchApp(cmd_line->argv(), env, fds_to_map, + /* wait= */false, &handle); +#endif + if (!launched) handle = base::kNullProcessHandle; } -#endif +#endif // else defined(OS_POSIX) ChromeThread::PostTask( client_thread_id_, FROM_HERE, diff --git a/chrome/browser/mach_broker_mac.cc b/chrome/browser/mach_broker_mac.cc index 59f7728..6ae3391 100644 --- a/chrome/browser/mach_broker_mac.cc +++ b/chrome/browser/mach_broker_mac.cc @@ -5,6 +5,44 @@ #include "chrome/browser/mach_broker_mac.h" #include "base/logging.h" +#include "chrome/browser/extensions/extension_host.h" +#include "chrome/browser/renderer_host/render_process_host.h" +#include "chrome/common/child_process_info.h" +#include "chrome/common/notification_service.h" + +// Required because notifications happen on the UI thread. +class RegisterNotificationTask : public Task { + public: + RegisterNotificationTask( + MachBroker* broker) + : broker_(broker) { } + + virtual void Run() { + broker_->registrar_.Add(broker_, + NotificationType::RENDERER_PROCESS_CLOSED, + NotificationService::AllSources()); + broker_->registrar_.Add(broker_, + NotificationType::RENDERER_PROCESS_TERMINATED, + NotificationService::AllSources()); + broker_->registrar_.Add(broker_, + NotificationType::CHILD_PROCESS_CRASHED, + NotificationService::AllSources()); + broker_->registrar_.Add(broker_, + NotificationType::CHILD_PROCESS_HOST_DISCONNECTED, + NotificationService::AllSources()); + broker_->registrar_.Add(broker_, + NotificationType::EXTENSION_PROCESS_TERMINATED, + NotificationService::AllSources()); + } + + private: + MachBroker* broker_; +}; + +MachBroker::MachBroker() { + ChromeThread::PostTask( + ChromeThread::UI, FROM_HERE, new RegisterNotificationTask(this)); +} // Returns the global MachBroker. MachBroker* MachBroker::instance() { @@ -22,7 +60,16 @@ void MachBroker::RegisterPid( // Removes all mappings belonging to |pid| from the broker. void MachBroker::Invalidate(base::ProcessHandle pid) { AutoLock lock(lock_); - mach_map_.erase(pid); + MachBroker::MachMap::iterator it = mach_map_.find(pid); + if (it == mach_map_.end()) + return; + + kern_return_t kr = mach_port_deallocate(mach_task_self(), + it->second.mach_task_); + LOG_IF(WARNING, kr != KERN_SUCCESS) + << "Failed to mach_port_deallocate mach task " << it->second.mach_task_ + << ", error " << kr; + mach_map_.erase(it); } // Returns the mach task belonging to |pid|. @@ -33,3 +80,27 @@ mach_port_t MachBroker::TaskForPid(base::ProcessHandle pid) const { return MACH_PORT_NULL; return it->second.mach_task_; } + +void MachBroker::Observe(NotificationType type, + const NotificationSource& source, + const NotificationDetails& details) { + base::ProcessHandle handle = 0; + switch (type.value) { + case NotificationType::RENDERER_PROCESS_CLOSED: + case NotificationType::RENDERER_PROCESS_TERMINATED: + handle = Source<RenderProcessHost>(source)->GetHandle(); + break; + case NotificationType::EXTENSION_PROCESS_TERMINATED: + handle = + Details<ExtensionHost>(details)->render_process_host()->GetHandle(); + break; + case NotificationType::CHILD_PROCESS_CRASHED: + case NotificationType::CHILD_PROCESS_HOST_DISCONNECTED: + handle = Details<ChildProcessInfo>(details)->handle(); + break; + default: + NOTREACHED() << "Unexpected notification"; + break; + } + Invalidate(handle); +} diff --git a/chrome/browser/mach_broker_mac.h b/chrome/browser/mach_broker_mac.h index 67f4fec..1827fc9 100644 --- a/chrome/browser/mach_broker_mac.h +++ b/chrome/browser/mach_broker_mac.h @@ -13,6 +13,7 @@ #include "base/process.h" #include "base/process_util.h" #include "base/singleton.h" +#include "chrome/common/notification_registrar.h" // On OS X, the mach_port_t of a process is required to collect metrics about // the process. Running |task_for_pid()| is only allowed for privileged code. @@ -28,7 +29,8 @@ // // Since this data arrives over a separate channel, it is not available // immediately after a child process has been started. -class MachBroker : public base::ProcessMetrics::PortProvider { +class MachBroker : public base::ProcessMetrics::PortProvider, + public NotificationObserver { public: // Returns the global MachBroker. static MachBroker* instance(); @@ -53,9 +55,18 @@ class MachBroker : public base::ProcessMetrics::PortProvider { // Implement |ProcessMetrics::PortProvider|. virtual mach_port_t TaskForPid(base::ProcessHandle process) const; + // Implement |NotificationObserver|. + virtual void Observe(NotificationType type, + const NotificationSource& source, + const NotificationDetails& details); private: // Private constructor. - MachBroker() {} + MachBroker(); + + // Used to register for notifications received by NotificationObserver. + // Accessed only on the UI thread. + NotificationRegistrar registrar_; + friend struct DefaultSingletonTraits<MachBroker>; friend class MachBrokerTest; @@ -66,6 +77,7 @@ class MachBroker : public base::ProcessMetrics::PortProvider { // Mutex that guards |mach_map_|. mutable Lock lock_; + friend class RegisterNotificationTask; DISALLOW_COPY_AND_ASSIGN(MachBroker); }; diff --git a/chrome/common/mach_ipc_mac.h b/chrome/common/mach_ipc_mac.h deleted file mode 100644 index 42b9c65..0000000 --- a/chrome/common/mach_ipc_mac.h +++ /dev/null @@ -1,321 +0,0 @@ -// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#ifndef BASE_MACH_IPC_MAC_H_ -#define BASE_MACH_IPC_MAC_H_ - -#include <mach/mach.h> -#include <mach/message.h> -#include <servers/bootstrap.h> -#include <sys/types.h> - -#include <CoreServices/CoreServices.h> - -#include "base/basictypes.h" - -//============================================================================== -// DISCUSSION: -// -// The three main classes of interest are -// -// MachMessage: a wrapper for a mach message of the following form -// mach_msg_header_t -// mach_msg_body_t -// optional descriptors -// optional extra message data -// -// MachReceiveMessage and MachSendMessage subclass MachMessage -// and are used instead of MachMessage which is an abstract base class -// -// ReceivePort: -// Represents a mach port for which we have receive rights -// -// MachPortSender: -// Represents a mach port for which we have send rights -// -// Here's an example to receive a message on a server port: -// -// // This creates our named server port -// ReceivePort receivePort("com.Google.MyService"); -// -// 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); -// } -// -// Here is an example of using these classes to send a message to this port: -// -// // send to already named port -// MachPortSender sender("com.Google.MyService"); -// MachSendMessage message(57); // our message ID is 57 -// -// // 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); -// // timeout 1000ms -// kern_return_t result = sender.SendMessage(message, 1000); -// - -#define PRINT_MACH_RESULT(result_, message_) \ - printf(message_" %s (%d)\n", mach_error_string(result_), result_ ); - -//============================================================================== -// A wrapper class for mach_msg_port_descriptor_t (with same memory layout) -// with convenient constructors and accessors -class MachMsgPortDescriptor : public mach_msg_port_descriptor_t { - public: - // General-purpose constructor - MachMsgPortDescriptor(mach_port_t in_name, - mach_msg_type_name_t in_disposition) { - name = in_name; - pad1 = 0; - pad2 = 0; - disposition = in_disposition; - type = MACH_MSG_PORT_DESCRIPTOR; - } - - // For passing send rights to a port - MachMsgPortDescriptor(mach_port_t in_name) { - name = in_name; - pad1 = 0; - pad2 = 0; - disposition = MACH_MSG_TYPE_PORT_SEND; - type = MACH_MSG_PORT_DESCRIPTOR; - } - - // Copy constructor - MachMsgPortDescriptor(const MachMsgPortDescriptor& desc) { - name = desc.name; - pad1 = desc.pad1; - pad2 = desc.pad2; - disposition = desc.disposition; - type = desc.type; - } - - 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&() { - return *this; - } - - // For convenience - operator mach_port_t() const { - return GetMachPort(); - } -}; - -//============================================================================== -// MachMessage: a wrapper for a mach message -// (mach_msg_header_t, mach_msg_body_t, extra data) -// -// This considerably simplifies the construction of a message for sending -// and the getting at relevant data and descriptors for the receiver. -// -// 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 -// -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); - } - - // The message ID may be used as a code identifying the type of message - 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); - - int GetDescriptorCount() const { - return storage_->body.msgh_descriptor_count; - } - - MachMsgPortDescriptor *GetDescriptor(int n); - - // Convenience method which gets the mach port described by the descriptor - mach_port_t GetTranslatedPort(int n); - - // A simple message is one with no descriptors - bool IsSimpleMessage() const { return GetDescriptorCount() == 0; } - - // Sets raw data for the message (returns false if not enough space) - 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(); - - // Constructor for use with preallocate storage. - // storage_length must be >= EmptyMessageSize() - MachMessage(void *storage, size_t storage_length); - - friend class ReceivePort; - friend class MachPortSender; - - // Represents raw data in our message - struct MessageDataPacket { - int32_t id; // little-endian - int32_t data_length; // little-endian - 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); - - // Returns total message size setting msgh_size in the header to this value - int CalculateSize(); - - // 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. - 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 - -//============================================================================== -class MachReceiveMessage : public MachMessage { - public: - 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); -}; - -//============================================================================== -// Represents a mach port for which we have receive rights -class ReceivePort { - public: - // Creates a new mach port for receiving messages and registers a name for it - ReceivePort(const char *receive_port_name); - - // Given an already existing mach port, use it. We take ownership of the - // port and deallocate it in our destructor. - ReceivePort(mach_port_t receive_port); - - // Create a new mach port for receiving messages - 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: - mach_port_t port_; - kern_return_t init_result_; - - DISALLOW_COPY_AND_ASSIGN(ReceivePort); -}; - -//============================================================================== -// Represents a mach port for which we have send rights -class MachPortSender { - public: - // 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: - 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 deleted file mode 100644 index 7693d9a..0000000 --- a/chrome/common/mach_ipc_mac.mm +++ /dev/null @@ -1,308 +0,0 @@ -// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -#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() { - 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; - - SetDescriptorCount(0); // start out with no descriptors - - SetMessageID(message_id); - SetData(NULL, 0); // client may add data later -} - -//============================================================================== -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(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 > 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; -} - -//============================================================================== -// calculates and returns the total size of the message -// Currently, the entire message MUST fit inside of the 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; - - return size; -} - -//============================================================================== -MachMessage::MessageDataPacket *MachMessage::GetDataPacket() { - int desc_size = sizeof(MachMsgPortDescriptor)*GetDescriptorCount(); - MessageDataPacket *packet = - reinterpret_cast<MessageDataPacket*>(storage_->padding + desc_size); - - return packet; -} - -//============================================================================== -void MachMessage::SetDescriptor(int n, - const MachMsgPortDescriptor &desc) { - MachMsgPortDescriptor *desc_array = - reinterpret_cast<MachMsgPortDescriptor*>(storage_->padding); - desc_array[n] = desc; -} - -//============================================================================== -// returns true if successful otherwise there was not enough space -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 > storage_length_bytes_) { - return false; // not enough space - } - - // unfortunately, we need to move the data to allow space for the - // 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) { - storage_->body.msgh_descriptor_count = n; - - if (n > 0) { - Head()->msgh_bits |= MACH_MSGH_BITS_COMPLEX; - } else { - Head()->msgh_bits &= ~MACH_MSGH_BITS_COMPLEX; - } -} - -//============================================================================== -MachMsgPortDescriptor *MachMessage::GetDescriptor(int n) { - if (n < GetDescriptorCount()) { - MachMsgPortDescriptor *desc = - reinterpret_cast<MachMsgPortDescriptor*>(storage_->padding); - return desc + n; - } - - return nil; -} - -//============================================================================== -mach_port_t MachMessage::GetTranslatedPort(int n) { - if (n < GetDescriptorCount()) { - return GetDescriptor(n)->GetMachPort(); - } - return MACH_PORT_NULL; -} - -#pragma mark - - -//============================================================================== -// create a new mach port for receiving messages and register a name for it -ReceivePort::ReceivePort(const char *receive_port_name) { - mach_port_t current_task = mach_task_self(); - - init_result_ = mach_port_allocate(current_task, - MACH_PORT_RIGHT_RECEIVE, - &port_); - - if (init_result_ != KERN_SUCCESS) - return; - - init_result_ = mach_port_insert_right(current_task, - port_, - port_, - MACH_MSG_TYPE_MAKE_SEND); - - if (init_result_ != KERN_SUCCESS) - return; - - NSPort *ns_port = [NSMachPort portWithMachPort:port_]; - NSString *port_name = [NSString stringWithUTF8String:receive_port_name]; - [[NSMachBootstrapServer sharedInstance] registerPort:ns_port name:port_name]; -} - -//============================================================================== -// create a new mach port for receiving messages -ReceivePort::ReceivePort() { - mach_port_t current_task = mach_task_self(); - - init_result_ = mach_port_allocate(current_task, - MACH_PORT_RIGHT_RECEIVE, - &port_); - - if (init_result_ != KERN_SUCCESS) - return; - - init_result_ = mach_port_insert_right(current_task, - port_, - port_, - MACH_MSG_TYPE_MAKE_SEND); -} - -//============================================================================== -// Given an already existing mach port, use it. We take ownership of the -// port and deallocate it in our destructor. -ReceivePort::ReceivePort(mach_port_t receive_port) - : port_(receive_port), - init_result_(KERN_SUCCESS) { -} - -//============================================================================== -ReceivePort::~ReceivePort() { - if (init_result_ == KERN_SUCCESS) - mach_port_deallocate(mach_task_self(), port_); -} - -//============================================================================== -kern_return_t ReceivePort::WaitForMessage(MachReceiveMessage *out_message, - mach_msg_timeout_t timeout) { - if (!out_message) { - return KERN_INVALID_ARGUMENT; - } - - // 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(), - MACH_RCV_MSG | MACH_RCV_TIMEOUT, - 0, - out_message->MaxSize(), - port_, - timeout, // timeout in ms - MACH_PORT_NULL); - - return result; -} - -#pragma mark - - -//============================================================================== -// get a port with send rights corresponding to a named registered service -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; - - init_result_ = bootstrap_look_up(bootstrap_port, - const_cast<char*>(receive_port_name), - &send_port_); -} - -//============================================================================== -MachPortSender::MachPortSender(mach_port_t send_port) - : send_port_(send_port), - init_result_(KERN_SUCCESS) { -} - -//============================================================================== -kern_return_t MachPortSender::SendMessage(MachSendMessage &message, - mach_msg_timeout_t timeout) { - 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(), - MACH_SEND_MSG | MACH_SEND_TIMEOUT, - message.Head()->msgh_size, - 0, - MACH_PORT_NULL, - timeout, // timeout in ms - MACH_PORT_NULL); - - return result; -} |