diff options
Diffstat (limited to 'test/util/thread_util.h')
-rw-r--r-- | test/util/thread_util.h | 93 |
1 files changed, 93 insertions, 0 deletions
diff --git a/test/util/thread_util.h b/test/util/thread_util.h new file mode 100644 index 000000000..923c4fe10 --- /dev/null +++ b/test/util/thread_util.h @@ -0,0 +1,93 @@ +// Copyright 2018 The gVisor Authors. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#ifndef GVISOR_TEST_UTIL_THREAD_UTIL_H_ +#define GVISOR_TEST_UTIL_THREAD_UTIL_H_ + +#include <pthread.h> +#ifdef __linux__ +#include <sys/syscall.h> +#endif +#include <unistd.h> + +#include <functional> +#include <utility> + +#include "test/util/logging.h" + +namespace gvisor { +namespace testing { + +// ScopedThread is a minimal wrapper around pthreads. +// +// This is used in lieu of more complex mechanisms because it provides very +// predictable behavior (no messing with timers, etc.) The thread will +// automatically joined when it is destructed (goes out of scope), but can be +// joined manually as well. +class ScopedThread { + public: + // Constructs a thread that executes f exactly once. + explicit ScopedThread(std::function<void*()> f) : f_(std::move(f)) { + CreateThread(); + } + + explicit ScopedThread(const std::function<void()>& f) { + f_ = [=] { + f(); + return nullptr; + }; + CreateThread(); + } + + ScopedThread(const ScopedThread& other) = delete; + ScopedThread& operator=(const ScopedThread& other) = delete; + + // Joins the thread. + ~ScopedThread() { Join(); } + + // Waits until this thread has finished executing. Join is idempotent and may + // be called multiple times, however Join itself is not thread-safe. + void* Join() { + if (!joined_) { + TEST_PCHECK(pthread_join(pt_, &retval_) == 0); + joined_ = true; + } + return retval_; + } + + private: + void CreateThread() { + TEST_PCHECK_MSG(pthread_create( + &pt_, /* attr = */ nullptr, + +[](void* arg) -> void* { + return static_cast<ScopedThread*>(arg)->f_(); + }, + this) == 0, + "thread creation failed"); + } + + std::function<void*()> f_; + pthread_t pt_; + bool joined_ = false; + void* retval_ = nullptr; +}; + +#ifdef __linux__ +inline pid_t gettid() { return syscall(SYS_gettid); } +#endif + +} // namespace testing +} // namespace gvisor + +#endif // GVISOR_TEST_UTIL_THREAD_UTIL_H_ |