Skip to content

Commit 0d88ba7

Browse files
committed
CXX-890 Spin in instance constructor if we observe concurrent destruction
1 parent c74d2ee commit 0d88ba7

File tree

1 file changed

+14
-3
lines changed

1 file changed

+14
-3
lines changed

src/mongocxx/instance.cpp

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -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+
6468
std::atomic<instance*> current_instance{nullptr};
6569
static_assert(std::is_standard_layout<decltype(current_instance)>::value, "Must be standard layout");
6670
static_assert(std::is_trivially_constructible<decltype(current_instance)>::value, "Must be trivially constructible");
@@ -96,16 +100,23 @@ instance::instance() : instance(nullptr) {
96100
}
97101

98102
instance::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

105115
instance::instance(instance &&) noexcept = default;
106116
instance &instance::operator=(instance &&) noexcept = default;
107117

108118
instance::~instance() {
119+
current_instance.store(reinterpret_cast<instance*>(&sentinel));
109120
_impl.reset();
110121
current_instance.store(nullptr);
111122
}

0 commit comments

Comments
 (0)