Revert "Using type-tags for test SingletonVaults"
[folly.git] / folly / experimental / Singleton.cpp
1 /*
2  * Copyright 2014 Facebook, Inc.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *   http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16
17 #include <folly/experimental/Singleton.h>
18
19 #include <string>
20
21 namespace folly {
22
23 namespace {
24
25 static constexpr std::chrono::seconds kDestroyWaitTime{5};
26
27 }
28
29 SingletonVault::~SingletonVault() { destroyInstances(); }
30
31 void SingletonVault::destroyInstances() {
32   RWSpinLock::WriteHolder state_wh(&stateMutex_);
33
34   if (state_ == SingletonVaultState::Quiescing) {
35     return;
36   }
37   state_ = SingletonVaultState::Quiescing;
38
39   RWSpinLock::ReadHolder state_rh(std::move(state_wh));
40
41   {
42     RWSpinLock::ReadHolder rh(&mutex_);
43
44     CHECK_GE(singletons_.size(), creation_order_.size());
45
46     for (auto type_iter = creation_order_.rbegin();
47          type_iter != creation_order_.rend();
48          ++type_iter) {
49       destroyInstance(singletons_.find(*type_iter));
50     }
51   }
52
53   {
54     RWSpinLock::WriteHolder wh(&mutex_);
55     creation_order_.clear();
56   }
57 }
58
59 /* Destroy and clean-up one singleton. Must be invoked while holding
60  * a read lock on mutex_.
61  * @param typeDescriptor - the type key for the removed singleton.
62  */
63 void SingletonVault::destroyInstance(SingletonMap::iterator entry_it) {
64   const auto& type = entry_it->first;
65   auto& entry = *(entry_it->second);
66
67   entry.state = detail::SingletonEntryState::Dead;
68   entry.instance.reset();
69   auto wait_result = entry.destroy_baton->timed_wait(
70     std::chrono::steady_clock::now() + kDestroyWaitTime);
71   if (!wait_result) {
72     LOG(ERROR) << "Singleton of type " << type.prettyName() << " has a living "
73                << "reference at destroyInstances time; beware! Raw pointer "
74                << "is " << entry.instance_ptr << ". It is very likely that "
75                << "some other singleton is holding a shared_ptr to it. Make "
76                << "sure dependencies between these singletons are properly "
77                << "defined.";
78   }
79 }
80
81 void SingletonVault::reenableInstances() {
82   RWSpinLock::WriteHolder state_wh(&stateMutex_);
83
84   stateCheck(SingletonVaultState::Quiescing);
85
86   state_ = SingletonVaultState::Running;
87 }
88
89 SingletonVault* SingletonVault::singleton() {
90   static SingletonVault* vault = new SingletonVault();
91   return vault;
92 }
93
94 void SingletonVault::scheduleDestroyInstances() {
95   RequestContext::getStaticContext();
96
97   class SingletonVaultDestructor {
98    public:
99     ~SingletonVaultDestructor() {
100       SingletonVault::singleton()->destroyInstances();
101     }
102   };
103
104   // Here we intialize a singleton, which calls destroyInstances in its
105   // destructor. Because of singleton destruction order - it will be destroyed
106   // before all the singletons, which were initialized before it and after all
107   // the singletons initialized after it.
108   static SingletonVaultDestructor singletonVaultDestructor;
109 }
110
111 }