68f531a6b778b91fc8bdc44a21a14b8d661d016e
[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 SingletonVault::~SingletonVault() { destroyInstances(); }
24
25 void SingletonVault::destroyInstances() {
26   RWSpinLock::WriteHolder state_wh(&stateMutex_);
27
28   if (state_ == SingletonVaultState::Quiescing) {
29     return;
30   }
31   state_ = SingletonVaultState::Quiescing;
32
33   RWSpinLock::ReadHolder state_rh(std::move(state_wh));
34
35   {
36     RWSpinLock::ReadHolder rh(&mutex_);
37
38     CHECK_GE(singletons_.size(), creation_order_.size());
39
40     for (auto type_iter = creation_order_.rbegin();
41          type_iter != creation_order_.rend();
42          ++type_iter) {
43       destroyInstance(singletons_.find(*type_iter));
44     }
45   }
46
47   {
48     RWSpinLock::WriteHolder wh(&mutex_);
49     creation_order_.clear();
50   }
51 }
52
53 /* Destroy and clean-up one singleton. Must be invoked while holding
54  * a read lock on mutex_.
55  * @param typeDescriptor - the type key for the removed singleton.
56  */
57 void SingletonVault::destroyInstance(SingletonMap::iterator entry_it) {
58   const auto& type = entry_it->first;
59   auto& entry = *(entry_it->second);
60   if (entry.instance.use_count() > 1) {
61     LOG(ERROR) << "Singleton of type " << type.name() << " has a living "
62                << "reference at destroyInstances time; beware! Raw pointer "
63                << "is " << entry.instance.get() << " with use_count of "
64                << entry.instance.use_count();
65   }
66   entry.state = detail::SingletonEntryState::Dead;
67   entry.instance.reset();
68 }
69
70 void SingletonVault::reenableInstances() {
71   RWSpinLock::WriteHolder state_wh(&stateMutex_);
72
73   stateCheck(SingletonVaultState::Quiescing);
74
75   state_ = SingletonVaultState::Running;
76 }
77
78 SingletonVault* SingletonVault::singleton() {
79   static SingletonVault* vault = new SingletonVault();
80   return vault;
81 }
82
83 void SingletonVault::scheduleDestroyInstances() {
84   class SingletonVaultDestructor {
85    public:
86     ~SingletonVaultDestructor() {
87       SingletonVault::singleton()->destroyInstances();
88     }
89   };
90
91   // Here we intialize a singleton, which calls destroyInstances in its
92   // destructor. Because of singleton destruction order - it will be destroyed
93   // before all the singletons, which were initialized before it and after all
94   // the singletons initialized after it.
95   static SingletonVaultDestructor singletonVaultDestructor;
96 }
97
98 }