Add ResourceLock for detecting parallel resource collisions

This commit is contained in:
Jack Andersen 2016-08-11 16:33:03 -10:00
parent 48a4a51853
commit 719c62f09f
5 changed files with 60 additions and 1 deletions

View File

@ -9,6 +9,7 @@
#include <algorithm> #include <algorithm>
#include <chrono> #include <chrono>
#include <thread> #include <thread>
#include <mutex>
#include <hecl/hecl.hpp> #include <hecl/hecl.hpp>
#include <hecl/Database.hpp> #include <hecl/Database.hpp>

View File

@ -68,6 +68,7 @@ private:
size_t _writeBuf(const void* buf, size_t len); size_t _writeBuf(const void* buf, size_t len);
void _closePipe(); void _closePipe();
void _blenderDied(); void _blenderDied();
public: public:
BlenderConnection(int verbosityLevel=1); BlenderConnection(int verbosityLevel=1);
~BlenderConnection(); ~BlenderConnection();

View File

@ -370,6 +370,7 @@ try:
elif cmdargs[0] == 'SAVE': elif cmdargs[0] == 'SAVE':
bpy.context.user_preferences.filepaths.save_version = 0 bpy.context.user_preferences.filepaths.save_version = 0
print('SAVING %s' % loaded_blend)
if loaded_blend: if loaded_blend:
if 'FINISHED' in bpy.ops.wm.save_as_mainfile(filepath=loaded_blend, check_existing=False, compress=True): if 'FINISHED' in bpy.ops.wm.save_as_mainfile(filepath=loaded_blend, check_existing=False, compress=True):
writepipeline(b'FINISHED') writepipeline(b'FINISHED')

View File

@ -44,7 +44,6 @@ class Project;
struct DataSpecEntry; struct DataSpecEntry;
} }
extern unsigned VerbosityLevel; extern unsigned VerbosityLevel;
extern logvisor::Module LogModule; extern logvisor::Module LogModule;
@ -1180,6 +1179,28 @@ public:
}; };
/**
* @brief Mutex-style centralized resource-path tracking
*
* Provides a means to safely parallelize resource processing; detecting when another
* thread is working on the same resource.
*/
class ResourceLock
{
static bool SetThreadRes(const ProjectPath& path);
static void ClearThreadRes();
bool good;
public:
operator bool() const { return good; }
static bool InProgress(const ProjectPath& path);
ResourceLock(const ProjectPath& path) { good = SetThreadRes(path); }
~ResourceLock() { if (good) ClearThreadRes(); }
ResourceLock(const ResourceLock&) = delete;
ResourceLock& operator=(const ResourceLock&) = delete;
ResourceLock(ResourceLock&&) = delete;
ResourceLock& operator=(ResourceLock&&) = delete;
};
/** /**
* @brief Search from within provided directory for the project root * @brief Search from within provided directory for the project root
* @param path absolute or relative file path to search from * @param path absolute or relative file path to search from

View File

@ -1,4 +1,7 @@
#include "hecl/hecl.hpp" #include "hecl/hecl.hpp"
#include <thread>
#include <mutex>
#include <unordered_map>
#ifdef WIN32 #ifdef WIN32
#include <windows.h> #include <windows.h>
@ -84,6 +87,38 @@ void SanitizePath(std::wstring& path)
}); });
} }
static std::mutex PathsMutex;
static std::unordered_map<std::thread::id, ProjectPath> PathsInProgress;
bool ResourceLock::InProgress(const ProjectPath& path)
{
std::unique_lock<std::mutex> lk(PathsMutex);
for (const auto& p : PathsInProgress)
if (p.second == path)
return true;
return false;
}
bool ResourceLock::SetThreadRes(const ProjectPath& path)
{
std::unique_lock<std::mutex> lk(PathsMutex);
if (PathsInProgress.find(std::this_thread::get_id()) != PathsInProgress.cend())
LogModule.report(logvisor::Fatal, "multiple resource locks on thread");
for (const auto& p : PathsInProgress)
if (p.second == path)
return false;
PathsInProgress[std::this_thread::get_id()] = path;
return true;
}
void ResourceLock::ClearThreadRes()
{
std::unique_lock<std::mutex> lk(PathsMutex);
PathsInProgress.erase(std::this_thread::get_id());
}
bool IsPathPNG(const hecl::ProjectPath& path) bool IsPathPNG(const hecl::ProjectPath& path)
{ {
FILE* fp = hecl::Fopen(path.getAbsolutePath().c_str(), _S("rb")); FILE* fp = hecl::Fopen(path.getAbsolutePath().c_str(), _S("rb"));