(wangle) fix after-delete assert
[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       auto type = *type_iter;
44       auto it = singletons_.find(type);
45       CHECK(it != singletons_.end());
46       auto& entry = it->second;
47       std::lock_guard<std::mutex> entry_guard(entry->mutex);
48       if (entry->instance.use_count() > 1) {
49         LOG(ERROR) << "Singleton of type " << type.name() << " has a living "
50                    << "reference at destroyInstances time; beware! Raw pointer "
51                    << "is " << entry->instance.get() << " with use_count of "
52                    << entry->instance.use_count();
53       }
54       entry->instance.reset();
55       entry->state = SingletonEntryState::Dead;
56       entry->state_condvar.notify_all();
57     }
58   }
59
60   {
61     RWSpinLock::WriteHolder wh(&mutex_);
62     creation_order_.clear();
63   }
64 }
65
66 void SingletonVault::reenableInstances() {
67   RWSpinLock::WriteHolder state_wh(&stateMutex_);
68
69   stateCheck(SingletonVaultState::Quiescing);
70
71   state_ = SingletonVaultState::Running;
72 }
73
74 SingletonVault* SingletonVault::singleton() {
75   static SingletonVault* vault = new SingletonVault();
76   return vault;
77 }
78
79 void SingletonVault::scheduleDestroyInstances() {
80   class SingletonVaultDestructor {
81    public:
82     ~SingletonVaultDestructor() {
83       SingletonVault::singleton()->destroyInstances();
84     }
85   };
86
87   // Here we intialize a singleton, which calls destroyInstances in its
88   // destructor. Because of singleton destruction order - it will be destroyed
89   // before all the singletons, which were initialized before it and after all
90   // the singletons initialized after it.
91   static SingletonVaultDestructor singletonVaultDestructor;
92 }
93
94 }