@@ -61,6 +61,10 @@ void user_log_handler(::mongoc_log_level_t mongoc_log_level, const char *log_dom
6161 stdx::string_view{log_domain}, stdx::string_view{message});
6262}
6363
64+ // A region of memory that acts as a sentintel value indicating that an instance object is being
65+ // destroyed. We only care about the address of this object, never its contents.
66+ typename std::aligned_storage<sizeof (instance), alignof (instance)>::type sentinel;
67+
6468std::atomic<instance*> current_instance{nullptr };
6569static_assert (std::is_standard_layout<decltype (current_instance)>::value, " Must be standard layout" );
6670static_assert (std::is_trivially_constructible<decltype (current_instance)>::value, " Must be trivially constructible" );
@@ -96,16 +100,23 @@ instance::instance() : instance(nullptr) {
96100}
97101
98102instance::instance (std::unique_ptr<logger> logger) {
99- instance* expected = nullptr ;
100- if (!current_instance.compare_exchange_strong (expected, this ))
101- throw logic_error{error_code::k_instance_already_exists};
103+
104+ while (true ) {
105+ instance* expected = nullptr ;
106+ if (current_instance.compare_exchange_strong (expected, this ))
107+ break ;
108+ if (expected != reinterpret_cast <instance*>(&sentinel))
109+ throw logic_error{error_code::k_instance_already_exists};
110+ }
111+
102112 _impl = stdx::make_unique<impl>(std::move (logger));
103113}
104114
105115instance::instance (instance &&) noexcept = default ;
106116instance &instance::operator =(instance &&) noexcept = default ;
107117
108118instance::~instance () {
119+ current_instance.store (reinterpret_cast <instance*>(&sentinel));
109120 _impl.reset ();
110121 current_instance.store (nullptr );
111122}
0 commit comments