diff options
author | rsesek@chromium.org <rsesek@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2013-04-11 00:07:25 +0000 |
---|---|---|
committer | rsesek@chromium.org <rsesek@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98> | 2013-04-11 00:07:25 +0000 |
commit | d52d8bff0029726f8f6e21a425b770093b57fa6b (patch) | |
tree | 005774df70f223fd59c0ffafdb23eecadedc2739 /base | |
parent | c553dcdf53ca9d4c14dceab5102b6cada415e494 (diff) | |
download | chromium_src-d52d8bff0029726f8f6e21a425b770093b57fa6b.zip chromium_src-d52d8bff0029726f8f6e21a425b770093b57fa6b.tar.gz chromium_src-d52d8bff0029726f8f6e21a425b770093b57fa6b.tar.bz2 |
Revert 193486 "[Mac] Remove base::LaunchSynchronize and rewrite ..."
> [Mac] Remove base::LaunchSynchronize and rewrite content::MachBroker.
>
> This restructures the way MachBroker parent-child communication happens. Now,
> the MachBroker lock will be held for the duration of LaunchProcess until the
> PID is returned and inserted into the MachMap. Since the lock must also be
> acquired on the broker thread to insert the received task port into the
> MachMap, this ensures that the placeholder is always inserted before the task
> port.
>
> MachBroker has also been rewritten to use Mach IPC directly, rather than the C++
> wrappers in base/mach_ipc_mac.h. The wrappers are not flexible enough to allow
> the use of an audit trailer. This trailer is used to verify the PID of the
> sender of the check in message in the parent. Previously, this was done by
> another kernel trap, pid_for_task.
>
> BUG=179923
>
>
> Review URL: https://chromiumcodereview.appspot.com/13845008
TBR=rsesek@chromium.org
Review URL: https://codereview.chromium.org/14120002
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@193511 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'base')
-rw-r--r-- | base/mac/scoped_mach_port.cc | 5 | ||||
-rw-r--r-- | base/mac/scoped_mach_port.h | 2 | ||||
-rw-r--r-- | base/process_util.h | 40 | ||||
-rw-r--r-- | base/process_util_posix.cc | 93 |
4 files changed, 133 insertions, 7 deletions
diff --git a/base/mac/scoped_mach_port.cc b/base/mac/scoped_mach_port.cc index 9e45a85..652e3f4 100644 --- a/base/mac/scoped_mach_port.cc +++ b/base/mac/scoped_mach_port.cc @@ -11,14 +11,9 @@ ScopedMachPort::ScopedMachPort(mach_port_t port) : port_(port) { } ScopedMachPort::~ScopedMachPort() { - reset(); -} - -void ScopedMachPort::reset(mach_port_t port) { if (port_ != MACH_PORT_NULL) { mach_port_deallocate(mach_task_self(), port_); } - port_ = port; } } // namespace mac diff --git a/base/mac/scoped_mach_port.h b/base/mac/scoped_mach_port.h index cc2ef20..d2aa2f7 100644 --- a/base/mac/scoped_mach_port.h +++ b/base/mac/scoped_mach_port.h @@ -22,8 +22,6 @@ class BASE_EXPORT ScopedMachPort { ~ScopedMachPort(); - void reset(mach_port_t port = MACH_PORT_NULL); - operator mach_port_t() const { return port_; } diff --git a/base/process_util.h b/base/process_util.h index a06f689..54d8533 100644 --- a/base/process_util.h +++ b/base/process_util.h @@ -232,6 +232,13 @@ BASE_EXPORT void CloseSuperfluousFds(const InjectiveMultimap& saved_map); typedef std::vector<std::pair<std::string, std::string> > EnvironmentVector; typedef std::vector<std::pair<int, int> > FileHandleMappingVector; +#if defined(OS_MACOSX) +// Used with LaunchOptions::synchronize and LaunchSynchronize, a +// LaunchSynchronizationHandle is an opaque value that LaunchProcess will +// create and set, and that LaunchSynchronize will consume and destroy. +typedef int* LaunchSynchronizationHandle; +#endif // defined(OS_MACOSX) + // Options for launching a subprocess that are passed to LaunchProcess(). // The default constructor constructs the object with default options. struct LaunchOptions { @@ -259,6 +266,9 @@ struct LaunchOptions { #if defined(OS_CHROMEOS) , ctrl_terminal_fd(-1) #endif // OS_CHROMEOS +#if defined(OS_MACOSX) + , synchronize(NULL) +#endif // defined(OS_MACOSX) #endif // !defined(OS_WIN) {} @@ -340,6 +350,27 @@ struct LaunchOptions { int ctrl_terminal_fd; #endif // defined(OS_CHROMEOS) +#if defined(OS_MACOSX) + // When non-NULL, a new LaunchSynchronizationHandle will be created and + // stored in *synchronize whenever LaunchProcess returns true in the parent + // process. The child process will have been created (with fork) but will + // be waiting (before exec) for the parent to call LaunchSynchronize with + // this handle. Only when LaunchSynchronize is called will the child be + // permitted to continue execution and call exec. LaunchSynchronize + // destroys the handle created by LaunchProcess. + // + // When synchronize is non-NULL, the parent must call LaunchSynchronize + // whenever LaunchProcess returns true. No exceptions. + // + // Synchronization is useful when the parent process needs to guarantee that + // it can take some action (such as recording the newly-forked child's + // process ID) before the child does something (such as using its process ID + // to communicate with its parent). + // + // |synchronize| and |wait| must not both be set simultaneously. + LaunchSynchronizationHandle* synchronize; +#endif // defined(OS_MACOSX) + #endif // !defined(OS_WIN) }; @@ -411,6 +442,15 @@ BASE_EXPORT bool LaunchProcess(const std::vector<std::string>& argv, // The returned array is allocated using new[] and must be freed by the caller. BASE_EXPORT char** AlterEnvironment(const EnvironmentVector& changes, const char* const* const env); + +#if defined(OS_MACOSX) + +// After a successful call to LaunchProcess with LaunchOptions::synchronize +// set, the parent process must call LaunchSynchronize to allow the child +// process to proceed, and to destroy the LaunchSynchronizationHandle. +BASE_EXPORT void LaunchSynchronize(LaunchSynchronizationHandle handle); + +#endif // defined(OS_MACOSX) #endif // defined(OS_POSIX) #if defined(OS_WIN) diff --git a/base/process_util_posix.cc b/base/process_util_posix.cc index 98ec183..52e964b 100644 --- a/base/process_util_posix.cc +++ b/base/process_util_posix.cc @@ -604,6 +604,15 @@ bool LaunchProcess(const std::vector<std::string>& argv, fd_shuffle_size = options.fds_to_remap->size(); } +#if defined(OS_MACOSX) + if (options.synchronize) { + // When synchronizing, the "read" end of the synchronization pipe needs + // to make it to the child process. This is handled by mapping it back to + // itself. + ++fd_shuffle_size; + } +#endif // defined(OS_MACOSX) + InjectiveMultimap fd_shuffle1; InjectiveMultimap fd_shuffle2; fd_shuffle1.reserve(fd_shuffle_size); @@ -614,6 +623,34 @@ bool LaunchProcess(const std::vector<std::string>& argv, if (options.environ) new_environ.reset(AlterEnvironment(*options.environ, GetEnvironment())); +#if defined(OS_MACOSX) + int synchronization_pipe_fds[2]; + file_util::ScopedFD synchronization_read_fd; + file_util::ScopedFD synchronization_write_fd; + + if (options.synchronize) { + // wait means "don't return from LaunchProcess until the child exits", and + // synchronize means "return from LaunchProcess but don't let the child + // run until LaunchSynchronize is called". These two options are highly + // incompatible. + DCHECK(!options.wait); + + // Create the pipe used for synchronization. + if (HANDLE_EINTR(pipe(synchronization_pipe_fds)) != 0) { + DPLOG(ERROR) << "pipe"; + return false; + } + + // The parent process will only use synchronization_write_fd as the write + // side of the pipe. It can close the read side as soon as the child + // process has forked off. The child process will only use + // synchronization_read_fd as the read side of the pipe. In that process, + // the write side can be closed as soon as it has forked. + synchronization_read_fd.reset(&synchronization_pipe_fds[0]); + synchronization_write_fd.reset(&synchronization_pipe_fds[1]); + } +#endif // OS_MACOSX + pid_t pid; #if defined(OS_LINUX) if (options.clone_flags) { @@ -706,6 +743,13 @@ bool LaunchProcess(const std::vector<std::string>& argv, RAW_LOG(INFO, "Right after signal/exception handler restoration."); } +#if defined(OS_MACOSX) + if (options.synchronize) { + // The "write" side of the synchronization pipe belongs to the parent. + synchronization_write_fd.reset(); // closes synchronization_pipe_fds[1] + } +#endif // defined(OS_MACOSX) + #if 0 // When debugging it can be helpful to check that we really aren't making // any hidden calls to malloc. @@ -745,6 +789,16 @@ bool LaunchProcess(const std::vector<std::string>& argv, RAW_LOG(INFO, "Right after fd_shuffle push_backs."); } +#if defined(OS_MACOSX) + if (options.synchronize) { + // Remap the read side of the synchronization pipe back onto itself, + // ensuring that it won't be closed by CloseSuperfluousFds. + int keep_fd = *synchronization_read_fd.get(); + fd_shuffle1.push_back(InjectionArc(keep_fd, keep_fd, false)); + fd_shuffle2.push_back(InjectionArc(keep_fd, keep_fd, false)); + } +#endif // defined(OS_MACOSX) + if (options.environ) SetEnvironment(new_environ.get()); @@ -762,6 +816,24 @@ bool LaunchProcess(const std::vector<std::string>& argv, RAW_LOG(INFO, "Right after CloseSuperfluousFds"); } +#if defined(OS_MACOSX) + if (options.synchronize) { + // Do a blocking read to wait until the parent says it's OK to proceed. + // The byte that's read here is written by LaunchSynchronize. + char read_char; + int read_result = + HANDLE_EINTR(read(*synchronization_read_fd.get(), &read_char, 1)); + if (read_result != 1) { + RAW_LOG(ERROR, "LaunchProcess: synchronization read: error"); + _exit(127); + } + + // The pipe is no longer useful. Don't let it live on in the new process + // after exec. + synchronization_read_fd.reset(); // closes synchronization_pipe_fds[0] + } +#endif // defined(OS_MACOSX) + if (options.debug) { RAW_LOG(INFO, "Right before execvp"); } @@ -786,6 +858,14 @@ bool LaunchProcess(const std::vector<std::string>& argv, if (process_handle) *process_handle = pid; + +#if defined(OS_MACOSX) + if (options.synchronize) { + // The "read" side of the synchronization pipe belongs to the child. + synchronization_read_fd.reset(); // closes synchronization_pipe_fds[0] + *options.synchronize = new int(*synchronization_write_fd.release()); + } +#endif // defined(OS_MACOSX) } return true; @@ -798,6 +878,19 @@ bool LaunchProcess(const CommandLine& cmdline, return LaunchProcess(cmdline.argv(), options, process_handle); } +#if defined(OS_MACOSX) +void LaunchSynchronize(LaunchSynchronizationHandle handle) { + int synchronization_fd = *handle; + file_util::ScopedFD synchronization_fd_closer(&synchronization_fd); + delete handle; + + // Write a '\0' character to the pipe. + if (HANDLE_EINTR(write(synchronization_fd, "", 1)) != 1) { + DPLOG(ERROR) << "write"; + } +} +#endif // defined(OS_MACOSX) + ProcessMetrics::~ProcessMetrics() { } void RaiseProcessToHighPriority() { |