| // Copyright 2018 The Chromium Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "crazy_linker_util_threads.h" |
| |
| #include <gtest/gtest.h> |
| |
| #include <memory> |
| |
| #include <sched.h> |
| |
| namespace crazy { |
| |
| TEST(ThreadBase, SimpleThread) { |
| // Create a test thread class that simply sets a flag to true in its |
| // main body and exits immediately. |
| class SimpleThread : public ThreadBase { |
| public: |
| SimpleThread(bool* flag_ptr) : flag_ptr_(flag_ptr) {} |
| |
| private: |
| void Main() override { *flag_ptr_ = true; } |
| bool* flag_ptr_; |
| }; |
| |
| bool flag = false; |
| SimpleThread thread(&flag); |
| thread.Join(); |
| ASSERT_TRUE(flag); |
| } |
| |
| TEST(Mutex, SimpleLockUnlock) { |
| Mutex m; |
| m.Lock(); |
| m.Unlock(); |
| } |
| |
| TEST(Mutex, ThreadSynchronization) { |
| // State shared by all threads, i.e. a mutex-protected counter. |
| struct SharedState { |
| Mutex mutex; |
| int counter = 0; |
| }; |
| // Create kMaxThreads that will use a common lock to increment a counter |
| // in succession. Each thread has a numerical id, and will loop until |
| // the counter reaches before incrementing it then exiting. |
| class TestThread : public ThreadBase { |
| public: |
| TestThread(SharedState* state, int id) : state_(state), id_(id) {} |
| |
| private: |
| void Main() override { |
| bool quit = false; |
| while (!quit) { |
| state_->mutex.Lock(); |
| if (state_->counter == id_) { |
| state_->counter += 1; |
| quit = true; |
| } else { |
| sched_yield(); |
| } |
| state_->mutex.Unlock(); |
| } |
| } |
| |
| SharedState* state_; |
| int id_; |
| }; |
| |
| SharedState state; |
| const int kMaxThreads = 100; |
| std::unique_ptr<TestThread> threads[kMaxThreads]; |
| |
| // Launch all threads |
| for (int n = kMaxThreads; n > 0; n--) { |
| threads[n - 1].reset(new TestThread(&state, n - 1)); |
| } |
| |
| // Join the last thread, this should only return when all other threads |
| // have completed. |
| threads[kMaxThreads - 1]->Join(); |
| |
| ASSERT_EQ(kMaxThreads, state.counter); |
| for (int n = 0; n < kMaxThreads - 1; n++) |
| threads[n]->Join(); |
| } |
| |
| TEST(Condition, ThreadSynchonization) { |
| // A TestThread class which will wait until Start() is called to increment |
| // a given integer counter then exiting. |
| class TestThread : public ThreadBase { |
| public: |
| TestThread(int* counter_ptr) : counter_ptr_(counter_ptr), cond_(&mutex_) {} |
| |
| void Start() { |
| mutex_.Lock(); |
| started_ = true; |
| cond_.Signal(); |
| mutex_.Unlock(); |
| } |
| |
| private: |
| void Main() override { |
| mutex_.Lock(); |
| while (!started_) |
| cond_.Wait(); |
| |
| *counter_ptr_ += 1; |
| mutex_.Unlock(); |
| } |
| |
| int* counter_ptr_; |
| Mutex mutex_; |
| Condition cond_; |
| bool started_ = false; |
| }; |
| |
| int counter = 0; |
| const int kMaxThreads = 100; |
| std::unique_ptr<TestThread> threads[kMaxThreads]; |
| |
| for (int n = 0; n < kMaxThreads; ++n) { |
| threads[n].reset(new TestThread(&counter)); |
| } |
| |
| ASSERT_EQ(0, counter); |
| for (int n = 0; n < kMaxThreads; ++n) { |
| threads[n]->Start(); |
| threads[n]->Join(); |
| ASSERT_EQ(n + 1, counter); |
| } |
| } |
| |
| } // namespace crazy |