Decided against child cook process

This commit is contained in:
Jack Andersen 2016-03-28 12:39:18 -10:00
parent 3822f001a8
commit c06cc88441
7 changed files with 76 additions and 159 deletions

View File

@ -25,7 +25,7 @@ set(BOO_INCLUDE_DIR extern/boo/include)
add_subdirectory(bintoc) add_subdirectory(bintoc)
add_subdirectory(extern) add_subdirectory(extern)
add_definitions(${BOO_SYS_DEFINES}) add_definitions(${BOO_SYS_DEFINES})
include_directories(include ${LOGVISOR_INCLUDE_DIR} ${ATHENA_INCLUDE_DIR} ${BOO_INCLUDE_DIR} ${ZLIB_INCLUDE_DIR}) include_directories(include blender ${LOGVISOR_INCLUDE_DIR} ${ATHENA_INCLUDE_DIR} ${BOO_INCLUDE_DIR} ${ZLIB_INCLUDE_DIR})
add_subdirectory(lib) add_subdirectory(lib)
add_subdirectory(blender) add_subdirectory(blender)
add_subdirectory(driver) add_subdirectory(driver)

View File

@ -34,7 +34,7 @@ namespace hecl
{ {
logvisor::Module BlenderLog("BlenderConnection"); logvisor::Module BlenderLog("BlenderConnection");
BlenderConnection* SharedBlenderConnection = nullptr; BlenderToken SharedBlenderToken;
#ifdef __APPLE__ #ifdef __APPLE__
#define DEFAULT_BLENDER_BIN "/Applications/Blender.app/Contents/MacOS/blender" #define DEFAULT_BLENDER_BIN "/Applications/Blender.app/Contents/MacOS/blender"
@ -952,4 +952,14 @@ void BlenderConnection::quitBlender()
_readLine(lineBuf, sizeof(lineBuf)); _readLine(lineBuf, sizeof(lineBuf));
} }
BlenderConnection& BlenderConnection::SharedConnection()
{
return SharedBlenderToken.getBlenderConnection();
}
void BlenderConnection::Shutdown()
{
SharedBlenderToken.shutdown();
}
} }

View File

@ -24,12 +24,13 @@
#include "hecl/HMDLMeta.hpp" #include "hecl/HMDLMeta.hpp"
#include <athena/Types.hpp> #include <athena/Types.hpp>
#include <athena/MemoryWriter.hpp> #include <athena/MemoryWriter.hpp>
#include <optional.hpp>
namespace hecl namespace hecl
{ {
extern logvisor::Module BlenderLog; extern logvisor::Module BlenderLog;
extern class BlenderConnection* SharedBlenderConnection; extern class BlenderToken SharedBlenderToken;
class HMDLBuffers; class HMDLBuffers;
class BlenderConnection class BlenderConnection
@ -681,31 +682,35 @@ public:
void quitBlender(); void quitBlender();
static BlenderConnection& SharedConnection()
{
if (!SharedBlenderConnection)
SharedBlenderConnection = new BlenderConnection(hecl::VerbosityLevel);
return *SharedBlenderConnection;
}
void closeStream() void closeStream()
{ {
if (m_lock) if (m_lock)
deleteBlend(); deleteBlend();
} }
static void Shutdown() static BlenderConnection& SharedConnection();
static void Shutdown();
};
class BlenderToken
{
std::experimental::optional<BlenderConnection> m_conn;
public:
BlenderConnection& getBlenderConnection()
{ {
if (SharedBlenderConnection) if (!m_conn)
m_conn.emplace();
return *m_conn;
}
void shutdown()
{ {
SharedBlenderConnection->closeStream(); if (m_conn)
SharedBlenderConnection->quitBlender(); {
delete SharedBlenderConnection; m_conn->quitBlender();
SharedBlenderConnection = nullptr; m_conn = std::experimental::nullopt;
BlenderLog.report(logvisor::Info, "BlenderConnection Shutdown Successful"); BlenderLog.report(logvisor::Info, "BlenderConnection Shutdown Successful");
} }
} }
}; };
class HMDLBuffers class HMDLBuffers

