lifetime_test.cc
Go to the documentation of this file.
00001 // Copyright 2017 The Abseil Authors.
00002 //
00003 // Licensed under the Apache License, Version 2.0 (the "License");
00004 // you may not use this file except in compliance with the License.
00005 // You may obtain a copy of the License at
00006 //
00007 //      https://www.apache.org/licenses/LICENSE-2.0
00008 //
00009 // Unless required by applicable law or agreed to in writing, software
00010 // distributed under the License is distributed on an "AS IS" BASIS,
00011 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
00012 // See the License for the specific language governing permissions and
00013 // limitations under the License.
00014 
00015 #include <cstdlib>
00016 #include <thread>  // NOLINT(build/c++11), Abseil test
00017 #include <type_traits>
00018 
00019 #include "absl/base/attributes.h"
00020 #include "absl/base/const_init.h"
00021 #include "absl/base/internal/raw_logging.h"
00022 #include "absl/base/thread_annotations.h"
00023 #include "absl/synchronization/mutex.h"
00024 #include "absl/synchronization/notification.h"
00025 
00026 namespace {
00027 
00028 // A two-threaded test which checks that Mutex, CondVar, and Notification have
00029 // correct basic functionality.  The intent is to establish that they
00030 // function correctly in various phases of construction and destruction.
00031 //
00032 // Thread one acquires a lock on 'mutex', wakes thread two via 'notification',
00033 // then waits for 'state' to be set, as signalled by 'condvar'.
00034 //
00035 // Thread two waits on 'notification', then sets 'state' inside the 'mutex',
00036 // signalling the change via 'condvar'.
00037 //
00038 // These tests use ABSL_RAW_CHECK to validate invariants, rather than EXPECT or
00039 // ASSERT from gUnit, because we need to invoke them during global destructors,
00040 // when gUnit teardown would have already begun.
00041 void ThreadOne(absl::Mutex* mutex, absl::CondVar* condvar,
00042                absl::Notification* notification, bool* state) {
00043   // Test that the notification is in a valid initial state.
00044   ABSL_RAW_CHECK(!notification->HasBeenNotified(), "invalid Notification");
00045   ABSL_RAW_CHECK(*state == false, "*state not initialized");
00046 
00047   {
00048     absl::MutexLock lock(mutex);
00049 
00050     notification->Notify();
00051     ABSL_RAW_CHECK(notification->HasBeenNotified(), "invalid Notification");
00052 
00053     while (*state == false) {
00054       condvar->Wait(mutex);
00055     }
00056   }
00057 }
00058 
00059 void ThreadTwo(absl::Mutex* mutex, absl::CondVar* condvar,
00060                absl::Notification* notification, bool* state) {
00061   ABSL_RAW_CHECK(*state == false, "*state not initialized");
00062 
00063   // Wake thread one
00064   notification->WaitForNotification();
00065   ABSL_RAW_CHECK(notification->HasBeenNotified(), "invalid Notification");
00066   {
00067     absl::MutexLock lock(mutex);
00068     *state = true;
00069     condvar->Signal();
00070   }
00071 }
00072 
00073 // Launch thread 1 and thread 2, and block on their completion.
00074 // If any of 'mutex', 'condvar', or 'notification' is nullptr, use a locally
00075 // constructed instance instead.
00076 void RunTests(absl::Mutex* mutex, absl::CondVar* condvar) {
00077   absl::Mutex default_mutex;
00078   absl::CondVar default_condvar;
00079   absl::Notification notification;
00080   if (!mutex) {
00081     mutex = &default_mutex;
00082   }
00083   if (!condvar) {
00084     condvar = &default_condvar;
00085   }
00086   bool state = false;
00087   std::thread thread_one(ThreadOne, mutex, condvar, &notification, &state);
00088   std::thread thread_two(ThreadTwo, mutex, condvar, &notification, &state);
00089   thread_one.join();
00090   thread_two.join();
00091 }
00092 
00093 void TestLocals() {
00094   absl::Mutex mutex;
00095   absl::CondVar condvar;
00096   RunTests(&mutex, &condvar);
00097 }
00098 
00099 // Normal kConstInit usage
00100 ABSL_CONST_INIT absl::Mutex const_init_mutex(absl::kConstInit);
00101 void TestConstInitGlobal() { RunTests(&const_init_mutex, nullptr); }
00102 
00103 // Global variables during start and termination
00104 //
00105 // In a translation unit, static storage duration variables are initialized in
00106 // the order of their definitions, and destroyed in the reverse order of their
00107 // definitions.  We can use this to arrange for tests to be run on these objects
00108 // before they are created, and after they are destroyed.
00109 
00110 using Function = void (*)();
00111 
00112 class OnConstruction {
00113  public:
00114   explicit OnConstruction(Function fn) { fn(); }
00115 };
00116 
00117 class OnDestruction {
00118  public:
00119   explicit OnDestruction(Function fn) : fn_(fn) {}
00120   ~OnDestruction() { fn_(); }
00121  private:
00122   Function fn_;
00123 };
00124 
00125 // kConstInit
00126 // Test early usage.  (Declaration comes first; definitions must appear after
00127 // the test runner.)
00128 extern absl::Mutex early_const_init_mutex;
00129 // (Normally I'd write this +[], to make the cast-to-function-pointer explicit,
00130 // but in some MSVC setups we support, lambdas provide conversion operators to
00131 // different flavors of function pointers, making this trick ambiguous.)
00132 OnConstruction test_early_const_init([] {
00133   RunTests(&early_const_init_mutex, nullptr);
00134 });
00135 // This definition appears before test_early_const_init, but it should be
00136 // initialized first (due to constant initialization).  Test that the object
00137 // actually works when constructed this way.
00138 ABSL_CONST_INIT absl::Mutex early_const_init_mutex(absl::kConstInit);
00139 
00140 // Furthermore, test that the const-init c'tor doesn't stomp over the state of
00141 // a Mutex.  Really, this is a test that the platform under test correctly
00142 // supports C++11 constant initialization.  (The constant-initialization
00143 // constructors of globals "happen at link time"; memory is pre-initialized,
00144 // before the constructors of either grab_lock or check_still_locked are run.)
00145 extern absl::Mutex const_init_sanity_mutex;
00146 OnConstruction grab_lock([]() NO_THREAD_SAFETY_ANALYSIS {
00147   const_init_sanity_mutex.Lock();
00148 });
00149 ABSL_CONST_INIT absl::Mutex const_init_sanity_mutex(absl::kConstInit);
00150 OnConstruction check_still_locked([]() NO_THREAD_SAFETY_ANALYSIS {
00151   const_init_sanity_mutex.AssertHeld();
00152   const_init_sanity_mutex.Unlock();
00153 });
00154 
00155 // Test shutdown usage.  (Declarations come first; definitions must appear after
00156 // the test runner.)
00157 extern absl::Mutex late_const_init_mutex;
00158 // OnDestruction is being used here as a global variable, even though it has a
00159 // non-trivial destructor.  This is against the style guide.  We're violating
00160 // that rule here to check that the exception we allow for kConstInit is safe.
00161 // NOLINTNEXTLINE
00162 OnDestruction test_late_const_init([] {
00163   RunTests(&late_const_init_mutex, nullptr);
00164 });
00165 ABSL_CONST_INIT absl::Mutex late_const_init_mutex(absl::kConstInit);
00166 
00167 }  // namespace
00168 
00169 int main() {
00170   TestLocals();
00171   TestConstInitGlobal();
00172   // Explicitly call exit(0) here, to make it clear that we intend for the
00173   // above global object destructors to run.
00174   std::exit(0);
00175 }


abseil_cpp
Author(s):
autogenerated on Wed Jun 19 2019 19:42:15