Disable crashing tests, my previous checkin to mark them flaky did not help.
[chromium-blink-merge.git] / base / mach_ipc_mac.mm
blobb6dedd2b89190b7cea5dba167105c77db155e818
1 // Copyright (c) 2011 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
5 #include "base/mach_ipc_mac.h"
7 #import <Foundation/Foundation.h>
9 #include <stdio.h>
10 #include "base/logging.h"
12 namespace base {
14 // static
15 const size_t MachMessage::kEmptyMessageSize = sizeof(mach_msg_header_t) +
16     sizeof(mach_msg_body_t) + sizeof(MessageDataPacket);
18 //==============================================================================
19 MachSendMessage::MachSendMessage(int32_t message_id) : MachMessage() {
20   Initialize(message_id);
23 MachSendMessage::MachSendMessage(void *storage, size_t storage_length,
24                                  int32_t message_id)
25     : MachMessage(storage, storage_length) {
26   Initialize(message_id);
29 void MachSendMessage::Initialize(int32_t message_id) {
30   Head()->msgh_bits = MACH_MSGH_BITS(MACH_MSG_TYPE_COPY_SEND, 0);
32   // head.msgh_remote_port = ...; // filled out in MachPortSender::SendMessage()
33   Head()->msgh_local_port = MACH_PORT_NULL;
34   Head()->msgh_reserved = 0;
35   Head()->msgh_id = 0;
37   SetDescriptorCount(0);  // start out with no descriptors
39   SetMessageID(message_id);
40   SetData(NULL, 0);       // client may add data later
43 //==============================================================================
44 MachMessage::MachMessage()
45     : storage_(new MachMessageData),  // Allocate storage_ ourselves
46       storage_length_bytes_(sizeof(MachMessageData)),
47       own_storage_(true) {
48   memset(storage_, 0, storage_length_bytes_);
51 //==============================================================================
52 MachMessage::MachMessage(void *storage, size_t storage_length)
53     : storage_(static_cast<MachMessageData*>(storage)),
54       storage_length_bytes_(storage_length),
55       own_storage_(false) {
56   DCHECK(storage);
57   DCHECK_GE(storage_length, kEmptyMessageSize);
60 //==============================================================================
61 MachMessage::~MachMessage() {
62   if (own_storage_) {
63     delete storage_;
64     storage_ = NULL;
65   }
68 //==============================================================================
69 // returns true if successful
70 bool MachMessage::SetData(const void* data,
71                           int32_t data_length) {
72   // Enforce the fact that it's only safe to call this method once on a
73   // message.
74   DCHECK(GetDataPacket()->data_length == 0);
76   // first check to make sure we have enough space
77   int size = CalculateSize();
78   int new_size = size + data_length;
80   if ((unsigned)new_size > storage_length_bytes_) {
81     return false;  // not enough space
82   }
84   GetDataPacket()->data_length = EndianU32_NtoL(data_length);
85   if (data) memcpy(GetDataPacket()->data, data, data_length);
87   // Update the Mach header with the new aligned size of the message.
88   CalculateSize();
90   return true;
93 //==============================================================================
94 // calculates and returns the total size of the message
95 // Currently, the entire message MUST fit inside of the MachMessage
96 //    messsage size <= EmptyMessageSize()
97 int MachMessage::CalculateSize() {
98   int size = sizeof(mach_msg_header_t) + sizeof(mach_msg_body_t);
100   // add space for MessageDataPacket
101   int32_t alignedDataLength = (GetDataLength() + 3) & ~0x3;
102   size += 2*sizeof(int32_t) + alignedDataLength;
104   // add space for descriptors
105   size += GetDescriptorCount() * sizeof(MachMsgPortDescriptor);
107   Head()->msgh_size = size;
109   return size;
112 //==============================================================================
113 MachMessage::MessageDataPacket *MachMessage::GetDataPacket() {
114   int desc_size = sizeof(MachMsgPortDescriptor)*GetDescriptorCount();
115   MessageDataPacket *packet =
116     reinterpret_cast<MessageDataPacket*>(storage_->padding + desc_size);
118   return packet;
121 //==============================================================================
122 void MachMessage::SetDescriptor(int n,
123                                 const MachMsgPortDescriptor &desc) {
124   MachMsgPortDescriptor *desc_array =
125     reinterpret_cast<MachMsgPortDescriptor*>(storage_->padding);
126   desc_array[n] = desc;
129 //==============================================================================
130 // returns true if successful otherwise there was not enough space
131 bool MachMessage::AddDescriptor(const MachMsgPortDescriptor &desc) {
132   // first check to make sure we have enough space
133   int size = CalculateSize();
134   int new_size = size + sizeof(MachMsgPortDescriptor);
136   if ((unsigned)new_size > storage_length_bytes_) {
137     return false;  // not enough space
138   }
140   // unfortunately, we need to move the data to allow space for the
141   // new descriptor
142   u_int8_t *p = reinterpret_cast<u_int8_t*>(GetDataPacket());
143   bcopy(p, p+sizeof(MachMsgPortDescriptor), GetDataLength()+2*sizeof(int32_t));
145   SetDescriptor(GetDescriptorCount(), desc);
146   SetDescriptorCount(GetDescriptorCount() + 1);
148   CalculateSize();
150   return true;
153 //==============================================================================
154 void MachMessage::SetDescriptorCount(int n) {
155   storage_->body.msgh_descriptor_count = n;
157   if (n > 0) {
158     Head()->msgh_bits |= MACH_MSGH_BITS_COMPLEX;
159   } else {
160     Head()->msgh_bits &= ~MACH_MSGH_BITS_COMPLEX;
161   }
164 //==============================================================================
165 MachMsgPortDescriptor *MachMessage::GetDescriptor(int n) {
166   if (n < GetDescriptorCount()) {
167     MachMsgPortDescriptor *desc =
168         reinterpret_cast<MachMsgPortDescriptor*>(storage_->padding);
169     return desc + n;
170   }
172   return nil;
175 //==============================================================================
176 mach_port_t MachMessage::GetTranslatedPort(int n) {
177   if (n < GetDescriptorCount()) {
178     return GetDescriptor(n)->GetMachPort();
179   }
180   return MACH_PORT_NULL;
183 #pragma mark -
185 //==============================================================================
186 // create a new mach port for receiving messages and register a name for it
187 ReceivePort::ReceivePort(const char *receive_port_name) {
188   mach_port_t current_task = mach_task_self();
190   init_result_ = mach_port_allocate(current_task,
191                                     MACH_PORT_RIGHT_RECEIVE,
192                                     &port_);
194   if (init_result_ != KERN_SUCCESS)
195     return;
197   init_result_ = mach_port_insert_right(current_task,
198                                         port_,
199                                         port_,
200                                         MACH_MSG_TYPE_MAKE_SEND);
202   if (init_result_ != KERN_SUCCESS)
203     return;
205   // Without |NSMachPortDeallocateNone|, the NSMachPort seems to deallocate
206   // receive rights on port when it is eventually released.  It is not necessary
207   // to deallocate any rights here as |port_| is fully deallocated in the
208   // ReceivePort destructor.
209   NSPort *ns_port = [NSMachPort portWithMachPort:port_
210                                          options:NSMachPortDeallocateNone];
211   NSString *port_name = [NSString stringWithUTF8String:receive_port_name];
212   [[NSMachBootstrapServer sharedInstance] registerPort:ns_port name:port_name];
215 //==============================================================================
216 // create a new mach port for receiving messages
217 ReceivePort::ReceivePort() {
218   mach_port_t current_task = mach_task_self();
220   init_result_ = mach_port_allocate(current_task,
221                                     MACH_PORT_RIGHT_RECEIVE,
222                                     &port_);
224   if (init_result_ != KERN_SUCCESS)
225     return;
227   init_result_ = mach_port_insert_right(current_task,
228                                         port_,
229                                         port_,
230                                         MACH_MSG_TYPE_MAKE_SEND);
233 //==============================================================================
234 // Given an already existing mach port, use it.  We take ownership of the
235 // port and deallocate it in our destructor.
236 ReceivePort::ReceivePort(mach_port_t receive_port)
237   : port_(receive_port),
238     init_result_(KERN_SUCCESS) {
241 //==============================================================================
242 ReceivePort::~ReceivePort() {
243   if (init_result_ == KERN_SUCCESS)
244     mach_port_deallocate(mach_task_self(), port_);
247 //==============================================================================
248 kern_return_t ReceivePort::WaitForMessage(MachReceiveMessage *out_message,
249                                           mach_msg_timeout_t timeout) {
250   if (!out_message) {
251     return KERN_INVALID_ARGUMENT;
252   }
254   // return any error condition encountered in constructor
255   if (init_result_ != KERN_SUCCESS)
256     return init_result_;
258   out_message->Head()->msgh_bits = 0;
259   out_message->Head()->msgh_local_port = port_;
260   out_message->Head()->msgh_remote_port = MACH_PORT_NULL;
261   out_message->Head()->msgh_reserved = 0;
262   out_message->Head()->msgh_id = 0;
264   mach_msg_option_t rcv_options = MACH_RCV_MSG;
265   if (timeout != MACH_MSG_TIMEOUT_NONE)
266     rcv_options |= MACH_RCV_TIMEOUT;
268   kern_return_t result = mach_msg(out_message->Head(),
269                                   rcv_options,
270                                   0,
271                                   out_message->MaxSize(),
272                                   port_,
273                                   timeout,              // timeout in ms
274                                   MACH_PORT_NULL);
276   return result;
279 #pragma mark -
281 //==============================================================================
282 // get a port with send rights corresponding to a named registered service
283 MachPortSender::MachPortSender(const char *receive_port_name) {
284   mach_port_t bootstrap_port = 0;
285   init_result_ = task_get_bootstrap_port(mach_task_self(), &bootstrap_port);
287   if (init_result_ != KERN_SUCCESS)
288     return;
290   init_result_ = bootstrap_look_up(bootstrap_port,
291                     const_cast<char*>(receive_port_name),
292                     &send_port_);
295 //==============================================================================
296 MachPortSender::MachPortSender(mach_port_t send_port)
297   : send_port_(send_port),
298     init_result_(KERN_SUCCESS) {
301 //==============================================================================
302 kern_return_t MachPortSender::SendMessage(MachSendMessage &message,
303                                           mach_msg_timeout_t timeout) {
304   if (message.Head()->msgh_size == 0) {
305     NOTREACHED();
306     return KERN_INVALID_VALUE;    // just for safety -- never should occur
307   };
309   if (init_result_ != KERN_SUCCESS)
310     return init_result_;
312   message.Head()->msgh_remote_port = send_port_;
314   kern_return_t result = mach_msg(message.Head(),
315                                   MACH_SEND_MSG | MACH_SEND_TIMEOUT,
316                                   message.Head()->msgh_size,
317                                   0,
318                                   MACH_PORT_NULL,
319                                   timeout,              // timeout in ms
320                                   MACH_PORT_NULL);
322   return result;
325 }  // namespace base