View File

@ -2,6 +2,8 @@
#define HECL_CLIENT_PROCESS_HPP #define HECL_CLIENT_PROCESS_HPP
#include "hecl.hpp" #include "hecl.hpp"
#include "Database.hpp"
#include "BlenderConnection.hpp"
#include <list> #include <list>
#include <thread> #include <thread>
#include <mutex> #include <mutex>
@ -26,7 +28,7 @@ public:
Cook Cook
} m_type; } m_type;
bool m_complete = false; bool m_complete = false;
virtual void run()=0; virtual void run(BlenderToken& btok)=0;
Transaction(ClientProcess& parent, Type tp) : m_parent(parent), m_type(tp) {} Transaction(ClientProcess& parent, Type tp) : m_parent(parent), m_type(tp) {}
}; };
struct BufferTransaction : Transaction struct BufferTransaction : Transaction
@ -35,7 +37,7 @@ public:
void* m_targetBuf; void* m_targetBuf;
size_t m_maxLen; size_t m_maxLen;
size_t m_offset; size_t m_offset;
void run(); void run(BlenderToken& btok);
BufferTransaction(ClientProcess& parent, const ProjectPath& path, BufferTransaction(ClientProcess& parent, const ProjectPath& path,
void* target, size_t maxLen, size_t offset) void* target, size_t maxLen, size_t offset)
: Transaction(parent, Type::Buffer), : Transaction(parent, Type::Buffer),
@ -45,10 +47,11 @@ public:
struct CookTransaction : Transaction struct CookTransaction : Transaction
{ {
ProjectPath m_path; ProjectPath m_path;
int m_returnVal = 0; Database::IDataSpec* m_dataSpec;
void run(); bool m_returnResult = false;
CookTransaction(ClientProcess& parent, const ProjectPath& path) void run(BlenderToken& btok);
: Transaction(parent, Type::Cook), m_path(path) {} CookTransaction(ClientProcess& parent, const ProjectPath& path, Database::IDataSpec* spec)
: Transaction(parent, Type::Cook), m_path(path), m_dataSpec(spec) {}
}; };
private: private:
std::list<std::unique_ptr<Transaction>> m_pendingQueue; std::list<std::unique_ptr<Transaction>> m_pendingQueue;
@ -59,6 +62,7 @@ private:
{ {
ClientProcess& m_proc; ClientProcess& m_proc;
std::thread m_thr; std::thread m_thr;
BlenderToken m_blendTok;
Worker(ClientProcess& proc); Worker(ClientProcess& proc);
void proc(); void proc();
}; };
@ -69,8 +73,8 @@ public:
~ClientProcess() {shutdown();} ~ClientProcess() {shutdown();}
const BufferTransaction* addBufferTransaction(const hecl::ProjectPath& path, void* target, const BufferTransaction* addBufferTransaction(const hecl::ProjectPath& path, void* target,
size_t maxLen, size_t offset); size_t maxLen, size_t offset);
const CookTransaction* addCookTransaction(const hecl::ProjectPath& path); const CookTransaction* addCookTransaction(const hecl::ProjectPath& path, Database::IDataSpec* spec);
int syncCook(const hecl::ProjectPath& path); bool syncCook(const hecl::ProjectPath& path, Database::IDataSpec* spec, BlenderToken& btok);
void swapCompletedQueue(std::list<std::unique_ptr<Transaction>>& queue); void swapCompletedQueue(std::list<std::unique_ptr<Transaction>>& queue);
void shutdown(); void shutdown();
}; };

View File

