github.com/SagerNet/gvisor@v0.0.0-20210707092255-7731c139d75c/test/util/thread_util.h (about) 1 // Copyright 2018 The gVisor Authors. 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 #ifndef GVISOR_TEST_UTIL_THREAD_UTIL_H_ 16 #define GVISOR_TEST_UTIL_THREAD_UTIL_H_ 17 18 #include <pthread.h> 19 #ifdef __linux__ 20 #include <sys/syscall.h> 21 #endif 22 #include <unistd.h> 23 24 #include <functional> 25 #include <utility> 26 27 #include "test/util/logging.h" 28 29 namespace gvisor { 30 namespace testing { 31 32 // ScopedThread is a minimal wrapper around pthreads. 33 // 34 // This is used in lieu of more complex mechanisms because it provides very 35 // predictable behavior (no messing with timers, etc.) The thread will 36 // automatically joined when it is destructed (goes out of scope), but can be 37 // joined manually as well. 38 class ScopedThread { 39 public: 40 // Constructs a thread that executes f exactly once. 41 explicit ScopedThread(std::function<void*()> f) : f_(std::move(f)) { 42 CreateThread(); 43 } 44 45 explicit ScopedThread(const std::function<void()>& f) { 46 f_ = [=] { 47 f(); 48 return nullptr; 49 }; 50 CreateThread(); 51 } 52 53 ScopedThread(const ScopedThread& other) = delete; 54 ScopedThread& operator=(const ScopedThread& other) = delete; 55 56 // Joins the thread. 57 ~ScopedThread() { Join(); } 58 59 // Waits until this thread has finished executing. Join is idempotent and may 60 // be called multiple times, however Join itself is not thread-safe. 61 void* Join() { 62 if (!joined_) { 63 TEST_PCHECK(pthread_join(pt_, &retval_) == 0); 64 joined_ = true; 65 } 66 return retval_; 67 } 68 69 private: 70 void CreateThread() { 71 TEST_PCHECK_MSG(pthread_create( 72 &pt_, /* attr = */ nullptr, 73 +[](void* arg) -> void* { 74 return static_cast<ScopedThread*>(arg)->f_(); 75 }, 76 this) == 0, 77 "thread creation failed"); 78 } 79 80 std::function<void*()> f_; 81 pthread_t pt_; 82 bool joined_ = false; 83 void* retval_ = nullptr; 84 }; 85 86 #ifdef __linux__ 87 inline pid_t gettid() { return syscall(SYS_gettid); } 88 #endif 89 90 } // namespace testing 91 } // namespace gvisor 92 93 #endif // GVISOR_TEST_UTIL_THREAD_UTIL_H_