| Index: sandbox/linux/services/thread_helpers.cc
 | 
| diff --git a/sandbox/linux/services/thread_helpers.cc b/sandbox/linux/services/thread_helpers.cc
 | 
| index dbadbd44e7011593174770856ad89a700c95bcb2..51feb98864637c0a404259a4807f6b8be161130e 100644
 | 
| --- a/sandbox/linux/services/thread_helpers.cc
 | 
| +++ b/sandbox/linux/services/thread_helpers.cc
 | 
| @@ -14,16 +14,23 @@
 | 
|  #include <string>
 | 
|  
 | 
|  #include "base/basictypes.h"
 | 
| +#include "base/bind.h"
 | 
| +#include "base/callback.h"
 | 
| +#include "base/files/scoped_file.h"
 | 
|  #include "base/logging.h"
 | 
|  #include "base/posix/eintr_wrapper.h"
 | 
|  #include "base/strings/string_number_conversions.h"
 | 
|  #include "base/threading/platform_thread.h"
 | 
|  #include "base/threading/thread.h"
 | 
| +#include "sandbox/linux/services/proc_util.h"
 | 
|  
 | 
|  namespace sandbox {
 | 
|  
 | 
|  namespace {
 | 
|  
 | 
| +const char kAssertSingleThreadedError[] =
 | 
| +    "Current process is not mono-threaded!";
 | 
| +
 | 
|  bool IsSingleThreadedImpl(int proc_self_task) {
 | 
|    CHECK_LE(0, proc_self_task);
 | 
|    struct stat task_stat;
 | 
| @@ -38,22 +45,91 @@ bool IsSingleThreadedImpl(int proc_self_task) {
 | 
|    return task_stat.st_nlink == 3;
 | 
|  }
 | 
|  
 | 
| +bool IsThreadPresentInProcFS(int proc_self_task,
 | 
| +                             const std::string& thread_id_dir_str) {
 | 
| +  struct stat task_stat;
 | 
| +  const int fstat_ret =
 | 
| +      fstatat(proc_self_task, thread_id_dir_str.c_str(), &task_stat, 0);
 | 
| +  if (fstat_ret < 0) {
 | 
| +    PCHECK(ENOENT == errno);
 | 
| +    return false;
 | 
| +  }
 | 
| +  return true;
 | 
| +}
 | 
| +
 | 
| +// 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) {
 | 
| +#if defined(NDEBUG)
 | 
| +  // In Release mode, crash after 30 iterations, which means having spent
 | 
| +  // roughly 2s in
 | 
| +  // nanosleep(2) cumulatively.
 | 
| +  const unsigned int kMaxIterations = 30U;
 | 
| +#else
 | 
| +  // In practice, this never goes through more than a couple iterations. In
 | 
| +  // debug mode, crash after 64ms (+ eventually 25 times the granularity of
 | 
| +  // the clock) in nanosleep(2). This ensures that this is not becoming too
 | 
| +  // slow.
 | 
| +  const unsigned int kMaxIterations = 25U;
 | 
| +#endif
 | 
| +
 | 
| +  // Run |cb| with an exponential back-off, sleeping 2^iterations nanoseconds
 | 
| +  // in nanosleep(2).
 | 
| +  // Note: the clock may not allow for nanosecond granularity, in this case the
 | 
| +  // first iterations would sleep a tiny bit more instead, which would not
 | 
| +  // change the calculations significantly.
 | 
| +  for (unsigned int i = 0; i < kMaxIterations; ++i) {
 | 
| +    if (!cb.Run()) {
 | 
| +      return;
 | 
| +    }
 | 
| +
 | 
| +    // Increase the waiting time exponentially.
 | 
| +    struct timespec ts = {0, 1L << i /* nanoseconds */};
 | 
| +    PCHECK(0 == HANDLE_EINTR(nanosleep(&ts, &ts)));
 | 
| +  }
 | 
| +
 | 
| +  LOG(FATAL) << kAssertSingleThreadedError << " (iterations: " << kMaxIterations
 | 
| +             << ")";
 | 
| +
 | 
| +  NOTREACHED();
 | 
| +}
 | 
| +
 | 
| +bool IsMultiThreaded(int proc_self_task) {
 | 
| +  return !ThreadHelpers::IsSingleThreaded(proc_self_task);
 | 
| +}
 | 
| +
 | 
|  }  // namespace
 | 
|  
 | 
| +// static
 | 
|  bool ThreadHelpers::IsSingleThreaded(int proc_self_task) {
 | 
| -  DCHECK_LE(-1, proc_self_task);
 | 
| -  if (-1 == proc_self_task) {
 | 
| -    const int task_fd =
 | 
| -        open("/proc/self/task/", O_RDONLY | O_DIRECTORY | O_CLOEXEC);
 | 
| -    PCHECK(0 <= task_fd);
 | 
| -    const bool result = IsSingleThreadedImpl(task_fd);
 | 
| -    PCHECK(0 == IGNORE_EINTR(close(task_fd)));
 | 
| -    return result;
 | 
| -  } else {
 | 
| -    return IsSingleThreadedImpl(proc_self_task);
 | 
| -  }
 | 
| +  DCHECK_LE(0, proc_self_task);
 | 
| +  return IsSingleThreadedImpl(proc_self_task);
 | 
| +}
 | 
| +
 | 
| +// static
 | 
| +bool ThreadHelpers::IsSingleThreaded() {
 | 
| +  base::ScopedFD task_fd(ProcUtil::OpenProcSelfTask());
 | 
| +  return IsSingleThreaded(task_fd.get());
 | 
| +}
 | 
| +
 | 
| +// static
 | 
| +void ThreadHelpers::AssertSingleThreaded(int proc_self_task) {
 | 
| +  DCHECK_LE(0, proc_self_task);
 | 
| +  const base::Callback<bool(void)> cb =
 | 
| +      base::Bind(&IsMultiThreaded, proc_self_task);
 | 
| +  RunWhileTrue(cb);
 | 
|  }
 | 
|  
 | 
| +void ThreadHelpers::AssertSingleThreaded() {
 | 
| +  base::ScopedFD task_fd(ProcUtil::OpenProcSelfTask());
 | 
| +  AssertSingleThreaded(task_fd.get());
 | 
| +}
 | 
| +
 | 
| +// static
 | 
|  bool ThreadHelpers::StopThreadAndWatchProcFS(int proc_self_task,
 | 
|                                               base::Thread* thread) {
 | 
|    DCHECK_LE(0, proc_self_task);
 | 
| @@ -66,38 +142,17 @@ bool ThreadHelpers::StopThreadAndWatchProcFS(int proc_self_task,
 | 
|    // not have been updated.
 | 
|    thread->Stop();
 | 
|  
 | 
| -  unsigned int iterations = 0;
 | 
| -  bool thread_present_in_procfs = true;
 | 
| -  // Poll /proc with an exponential back-off, sleeping 2^iterations nanoseconds
 | 
| -  // in nanosleep(2).
 | 
| -  // Note: the clock may not allow for nanosecond granularity, in this case the
 | 
| -  // first iterations would sleep a tiny bit more instead, which would not
 | 
| -  // change the calculations significantly.
 | 
| -  while (thread_present_in_procfs) {
 | 
| -    struct stat task_stat;
 | 
| -    const int fstat_ret =
 | 
| -        fstatat(proc_self_task, thread_id_dir_str.c_str(), &task_stat, 0);
 | 
| -    if (fstat_ret < 0) {
 | 
| -      PCHECK(ENOENT == errno);
 | 
| -      // The thread disappeared from /proc, we're done.
 | 
| -      thread_present_in_procfs = false;
 | 
| -      break;
 | 
| -    }
 | 
| -    // Increase the waiting time exponentially.
 | 
| -    struct timespec ts = {0, 1L << iterations /* nanoseconds */};
 | 
| -    PCHECK(0 == HANDLE_EINTR(nanosleep(&ts, &ts)));
 | 
| -    ++iterations;
 | 
| -
 | 
| -    // Crash after 30 iterations, which means having spent roughly 2s in
 | 
| -    // nanosleep(2) cumulatively.
 | 
| -    CHECK_GT(30U, iterations);
 | 
| -    // In practice, this never goes through more than a couple iterations. In
 | 
| -    // debug mode, crash after 64ms (+ eventually 25 times the granularity of
 | 
| -    // the clock) in nanosleep(2).
 | 
| -    DCHECK_GT(25U, iterations);
 | 
| -  }
 | 
| +  const base::Callback<bool(void)> cb =
 | 
| +      base::Bind(&IsThreadPresentInProcFS, proc_self_task, thread_id_dir_str);
 | 
| +
 | 
| +  RunWhileTrue(cb);
 | 
|  
 | 
|    return true;
 | 
|  }
 | 
|  
 | 
| +// static
 | 
| +const char* ThreadHelpers::GetAssertSingleThreadedErrorMessageForTests() {
 | 
| +  return kAssertSingleThreadedError;
 | 
| +}
 | 
| +
 | 
|  }  // namespace sandbox
 | 
| 
 |