d4b6e81d824161c83168bfc7058cd8ec8414babe
[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 detail {
24
25 constexpr std::chrono::seconds SingletonHolderBase::kDestroyWaitTime;
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       singletons_[*type_iter]->destroyInstance();
50     }
51
52     for (auto& singleton_type: creation_order_) {
53       auto singleton = singletons_[singleton_type];
54       if (!singleton->hasLiveInstance()) {
55         continue;
56       }
57
58       LOG(DFATAL) << "Singleton of type " << singleton->type().name() << " has "
59                   << "a living reference after destroyInstances was finished;"
60                   << "beware! It is very likely that this singleton instance "
61                   << "will be leaked.";
62     }
63   }
64
65   {
66     RWSpinLock::WriteHolder wh(&mutex_);
67     creation_order_.clear();
68   }
69 }
70
71 void SingletonVault::reenableInstances() {
72   RWSpinLock::WriteHolder state_wh(&stateMutex_);
73
74   stateCheck(SingletonVaultState::Quiescing);
75
76   state_ = SingletonVaultState::Running;
77 }
78
79 void SingletonVault::scheduleDestroyInstances() {
80   RequestContext::getStaticContext();
81
82   class SingletonVaultDestructor {
83    public:
84     ~SingletonVaultDestructor() {
85       SingletonVault::singleton()->destroyInstances();
86     }
87   };
88
89   // Here we intialize a singleton, which calls destroyInstances in its
90   // destructor. Because of singleton destruction order - it will be destroyed
91   // before all the singletons, which were initialized before it and after all
92   // the singletons initialized after it.
93   static SingletonVaultDestructor singletonVaultDestructor;
94 }
95
96 }