Skip to content

Commit e5432f7

Browse files
authored
Merge pull request #252 from brycehutchings/loader_multithreaded_protections
Add locking to protect against multithreaded conformance test usage.
2 parents 57cfe17 + 40bd6c6 commit e5432f7

File tree

4 files changed

+26
-17
lines changed

4 files changed

+26
-17
lines changed
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Loader: Improved locking around a few areas of the loader that aren't robust against usual concurrent calls.

src/loader/loader_core.cpp

Lines changed: 13 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -32,16 +32,12 @@
3232
#include <utility>
3333
#include <vector>
3434

35-
// Global lock to prevent reading JSON manifest files at the same time.
36-
std::mutex &GetLoaderJsonMutex() {
37-
static std::mutex loader_json_mutex;
38-
return loader_json_mutex;
39-
}
40-
41-
// Global lock to prevent simultaneous instance creation/destruction
42-
std::mutex &GetInstanceCreateDestroyMutex() {
43-
static std::mutex instance_create_destroy_mutex;
44-
return instance_create_destroy_mutex;
35+
// Global loader lock to:
36+
// 1. Ensure ActiveLoaderInstance get and set operations are done atomically.
37+
// 2. Ensure RuntimeInterface isn't used to unload the runtime while the runtime is in use.
38+
std::mutex &GetGlobalLoaderMutex() {
39+
static std::mutex loader_mutex;
40+
return loader_mutex;
4541
}
4642

4743
// Prototypes for the debug utils calls used internally.
@@ -90,7 +86,7 @@ static XRAPI_ATTR XrResult XRAPI_CALL LoaderXrEnumerateApiLayerProperties(uint32
9086
LoaderLogger::LogVerboseMessage("xrEnumerateApiLayerProperties", "Entering loader trampoline");
9187

9288
// Make sure only one thread is attempting to read the JSON files at a time.
93-
std::unique_lock<std::mutex> json_lock(GetLoaderJsonMutex());
89+
std::unique_lock<std::mutex> loader_lock(GetGlobalLoaderMutex());
9490

9591
XrResult result = ApiLayerInterface::GetApiLayerProperties("xrEnumerateApiLayerProperties", propertyCapacityInput,
9692
propertyCountOutput, properties);
@@ -123,8 +119,8 @@ LoaderXrEnumerateInstanceExtensionProperties(const char *layerName, uint32_t pro
123119
XrResult result;
124120

125121
{
126-
// Make sure only one thread is attempting to read the JSON files at a time.
127-
std::unique_lock<std::mutex> json_lock(GetLoaderJsonMutex());
122+
// Make sure the runtime isn't unloaded while this call is in progress.
123+
std::unique_lock<std::mutex> loader_lock(GetGlobalLoaderMutex());
128124

129125
// Get the layer extension properties
130126
result = ApiLayerInterface::GetInstanceExtensionProperties("xrEnumerateInstanceExtensionProperties", layerName,
@@ -238,7 +234,8 @@ static XRAPI_ATTR XrResult XRAPI_CALL LoaderXrCreateInstance(const XrInstanceCre
238234
return XR_ERROR_VALIDATION_FAILURE;
239235
}
240236

241-
std::unique_lock<std::mutex> instance_lock(GetInstanceCreateDestroyMutex());
237+
// Make sure the ActiveLoaderInstance::IsAvailable check is done atomically with RuntimeInterface::LoadRuntime.
238+
std::unique_lock<std::mutex> instance_lock(GetGlobalLoaderMutex());
242239

243240
// Check if there is already an XrInstance that is alive. If so, another instance cannot be created.
244241
// The loader does not support multiple simultaneous instances because the loader is intended to be
@@ -255,7 +252,6 @@ static XRAPI_ATTR XrResult XRAPI_CALL LoaderXrCreateInstance(const XrInstanceCre
255252

256253
// Make sure only one thread is attempting to read the JSON files and use the instance.
257254
{
258-
std::unique_lock<std::mutex> json_lock(GetLoaderJsonMutex());
259255
// Load the available runtime
260256
result = RuntimeInterface::LoadRuntime("xrCreateInstance");
261257
if (XR_FAILED(result)) {
@@ -326,7 +322,8 @@ static XRAPI_ATTR XrResult XRAPI_CALL LoaderXrDestroyInstance(XrInstance instanc
326322
return XR_ERROR_HANDLE_INVALID;
327323
}
328324

329-
std::unique_lock<std::mutex> loader_instance_lock(GetInstanceCreateDestroyMutex());
325+
// Make sure the runtime isn't unloaded while it is being used by xrEnumerateInstanceExtensionProperties.
326+
std::unique_lock<std::mutex> loader_lock(GetGlobalLoaderMutex());
330327

331328
LoaderInstance *loader_instance;
332329
XrResult result = ActiveLoaderInstance::Get(&loader_instance, "xrDestroyInstance");

src/loader/loader_logger.cpp

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -136,14 +136,19 @@ LoaderLogger::LoaderLogger() {
136136
}
137137
}
138138

139-
void LoaderLogger::AddLogRecorder(std::unique_ptr<LoaderLogRecorder>&& recorder) { _recorders.push_back(std::move(recorder)); }
139+
void LoaderLogger::AddLogRecorder(std::unique_ptr<LoaderLogRecorder>&& recorder) {
140+
std::unique_lock<std::shared_timed_mutex> lock(_mutex);
141+
_recorders.push_back(std::move(recorder));
142+
}
140143

141144
void LoaderLogger::AddLogRecorderForXrInstance(XrInstance instance, std::unique_ptr<LoaderLogRecorder>&& recorder) {
145+
std::unique_lock<std::shared_timed_mutex> lock(_mutex);
142146
_recordersByInstance[instance].insert(recorder->UniqueId());
143147
_recorders.emplace_back(std::move(recorder));
144148
}
145149

146150
void LoaderLogger::RemoveLogRecorder(uint64_t unique_id) {
151+
std::unique_lock<std::shared_timed_mutex> lock(_mutex);
147152
vector_remove_if_and_erase(
148153
_recorders, [=](std::unique_ptr<LoaderLogRecorder> const& recorder) { return recorder->UniqueId() == unique_id; });
149154
for (auto& recorders : _recordersByInstance) {
@@ -155,6 +160,7 @@ void LoaderLogger::RemoveLogRecorder(uint64_t unique_id) {
155160
}
156161

157162
void LoaderLogger::RemoveLogRecordersForXrInstance(XrInstance instance) {
163+
std::unique_lock<std::shared_timed_mutex> lock(_mutex);
158164
if (_recordersByInstance.find(instance) != _recordersByInstance.end()) {
159165
auto recorders = _recordersByInstance[instance];
160166
vector_remove_if_and_erase(_recorders, [=](std::unique_ptr<LoaderLogRecorder> const& recorder) {
@@ -179,6 +185,7 @@ bool LoaderLogger::LogMessage(XrLoaderLogMessageSeverityFlagBits message_severit
179185
callback_data.session_labels = names_and_labels.labels.empty() ? nullptr : names_and_labels.labels.data();
180186
callback_data.session_labels_count = static_cast<uint8_t>(names_and_labels.labels.size());
181187

188+
std::shared_lock<std::shared_timed_mutex> lock(_mutex);
182189
bool exit_app = false;
183190
for (std::unique_ptr<LoaderLogRecorder>& recorder : _recorders) {
184191
if ((recorder->MessageSeverities() & message_severity) == message_severity &&
@@ -201,6 +208,7 @@ bool LoaderLogger::LogDebugUtilsMessage(XrDebugUtilsMessageSeverityFlagsEXT mess
201208
data_.WrapCallbackData(&augmented_data, callback_data);
202209

203210
// Loop through the recorders
211+
std::shared_lock<std::shared_timed_mutex> lock(_mutex);
204212
for (std::unique_ptr<LoaderLogRecorder>& recorder : _recorders) {
205213
// Only send the message if it's a debug utils recorder and of the type the recorder cares about.
206214
if (recorder->Type() != XR_LOADER_LOG_DEBUG_UTILS ||

src/loader/loader_logger.hpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
#include <vector>
1818
#include <set>
1919
#include <map>
20+
#include <shared_mutex>
2021

2122
#include <openxr/openxr.h>
2223

@@ -173,6 +174,8 @@ class LoaderLogger {
173174
private:
174175
LoaderLogger();
175176

177+
std::shared_timed_mutex _mutex;
178+
176179
// List of *all* available recorder objects (including created specifically for an Instance)
177180
std::vector<std::unique_ptr<LoaderLogRecorder>> _recorders;
178181

0 commit comments

Comments
 (0)