| Index: sandbox/linux/services/thread_helpers.cc
|
| diff --git a/sandbox/linux/services/thread_helpers.cc b/sandbox/linux/services/thread_helpers.cc
|
| index 80766a9bc5dc970666efbb5c3e7ff21ad646c4ff..c1ba04a248c37c75346690dfdfaa5297dbd5c713 100644
|
| --- a/sandbox/linux/services/thread_helpers.cc
|
| +++ b/sandbox/linux/services/thread_helpers.cc
|
| @@ -29,6 +29,10 @@ namespace {
|
|
|
| const char kAssertSingleThreadedError[] =
|
| "Current process is not mono-threaded!";
|
| +const char kAssertThreadDoesNotAppearInProcFS[] =
|
| + "Started thread does not appear in /proc";
|
| +const char kAssertThreadDoesNotDisappearInProcFS[] =
|
| + "Stopped thread does not disappear in /proc";
|
|
|
| bool IsSingleThreadedImpl(int proc_fd) {
|
| CHECK_LE(0, proc_fd);
|
| @@ -56,13 +60,18 @@ bool IsThreadPresentInProcFS(int proc_fd,
|
| return true;
|
| }
|
|
|
| +bool IsNotThreadPresentInProcFS(int proc_fd,
|
| + const std::string& thread_id_dir_str) {
|
| + return !IsThreadPresentInProcFS(proc_fd, thread_id_dir_str);
|
| +}
|
| +
|
| // Run |cb| in a loop until it returns false. Every time |cb| runs, sleep
|
| // for an exponentially increasing amount of time. |cb| is expected to return
|
| // false very quickly and this will crash if it doesn't happen within ~64ms on
|
| // Debug builds (2s on Release builds).
|
| // This is guaranteed to not sleep more than twice as much as the bare minimum
|
| // amount of time.
|
| -void RunWhileTrue(const base::Callback<bool(void)>& cb) {
|
| +void RunWhileTrue(const base::Callback<bool(void)>& cb, const char* message) {
|
| #if defined(NDEBUG)
|
| // In Release mode, crash after 30 iterations, which means having spent
|
| // roughly 2s in
|
| @@ -91,8 +100,7 @@ void RunWhileTrue(const base::Callback<bool(void)>& cb) {
|
| PCHECK(0 == HANDLE_EINTR(nanosleep(&ts, &ts)));
|
| }
|
|
|
| - LOG(FATAL) << kAssertSingleThreadedError << " (iterations: " << kMaxIterations
|
| - << ")";
|
| + LOG(FATAL) << message << " (iterations: " << kMaxIterations << ")";
|
|
|
| NOTREACHED();
|
| }
|
| @@ -101,6 +109,51 @@ bool IsMultiThreaded(int proc_fd) {
|
| return !ThreadHelpers::IsSingleThreaded(proc_fd);
|
| }
|
|
|
| +enum class ThreadAction { Start, Stop };
|
| +
|
| +bool ChangeThreadStateAndWatchProcFS(
|
| + int proc_fd, base::Thread* thread, ThreadAction action) {
|
| + DCHECK_LE(0, proc_fd);
|
| + DCHECK(thread);
|
| + DCHECK(action == ThreadAction::Start || action == ThreadAction::Stop);
|
| +
|
| + base::Callback<bool(void)> cb;
|
| + const char* message;
|
| +
|
| + if (action == ThreadAction::Start) {
|
| + // Should start the thread before calling thread_id().
|
| + if (!thread->Start())
|
| + return false;
|
| + }
|
| +
|
| + const base::PlatformThreadId thread_id = thread->thread_id();
|
| + const std::string thread_id_dir_str =
|
| + "self/task/" + base::IntToString(thread_id) + "/";
|
| +
|
| + if (action == ThreadAction::Stop) {
|
| + // The target thread should exist in /proc.
|
| + DCHECK(IsThreadPresentInProcFS(proc_fd, thread_id_dir_str));
|
| + thread->Stop();
|
| + }
|
| +
|
| + // The kernel is at liberty to wake the thread id futex before updating
|
| + // /proc. Start() above or following Stop(), the thread is started or joined,
|
| + // but entries in /proc may not have been updated.
|
| + if (action == ThreadAction::Start) {
|
| + cb = base::Bind(&IsNotThreadPresentInProcFS, proc_fd, thread_id_dir_str);
|
| + message = kAssertThreadDoesNotAppearInProcFS;
|
| + } else {
|
| + cb = base::Bind(&IsThreadPresentInProcFS, proc_fd, thread_id_dir_str);
|
| + message = kAssertThreadDoesNotDisappearInProcFS;
|
| + }
|
| + RunWhileTrue(cb, message);
|
| +
|
| + DCHECK_EQ(action == ThreadAction::Start,
|
| + IsThreadPresentInProcFS(proc_fd, thread_id_dir_str));
|
| +
|
| + return true;
|
| +}
|
| +
|
| } // namespace
|
|
|
| // static
|
| @@ -119,7 +172,7 @@ bool ThreadHelpers::IsSingleThreaded() {
|
| void ThreadHelpers::AssertSingleThreaded(int proc_fd) {
|
| DCHECK_LE(0, proc_fd);
|
| const base::Callback<bool(void)> cb = base::Bind(&IsMultiThreaded, proc_fd);
|
| - RunWhileTrue(cb);
|
| + RunWhileTrue(cb, kAssertSingleThreadedError);
|
| }
|
|
|
| void ThreadHelpers::AssertSingleThreaded() {
|
| @@ -128,25 +181,15 @@ void ThreadHelpers::AssertSingleThreaded() {
|
| }
|
|
|
| // static
|
| +bool ThreadHelpers::StartThreadAndWatchProcFS(int proc_fd,
|
| + base::Thread* thread) {
|
| + return ChangeThreadStateAndWatchProcFS(proc_fd, thread, ThreadAction::Start);
|
| +}
|
| +
|
| +// static
|
| bool ThreadHelpers::StopThreadAndWatchProcFS(int proc_fd,
|
| base::Thread* thread) {
|
| - DCHECK_LE(0, proc_fd);
|
| - DCHECK(thread);
|
| - const base::PlatformThreadId thread_id = thread->thread_id();
|
| - const std::string thread_id_dir_str =
|
| - "self/task/" + base::IntToString(thread_id) + "/";
|
| -
|
| - // The kernel is at liberty to wake the thread id futex before updating
|
| - // /proc. Following Stop(), the thread is joined, but entries in /proc may
|
| - // not have been updated.
|
| - thread->Stop();
|
| -
|
| - const base::Callback<bool(void)> cb =
|
| - base::Bind(&IsThreadPresentInProcFS, proc_fd, thread_id_dir_str);
|
| -
|
| - RunWhileTrue(cb);
|
| -
|
| - return true;
|
| + return ChangeThreadStateAndWatchProcFS(proc_fd, thread, ThreadAction::Stop);
|
| }
|
|
|
| // static
|
|
|