Bug 771765 - Support template content process, part 2: IPC and glue changes. r=bent

Changes include:
* Getting/resetting platform thread ID.
* Creating an IPC channel with existing file descriptor sent from the template process.
* Child process host with existing process forked from the template.
This commit is contained in:
Thinker Lee ext:(%2C%20Cervantes%20Yu%20%3Ccyu%40mozilla.com%3E) 2013-05-31 21:16:54 +08:00
parent 571a106743
commit 7d20b19ad7
11 changed files with 159 additions and 20 deletions

View File

@ -49,7 +49,11 @@ PlatformThreadId PlatformThread::CurrentId() {
mach_port_deallocate(mach_task_self(), port);
return port;
#elif defined(OS_LINUX)
#ifdef MOZ_WIDGET_GONK
return (intptr_t) (pthread_self());
#else
return syscall(__NR_gettid);
#endif
#elif defined(OS_OPENBSD) || defined(__GLIBC__)
return (intptr_t) (pthread_self());
#elif defined(OS_NETBSD)

View File

@ -248,6 +248,9 @@ bool DidProcessCrash(bool* child_exited, ProcessHandle handle) {
int status;
const int result = HANDLE_EINTR(waitpid(handle, &status, WNOHANG));
if (result == -1) {
// The dead process originally spawned from Nuwa might be taken as not
// crashed because the above waitpid() call returns -1 and ECHILD. The
// caller shouldn't behave incorrectly because of this false negative.
LOG(ERROR) << "waitpid failed pid:" << handle << " errno:" << errno;
if (child_exited)
*child_exited = false;

View File

@ -106,6 +106,12 @@ class Thread : PlatformThread::Delegate {
// The thread ID.
PlatformThreadId thread_id() const { return thread_id_; }
// Reset thread ID as current thread.
PlatformThreadId reset_thread_id() {
thread_id_ = PlatformThread::CurrentId();
return thread_id_;
}
// Returns true if the thread has been started, and not yet stopped.
// When a thread is running, the thread_id_ is non-zero.
bool IsRunning() const { return thread_id_ != 0; }

View File

@ -12,6 +12,7 @@
#include "base/waitable_event.h"
#include "mozilla/ipc/ProcessChild.h"
#include "mozilla/ipc/BrowserProcessSubThread.h"
#include "mozilla/ipc/Transport.h"
typedef mozilla::ipc::BrowserProcessSubThread ChromeThread;
#include "chrome/common/ipc_logging.h"
#include "chrome/common/notification_service.h"
@ -19,6 +20,7 @@ typedef mozilla::ipc::BrowserProcessSubThread ChromeThread;
#include "chrome/common/process_watcher.h"
#include "chrome/common/result_codes.h"
using mozilla::ipc::FileDescriptor;
namespace {
typedef std::list<ChildProcessHost*> ChildProcessList;
@ -84,6 +86,22 @@ bool ChildProcessHost::CreateChannel() {
return true;
}
bool ChildProcessHost::CreateChannel(FileDescriptor& aFileDescriptor) {
if (channel_.get()) {
channel_->Close();
}
channel_.reset(mozilla::ipc::OpenDescriptor(
aFileDescriptor, IPC::Channel::MODE_SERVER));
channel_->set_listener(&listener_);
if (!channel_->Connect()) {
return false;
}
opening_channel_ = true;
return true;
}
void ChildProcessHost::SetHandle(base::ProcessHandle process) {
#if defined(OS_WIN)
process_event_.reset(new base::WaitableEvent(process));

View File

@ -15,6 +15,12 @@
#include "chrome/common/child_process_info.h"
#include "chrome/common/ipc_channel.h"
namespace mozilla {
namespace ipc {
class FileDescriptor;
}
}
class NotificationType;
// Plugins/workers and other child processes that live on the IO thread should
@ -59,6 +65,8 @@ class ChildProcessHost :
// Creates the IPC channel. Returns true iff it succeeded.
bool CreateChannel();
bool CreateChannel(mozilla::ipc::FileDescriptor& aFileDescriptor);
// Once the subclass gets a handle to the process, it needs to tell
// ChildProcessHost using this function.
void SetHandle(base::ProcessHandle handle);

View File

@ -117,8 +117,11 @@ class Channel : public Message::Sender {
// socketpair() in which case this method returns -1 for both parameters.
void GetClientFileDescriptorMapping(int *src_fd, int *dest_fd) const;
// Return the server side of the socketpair.
int GetServerFileDescriptor() const;
// Return the file descriptor for communication with the peer.
int GetFileDescriptor() const;
// Reset the file descriptor for communication with the peer.
void ResetFileDescriptor(int fd);
// Close the client side of the socketpair.
void CloseClientFileDescriptor();

View File

@ -356,6 +356,15 @@ bool Channel::ChannelImpl::CreatePipe(const std::wstring& channel_id,
return EnqueueHelloMessage();
}
/**
* Reset the file descriptor for communication with the peer.
*/
void Channel::ChannelImpl::ResetFileDescriptor(int fd) {
NS_ASSERTION(fd > 0 && fd == pipe_, "Invalid file descriptor");
EnqueueHelloMessage();
}
bool Channel::ChannelImpl::EnqueueHelloMessage() {
scoped_ptr<Message> msg(new Message(MSG_ROUTING_NONE,
HELLO_MESSAGE_TYPE,
@ -971,8 +980,12 @@ void Channel::GetClientFileDescriptorMapping(int *src_fd, int *dest_fd) const {
return channel_impl_->GetClientFileDescriptorMapping(src_fd, dest_fd);
}
int Channel::GetServerFileDescriptor() const {
return channel_impl_->GetServerFileDescriptor();
void Channel::ResetFileDescriptor(int fd) {
channel_impl_->ResetFileDescriptor(fd);
}
int Channel::GetFileDescriptor() const {
return channel_impl_->GetFileDescriptor();
}
void Channel::CloseClientFileDescriptor() {

View File

@ -36,9 +36,11 @@ class Channel::ChannelImpl : public MessageLoopForIO::Watcher {
}
bool Send(Message* message);
void GetClientFileDescriptorMapping(int *src_fd, int *dest_fd) const;
int GetServerFileDescriptor() const {
DCHECK(mode_ == MODE_SERVER);
return pipe_;
void ResetFileDescriptor(int fd);
int GetFileDescriptor() const {
return pipe_;
}
void CloseClientFileDescriptor();

View File

@ -34,6 +34,10 @@
#define NS_TASKBAR_CONTRACTID "@mozilla.org/windows-taskbar;1"
#endif
#include "nsTArray.h"
#include "nsClassHashtable.h"
#include "nsHashKeys.h"
using mozilla::MonitorAutoLock;
using mozilla::ipc::GeckoChildProcessHost;
@ -89,11 +93,6 @@ GeckoChildProcessHost::GeckoChildProcessHost(GeckoProcessType aProcessType,
#endif
{
MOZ_COUNT_CTOR(GeckoChildProcessHost);
MessageLoop* ioLoop = XRE_GetIOMessageLoop();
ioLoop->PostTask(FROM_HERE,
NewRunnableMethod(this,
&GeckoChildProcessHost::InitializeChannel));
}
GeckoChildProcessHost::~GeckoChildProcessHost()
@ -287,7 +286,7 @@ GeckoChildProcessHost::SyncLaunch(std::vector<std::string> aExtraOpts, int aTime
ioLoop->PostTask(FROM_HERE,
NewRunnableMethod(this,
&GeckoChildProcessHost::PerformAsyncLaunch,
&GeckoChildProcessHost::RunPerformAsyncLaunch,
aExtraOpts, arch));
// NB: this uses a different mechanism than the chromium parent
// class.
@ -322,7 +321,7 @@ GeckoChildProcessHost::AsyncLaunch(std::vector<std::string> aExtraOpts)
MessageLoop* ioLoop = XRE_GetIOMessageLoop();
ioLoop->PostTask(FROM_HERE,
NewRunnableMethod(this,
&GeckoChildProcessHost::PerformAsyncLaunch,
&GeckoChildProcessHost::RunPerformAsyncLaunch,
aExtraOpts, base::GetCurrentProcessArchitecture()));
// This may look like the sync launch wait, but we only delay as
@ -343,7 +342,7 @@ GeckoChildProcessHost::LaunchAndWaitForProcessHandle(StringVector aExtraOpts)
MessageLoop* ioLoop = XRE_GetIOMessageLoop();
ioLoop->PostTask(FROM_HERE,
NewRunnableMethod(this,
&GeckoChildProcessHost::PerformAsyncLaunch,
&GeckoChildProcessHost::RunPerformAsyncLaunch,
aExtraOpts, base::GetCurrentProcessArchitecture()));
MonitorAutoLock lock(mMonitor);
@ -425,6 +424,14 @@ GeckoChildProcessHost::PerformAsyncLaunch(std::vector<std::string> aExtraOpts, b
return retval;
}
bool
GeckoChildProcessHost::RunPerformAsyncLaunch(std::vector<std::string> aExtraOpts,
base::ProcessArchitecture aArch)
{
InitializeChannel();
return PerformAsyncLaunch(aExtraOpts, aArch);
}
void
#if defined(XP_WIN)
AddAppDirToCommandLine(CommandLine& aCmdLine)
@ -833,3 +840,52 @@ GeckoChildProcessHost::OnWaitableEventSignaled(base::WaitableEvent *event)
}
ChildProcessHost::OnWaitableEventSignaled(event);
}
#ifdef MOZ_NUWA_PROCESS
using mozilla::ipc::GeckoExistingProcessHost;
using mozilla::ipc::FileDescriptor;
GeckoExistingProcessHost::
GeckoExistingProcessHost(GeckoProcessType aProcessType,
base::ProcessHandle aProcess,
const FileDescriptor& aFileDescriptor,
ChildPrivileges aPrivileges)
: GeckoChildProcessHost(aProcessType, aPrivileges)
, mExistingProcessHandle(aProcess)
, mExistingFileDescriptor(aFileDescriptor)
{
NS_ASSERTION(aFileDescriptor.IsValid(),
"Expected file descriptor to be valid");
}
GeckoExistingProcessHost::~GeckoExistingProcessHost()
{
}
bool
GeckoExistingProcessHost::PerformAsyncLaunch(StringVector aExtraOpts,
base::ProcessArchitecture aArch)
{
SetHandle(mExistingProcessHandle);
OpenPrivilegedHandle(base::GetProcId(mExistingProcessHandle));
MonitorAutoLock lock(mMonitor);
mProcessState = PROCESS_CREATED;
lock.Notify();
return true;
}
void
GeckoExistingProcessHost::InitializeChannel()
{
CreateChannel(mExistingFileDescriptor);
MonitorAutoLock lock(mMonitor);
mProcessState = CHANNEL_INITIALIZED;
lock.Notify();
}
#endif /* MOZ_NUWA_PROCESS */

View File

@ -11,6 +11,7 @@
#include "base/waitable_event.h"
#include "chrome/common/child_process_host.h"
#include "mozilla/ipc/FileDescriptor.h"
#include "mozilla/Monitor.h"
#include "nsXULAppAPI.h" // for GeckoProcessType
@ -66,15 +67,15 @@ public:
int32_t timeoutMs=0,
base::ProcessArchitecture arch=base::GetCurrentProcessArchitecture());
bool PerformAsyncLaunch(StringVector aExtraOpts=StringVector(),
base::ProcessArchitecture arch=base::GetCurrentProcessArchitecture());
virtual bool PerformAsyncLaunch(StringVector aExtraOpts=StringVector(),
base::ProcessArchitecture aArch=base::GetCurrentProcessArchitecture());
virtual void OnChannelConnected(int32_t peer_pid);
virtual void OnMessageReceived(const IPC::Message& aMsg);
virtual void OnChannelError();
virtual void GetQueuedMessages(std::queue<IPC::Message>& queue);
void InitializeChannel();
virtual void InitializeChannel();
virtual bool CanShutdown() { return true; }
@ -146,6 +147,8 @@ protected:
task_t mChildTask;
#endif
void OpenPrivilegedHandle(base::ProcessId aPid);
private:
DISALLOW_EVIL_CONSTRUCTORS(GeckoChildProcessHost);
@ -153,7 +156,8 @@ private:
bool PerformAsyncLaunchInternal(std::vector<std::string>& aExtraOpts,
base::ProcessArchitecture arch);
void OpenPrivilegedHandle(base::ProcessId aPid);
bool RunPerformAsyncLaunch(StringVector aExtraOpts=StringVector(),
base::ProcessArchitecture aArch=base::GetCurrentProcessArchitecture());
// In between launching the subprocess and handing off its IPC
// channel, there's a small window of time in which *we* might still
@ -165,6 +169,28 @@ private:
std::queue<IPC::Message> mQueue;
};
#ifdef MOZ_NUWA_PROCESS
class GeckoExistingProcessHost MOZ_FINAL : public GeckoChildProcessHost
{
public:
GeckoExistingProcessHost(GeckoProcessType aProcessType,
base::ProcessHandle aProcess,
const FileDescriptor& aFileDescriptor,
ChildPrivileges aPrivileges=base::PRIVILEGES_DEFAULT);
~GeckoExistingProcessHost();
virtual bool PerformAsyncLaunch(StringVector aExtraOpts=StringVector(),
base::ProcessArchitecture aArch=base::GetCurrentProcessArchitecture()) MOZ_OVERRIDE;
virtual void InitializeChannel() MOZ_OVERRIDE;
private:
base::ProcessHandle mExistingProcessHandle;
mozilla::ipc::FileDescriptor mExistingFileDescriptor;
};
#endif /* MOZ_NUWA_PROCESS */
} /* namespace ipc */
} /* namespace mozilla */

View File

@ -29,7 +29,7 @@ CreateTransport(ProcessHandle /*unused*/, ProcessHandle /*unused*/,
wstring id = ChildProcessInfo::GenerateRandomChannelID(aOne);
// Use MODE_SERVER to force creation of the socketpair
Transport t(id, Transport::MODE_SERVER, nullptr);
int fd1 = t.GetServerFileDescriptor();
int fd1 = t.GetFileDescriptor();
int fd2, dontcare;
t.GetClientFileDescriptorMapping(&fd2, &dontcare);
if (fd1 < 0 || fd2 < 0) {