folly/wangle -> wangle cutover
[folly.git] / folly / Singleton.cpp
1 /*
2  * Copyright 2015 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/Singleton.h>
18
19 #include <string>
20
21 namespace folly {
22
23 namespace detail {
24
25 constexpr std::chrono::seconds SingletonHolderBase::kDestroyWaitTime;
26
27 }
28
29 namespace {
30
31 struct FatalHelper {
32   ~FatalHelper() {
33     if (!leakedSingletons_.empty()) {
34       std::string leakedTypes;
35       for (const auto& singleton : leakedSingletons_) {
36         leakedTypes += "\t" + singleton.name() + "\n";
37       }
38       LOG(DFATAL) << "Singletons of the following types had living references "
39                   << "after destroyInstances was finished:\n" << leakedTypes
40                   << "beware! It is very likely that those singleton instances "
41                   << "are leaked.";
42     }
43   }
44
45   std::vector<detail::TypeDescriptor> leakedSingletons_;
46 };
47
48 #ifdef __APPLE__
49 // OS X doesn't support constructor priorities.
50 FatalHelper fatalHelper;
51 #else
52 FatalHelper __attribute__ ((__init_priority__ (101))) fatalHelper;
53 #endif
54
55 }
56
57 SingletonVault::~SingletonVault() { destroyInstances(); }
58
59 void SingletonVault::destroyInstances() {
60   RWSpinLock::WriteHolder state_wh(&stateMutex_);
61
62   if (state_ == SingletonVaultState::Quiescing) {
63     return;
64   }
65   state_ = SingletonVaultState::Quiescing;
66
67   RWSpinLock::ReadHolder state_rh(std::move(state_wh));
68
69   {
70     RWSpinLock::ReadHolder rh(&mutex_);
71
72     CHECK_GE(singletons_.size(), creation_order_.size());
73
74     for (auto type_iter = creation_order_.rbegin();
75          type_iter != creation_order_.rend();
76          ++type_iter) {
77       singletons_[*type_iter]->destroyInstance();
78     }
79
80     for (auto& singleton_type: creation_order_) {
81       auto singleton = singletons_[singleton_type];
82       if (!singleton->hasLiveInstance()) {
83         continue;
84       }
85
86       fatalHelper.leakedSingletons_.push_back(singleton->type());
87     }
88   }
89
90   {
91     RWSpinLock::WriteHolder wh(&mutex_);
92     creation_order_.clear();
93   }
94 }
95
96 void SingletonVault::reenableInstances() {
97   RWSpinLock::WriteHolder state_wh(&stateMutex_);
98
99   stateCheck(SingletonVaultState::Quiescing);
100
101   state_ = SingletonVaultState::Running;
102 }
103
104 void SingletonVault::scheduleDestroyInstances() {
105   RequestContext::saveContext();
106
107   class SingletonVaultDestructor {
108    public:
109     ~SingletonVaultDestructor() {
110       SingletonVault::singleton()->destroyInstances();
111     }
112   };
113
114   // Here we intialize a singleton, which calls destroyInstances in its
115   // destructor. Because of singleton destruction order - it will be destroyed
116   // before all the singletons, which were initialized before it and after all
117   // the singletons initialized after it.
118   static SingletonVaultDestructor singletonVaultDestructor;
119 }
120
121 }