@ -22,6 +22,8 @@
namespace hecl namespace hecl
{ {
class BlenderToken;
namespace Database namespace Database
{ {
class Project; class Project;
@ -64,7 +66,9 @@ public:
*/ */
class IDataSpec class IDataSpec
{ {
const DataSpecEntry* m_specEntry;
public: public:
IDataSpec(const DataSpecEntry* specEntry) : m_specEntry(specEntry) {}
virtual ~IDataSpec() {} virtual ~IDataSpec() {}
using FProgress = hecl::Database::FProgress; using FProgress = hecl::Database::FProgress;
using FCookProgress = std::function<void(const SystemChar*)>; using FCookProgress = std::function<void(const SystemChar*)>;
@ -100,13 +104,14 @@ public:
virtual void doExtract(const ExtractPassInfo& info, FProgress progress) virtual void doExtract(const ExtractPassInfo& info, FProgress progress)
{(void)info;(void)progress;} {(void)info;(void)progress;}
virtual bool canCook(const ProjectPath& path) virtual bool canCook(const ProjectPath& path, BlenderToken& btok)
{(void)path;LogModule.report(logvisor::Error, "not implemented");return false;} {(void)path;LogModule.report(logvisor::Error, "not implemented");return false;}
virtual const DataSpecEntry* overrideDataSpec(const hecl::ProjectPath& path, virtual const DataSpecEntry* overrideDataSpec(const ProjectPath& path,
const hecl::Database::DataSpecEntry* oldEntry) const Database::DataSpecEntry* oldEntry,
BlenderToken& btok)
{(void)path;return oldEntry;} {(void)path;return oldEntry;}
virtual void doCook(const ProjectPath& path, const ProjectPath& cookedPath, virtual void doCook(const ProjectPath& path, const ProjectPath& cookedPath,
bool fast, FCookProgress progress) bool fast, BlenderToken& btok, FCookProgress progress)
{(void)path;(void)cookedPath;(void)fast;(void)progress;} {(void)path;(void)cookedPath;(void)fast;(void)progress;}
/** /**
@ -130,6 +135,8 @@ public:
{(void)info;(void)implicitsOut;} {(void)info;(void)implicitsOut;}
virtual void doPackage(const PackagePassInfo& info) virtual void doPackage(const PackagePassInfo& info)
{(void)info;} {(void)info;}
const DataSpecEntry* getDataSpecEntry() const {return m_specEntry;}
}; };
/** /**

View File

@ -1,6 +1,7 @@
#include "hecl/ClientProcess.hpp" #include "hecl/ClientProcess.hpp"
#include "hecl/Database.hpp" #include "hecl/Database.hpp"
#include "athena/FileReader.hpp" #include "athena/FileReader.hpp"
#include "BlenderConnection.hpp"
#ifdef _WIN32 #ifdef _WIN32
#define WIN32_LEAN_AND_MEAN #define WIN32_LEAN_AND_MEAN
@ -13,115 +14,6 @@ namespace hecl
{ {
static logvisor::Module Log("hecl::ClientProcess"); static logvisor::Module Log("hecl::ClientProcess");
static bool ExecProcessAndWait(bool verbose,
const SystemChar* exePath,
const SystemChar* workDir,
const SystemChar* args[],
int& returnCode)
{
#if _WIN32
std::wstring cmdLine;
for (const SystemChar** it=args ; *it ; ++it)
{
if (it != args)
cmdLine.append(L' ');
cmdLine.append(*it);
}
STARTUPINFO sinfo = {sizeof(STARTUPINFO)};
HANDLE nulHandle = NULL;
if (!verbose)
{
SECURITY_ATTRIBUTES sattrs = {sizeof(SECURITY_ATTRIBUTES), NULL, TRUE};
nulHandle = CreateFileW(L"nul", GENERIC_WRITE, FILE_SHARE_READ|FILE_SHARE_WRITE, &sattrs,
OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
sinfo.hStdError = nulHandle;
sinfo.hStdOutput = nulHandle;
sinfo.dwFlags = STARTF_USESTDHANDLES;
}
PROCESS_INFORMATION pinfo;
if (!CreateProcessW(exePath, cmdLine.c_str(), NULL, NULL, TRUE, NORMAL_PRIORITY_CLASS, NULL, workDir, &sinfo, &pinfo))
{
LPWSTR messageBuffer = nullptr;
size_t size = FormatMessageW(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
NULL, GetLastError(), MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPWSTR)&messageBuffer, 0, NULL);
Log.report(logvisor::Fatal, L"error launching '%s': %s", exePath, messageBuffer);
}
if (nulHandle)
CloseHandle(nulHandle);
CloseHandle(pinfo.hThread);
WaitForSingleObject(pinfo.hProcess, INFINITE);
DWORD exitCode;
GetExitCodeProcess(pinfo.hProcess, &exitCode);
returnCode = exitCode;
CloseHandle(pinfo.hProcess);
if (exitCode == 0)
return true;
return false;
#else
/* Assemble command args */
std::vector<const SystemChar*> assembleArgs;
size_t argCount = 0;
for (const SystemChar** it=args ; *it ; ++it) ++argCount;
assembleArgs.reserve(argCount+2);
assembleArgs.push_back(exePath);
for (const SystemChar** it=args ; *it ; ++it) assembleArgs.push_back(*it);
assembleArgs.push_back(nullptr);
if (verbose)
{
printf("cd %s\n", workDir);
for (const SystemChar* arg : assembleArgs)
if (arg)
printf("%s ", arg);
printf("\n");
fflush(stdout);
}
pid_t pid = fork();
if (!pid)
{
chdir(workDir);
if (!verbose)
{
int devNull = open("/dev/null", O_WRONLY);
dup2(devNull, STDOUT_FILENO);
dup2(devNull, STDERR_FILENO);
}
if (execvp(exePath, (char*const*)assembleArgs.data()) < 0)
{
Log.report(logvisor::Fatal, _S("error execing '%s': %s"), exePath, strerror(errno));
}
exit(1);
}
int exitStatus;
if (waitpid(pid, &exitStatus, 0) < 0)
Log.report(logvisor::Fatal, "unable to wait for hecl process to complete: %s", strerror(errno));
if (WIFEXITED(exitStatus))
{
returnCode = WEXITSTATUS(exitStatus);
if (WEXITSTATUS(exitStatus) == 0)
{
return true;
}
}
return false;
#endif
}
static int GetCPUCount() static int GetCPUCount()
{ {
#if _WIN32 #if _WIN32
@ -133,7 +25,7 @@ static int GetCPUCount()
#endif #endif
} }
void ClientProcess::BufferTransaction::run() void ClientProcess::BufferTransaction::run(BlenderToken& btok)
{ {
athena::io::FileReader r(m_path.getAbsolutePath(), 32 * 1024, false); athena::io::FileReader r(m_path.getAbsolutePath(), 32 * 1024, false);
if (r.hasError()) if (r.hasError())
@ -148,9 +40,9 @@ void ClientProcess::BufferTransaction::run()
m_complete = true; m_complete = true;
} }
void ClientProcess::CookTransaction::run() void ClientProcess::CookTransaction::run(BlenderToken& btok)
{ {
m_returnVal = m_parent.syncCook(m_path); m_returnResult = m_parent.syncCook(m_path, m_dataSpec, btok);
m_complete = true; m_complete = true;
} }
@ -170,7 +62,7 @@ void ClientProcess::Worker::proc()
std::unique_ptr<Transaction> trans = std::move(m_proc.m_pendingQueue.front()); std::unique_ptr<Transaction> trans = std::move(m_proc.m_pendingQueue.front());
m_proc.m_pendingQueue.pop_front(); m_proc.m_pendingQueue.pop_front();
lk.unlock(); lk.unlock();
trans->run(); trans->run(m_blendTok);
lk.lock(); lk.lock();
m_proc.m_completedQueue.push_back(std::move(trans)); m_proc.m_completedQueue.push_back(std::move(trans));
} }
@ -199,30 +91,28 @@ ClientProcess::addBufferTransaction(const ProjectPath& path, void* target,
} }
const ClientProcess::CookTransaction* const ClientProcess::CookTransaction*
ClientProcess::addCookTransaction(const hecl::ProjectPath& path) ClientProcess::addCookTransaction(const hecl::ProjectPath& path, Database::IDataSpec* spec)
{ {
std::unique_lock<std::mutex> lk(m_mutex); std::unique_lock<std::mutex> lk(m_mutex);
CookTransaction* ret = new CookTransaction(*this, path); CookTransaction* ret = new CookTransaction(*this, path, spec);
m_pendingQueue.emplace_back(ret); m_pendingQueue.emplace_back(ret);
m_cv.notify_one(); m_cv.notify_one();
return ret; return ret;
} }
int ClientProcess::syncCook(const hecl::ProjectPath& path) bool ClientProcess::syncCook(const hecl::ProjectPath& path, Database::IDataSpec* spec, BlenderToken& btok)
{ {
const SystemChar* workDir = path.getProject().getProjectWorkingPath().getAbsolutePath().c_str(); if (spec->canCook(path, btok))
const SystemChar* args[] = {_S("cook"), path.getAbsolutePath().c_str(), nullptr};
int returnCode;
const SystemChar* heclOverride = hecl::GetEnv(_S("HECL_BIN"));
if (heclOverride)
{ {
if (ExecProcessAndWait(m_verbosity != 0, heclOverride, workDir, args, returnCode)) const Database::DataSpecEntry* specEnt = spec->overrideDataSpec(path, spec->getDataSpecEntry(), btok);
return returnCode; if (specEnt)
{
hecl::ProjectPath cooked = path.getCookedPath(*specEnt);
spec->doCook(path, cooked, false, btok, [](const SystemChar*) {});
return true;
} }
if (!ExecProcessAndWait(m_verbosity != 0, _S("hecl"), workDir, args, returnCode)) }
Log.report(logvisor::Fatal, _S("unable to background-cook '%s'"), return false;
path.getAbsolutePath().c_str());
return returnCode;
} }
void ClientProcess::swapCompletedQueue(std::list<std::unique_ptr<Transaction>>& queue) void ClientProcess::swapCompletedQueue(std::list<std::unique_ptr<Transaction>>& queue)

View File

@ -10,6 +10,7 @@
#endif #endif
#include "hecl/Database.hpp" #include "hecl/Database.hpp"
#include "BlenderConnection.hpp"
namespace hecl namespace hecl
{ {
@ -379,9 +380,9 @@ static void VisitFile(const ProjectPath& path, bool force, bool fast,
{ {
for (SpecInst& spec : specInsts) for (SpecInst& spec : specInsts)
{ {
if (spec.second->canCook(path)) if (spec.second->canCook(path, hecl::SharedBlenderToken))
{ {
const DataSpecEntry* override = spec.second->overrideDataSpec(path, spec.first); const DataSpecEntry* override = spec.second->overrideDataSpec(path, spec.first, hecl::SharedBlenderToken);
if (!override) if (!override)
continue; continue;
ProjectPath cooked = path.getCookedPath(*override); ProjectPath cooked = path.getCookedPath(*override);
@ -391,7 +392,7 @@ static void VisitFile(const ProjectPath& path, bool force, bool fast,
path.getModtime() > cooked.getModtime()) path.getModtime() > cooked.getModtime())
{ {
progress.reportFile(override); progress.reportFile(override);
spec.second->doCook(path, cooked, fast, spec.second->doCook(path, cooked, fast, hecl::SharedBlenderToken,
[&](const SystemChar* extra) [&](const SystemChar* extra)
{ {
progress.reportFile(override, extra); progress.reportFile(override, extra);