summaryrefslogtreecommitdiffstats
path: root/base
diff options
context:
space:
mode:
authorrsesek@chromium.org <rsesek@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2013-04-11 00:07:25 +0000
committerrsesek@chromium.org <rsesek@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2013-04-11 00:07:25 +0000
commitd52d8bff0029726f8f6e21a425b770093b57fa6b (patch)
tree005774df70f223fd59c0ffafdb23eecadedc2739 /base
parentc553dcdf53ca9d4c14dceab5102b6cada415e494 (diff)
downloadchromium_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.cc5
-rw-r--r--base/mac/scoped_mach_port.h2
-rw-r--r--base/process_util.h40
-rw-r--r--base/process_util_posix.cc93
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() {