Commit 377573cc by Ben Clayton

Use Thread Safety Analysis annotations throughout SwiftShader.

Switch from std::mutex and std::unique_lock to marl::mutex and marl::lock. The marl versions are TSA-friendly replacements, and do not involve the marl scheduler. Bug: b/153194656 Change-Id: Ief3758fb0d52b8fcdaa4208d2c25ad04c2d40108 Reviewed-on: https://swiftshader-review.googlesource.com/c/SwiftShader/+/43436Reviewed-by: 's avatarNicolas Capens <nicolascapens@google.com> Tested-by: 's avatarBen Clayton <bclayton@google.com> Kokoro-Result: kokoro <noreply+kokoro@google.com>
parent 08090462
......@@ -582,6 +582,10 @@ if(BUILD_MARL)
add_subdirectory(${THIRD_PARTY_DIR}/marl)
endif()
if(MARL_THREAD_SAFETY_ANALYSIS_SUPPORTED)
list(APPEND SWIFTSHADER_COMPILE_OPTIONS "-Wthread-safety")
endif()
###########################################################
# cppdap
###########################################################
......
......@@ -1683,7 +1683,7 @@ Blitter::BlitRoutineType Blitter::generate(const State &state)
Blitter::BlitRoutineType Blitter::getBlitRoutine(const State &state)
{
std::unique_lock<std::mutex> lock(blitMutex);
marl::lock lock(blitMutex);
auto blitRoutine = blitCache.lookup(state);
if(!blitRoutine)
......@@ -1697,7 +1697,7 @@ Blitter::BlitRoutineType Blitter::getBlitRoutine(const State &state)
Blitter::CornerUpdateRoutineType Blitter::getCornerUpdateRoutine(const State &state)
{
std::unique_lock<std::mutex> lock(cornerUpdateMutex);
marl::lock lock(cornerUpdateMutex);
auto cornerUpdateRoutine = cornerUpdateCache.lookup(state);
if(!cornerUpdateRoutine)
......
......@@ -20,8 +20,10 @@
#include "Reactor/Reactor.hpp"
#include "Vulkan/VkFormat.h"
#include "marl/mutex.h"
#include "marl/tsa.h"
#include <cstring>
#include <mutex>
namespace vk {
......@@ -186,10 +188,11 @@ private:
const VkImageSubresourceLayers &dstSubresourceLayers, Edge dstEdge,
const VkImageSubresourceLayers &srcSubresourceLayers, Edge srcEdge);
std::mutex blitMutex;
RoutineCache<State, BlitFunction::CFunctionType> blitCache; // guarded by blitMutex
std::mutex cornerUpdateMutex;
RoutineCache<State, CornerUpdateFunction::CFunctionType> cornerUpdateCache; // guarded by cornerUpdateMutex
marl::mutex blitMutex;
RoutineCache<State, BlitFunction::CFunctionType> blitCache GUARDED_BY(blitMutex);
marl::mutex cornerUpdateMutex;
RoutineCache<State, CornerUpdateFunction::CFunctionType> cornerUpdateCache GUARDED_BY(cornerUpdateMutex);
};
} // namespace sw
......
......@@ -25,9 +25,10 @@
#include <assert.h>
#include <chrono>
#include <condition_variable>
#include <mutex>
#include <queue>
#include "marl/mutex.h"
namespace sw {
// TaskEvents is an interface for notifying when tasks begin and end.
......@@ -64,7 +65,7 @@ public:
// add() begins a new task.
void add()
{
std::unique_lock<std::mutex> lock(mutex);
marl::lock lock(mutex);
++count_;
}
......@@ -73,7 +74,7 @@ public:
// WaitGroup.
bool done()
{
std::unique_lock<std::mutex> lock(mutex);
marl::lock lock(mutex);
assert(count_ > 0);
--count_;
if(count_ == 0)
......@@ -86,8 +87,8 @@ public:
// wait() blocks until all the tasks have been finished.
void wait()
{
std::unique_lock<std::mutex> lock(mutex);
condition.wait(lock, [this] { return count_ == 0; });
marl::lock lock(mutex);
lock.wait(condition, [this]() REQUIRES(mutex) { return count_ == 0; });
}
// wait() blocks until all the tasks have been finished or the timeout
......@@ -96,8 +97,8 @@ public:
template<class CLOCK, class DURATION>
bool wait(const std::chrono::time_point<CLOCK, DURATION> &timeout)
{
std::unique_lock<std::mutex> lock(mutex);
return condition.wait_until(lock, timeout, [this] { return count_ == 0; });
marl::lock lock(mutex);
return condition.wait_until(lock, timeout, [this]() REQUIRES(mutex) { return count_ == 0; });
}
// count() returns the number of times add() has been called without a call
......@@ -106,7 +107,7 @@ public:
// change after returning.
int32_t count()
{
std::unique_lock<std::mutex> lock(mutex);
marl::lock lock(mutex);
return count_;
}
......@@ -115,8 +116,8 @@ public:
void finish() override { done(); }
private:
int32_t count_ = 0; // guarded by mutex
std::mutex mutex;
marl::mutex mutex;
int32_t count_ GUARDED_BY(mutex) = 0;
std::condition_variable condition;
};
......@@ -147,8 +148,8 @@ public:
size_t count();
private:
std::queue<T> queue;
std::mutex mutex;
marl::mutex mutex;
std::queue<T> queue GUARDED_BY(mutex);
std::condition_variable added;
};
......@@ -159,9 +160,9 @@ Chan<T>::Chan()
template<typename T>
T Chan<T>::take()
{
std::unique_lock<std::mutex> lock(mutex);
marl::lock lock(mutex);
// Wait for item to be added.
added.wait(lock, [this] { return queue.size() > 0; });
lock.wait(added, [this]() REQUIRES(mutex) { return queue.size() > 0; });
T out = queue.front();
queue.pop();
return out;
......@@ -170,7 +171,7 @@ T Chan<T>::take()
template<typename T>
std::pair<T, bool> Chan<T>::tryTake()
{
std::unique_lock<std::mutex> lock(mutex);
marl::lock lock(mutex);
if(queue.size() == 0)
{
return std::make_pair(T{}, false);
......@@ -183,7 +184,7 @@ std::pair<T, bool> Chan<T>::tryTake()
template<typename T>
void Chan<T>::put(const T &item)
{
std::unique_lock<std::mutex> lock(mutex);
marl::lock lock(mutex);
queue.push(item);
added.notify_one();
}
......@@ -191,7 +192,7 @@ void Chan<T>::put(const T &item)
template<typename T>
size_t Chan<T>::count()
{
std::unique_lock<std::mutex> lock(mutex);
marl::lock lock(mutex);
return queue.size();
}
......
......@@ -130,7 +130,6 @@ public:
Broadcaster broadcaster;
std::mutex mutex;
std::vector<EventListener *> eventListeners;
std::unordered_map<std::thread::id, std::shared_ptr<Thread>> threadsByStdId;
std::unordered_set<std::string> functionBreakpoints;
std::unordered_map<std::string, std::vector<int>> pendingBreakpoints;
......
......@@ -14,7 +14,8 @@
#include "File.hpp"
#include <mutex>
#include "marl/mutex.h"
#include <unordered_set>
namespace {
......@@ -33,8 +34,8 @@ protected:
FileBase(ID id, std::string dir, std::string name, std::string source);
private:
mutable std::mutex breakpointMutex;
std::unordered_set<int> breakpoints; // guarded by breakpointMutex
mutable marl::mutex breakpointMutex;
std::unordered_set<int> breakpoints GUARDED_BY(breakpointMutex);
};
FileBase::FileBase(ID id, std::string dir, std::string name, std::string source)
......@@ -43,19 +44,19 @@ FileBase::FileBase(ID id, std::string dir, std::string name, std::string source)
void FileBase::clearBreakpoints()
{
std::unique_lock<std::mutex> lock(breakpointMutex);
marl::lock lock(breakpointMutex);
breakpoints.clear();
}
void FileBase::addBreakpoint(int line)
{
std::unique_lock<std::mutex> lock(breakpointMutex);
marl::lock lock(breakpointMutex);
breakpoints.emplace(line);
}
bool FileBase::hasBreakpoint(int line) const
{
std::unique_lock<std::mutex> lock(breakpointMutex);
marl::lock lock(breakpointMutex);
return breakpoints.count(line) > 0;
}
......
......@@ -28,17 +28,17 @@ Thread::Thread(ID id, Context *ctx)
void Thread::setName(const std::string &name)
{
std::unique_lock<std::mutex> lock(mutex);
marl::lock lock(mutex);
name_ = name;
}
std::string Thread::name() const
{
std::unique_lock<std::mutex> lock(mutex);
marl::lock lock(mutex);
return name_;
}
void Thread::onLocationUpdate(std::unique_lock<std::mutex> &lock)
void Thread::onLocationUpdate(marl::lock &lock)
{
auto location = frames.back()->location;
......@@ -55,7 +55,7 @@ void Thread::onLocationUpdate(std::unique_lock<std::mutex> &lock)
{
case State::Paused:
{
stateCV.wait(lock, [this] { return state_ != State::Paused; });
lock.wait(stateCV, [this]() REQUIRES(mutex) { return state_ != State::Paused; });
break;
}
......@@ -65,7 +65,7 @@ void Thread::onLocationUpdate(std::unique_lock<std::mutex> &lock)
{
broadcast->onThreadStepped(id);
state_ = State::Paused;
stateCV.wait(lock, [this] { return state_ != State::Paused; });
lock.wait(stateCV, [this]() REQUIRES(mutex) { return state_ != State::Paused; });
pauseAtFrame = 0;
}
break;
......@@ -81,7 +81,7 @@ void Thread::enter(Context::Lock &ctxlck, const std::shared_ptr<File> &file, con
auto frame = ctxlck.createFrame(file, function);
auto isFunctionBreakpoint = ctxlck.isFunctionBreakpoint(function);
std::unique_lock<std::mutex> lock(mutex);
marl::lock lock(mutex);
frames.push_back(frame);
if(isFunctionBreakpoint)
{
......@@ -92,13 +92,13 @@ void Thread::enter(Context::Lock &ctxlck, const std::shared_ptr<File> &file, con
void Thread::exit()
{
std::unique_lock<std::mutex> lock(mutex);
marl::lock lock(mutex);
frames.pop_back();
}
void Thread::update(std::function<void(Frame &)> f)
{
std::unique_lock<std::mutex> lock(mutex);
marl::lock lock(mutex);
auto &frame = *frames.back();
auto oldLocation = frame.location;
f(frame);
......@@ -110,13 +110,13 @@ void Thread::update(std::function<void(Frame &)> f)
Frame Thread::frame() const
{
std::unique_lock<std::mutex> lock(mutex);
marl::lock lock(mutex);
return *frames.back();
}
std::vector<Frame> Thread::stack() const
{
std::unique_lock<std::mutex> lock(mutex);
marl::lock lock(mutex);
std::vector<Frame> out;
out.reserve(frames.size());
for(auto frame : frames)
......@@ -128,27 +128,28 @@ std::vector<Frame> Thread::stack() const
Thread::State Thread::state() const
{
std::unique_lock<std::mutex> lock(mutex);
marl::lock lock(mutex);
return state_;
}
void Thread::resume()
{
std::unique_lock<std::mutex> lock(mutex);
state_ = State::Running;
lock.unlock();
{
marl::lock lock(mutex);
state_ = State::Running;
}
stateCV.notify_all();
}
void Thread::pause()
{
std::unique_lock<std::mutex> lock(mutex);
marl::lock lock(mutex);
state_ = State::Paused;
}
void Thread::stepIn()
{
std::unique_lock<std::mutex> lock(mutex);
marl::lock lock(mutex);
state_ = State::Stepping;
pauseAtFrame.reset();
stateCV.notify_all();
......@@ -156,7 +157,7 @@ void Thread::stepIn()
void Thread::stepOver()
{
std::unique_lock<std::mutex> lock(mutex);
marl::lock lock(mutex);
state_ = State::Stepping;
pauseAtFrame = frames.back();
stateCV.notify_all();
......@@ -164,7 +165,7 @@ void Thread::stepOver()
void Thread::stepOut()
{
std::unique_lock<std::mutex> lock(mutex);
marl::lock lock(mutex);
state_ = State::Stepping;
pauseAtFrame = (frames.size() > 1) ? frames[frames.size() - 1] : nullptr;
stateCV.notify_all();
......
......@@ -19,9 +19,11 @@
#include "ID.hpp"
#include "Location.hpp"
#include "marl/mutex.h"
#include "marl/tsa.h"
#include <condition_variable>
#include <memory>
#include <mutex>
#include <string>
#include <vector>
......@@ -173,14 +175,15 @@ public:
private:
EventListener *const broadcast;
void onLocationUpdate(std::unique_lock<std::mutex> &lock);
void onLocationUpdate(marl::lock &lock) REQUIRES(mutex);
mutable marl::mutex mutex;
std::string name_ GUARDED_BY(mutex);
std::vector<std::shared_ptr<Frame>> frames GUARDED_BY(mutex);
State state_ GUARDED_BY(mutex) = State::Running;
std::shared_ptr<Frame> pauseAtFrame GUARDED_BY(mutex);
mutable std::mutex mutex;
std::string name_;
std::vector<std::shared_ptr<Frame>> frames;
std::condition_variable stateCV;
State state_ = State::Running;
std::shared_ptr<Frame> pauseAtFrame;
};
} // namespace dbg
......
......@@ -19,9 +19,11 @@
#include "Type.hpp"
#include "Value.hpp"
#include "marl/mutex.h"
#include "marl/tsa.h"
#include <algorithm>
#include <memory>
#include <mutex>
#include <string>
#include <unordered_map>
#include <vector>
......@@ -81,10 +83,10 @@ private:
inline std::shared_ptr<Type> type() const override;
inline const void *get() const override;
mutable std::mutex mutex;
std::vector<Variable> variables;
std::unordered_map<std::string, int> indices;
std::vector<std::shared_ptr<VariableContainer>> extends;
mutable marl::mutex mutex;
std::vector<Variable> variables GUARDED_BY(mutex);
std::unordered_map<std::string, int> indices GUARDED_BY(mutex);
std::vector<std::shared_ptr<VariableContainer>> extends GUARDED_BY(mutex);
};
VariableContainer::VariableContainer(ID id)
......@@ -101,7 +103,7 @@ void VariableContainer::foreach(size_t startIndex, size_t count, const F &cb) co
template<typename F>
void VariableContainer::foreach(ForeachIndex &index, const F &cb) const
{
std::unique_lock<std::mutex> lock(mutex);
marl::lock lock(mutex);
for(size_t i = index.start; i < variables.size() && i < index.count; i++)
{
cb(variables[i]);
......@@ -119,7 +121,7 @@ void VariableContainer::foreach(ForeachIndex &index, const F &cb) const
template<typename F>
bool VariableContainer::find(const std::string &name, const F &cb) const
{
std::unique_lock<std::mutex> lock(mutex);
marl::lock lock(mutex);
for(auto const &var : variables)
{
if(var.name == name)
......@@ -140,7 +142,7 @@ bool VariableContainer::find(const std::string &name, const F &cb) const
void VariableContainer::put(const Variable &var)
{
std::unique_lock<std::mutex> lock(mutex);
marl::lock lock(mutex);
auto it = indices.find(var.name);
if(it == indices.end())
{
......@@ -161,7 +163,7 @@ void VariableContainer::put(const std::string &name,
void VariableContainer::extend(const std::shared_ptr<VariableContainer> &base)
{
std::unique_lock<std::mutex> lock(mutex);
marl::lock lock(mutex);
extends.emplace_back(base);
}
......
......@@ -40,7 +40,7 @@ namespace vk {
void Device::SamplingRoutineCache::updateSnapshot()
{
std::unique_lock<std::mutex> lock(mutex);
marl::lock lock(mutex);
if(snapshotNeedsUpdate)
{
......@@ -62,7 +62,7 @@ Device::SamplerIndexer::~SamplerIndexer()
uint32_t Device::SamplerIndexer::index(const SamplerState &samplerState)
{
std::unique_lock<std::mutex> lock(mutex);
marl::lock lock(mutex);
auto it = map.find(samplerState);
......@@ -81,7 +81,7 @@ uint32_t Device::SamplerIndexer::index(const SamplerState &samplerState)
void Device::SamplerIndexer::remove(const SamplerState &samplerState)
{
std::unique_lock<std::mutex> lock(mutex);
marl::lock lock(mutex);
auto it = map.find(samplerState);
ASSERT(it != map.end());
......
......@@ -20,9 +20,11 @@
#include "Reactor/Routine.hpp"
#include "System/LRUCache.hpp"
#include "marl/mutex.h"
#include "marl/tsa.h"
#include <map>
#include <memory>
#include <mutex>
#include <unordered_map>
namespace marl {
......@@ -99,7 +101,7 @@ public:
auto it = snapshot.find(key);
if(it != snapshot.end()) { return it->second; }
std::unique_lock<std::mutex> lock(mutex);
marl::lock lock(mutex);
if(auto existingRoutine = cache.lookup(key))
{
return existingRoutine;
......@@ -118,8 +120,8 @@ public:
bool snapshotNeedsUpdate = false;
std::unordered_map<Key, std::shared_ptr<rr::Routine>, Key::Hash> snapshot;
sw::LRUCache<Key, std::shared_ptr<rr::Routine>, Key::Hash> cache; // guarded by mutex
std::mutex mutex;
marl::mutex mutex;
sw::LRUCache<Key, std::shared_ptr<rr::Routine>, Key::Hash> cache GUARDED_BY(mutex);
};
SamplingRoutineCache *getSamplingRoutineCache() const;
......@@ -140,8 +142,8 @@ public:
uint32_t count; // Number of samplers sharing this state identifier.
};
std::map<SamplerState, Identifier> map; // guarded by mutex
std::mutex mutex;
marl::mutex mutex;
std::map<SamplerState, Identifier> map GUARDED_BY(mutex);
uint32_t nextID = 0;
};
......
......@@ -16,8 +16,11 @@
#define VK_EVENT_HPP_
#include "VkObject.hpp"
#include "marl/mutex.h"
#include "marl/tsa.h"
#include <condition_variable>
#include <mutex>
namespace vk {
......@@ -35,35 +38,35 @@ public:
void signal()
{
std::unique_lock<std::mutex> lock(mutex);
status = VK_EVENT_SET;
lock.unlock();
{
marl::lock lock(mutex);
status = VK_EVENT_SET;
}
condition.notify_all();
}
void reset()
{
std::unique_lock<std::mutex> lock(mutex);
marl::lock lock(mutex);
status = VK_EVENT_RESET;
}
VkResult getStatus()
{
std::unique_lock<std::mutex> lock(mutex);
marl::lock lock(mutex);
auto result = status;
lock.unlock();
return result;
}
void wait()
{
std::unique_lock<std::mutex> lock(mutex);
condition.wait(lock, [this] { return status == VK_EVENT_SET; });
marl::lock lock(mutex);
lock.wait(condition, [this]() REQUIRES(mutex) { return status == VK_EVENT_SET; });
}
private:
VkResult status = VK_EVENT_RESET; // guarded by mutex
std::mutex mutex;
marl::mutex mutex;
VkResult status GUARDED_BY(mutex) = VK_EVENT_RESET;
std::condition_variable condition;
};
......
......@@ -136,14 +136,14 @@ VkResult PipelineCache::merge(uint32_t srcCacheCount, const VkPipelineCache *pSr
PipelineCache *srcCache = Cast(pSrcCaches[i]);
{
std::unique_lock<std::mutex> thisLock(spirvShadersMutex);
std::unique_lock<std::mutex> srcLock(srcCache->spirvShadersMutex);
marl::lock thisLock(spirvShadersMutex);
marl::lock srcLock(srcCache->spirvShadersMutex);
spirvShaders.insert(srcCache->spirvShaders.begin(), srcCache->spirvShaders.end());
}
{
std::unique_lock<std::mutex> thisLock(computeProgramsMutex);
std::unique_lock<std::mutex> srcLock(srcCache->computeProgramsMutex);
marl::lock thisLock(computeProgramsMutex);
marl::lock srcLock(srcCache->computeProgramsMutex);
computePrograms.insert(srcCache->computePrograms.begin(), srcCache->computePrograms.end());
}
}
......
......@@ -18,11 +18,13 @@
#include "VkObject.hpp"
#include "VkSpecializationInfo.hpp"
#include "marl/mutex.h"
#include "marl/tsa.h"
#include <cstring>
#include <functional>
#include <map>
#include <memory>
#include <mutex>
#include <string>
#include <vector>
......@@ -127,11 +129,11 @@ private:
size_t dataSize = 0;
uint8_t *data = nullptr;
std::mutex spirvShadersMutex;
std::map<SpirvShaderKey, std::shared_ptr<sw::SpirvShader>> spirvShaders; // guarded by spirvShadersMutex
marl::mutex spirvShadersMutex;
std::map<SpirvShaderKey, std::shared_ptr<sw::SpirvShader>> spirvShaders GUARDED_BY(spirvShadersMutex);
std::mutex computeProgramsMutex;
std::map<ComputeProgramKey, std::shared_ptr<sw::ComputeProgram>> computePrograms; // guarded by computeProgramsMutex
marl::mutex computeProgramsMutex;
std::map<ComputeProgramKey, std::shared_ptr<sw::ComputeProgram>> computePrograms GUARDED_BY(computeProgramsMutex);
};
static inline PipelineCache *Cast(VkPipelineCache object)
......@@ -142,7 +144,7 @@ static inline PipelineCache *Cast(VkPipelineCache object)
template<typename Function>
std::shared_ptr<sw::ComputeProgram> PipelineCache::getOrCreateComputeProgram(const PipelineCache::ComputeProgramKey &key, Function &&create)
{
std::unique_lock<std::mutex> lock(computeProgramsMutex);
marl::lock lock(computeProgramsMutex);
auto it = computePrograms.find(key);
if(it != computePrograms.end()) { return it->second; }
......@@ -155,7 +157,7 @@ std::shared_ptr<sw::ComputeProgram> PipelineCache::getOrCreateComputeProgram(con
template<typename Function>
std::shared_ptr<sw::SpirvShader> PipelineCache::getOrCreateShader(const PipelineCache::SpirvShaderKey &key, Function &&create)
{
std::unique_lock<std::mutex> lock(spirvShadersMutex);
marl::lock lock(spirvShadersMutex);
auto it = spirvShaders.find(key);
if(it != spirvShaders.end()) { return it->second; }
......
......@@ -130,7 +130,7 @@ struct SemaphoreCreateInfo
void Semaphore::wait()
{
std::unique_lock<std::mutex> lock(mutex);
marl::lock lock(mutex);
External *ext = tempExternal ? tempExternal : external;
if(ext)
{
......@@ -141,11 +141,11 @@ void Semaphore::wait()
// call, it is assumed that this is negligible
// compared with the actual semaphore wait()
// operation.
lock.unlock();
lock.unlock_no_tsa();
marl::blocking_call([ext]() {
ext->wait();
});
lock.lock();
lock.lock_no_tsa();
}
// If the import was temporary, reset the semaphore to its previous state.
......@@ -164,7 +164,7 @@ void Semaphore::wait()
void Semaphore::signal()
{
std::unique_lock<std::mutex> lock(mutex);
marl::lock lock(mutex);
External *ext = tempExternal ? tempExternal : external;
if(ext)
{
......@@ -187,7 +187,7 @@ Semaphore::Semaphore(const VkSemaphoreCreateInfo *pCreateInfo, void *mem, const
void Semaphore::destroy(const VkAllocationCallbacks *pAllocator)
{
std::unique_lock<std::mutex> lock(mutex);
marl::lock lock(mutex);
while(tempExternal)
{
External *ext = tempExternal;
......@@ -227,7 +227,7 @@ VkResult Semaphore::importPayload(bool temporaryImport,
ALLOC_FUNC alloc_func,
IMPORT_FUNC import_func)
{
std::unique_lock<std::mutex> lock(mutex);
marl::lock lock(mutex);
// Create new External instance if needed.
External *ext = external;
......@@ -260,7 +260,7 @@ VkResult Semaphore::importPayload(bool temporaryImport,
template<typename ALLOC_FUNC, typename EXPORT_FUNC>
VkResult Semaphore::exportPayload(ALLOC_FUNC alloc_func, EXPORT_FUNC export_func)
{
std::unique_lock<std::mutex> lock(mutex);
marl::lock lock(mutex);
// Sanity check, do not try to export a semaphore that has a temporary import.
if(tempExternal != nullptr)
{
......
......@@ -19,7 +19,8 @@
#include "VkObject.hpp"
#include "marl/event.h"
#include <mutex>
#include "marl/mutex.h"
#include "marl/tsa.h"
#if VK_USE_PLATFORM_FUCHSIA
# include <zircon/types.h>
......@@ -147,10 +148,10 @@ private:
const VkAllocationCallbacks *allocator = nullptr;
VkExternalSemaphoreHandleTypeFlags exportableHandleTypes = (VkExternalSemaphoreHandleTypeFlags)0;
std::mutex mutex;
marl::Event internal;
External *external = nullptr;
External *tempExternal = nullptr;
marl::mutex mutex;
External *external GUARDED_BY(mutex) = nullptr;
External *tempExternal GUARDED_BY(mutex) = nullptr;
};
static inline Semaphore *Cast(VkSemaphore object)
......
......@@ -71,8 +71,10 @@
#include "Reactor/Nucleus.hpp"
#include "marl/mutex.h"
#include "marl/scheduler.h"
#include "marl/thread.h"
#include "marl/tsa.h"
#include "System/CPUID.hpp"
......@@ -133,21 +135,27 @@ void setCPUDefaults()
std::shared_ptr<marl::Scheduler> getOrCreateScheduler()
{
static std::mutex mutex;
static std::weak_ptr<marl::Scheduler> schedulerWeak;
std::unique_lock<std::mutex> lock(mutex);
auto scheduler = schedulerWeak.lock();
if(!scheduler)
struct Scheduler
{
scheduler = std::make_shared<marl::Scheduler>();
scheduler->setThreadInitializer([] {
marl::mutex mutex;
std::weak_ptr<marl::Scheduler> weakptr GUARDED_BY(mutex);
};
static Scheduler scheduler;
marl::lock lock(scheduler.mutex);
auto sptr = scheduler.weakptr.lock();
if(!sptr)
{
sptr = std::make_shared<marl::Scheduler>();
sptr->setThreadInitializer([] {
sw::CPUID::setFlushToZero(true);
sw::CPUID::setDenormalsAreZero(true);
});
scheduler->setWorkerThreadCount(std::min<size_t>(marl::Thread::numLogicalCPUs(), 16));
schedulerWeak = scheduler;
sptr->setWorkerThreadCount(std::min<size_t>(marl::Thread::numLogicalCPUs(), 16));
scheduler.weakptr = sptr;
}
return scheduler;
return sptr;
}
// initializeLibrary() is called by vkCreateInstance() to perform one-off global
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment