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