mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
bug 1161166 - Use mach shared memory for shared memory on OSX r=billm
This commit is contained in:
parent
e95e2935c2
commit
99e1dd3dad
@ -274,6 +274,9 @@ class ReceivePort {
|
|||||||
kern_return_t WaitForMessage(MachReceiveMessage *out_message,
|
kern_return_t WaitForMessage(MachReceiveMessage *out_message,
|
||||||
mach_msg_timeout_t timeout);
|
mach_msg_timeout_t timeout);
|
||||||
|
|
||||||
|
kern_return_t SendMessageToSelf(MachSendMessage& msg,
|
||||||
|
mach_msg_timeout_t timeout);
|
||||||
|
|
||||||
// The underlying mach port that we wrap
|
// The underlying mach port that we wrap
|
||||||
mach_port_t GetPort() const { return port_; }
|
mach_port_t GetPort() const { return port_; }
|
||||||
|
|
||||||
|
@ -266,7 +266,7 @@ kern_return_t ReceivePort::WaitForMessage(MachReceiveMessage *out_message,
|
|||||||
out_message->Head()->msgh_id = 0;
|
out_message->Head()->msgh_id = 0;
|
||||||
|
|
||||||
kern_return_t result = mach_msg(out_message->Head(),
|
kern_return_t result = mach_msg(out_message->Head(),
|
||||||
MACH_RCV_MSG | MACH_RCV_TIMEOUT,
|
MACH_RCV_MSG | (timeout == MACH_MSG_TIMEOUT_NONE ? 0 : MACH_RCV_TIMEOUT),
|
||||||
0,
|
0,
|
||||||
out_message->MaxSize(),
|
out_message->MaxSize(),
|
||||||
port_,
|
port_,
|
||||||
@ -276,6 +276,34 @@ kern_return_t ReceivePort::WaitForMessage(MachReceiveMessage *out_message,
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//==============================================================================
|
||||||
|
// send a message to this port
|
||||||
|
kern_return_t ReceivePort::SendMessageToSelf(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 = port_;
|
||||||
|
message.Head()->msgh_bits
|
||||||
|
= MACH_MSGH_BITS (MACH_MSG_TYPE_MAKE_SEND,
|
||||||
|
MACH_MSG_TYPE_MAKE_SEND_ONCE);
|
||||||
|
kern_return_t result = mach_msg(message.Head(),
|
||||||
|
MACH_SEND_MSG | (timeout == MACH_MSG_TIMEOUT_NONE ? 0 : MACH_SEND_TIMEOUT),
|
||||||
|
message.Head()->msgh_size,
|
||||||
|
0,
|
||||||
|
MACH_PORT_NULL,
|
||||||
|
timeout, // timeout in ms
|
||||||
|
MACH_PORT_NULL);
|
||||||
|
|
||||||
|
return result;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
#pragma mark -
|
#pragma mark -
|
||||||
|
|
||||||
//==============================================================================
|
//==============================================================================
|
||||||
@ -312,7 +340,7 @@ kern_return_t MachPortSender::SendMessage(MachSendMessage &message,
|
|||||||
message.Head()->msgh_remote_port = send_port_;
|
message.Head()->msgh_remote_port = send_port_;
|
||||||
|
|
||||||
kern_return_t result = mach_msg(message.Head(),
|
kern_return_t result = mach_msg(message.Head(),
|
||||||
MACH_SEND_MSG | MACH_SEND_TIMEOUT,
|
MACH_SEND_MSG | (timeout == MACH_MSG_TIMEOUT_NONE ? 0 : MACH_SEND_TIMEOUT),
|
||||||
message.Head()->msgh_size,
|
message.Head()->msgh_size,
|
||||||
0,
|
0,
|
||||||
MACH_PORT_NULL,
|
MACH_PORT_NULL,
|
||||||
|
@ -14,6 +14,7 @@
|
|||||||
#include "chrome/common/mach_ipc_mac.h"
|
#include "chrome/common/mach_ipc_mac.h"
|
||||||
#include "base/rand_util.h"
|
#include "base/rand_util.h"
|
||||||
#include "nsILocalFileMac.h"
|
#include "nsILocalFileMac.h"
|
||||||
|
#include "SharedMemoryBasic.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include "MainThreadUtils.h"
|
#include "MainThreadUtils.h"
|
||||||
@ -119,12 +120,16 @@ GeckoChildProcessHost::~GeckoChildProcessHost()
|
|||||||
|
|
||||||
MOZ_COUNT_DTOR(GeckoChildProcessHost);
|
MOZ_COUNT_DTOR(GeckoChildProcessHost);
|
||||||
|
|
||||||
if (mChildProcessHandle > 0)
|
if (mChildProcessHandle > 0) {
|
||||||
|
#if defined(MOZ_WIDGET_COCOA)
|
||||||
|
SharedMemoryBasic::CleanupForPid(mChildProcessHandle);
|
||||||
|
#endif
|
||||||
ProcessWatcher::EnsureProcessTerminated(mChildProcessHandle
|
ProcessWatcher::EnsureProcessTerminated(mChildProcessHandle
|
||||||
#if defined(NS_BUILD_REFCNT_LOGGING)
|
#if defined(NS_BUILD_REFCNT_LOGGING)
|
||||||
, false // don't "force"
|
, false // don't "force"
|
||||||
#endif
|
#endif
|
||||||
);
|
);
|
||||||
|
}
|
||||||
|
|
||||||
#if defined(MOZ_WIDGET_COCOA)
|
#if defined(MOZ_WIDGET_COCOA)
|
||||||
if (mChildTask != MACH_PORT_NULL)
|
if (mChildTask != MACH_PORT_NULL)
|
||||||
@ -783,18 +788,44 @@ GeckoChildProcessHost::PerformAsyncLaunchInternal(std::vector<std::string>& aExt
|
|||||||
}
|
}
|
||||||
MachPortSender parent_sender(child_message.GetTranslatedPort(1));
|
MachPortSender parent_sender(child_message.GetTranslatedPort(1));
|
||||||
|
|
||||||
|
if (child_message.GetTranslatedPort(2) == MACH_PORT_NULL) {
|
||||||
|
CHROMIUM_LOG(ERROR) << "parent GetTranslatedPort(2) failed.";
|
||||||
|
}
|
||||||
|
MachPortSender* parent_recv_port_memory_ack = new MachPortSender(child_message.GetTranslatedPort(2));
|
||||||
|
|
||||||
|
if (child_message.GetTranslatedPort(3) == MACH_PORT_NULL) {
|
||||||
|
CHROMIUM_LOG(ERROR) << "parent GetTranslatedPort(3) failed.";
|
||||||
|
}
|
||||||
|
MachPortSender* parent_send_port_memory = new MachPortSender(child_message.GetTranslatedPort(3));
|
||||||
|
|
||||||
MachSendMessage parent_message(/* id= */0);
|
MachSendMessage parent_message(/* id= */0);
|
||||||
if (!parent_message.AddDescriptor(MachMsgPortDescriptor(bootstrap_port))) {
|
if (!parent_message.AddDescriptor(MachMsgPortDescriptor(bootstrap_port))) {
|
||||||
CHROMIUM_LOG(ERROR) << "parent AddDescriptor(" << bootstrap_port << ") failed.";
|
CHROMIUM_LOG(ERROR) << "parent AddDescriptor(" << bootstrap_port << ") failed.";
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ReceivePort* parent_recv_port_memory = new ReceivePort();
|
||||||
|
if (!parent_message.AddDescriptor(MachMsgPortDescriptor(parent_recv_port_memory->GetPort()))) {
|
||||||
|
CHROMIUM_LOG(ERROR) << "parent AddDescriptor(" << parent_recv_port_memory->GetPort() << ") failed.";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
ReceivePort* parent_send_port_memory_ack = new ReceivePort();
|
||||||
|
if (!parent_message.AddDescriptor(MachMsgPortDescriptor(parent_send_port_memory_ack->GetPort()))) {
|
||||||
|
CHROMIUM_LOG(ERROR) << "parent AddDescriptor(" << parent_send_port_memory_ack->GetPort() << ") failed.";
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
err = parent_sender.SendMessage(parent_message, kTimeoutMs);
|
err = parent_sender.SendMessage(parent_message, kTimeoutMs);
|
||||||
if (err != KERN_SUCCESS) {
|
if (err != KERN_SUCCESS) {
|
||||||
std::string errString = StringPrintf("0x%x %s", err, mach_error_string(err));
|
std::string errString = StringPrintf("0x%x %s", err, mach_error_string(err));
|
||||||
CHROMIUM_LOG(ERROR) << "parent SendMessage() failed: " << errString;
|
CHROMIUM_LOG(ERROR) << "parent SendMessage() failed: " << errString;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
SharedMemoryBasic::SetupMachMemory(process, parent_recv_port_memory, parent_recv_port_memory_ack,
|
||||||
|
parent_send_port_memory, parent_send_port_memory_ack, false);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
//--------------------------------------------------
|
//--------------------------------------------------
|
||||||
|
@ -10,6 +10,8 @@
|
|||||||
|
|
||||||
#ifdef ANDROID
|
#ifdef ANDROID
|
||||||
# include "mozilla/ipc/SharedMemoryBasic_android.h"
|
# include "mozilla/ipc/SharedMemoryBasic_android.h"
|
||||||
|
#elif defined(XP_MACOSX)
|
||||||
|
# include "mozilla/ipc/SharedMemoryBasic_mach.h"
|
||||||
#else
|
#else
|
||||||
# include "mozilla/ipc/SharedMemoryBasic_chromium.h"
|
# include "mozilla/ipc/SharedMemoryBasic_chromium.h"
|
||||||
#endif
|
#endif
|
||||||
|
623
ipc/glue/SharedMemoryBasic_mach.cpp
Normal file
623
ipc/glue/SharedMemoryBasic_mach.cpp
Normal file
@ -0,0 +1,623 @@
|
|||||||
|
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
|
||||||
|
* vim: sw=2 ts=8 et :
|
||||||
|
*/
|
||||||
|
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||||
|
|
||||||
|
#include <map>
|
||||||
|
|
||||||
|
#include <mach/vm_map.h>
|
||||||
|
#include <mach/mach_port.h>
|
||||||
|
#include <mach/mach_vm.h>
|
||||||
|
#include "SharedMemoryBasic.h"
|
||||||
|
#include "chrome/common/mach_ipc_mac.h"
|
||||||
|
|
||||||
|
#include "mozilla/StaticMutex.h"
|
||||||
|
|
||||||
|
#ifdef DEBUG
|
||||||
|
#define LOG_ERROR(str, args...) \
|
||||||
|
PR_BEGIN_MACRO \
|
||||||
|
char *msg = PR_smprintf(str, ## args); \
|
||||||
|
NS_WARNING(msg); \
|
||||||
|
PR_smprintf_free(msg); \
|
||||||
|
PR_END_MACRO
|
||||||
|
#else
|
||||||
|
#define LOG_ERROR(str, args...) do { /* nothing */ } while(0)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define CHECK_MACH_ERROR(kr, msg) \
|
||||||
|
PR_BEGIN_MACRO \
|
||||||
|
if (kr != KERN_SUCCESS) { \
|
||||||
|
LOG_ERROR("%s %s (%x)\n", msg, mach_error_string(kr), kr); \
|
||||||
|
return false; \
|
||||||
|
} \
|
||||||
|
PR_END_MACRO
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This code is responsible for sharing memory between processes. Memory can be
|
||||||
|
* shared between parent and child or between two children. Each memory region is
|
||||||
|
* referenced via a Mach port. Mach ports are also used for messaging when
|
||||||
|
* sharing a memory region.
|
||||||
|
*
|
||||||
|
* When the parent starts a child, it starts a thread whose only purpose is to
|
||||||
|
* communicate with the child about shared memory. Once the child has started,
|
||||||
|
* it starts a similar thread for communicating with the parent. Each side can
|
||||||
|
* communicate with the thread on the other side via Mach ports. When either
|
||||||
|
* side wants to share memory with the other, it sends a Mach message to the
|
||||||
|
* other side. Attached to the message is the port that references the shared
|
||||||
|
* memory region. When the other side receives the message, it automatically
|
||||||
|
* gets access to the region. It sends a reply (also via a Mach port) so that
|
||||||
|
* the originating side can continue.
|
||||||
|
*
|
||||||
|
* The two sides communicate using four ports. Two ports are used when the
|
||||||
|
* parent shares memory with the child. The other two are used when the child
|
||||||
|
* shares memory with the parent. One of these two ports is used for sending the
|
||||||
|
* "share" message and the other is used for the reply.
|
||||||
|
*
|
||||||
|
* If a child wants to share memory with another child, it sends a "GetPorts"
|
||||||
|
* message to the parent. The parent forwards this GetPorts message to the
|
||||||
|
* target child. The message includes some ports so that the children can talk
|
||||||
|
* directly. Both children start up a thread to communicate with the other child,
|
||||||
|
* similar to the way parent and child communicate. In the future, when these
|
||||||
|
* two children want to communicate, they re-use the channels that were created.
|
||||||
|
*
|
||||||
|
* When a child shuts down, the parent notifies all other children. Those
|
||||||
|
* children then have the opportunity to shut down any threads they might have
|
||||||
|
* been using to communicate directly with that child.
|
||||||
|
*/
|
||||||
|
|
||||||
|
namespace mozilla {
|
||||||
|
namespace ipc {
|
||||||
|
|
||||||
|
struct MemoryPorts {
|
||||||
|
MachPortSender* mSender;
|
||||||
|
ReceivePort* mReceiver;
|
||||||
|
|
||||||
|
MemoryPorts() {}
|
||||||
|
MemoryPorts(MachPortSender* sender, ReceivePort* receiver)
|
||||||
|
: mSender(sender), mReceiver(receiver) {}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Protects gMemoryCommPorts and gThreads.
|
||||||
|
static StaticMutex gMutex;
|
||||||
|
|
||||||
|
static std::map<pid_t, MemoryPorts> gMemoryCommPorts;
|
||||||
|
|
||||||
|
enum {
|
||||||
|
kGetPortsMsg = 1,
|
||||||
|
kSharePortsMsg,
|
||||||
|
kReturnIdMsg,
|
||||||
|
kReturnPortsMsg,
|
||||||
|
kShutdownMsg,
|
||||||
|
kCleanupMsg,
|
||||||
|
};
|
||||||
|
|
||||||
|
const int kTimeout = 1000;
|
||||||
|
|
||||||
|
pid_t gParentPid = 0;
|
||||||
|
|
||||||
|
struct PIDPair {
|
||||||
|
pid_t mRequester;
|
||||||
|
pid_t mRequested;
|
||||||
|
|
||||||
|
PIDPair(pid_t requester, pid_t requested)
|
||||||
|
: mRequester(requester), mRequested(requested) {}
|
||||||
|
};
|
||||||
|
|
||||||
|
struct ListeningThread {
|
||||||
|
pthread_t mThread;
|
||||||
|
MemoryPorts* mPorts;
|
||||||
|
|
||||||
|
ListeningThread() {}
|
||||||
|
ListeningThread(pthread_t thread, MemoryPorts* ports)
|
||||||
|
: mThread(thread), mPorts(ports) {}
|
||||||
|
};
|
||||||
|
|
||||||
|
std::map<pid_t, ListeningThread> gThreads;
|
||||||
|
|
||||||
|
static void *
|
||||||
|
PortServerThread(void *argument);
|
||||||
|
|
||||||
|
|
||||||
|
static void
|
||||||
|
SetupMachMemory(pid_t pid,
|
||||||
|
ReceivePort* listen_port,
|
||||||
|
MachPortSender* listen_port_ack,
|
||||||
|
MachPortSender* send_port,
|
||||||
|
ReceivePort* send_port_ack,
|
||||||
|
bool pidIsParent)
|
||||||
|
{
|
||||||
|
if (pidIsParent) {
|
||||||
|
gParentPid = pid;
|
||||||
|
}
|
||||||
|
MemoryPorts* listen_ports = new MemoryPorts(listen_port_ack, listen_port);
|
||||||
|
pthread_t thread;
|
||||||
|
int err = pthread_create(&thread, nullptr, PortServerThread, listen_ports);
|
||||||
|
if (err) {
|
||||||
|
LOG_ERROR("pthread_create failed with %x\n", err);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
gMutex.AssertCurrentThreadOwns();
|
||||||
|
gThreads[pid] = ListeningThread(thread, listen_ports);
|
||||||
|
gMemoryCommPorts[pid] = MemoryPorts(send_port, send_port_ack);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Send two communication ports to another process along with the pid of the process that is
|
||||||
|
// listening on them.
|
||||||
|
bool
|
||||||
|
SendPortsMessage(MachPortSender* sender,
|
||||||
|
mach_port_t ports_in_receiver,
|
||||||
|
mach_port_t ports_out_receiver,
|
||||||
|
PIDPair pid_pair)
|
||||||
|
{
|
||||||
|
MachSendMessage getPortsMsg(kGetPortsMsg);
|
||||||
|
if (!getPortsMsg.AddDescriptor(MachMsgPortDescriptor(ports_in_receiver))) {
|
||||||
|
LOG_ERROR("Adding descriptor to message failed");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (!getPortsMsg.AddDescriptor(MachMsgPortDescriptor(ports_out_receiver))) {
|
||||||
|
LOG_ERROR("Adding descriptor to message failed");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
getPortsMsg.SetData(&pid_pair, sizeof(PIDPair));
|
||||||
|
kern_return_t err = sender->SendMessage(getPortsMsg, kTimeout);
|
||||||
|
if (KERN_SUCCESS != err) {
|
||||||
|
LOG_ERROR("Error sending get ports message %s (%x)\n", mach_error_string(err), err);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Receive two communication ports from another process
|
||||||
|
bool
|
||||||
|
RecvPortsMessage(ReceivePort* receiver, mach_port_t* ports_in_sender, mach_port_t* ports_out_sender)
|
||||||
|
{
|
||||||
|
MachReceiveMessage rcvPortsMsg;
|
||||||
|
kern_return_t err = receiver->WaitForMessage(&rcvPortsMsg, kTimeout);
|
||||||
|
if (KERN_SUCCESS != err) {
|
||||||
|
LOG_ERROR("Error receiving get ports message %s (%x)\n", mach_error_string(err), err);
|
||||||
|
}
|
||||||
|
if (rcvPortsMsg.GetTranslatedPort(0) == MACH_PORT_NULL) {
|
||||||
|
LOG_ERROR("GetTranslatedPort(0) failed");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
*ports_in_sender = rcvPortsMsg.GetTranslatedPort(0);
|
||||||
|
|
||||||
|
if (rcvPortsMsg.GetTranslatedPort(1) == MACH_PORT_NULL) {
|
||||||
|
LOG_ERROR("GetTranslatedPort(1) failed");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
*ports_out_sender = rcvPortsMsg.GetTranslatedPort(1);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Send two communication ports to another process and receive two back
|
||||||
|
bool
|
||||||
|
RequestPorts(const MemoryPorts& request_ports,
|
||||||
|
mach_port_t ports_in_receiver,
|
||||||
|
mach_port_t* ports_in_sender,
|
||||||
|
mach_port_t* ports_out_sender,
|
||||||
|
mach_port_t ports_out_receiver,
|
||||||
|
PIDPair pid_pair)
|
||||||
|
{
|
||||||
|
if (!SendPortsMessage(request_ports.mSender, ports_in_receiver, ports_out_receiver, pid_pair)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return RecvPortsMessage(request_ports.mReceiver, ports_in_sender, ports_out_sender);
|
||||||
|
}
|
||||||
|
|
||||||
|
MemoryPorts*
|
||||||
|
GetMemoryPortsForPid(pid_t pid)
|
||||||
|
{
|
||||||
|
gMutex.AssertCurrentThreadOwns();
|
||||||
|
|
||||||
|
if (gMemoryCommPorts.find(pid) == gMemoryCommPorts.end()) {
|
||||||
|
// We don't have the ports open to communicate with that pid, so we're going to
|
||||||
|
// ask our parent process over IPC to set them up for us.
|
||||||
|
if (gParentPid == 0) {
|
||||||
|
// If we're the top level parent process, we have no parent to ask.
|
||||||
|
LOG_ERROR("request for ports for pid %d, but we're the chrome process\n", pid);
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
const MemoryPorts& parent = gMemoryCommPorts[gParentPid];
|
||||||
|
|
||||||
|
// Create two receiving ports in this process to send to the parent. One will be used for
|
||||||
|
// for listening for incoming memory to be shared, the other for getting the Handle of
|
||||||
|
// memory we share to the other process.
|
||||||
|
ReceivePort* ports_in_receiver = new ReceivePort();
|
||||||
|
ReceivePort* ports_out_receiver = new ReceivePort();
|
||||||
|
mach_port_t raw_ports_in_sender, raw_ports_out_sender;
|
||||||
|
if (!RequestPorts(parent,
|
||||||
|
ports_in_receiver->GetPort(),
|
||||||
|
&raw_ports_in_sender,
|
||||||
|
&raw_ports_out_sender,
|
||||||
|
ports_out_receiver->GetPort(),
|
||||||
|
PIDPair(getpid(), pid))) {
|
||||||
|
LOG_ERROR("failed to request ports\n");
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
// Our parent process sent us two ports, one is for sending new memory to, the other
|
||||||
|
// is for replying with the Handle when we receive new memory.
|
||||||
|
MachPortSender* ports_in_sender = new MachPortSender(raw_ports_in_sender);
|
||||||
|
MachPortSender* ports_out_sender = new MachPortSender(raw_ports_out_sender);
|
||||||
|
SetupMachMemory(pid,
|
||||||
|
ports_in_receiver,
|
||||||
|
ports_in_sender,
|
||||||
|
ports_out_sender,
|
||||||
|
ports_out_receiver,
|
||||||
|
false);
|
||||||
|
MOZ_ASSERT(gMemoryCommPorts.find(pid) != gMemoryCommPorts.end());
|
||||||
|
}
|
||||||
|
return &gMemoryCommPorts.at(pid);
|
||||||
|
}
|
||||||
|
|
||||||
|
// We just received a port representing a region of shared memory, reply to
|
||||||
|
// the process that set it with the mach_port_t that represents it in this process.
|
||||||
|
// That will be the Handle to be shared over normal IPC
|
||||||
|
void
|
||||||
|
HandleSharePortsMessage(MachReceiveMessage* rmsg, MemoryPorts* ports)
|
||||||
|
{
|
||||||
|
mach_port_t port = rmsg->GetTranslatedPort(0);
|
||||||
|
MachSendMessage msg(kReturnIdMsg);
|
||||||
|
msg.SetData(&port, sizeof(port));
|
||||||
|
kern_return_t err = ports->mSender->SendMessage(msg, kTimeout);
|
||||||
|
if (KERN_SUCCESS != err) {
|
||||||
|
LOG_ERROR("SendMessage failed 0x%x %s\n", err, mach_error_string(err));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// We were asked by another process to get communications ports to some process. Return
|
||||||
|
// those ports via an IPC message.
|
||||||
|
bool
|
||||||
|
SendReturnPortsMsg(MachPortSender* sender,
|
||||||
|
mach_port_t raw_ports_in_sender,
|
||||||
|
mach_port_t raw_ports_out_sender)
|
||||||
|
{
|
||||||
|
MachSendMessage getPortsMsg(kReturnPortsMsg);
|
||||||
|
if (!getPortsMsg.AddDescriptor(MachMsgPortDescriptor(raw_ports_in_sender))) {
|
||||||
|
LOG_ERROR("Adding descriptor to message failed");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!getPortsMsg.AddDescriptor(MachMsgPortDescriptor(raw_ports_out_sender))) {
|
||||||
|
LOG_ERROR("Adding descriptor to message failed");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
kern_return_t err = sender->SendMessage(getPortsMsg, kTimeout);
|
||||||
|
if (KERN_SUCCESS != err) {
|
||||||
|
LOG_ERROR("Error sending get ports message %s (%x)\n", mach_error_string(err), err);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// We were asked for communcations ports to a process that isn't us. Assuming that process
|
||||||
|
// is one of our children, forward that request on.
|
||||||
|
void
|
||||||
|
ForwardGetPortsMessage(MachReceiveMessage* rmsg, MemoryPorts* ports, PIDPair* pid_pair)
|
||||||
|
{
|
||||||
|
if (rmsg->GetTranslatedPort(0) == MACH_PORT_NULL) {
|
||||||
|
LOG_ERROR("GetTranslatedPort(0) failed");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (rmsg->GetTranslatedPort(1) == MACH_PORT_NULL) {
|
||||||
|
LOG_ERROR("GetTranslatedPort(1) failed");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
mach_port_t raw_ports_in_sender, raw_ports_out_sender;
|
||||||
|
MemoryPorts* requestedPorts = GetMemoryPortsForPid(pid_pair->mRequested);
|
||||||
|
if (!requestedPorts) {
|
||||||
|
LOG_ERROR("failed to find port for process\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (!RequestPorts(*requestedPorts, rmsg->GetTranslatedPort(0), &raw_ports_in_sender,
|
||||||
|
&raw_ports_out_sender, rmsg->GetTranslatedPort(1), *pid_pair)) {
|
||||||
|
LOG_ERROR("failed to request ports\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
SendReturnPortsMsg(ports->mSender, raw_ports_in_sender, raw_ports_out_sender);
|
||||||
|
}
|
||||||
|
|
||||||
|
// We receieved a message asking us to get communications ports for another process
|
||||||
|
void
|
||||||
|
HandleGetPortsMessage(MachReceiveMessage* rmsg, MemoryPorts* ports)
|
||||||
|
{
|
||||||
|
PIDPair* pid_pair;
|
||||||
|
if (rmsg->GetDataLength() != sizeof(PIDPair)) {
|
||||||
|
LOG_ERROR("Improperly formatted message\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
pid_pair = reinterpret_cast<PIDPair*>(rmsg->GetData());
|
||||||
|
if (pid_pair->mRequested != getpid()) {
|
||||||
|
// This request is for ports to a process that isn't us, forward it to that process
|
||||||
|
ForwardGetPortsMessage(rmsg, ports, pid_pair);
|
||||||
|
} else {
|
||||||
|
if (rmsg->GetTranslatedPort(0) == MACH_PORT_NULL) {
|
||||||
|
LOG_ERROR("GetTranslatedPort(0) failed");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (rmsg->GetTranslatedPort(1) == MACH_PORT_NULL) {
|
||||||
|
LOG_ERROR("GetTranslatedPort(1) failed");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
MachPortSender* ports_in_sender = new MachPortSender(rmsg->GetTranslatedPort(0));
|
||||||
|
MachPortSender* ports_out_sender = new MachPortSender(rmsg->GetTranslatedPort(1));
|
||||||
|
|
||||||
|
ReceivePort* ports_in_receiver = new ReceivePort();
|
||||||
|
ReceivePort* ports_out_receiver = new ReceivePort();
|
||||||
|
if (SendReturnPortsMsg(ports->mSender, ports_in_receiver->GetPort(), ports_out_receiver->GetPort())) {
|
||||||
|
SetupMachMemory(pid_pair->mRequester,
|
||||||
|
ports_out_receiver,
|
||||||
|
ports_out_sender,
|
||||||
|
ports_in_sender,
|
||||||
|
ports_in_receiver,
|
||||||
|
false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void *
|
||||||
|
PortServerThread(void *argument)
|
||||||
|
{
|
||||||
|
MemoryPorts* ports = static_cast<MemoryPorts*>(argument);
|
||||||
|
MachReceiveMessage child_message;
|
||||||
|
while (true) {
|
||||||
|
MachReceiveMessage rmsg;
|
||||||
|
kern_return_t err = ports->mReceiver->WaitForMessage(&rmsg, MACH_MSG_TIMEOUT_NONE);
|
||||||
|
if (err != KERN_SUCCESS) {
|
||||||
|
LOG_ERROR("Wait for message failed 0x%x %s\n", err, mach_error_string(err));
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (rmsg.GetMessageID() == kShutdownMsg) {
|
||||||
|
delete ports->mSender;
|
||||||
|
delete ports->mReceiver;
|
||||||
|
delete ports;
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
StaticMutexAutoLock smal(gMutex);
|
||||||
|
switch (rmsg.GetMessageID()) {
|
||||||
|
case kSharePortsMsg:
|
||||||
|
HandleSharePortsMessage(&rmsg, ports);
|
||||||
|
break;
|
||||||
|
case kGetPortsMsg:
|
||||||
|
HandleGetPortsMessage(&rmsg, ports);
|
||||||
|
break;
|
||||||
|
case kCleanupMsg:
|
||||||
|
if (gParentPid == 0) {
|
||||||
|
LOG_ERROR("Cleanup message not valid for parent process");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
pid_t* pid;
|
||||||
|
if (rmsg.GetDataLength() != sizeof(pid_t)) {
|
||||||
|
LOG_ERROR("Improperly formatted message\n");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
pid = reinterpret_cast<pid_t*>(rmsg.GetData());
|
||||||
|
SharedMemoryBasic::CleanupForPid(*pid);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
LOG_ERROR("Unknown message\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
SharedMemoryBasic::SetupMachMemory(pid_t pid,
|
||||||
|
ReceivePort* listen_port,
|
||||||
|
MachPortSender* listen_port_ack,
|
||||||
|
MachPortSender* send_port,
|
||||||
|
ReceivePort* send_port_ack,
|
||||||
|
bool pidIsParent)
|
||||||
|
{
|
||||||
|
StaticMutexAutoLock smal(gMutex);
|
||||||
|
mozilla::ipc::SetupMachMemory(pid, listen_port, listen_port_ack, send_port, send_port_ack, pidIsParent);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
SharedMemoryBasic::Shutdown()
|
||||||
|
{
|
||||||
|
StaticMutexAutoLock smal(gMutex);
|
||||||
|
|
||||||
|
for (auto it = gThreads.begin(); it != gThreads.end(); ++it) {
|
||||||
|
MachSendMessage shutdownMsg(kShutdownMsg);
|
||||||
|
it->second.mPorts->mReceiver->SendMessageToSelf(shutdownMsg, kTimeout);
|
||||||
|
pthread_join(it->second.mThread, nullptr);
|
||||||
|
}
|
||||||
|
gThreads.clear();
|
||||||
|
|
||||||
|
for (auto it = gMemoryCommPorts.begin(); it != gMemoryCommPorts.end(); ++it) {
|
||||||
|
delete it->second.mSender;
|
||||||
|
delete it->second.mReceiver;
|
||||||
|
}
|
||||||
|
gMemoryCommPorts.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
SharedMemoryBasic::CleanupForPid(pid_t pid)
|
||||||
|
{
|
||||||
|
if (gThreads.find(pid) == gThreads.end()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const ListeningThread& listeningThread = gThreads[pid];
|
||||||
|
MachSendMessage shutdownMsg(kShutdownMsg);
|
||||||
|
kern_return_t ret = listeningThread.mPorts->mReceiver->SendMessageToSelf(shutdownMsg, kTimeout);
|
||||||
|
if (ret != KERN_SUCCESS) {
|
||||||
|
LOG_ERROR("sending shutdown msg failed %s %x\n", mach_error_string(ret), ret);
|
||||||
|
}
|
||||||
|
gThreads.erase(pid);
|
||||||
|
|
||||||
|
if (gParentPid == 0) {
|
||||||
|
// We're the parent. Broadcast the cleanup message to everyone else.
|
||||||
|
for (auto it = gMemoryCommPorts.begin(); it != gMemoryCommPorts.end(); ++it) {
|
||||||
|
MachSendMessage msg(kCleanupMsg);
|
||||||
|
msg.SetData(&pid, sizeof(pid));
|
||||||
|
// We don't really care if this fails, we could be trying to send to an already shut down proc
|
||||||
|
it->second.mSender->SendMessage(msg, kTimeout);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
MemoryPorts& ports = gMemoryCommPorts[pid];
|
||||||
|
delete ports.mSender;
|
||||||
|
delete ports.mReceiver;
|
||||||
|
gMemoryCommPorts.erase(pid);
|
||||||
|
}
|
||||||
|
|
||||||
|
SharedMemoryBasic::SharedMemoryBasic()
|
||||||
|
: mPort(MACH_PORT_NULL)
|
||||||
|
, mMemory(nullptr)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
SharedMemoryBasic::SharedMemoryBasic(Handle aHandle)
|
||||||
|
: mPort(MACH_PORT_NULL)
|
||||||
|
, mMemory(nullptr)
|
||||||
|
{
|
||||||
|
mPort = aHandle;
|
||||||
|
}
|
||||||
|
|
||||||
|
SharedMemoryBasic::~SharedMemoryBasic()
|
||||||
|
{
|
||||||
|
Unmap();
|
||||||
|
Destroy();
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void*
|
||||||
|
toPointer(mach_vm_address_t address)
|
||||||
|
{
|
||||||
|
return reinterpret_cast<void*>(static_cast<uintptr_t>(address));
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline mach_vm_address_t
|
||||||
|
toVMAddress(void* pointer)
|
||||||
|
{
|
||||||
|
return static_cast<mach_vm_address_t>(reinterpret_cast<uintptr_t>(pointer));
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
SharedMemoryBasic::Create(size_t size)
|
||||||
|
{
|
||||||
|
mach_vm_address_t address;
|
||||||
|
|
||||||
|
kern_return_t kr = mach_vm_allocate(mach_task_self(), &address, round_page(size), VM_FLAGS_ANYWHERE);
|
||||||
|
if (kr != KERN_SUCCESS) {
|
||||||
|
LOG_ERROR("Failed to allocate mach_vm_allocate shared memory (%zu bytes). %s (%x)\n",
|
||||||
|
size, mach_error_string(kr), kr);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
memory_object_size_t memoryObjectSize = round_page(size);
|
||||||
|
|
||||||
|
kr = mach_make_memory_entry_64(mach_task_self(),
|
||||||
|
&memoryObjectSize,
|
||||||
|
address,
|
||||||
|
VM_PROT_DEFAULT,
|
||||||
|
&mPort,
|
||||||
|
MACH_PORT_NULL);
|
||||||
|
if (kr != KERN_SUCCESS) {
|
||||||
|
LOG_ERROR("Failed to make memory entry (%zu bytes). %s (%x)\n",
|
||||||
|
size, mach_error_string(kr), kr);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
mMemory = toPointer(address);
|
||||||
|
Mapped(size);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
SharedMemoryBasic::Map(size_t size)
|
||||||
|
{
|
||||||
|
if (mMemory) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (MACH_PORT_NULL == mPort) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
kern_return_t kr;
|
||||||
|
mach_vm_address_t address = 0;
|
||||||
|
|
||||||
|
vm_prot_t vmProtection = VM_PROT_READ | VM_PROT_WRITE;
|
||||||
|
|
||||||
|
kr = mach_vm_map(mach_task_self(), &address, round_page(size), 0, VM_FLAGS_ANYWHERE,
|
||||||
|
mPort, 0, false, vmProtection, vmProtection, VM_INHERIT_NONE);
|
||||||
|
if (kr != KERN_SUCCESS) {
|
||||||
|
LOG_ERROR("Failed to map shared memory (%zu bytes) into %x, port %x. %s (%x)\n",
|
||||||
|
size, mach_task_self(), mPort, mach_error_string(kr), kr);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
mMemory = toPointer(address);
|
||||||
|
Mapped(size);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
SharedMemoryBasic::ShareToProcess(base::ProcessId pid,
|
||||||
|
Handle* aNewHandle)
|
||||||
|
{
|
||||||
|
StaticMutexAutoLock smal(gMutex);
|
||||||
|
|
||||||
|
MemoryPorts* ports = GetMemoryPortsForPid(pid);
|
||||||
|
if (!ports) {
|
||||||
|
LOG_ERROR("Unable to get ports for process.\n");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
MachSendMessage smsg(kSharePortsMsg);
|
||||||
|
smsg.AddDescriptor(MachMsgPortDescriptor(mPort, MACH_MSG_TYPE_COPY_SEND));
|
||||||
|
kern_return_t err = ports->mSender->SendMessage(smsg, kTimeout);
|
||||||
|
if (err != KERN_SUCCESS) {
|
||||||
|
LOG_ERROR("sending port failed %s %x\n", mach_error_string(err), err);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
MachReceiveMessage msg;
|
||||||
|
err = ports->mReceiver->WaitForMessage(&msg, kTimeout);
|
||||||
|
if (err != KERN_SUCCESS) {
|
||||||
|
LOG_ERROR("didn't get an id %s %x\n", mach_error_string(err), err);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (msg.GetDataLength() != sizeof(mach_port_t)) {
|
||||||
|
LOG_ERROR("Improperly formatted reply\n");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
mach_port_t *id = reinterpret_cast<mach_port_t*>(msg.GetData());
|
||||||
|
*aNewHandle = *id;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
SharedMemoryBasic::Unmap()
|
||||||
|
{
|
||||||
|
if (!mMemory) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
vm_address_t address = toVMAddress(mMemory);
|
||||||
|
kern_return_t kr = vm_deallocate(mach_task_self(), address, vm_page_size);
|
||||||
|
if (kr != KERN_SUCCESS) {
|
||||||
|
LOG_ERROR("Failed to deallocate shared memory. %s (%x)\n", mach_error_string(kr), kr);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
mMemory = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
SharedMemoryBasic::Destroy()
|
||||||
|
{
|
||||||
|
mach_port_deallocate(mach_task_self(), mPort);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
SharedMemoryBasic::IsHandleValid(const Handle& aHandle)
|
||||||
|
{
|
||||||
|
return aHandle > 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace ipc
|
||||||
|
} // namespace mozilla
|
86
ipc/glue/SharedMemoryBasic_mach.h
Normal file
86
ipc/glue/SharedMemoryBasic_mach.h
Normal file
@ -0,0 +1,86 @@
|
|||||||
|
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
|
||||||
|
* vim: sw=2 ts=8 et :
|
||||||
|
*/
|
||||||
|
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||||
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||||
|
|
||||||
|
#ifndef mozilla_ipc_SharedMemoryBasic_mach_h
|
||||||
|
#define mozilla_ipc_SharedMemoryBasic_mach_h
|
||||||
|
|
||||||
|
#include "base/file_descriptor_posix.h"
|
||||||
|
#include "base/process.h"
|
||||||
|
|
||||||
|
#include "SharedMemory.h"
|
||||||
|
#include <mach/port.h>
|
||||||
|
|
||||||
|
//
|
||||||
|
// This is a low-level wrapper around platform shared memory. Don't
|
||||||
|
// use it directly; use Shmem allocated through IPDL interfaces.
|
||||||
|
//
|
||||||
|
|
||||||
|
class MachPortSender;
|
||||||
|
class ReceivePort;
|
||||||
|
|
||||||
|
namespace mozilla {
|
||||||
|
namespace ipc {
|
||||||
|
|
||||||
|
class SharedMemoryBasic final : public SharedMemory
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
typedef mach_port_t Handle;
|
||||||
|
|
||||||
|
static void SetupMachMemory(pid_t pid,
|
||||||
|
ReceivePort* listen_port,
|
||||||
|
MachPortSender* listen_port_ack,
|
||||||
|
MachPortSender* send_port,
|
||||||
|
ReceivePort* send_port_ack,
|
||||||
|
bool pidIsParent);
|
||||||
|
|
||||||
|
static void CleanupForPid(pid_t pid);
|
||||||
|
|
||||||
|
static void Shutdown();
|
||||||
|
|
||||||
|
SharedMemoryBasic();
|
||||||
|
|
||||||
|
explicit SharedMemoryBasic(Handle aHandle);
|
||||||
|
|
||||||
|
virtual bool Create(size_t aNbytes) override;
|
||||||
|
|
||||||
|
virtual bool Map(size_t nBytes) override;
|
||||||
|
|
||||||
|
virtual void* memory() const override
|
||||||
|
{
|
||||||
|
return mMemory;
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual SharedMemoryType Type() const override
|
||||||
|
{
|
||||||
|
return TYPE_BASIC;
|
||||||
|
}
|
||||||
|
|
||||||
|
static Handle NULLHandle()
|
||||||
|
{
|
||||||
|
return Handle();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static bool IsHandleValid(const Handle &aHandle);
|
||||||
|
|
||||||
|
bool ShareToProcess(base::ProcessId aProcessId,
|
||||||
|
Handle* aNewHandle);
|
||||||
|
|
||||||
|
private:
|
||||||
|
~SharedMemoryBasic();
|
||||||
|
|
||||||
|
void Unmap();
|
||||||
|
void Destroy();
|
||||||
|
mach_port_t mPort;
|
||||||
|
// Pointer to mapped region, null if unmapped.
|
||||||
|
void *mMemory;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace ipc
|
||||||
|
} // namespace mozilla
|
||||||
|
|
||||||
|
#endif // ifndef mozilla_ipc_SharedMemoryBasic_mach_h
|
@ -76,6 +76,11 @@ if CONFIG['OS_TARGET'] == 'Android':
|
|||||||
UNIFIED_SOURCES += [
|
UNIFIED_SOURCES += [
|
||||||
'SharedMemoryBasic_android.cpp',
|
'SharedMemoryBasic_android.cpp',
|
||||||
]
|
]
|
||||||
|
elif CONFIG['OS_ARCH'] == 'Darwin':
|
||||||
|
EXPORTS.mozilla.ipc += ['SharedMemoryBasic_mach.h']
|
||||||
|
SOURCES += [
|
||||||
|
'SharedMemoryBasic_mach.cpp',
|
||||||
|
]
|
||||||
else:
|
else:
|
||||||
EXPORTS.mozilla.ipc += ['SharedMemoryBasic_chromium.h']
|
EXPORTS.mozilla.ipc += ['SharedMemoryBasic_chromium.h']
|
||||||
|
|
||||||
|
@ -378,6 +378,18 @@ XRE_InitChildProcess(int aArgc,
|
|||||||
return NS_ERROR_FAILURE;
|
return NS_ERROR_FAILURE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ReceivePort* ports_out_receiver = new ReceivePort();
|
||||||
|
if (!child_message.AddDescriptor(MachMsgPortDescriptor(ports_out_receiver->GetPort()))) {
|
||||||
|
NS_WARNING("Adding descriptor to message failed");
|
||||||
|
return NS_ERROR_FAILURE;
|
||||||
|
}
|
||||||
|
|
||||||
|
ReceivePort* ports_in_receiver = new ReceivePort();
|
||||||
|
if (!child_message.AddDescriptor(MachMsgPortDescriptor(ports_in_receiver->GetPort()))) {
|
||||||
|
NS_WARNING("Adding descriptor to message failed");
|
||||||
|
return NS_ERROR_FAILURE;
|
||||||
|
}
|
||||||
|
|
||||||
MachPortSender child_sender(mach_port_name);
|
MachPortSender child_sender(mach_port_name);
|
||||||
kern_return_t err = child_sender.SendMessage(child_message, kTimeoutMs);
|
kern_return_t err = child_sender.SendMessage(child_message, kTimeoutMs);
|
||||||
if (err != KERN_SUCCESS) {
|
if (err != KERN_SUCCESS) {
|
||||||
@ -396,12 +408,27 @@ XRE_InitChildProcess(int aArgc,
|
|||||||
NS_WARNING("child GetTranslatedPort(0) failed");
|
NS_WARNING("child GetTranslatedPort(0) failed");
|
||||||
return NS_ERROR_FAILURE;
|
return NS_ERROR_FAILURE;
|
||||||
}
|
}
|
||||||
|
|
||||||
err = task_set_bootstrap_port(mach_task_self(),
|
err = task_set_bootstrap_port(mach_task_self(),
|
||||||
parent_message.GetTranslatedPort(0));
|
parent_message.GetTranslatedPort(0));
|
||||||
|
|
||||||
|
if (parent_message.GetTranslatedPort(1) == MACH_PORT_NULL) {
|
||||||
|
NS_WARNING("child GetTranslatedPort(1) failed");
|
||||||
|
return NS_ERROR_FAILURE;
|
||||||
|
}
|
||||||
|
MachPortSender* ports_out_sender = new MachPortSender(parent_message.GetTranslatedPort(1));
|
||||||
|
|
||||||
|
if (parent_message.GetTranslatedPort(2) == MACH_PORT_NULL) {
|
||||||
|
NS_WARNING("child GetTranslatedPort(2) failed");
|
||||||
|
return NS_ERROR_FAILURE;
|
||||||
|
}
|
||||||
|
MachPortSender* ports_in_sender = new MachPortSender(parent_message.GetTranslatedPort(2));
|
||||||
|
|
||||||
if (err != KERN_SUCCESS) {
|
if (err != KERN_SUCCESS) {
|
||||||
NS_WARNING("child task_set_bootstrap_port() failed");
|
NS_WARNING("child task_set_bootstrap_port() failed");
|
||||||
return NS_ERROR_FAILURE;
|
return NS_ERROR_FAILURE;
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
SetupErrorHandling(aArgv[0]);
|
SetupErrorHandling(aArgv[0]);
|
||||||
@ -470,6 +497,11 @@ XRE_InitChildProcess(int aArgc,
|
|||||||
base::ProcessId parentPID = strtol(parentPIDString, &end, 10);
|
base::ProcessId parentPID = strtol(parentPIDString, &end, 10);
|
||||||
MOZ_ASSERT(!*end, "invalid parent PID");
|
MOZ_ASSERT(!*end, "invalid parent PID");
|
||||||
|
|
||||||
|
#ifdef XP_MACOSX
|
||||||
|
mozilla::ipc::SharedMemoryBasic::SetupMachMemory(parentPID, ports_in_receiver, ports_in_sender,
|
||||||
|
ports_out_sender, ports_out_receiver, true);
|
||||||
|
#endif
|
||||||
|
|
||||||
#if defined(XP_WIN)
|
#if defined(XP_WIN)
|
||||||
// On Win7+, register the application user model id passed in by
|
// On Win7+, register the application user model id passed in by
|
||||||
// parent. This insures windows created by the container properly
|
// parent. This insures windows created by the container properly
|
||||||
@ -757,6 +789,9 @@ void
|
|||||||
XRE_ShutdownChildProcess()
|
XRE_ShutdownChildProcess()
|
||||||
{
|
{
|
||||||
MOZ_ASSERT(NS_IsMainThread(), "Wrong thread!");
|
MOZ_ASSERT(NS_IsMainThread(), "Wrong thread!");
|
||||||
|
#if defined(XP_MACOSX)
|
||||||
|
mozilla::ipc::SharedMemoryBasic::Shutdown();
|
||||||
|
#endif
|
||||||
|
|
||||||
mozilla::DebugOnly<MessageLoop*> ioLoop = XRE_GetIOMessageLoop();
|
mozilla::DebugOnly<MessageLoop*> ioLoop = XRE_GetIOMessageLoop();
|
||||||
MOZ_ASSERT(!!ioLoop, "Bad shutdown order");
|
MOZ_ASSERT(!!ioLoop, "Bad shutdown order");
|
||||||
|
Loading…
Reference in New Issue
Block a user