| OLD | NEW | 
|---|
| 1 // Copyright 2014 The Chromium Authors. All rights reserved. | 1 // Copyright 2014 The Chromium Authors. All rights reserved. | 
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be | 
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. | 
| 4 | 4 | 
| 5 #include "sandbox/linux/services/thread_helpers.h" | 5 #include "sandbox/linux/services/thread_helpers.h" | 
| 6 | 6 | 
| 7 #include <errno.h> | 7 #include <errno.h> | 
| 8 #include <fcntl.h> | 8 #include <fcntl.h> | 
| 9 #include <signal.h> | 9 #include <signal.h> | 
| 10 #include <sys/types.h> | 10 #include <sys/types.h> | 
| 11 #include <sys/stat.h> | 11 #include <sys/stat.h> | 
| 12 #include <unistd.h> | 12 #include <unistd.h> | 
| 13 | 13 | 
| 14 #include <string> | 14 #include <string> | 
| 15 | 15 | 
| 16 #include "base/basictypes.h" | 16 #include "base/basictypes.h" | 
|  | 17 #include "base/bind.h" | 
|  | 18 #include "base/callback.h" | 
|  | 19 #include "base/files/scoped_file.h" | 
| 17 #include "base/logging.h" | 20 #include "base/logging.h" | 
| 18 #include "base/posix/eintr_wrapper.h" | 21 #include "base/posix/eintr_wrapper.h" | 
| 19 #include "base/strings/string_number_conversions.h" | 22 #include "base/strings/string_number_conversions.h" | 
| 20 #include "base/threading/platform_thread.h" | 23 #include "base/threading/platform_thread.h" | 
| 21 #include "base/threading/thread.h" | 24 #include "base/threading/thread.h" | 
|  | 25 #include "sandbox/linux/services/proc_util.h" | 
| 22 | 26 | 
| 23 namespace sandbox { | 27 namespace sandbox { | 
| 24 | 28 | 
| 25 namespace { | 29 namespace { | 
| 26 | 30 | 
|  | 31 const char kAssertSingleThreadedError[] = | 
|  | 32     "Current process is not mono-threaded!"; | 
|  | 33 | 
| 27 bool IsSingleThreadedImpl(int proc_self_task) { | 34 bool IsSingleThreadedImpl(int proc_self_task) { | 
| 28   CHECK_LE(0, proc_self_task); | 35   CHECK_LE(0, proc_self_task); | 
| 29   struct stat task_stat; | 36   struct stat task_stat; | 
| 30   int fstat_ret = fstat(proc_self_task, &task_stat); | 37   int fstat_ret = fstat(proc_self_task, &task_stat); | 
| 31   PCHECK(0 == fstat_ret); | 38   PCHECK(0 == fstat_ret); | 
| 32 | 39 | 
| 33   // At least "..", "." and the current thread should be present. | 40   // At least "..", "." and the current thread should be present. | 
| 34   CHECK_LE(3UL, task_stat.st_nlink); | 41   CHECK_LE(3UL, task_stat.st_nlink); | 
| 35   // Counting threads via /proc/self/task could be racy. For the purpose of | 42   // Counting threads via /proc/self/task could be racy. For the purpose of | 
| 36   // determining if the current proces is monothreaded it works: if at any | 43   // determining if the current proces is monothreaded it works: if at any | 
| 37   // time it becomes monothreaded, it'll stay so. | 44   // time it becomes monothreaded, it'll stay so. | 
| 38   return task_stat.st_nlink == 3; | 45   return task_stat.st_nlink == 3; | 
| 39 } | 46 } | 
| 40 | 47 | 
|  | 48 bool IsThreadPresentInProcFS(int proc_self_task, | 
|  | 49                              const std::string& thread_id_dir_str) { | 
|  | 50   struct stat task_stat; | 
|  | 51   const int fstat_ret = | 
|  | 52       fstatat(proc_self_task, thread_id_dir_str.c_str(), &task_stat, 0); | 
|  | 53   if (fstat_ret < 0) { | 
|  | 54     PCHECK(ENOENT == errno); | 
|  | 55     return false; | 
|  | 56   } | 
|  | 57   return true; | 
|  | 58 } | 
|  | 59 | 
|  | 60 // Run |cb| in a loop until it returns false. Every time |cb| runs, sleep | 
|  | 61 // for an exponentially increasing amount of time. |cb| is expected to return | 
|  | 62 // false very quickly and this will crash if it doesn't happen within ~64ms on | 
|  | 63 // Debug builds (2s on Release builds). | 
|  | 64 // This is guaranteed to not sleep more than twice as much as the bare minimum | 
|  | 65 // amount of time. | 
|  | 66 void RunWhileTrue(const base::Callback<bool(void)>& cb) { | 
|  | 67 #if defined(NDEBUG) | 
|  | 68   // In Release mode, crash after 30 iterations, which means having spent | 
|  | 69   // roughly 2s in | 
|  | 70   // nanosleep(2) cumulatively. | 
|  | 71   const unsigned int kMaxIterations = 30U; | 
|  | 72 #else | 
|  | 73   // In practice, this never goes through more than a couple iterations. In | 
|  | 74   // debug mode, crash after 64ms (+ eventually 25 times the granularity of | 
|  | 75   // the clock) in nanosleep(2). This ensures that this is not becoming too | 
|  | 76   // slow. | 
|  | 77   const unsigned int kMaxIterations = 25U; | 
|  | 78 #endif | 
|  | 79 | 
|  | 80   // Run |cb| with an exponential back-off, sleeping 2^iterations nanoseconds | 
|  | 81   // in nanosleep(2). | 
|  | 82   // Note: the clock may not allow for nanosecond granularity, in this case the | 
|  | 83   // first iterations would sleep a tiny bit more instead, which would not | 
|  | 84   // change the calculations significantly. | 
|  | 85   for (unsigned int i = 0; i < kMaxIterations; ++i) { | 
|  | 86     if (!cb.Run()) { | 
|  | 87       return; | 
|  | 88     } | 
|  | 89 | 
|  | 90     // Increase the waiting time exponentially. | 
|  | 91     struct timespec ts = {0, 1L << i /* nanoseconds */}; | 
|  | 92     PCHECK(0 == HANDLE_EINTR(nanosleep(&ts, &ts))); | 
|  | 93   } | 
|  | 94 | 
|  | 95   LOG(FATAL) << kAssertSingleThreadedError << " (iterations: " << kMaxIterations | 
|  | 96              << ")"; | 
|  | 97 | 
|  | 98   NOTREACHED(); | 
|  | 99 } | 
|  | 100 | 
|  | 101 bool IsMultiThreaded(int proc_self_task) { | 
|  | 102   return !ThreadHelpers::IsSingleThreaded(proc_self_task); | 
|  | 103 } | 
|  | 104 | 
| 41 }  // namespace | 105 }  // namespace | 
| 42 | 106 | 
|  | 107 // static | 
| 43 bool ThreadHelpers::IsSingleThreaded(int proc_self_task) { | 108 bool ThreadHelpers::IsSingleThreaded(int proc_self_task) { | 
| 44   DCHECK_LE(-1, proc_self_task); | 109   DCHECK_LE(0, proc_self_task); | 
| 45   if (-1 == proc_self_task) { | 110   return IsSingleThreadedImpl(proc_self_task); | 
| 46     const int task_fd = |  | 
| 47         open("/proc/self/task/", O_RDONLY | O_DIRECTORY | O_CLOEXEC); |  | 
| 48     PCHECK(0 <= task_fd); |  | 
| 49     const bool result = IsSingleThreadedImpl(task_fd); |  | 
| 50     PCHECK(0 == IGNORE_EINTR(close(task_fd))); |  | 
| 51     return result; |  | 
| 52   } else { |  | 
| 53     return IsSingleThreadedImpl(proc_self_task); |  | 
| 54   } |  | 
| 55 } | 111 } | 
| 56 | 112 | 
|  | 113 // static | 
|  | 114 bool ThreadHelpers::IsSingleThreaded() { | 
|  | 115   base::ScopedFD task_fd(ProcUtil::OpenProcSelfTask()); | 
|  | 116   return IsSingleThreaded(task_fd.get()); | 
|  | 117 } | 
|  | 118 | 
|  | 119 // static | 
|  | 120 void ThreadHelpers::AssertSingleThreaded(int proc_self_task) { | 
|  | 121   DCHECK_LE(0, proc_self_task); | 
|  | 122   const base::Callback<bool(void)> cb = | 
|  | 123       base::Bind(&IsMultiThreaded, proc_self_task); | 
|  | 124   RunWhileTrue(cb); | 
|  | 125 } | 
|  | 126 | 
|  | 127 void ThreadHelpers::AssertSingleThreaded() { | 
|  | 128   base::ScopedFD task_fd(ProcUtil::OpenProcSelfTask()); | 
|  | 129   AssertSingleThreaded(task_fd.get()); | 
|  | 130 } | 
|  | 131 | 
|  | 132 // static | 
| 57 bool ThreadHelpers::StopThreadAndWatchProcFS(int proc_self_task, | 133 bool ThreadHelpers::StopThreadAndWatchProcFS(int proc_self_task, | 
| 58                                              base::Thread* thread) { | 134                                              base::Thread* thread) { | 
| 59   DCHECK_LE(0, proc_self_task); | 135   DCHECK_LE(0, proc_self_task); | 
| 60   DCHECK(thread); | 136   DCHECK(thread); | 
| 61   const base::PlatformThreadId thread_id = thread->thread_id(); | 137   const base::PlatformThreadId thread_id = thread->thread_id(); | 
| 62   const std::string thread_id_dir_str = base::IntToString(thread_id) + "/"; | 138   const std::string thread_id_dir_str = base::IntToString(thread_id) + "/"; | 
| 63 | 139 | 
| 64   // The kernel is at liberty to wake the thread id futex before updating | 140   // The kernel is at liberty to wake the thread id futex before updating | 
| 65   // /proc. Following Stop(), the thread is joined, but entries in /proc may | 141   // /proc. Following Stop(), the thread is joined, but entries in /proc may | 
| 66   // not have been updated. | 142   // not have been updated. | 
| 67   thread->Stop(); | 143   thread->Stop(); | 
| 68 | 144 | 
| 69   unsigned int iterations = 0; | 145   const base::Callback<bool(void)> cb = | 
| 70   bool thread_present_in_procfs = true; | 146       base::Bind(&IsThreadPresentInProcFS, proc_self_task, thread_id_dir_str); | 
| 71   // Poll /proc with an exponential back-off, sleeping 2^iterations nanoseconds |  | 
| 72   // in nanosleep(2). |  | 
| 73   // Note: the clock may not allow for nanosecond granularity, in this case the |  | 
| 74   // first iterations would sleep a tiny bit more instead, which would not |  | 
| 75   // change the calculations significantly. |  | 
| 76   while (thread_present_in_procfs) { |  | 
| 77     struct stat task_stat; |  | 
| 78     const int fstat_ret = |  | 
| 79         fstatat(proc_self_task, thread_id_dir_str.c_str(), &task_stat, 0); |  | 
| 80     if (fstat_ret < 0) { |  | 
| 81       PCHECK(ENOENT == errno); |  | 
| 82       // The thread disappeared from /proc, we're done. |  | 
| 83       thread_present_in_procfs = false; |  | 
| 84       break; |  | 
| 85     } |  | 
| 86     // Increase the waiting time exponentially. |  | 
| 87     struct timespec ts = {0, 1L << iterations /* nanoseconds */}; |  | 
| 88     PCHECK(0 == HANDLE_EINTR(nanosleep(&ts, &ts))); |  | 
| 89     ++iterations; |  | 
| 90 | 147 | 
| 91     // Crash after 30 iterations, which means having spent roughly 2s in | 148   RunWhileTrue(cb); | 
| 92     // nanosleep(2) cumulatively. |  | 
| 93     CHECK_GT(30U, iterations); |  | 
| 94     // In practice, this never goes through more than a couple iterations. In |  | 
| 95     // debug mode, crash after 64ms (+ eventually 25 times the granularity of |  | 
| 96     // the clock) in nanosleep(2). |  | 
| 97     DCHECK_GT(25U, iterations); |  | 
| 98   } |  | 
| 99 | 149 | 
| 100   return true; | 150   return true; | 
| 101 } | 151 } | 
| 102 | 152 | 
|  | 153 // static | 
|  | 154 const char* ThreadHelpers::GetAssertSingleThreadedErrorMessageForTests() { | 
|  | 155   return kAssertSingleThreadedError; | 
|  | 156 } | 
|  | 157 | 
| 103 }  // namespace sandbox | 158 }  // namespace sandbox | 
| OLD | NEW | 
|---|