Skip to content

Commit

Permalink
Merge pull request #35 from PsyCommando/dev
Browse files Browse the repository at this point in the history
Statsutil 0.23.1 Bugfix Release
  • Loading branch information
PsyCommando authored Aug 25, 2016
2 parents 2b3a3e6 + 5f32471 commit b9da472
Show file tree
Hide file tree
Showing 7 changed files with 484 additions and 12 deletions.
2 changes: 2 additions & 0 deletions readmes/ppmd_statsutil.txt
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,8 @@ Changelog:
This should make everything more readable, and customizable/maintainable no matter if there are ASM hacks applied to the game or not.
* Added support for importing/exporting script data along with scripts.
* Added support for dumping the level list to a SIR0 file. Its pretty much completely useless to anyone for now however.
-0.23.1(2016/08/24):
* Fixed issue on windows 10 where a lot of the scripts wouldn't export or import properly. The multithreading class was at fault.

----------------------------------------------------------------------------------------------------
License info:
Expand Down
25 changes: 14 additions & 11 deletions src/ppmdu/pmd2/pmd2_scripts_xml_io.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,8 @@
#include <ppmdu/pmd2/pmd2_scripts_opcodes.hpp>
#include <utils/pugixml_utils.hpp>
#include <utils/library_wide.hpp>
#include <utils/multiple_task_handler.hpp>
//#include <utils/multiple_task_handler.hpp>
#include <utils/parallel_tasks.hpp>
#include <ppmdu/fmts/ssb.hpp>
#include <atomic>
#include <thread>
Expand Down Expand Up @@ -2796,7 +2797,8 @@ namespace pmd2
out_dest.WriteScriptSet(out_dest.m_common);

//Prepare import of everything else!
multitask::CMultiTaskHandler taskhandler;
//multitask::CMultiTaskHandler taskhandler;
utils::AsyncTaskHandler taskhandler;
Poco::DirectoryIterator dirit(dir);
Poco::DirectoryIterator dirend;
while( dirit != dirend )
Expand All @@ -2806,7 +2808,7 @@ namespace pmd2

Poco::Path destination(out_dest.GetScriptDir());
destination.append(dirit.path().getBaseName());
taskhandler.AddTask( multitask::pktask_t( std::bind( RunLevelXMLImport,
taskhandler.QueueTask( utils::AsyncTaskHandler::task_t( std::bind( RunLevelXMLImport,
std::ref(out_dest),
dirit->path(),
destination.toString(),
Expand All @@ -2833,9 +2835,9 @@ namespace pmd2
// out_dest.m_setsindex.size(),
// std::ref(shouldUpdtProgress) );
}
taskhandler.Execute();
taskhandler.BlockUntilTaskQueueEmpty();
taskhandler.StopExecute();
taskhandler.Start();
taskhandler.WaitTasksFinished();
taskhandler.WaitStop();

shouldUpdtProgress = false;
if(updatethread.valid())
Expand Down Expand Up @@ -2873,11 +2875,12 @@ namespace pmd2
atomic_bool shouldUpdtProgress = true;
future<void> updtProgress;
atomic<uint32_t> completed = 0;
multitask::CMultiTaskHandler taskhandler;
//multitask::CMultiTaskHandler taskhandler;
utils::AsyncTaskHandler taskhandler;
//Export everything else
for( const auto & entry : gs.m_setsindex )
{
taskhandler.AddTask( multitask::pktask_t( std::bind( RunLevelXMLExport,
taskhandler.QueueTask( utils::AsyncTaskHandler::task_t( std::bind( RunLevelXMLExport,
std::cref(entry.second),
std::cref(dir),
std::cref(gs.GetConfig()),
Expand All @@ -2896,9 +2899,9 @@ namespace pmd2
gs.m_setsindex.size(),
std::ref(shouldUpdtProgress) );
}
taskhandler.Execute();
taskhandler.BlockUntilTaskQueueEmpty();
taskhandler.StopExecute();
taskhandler.Start();
taskhandler.WaitTasksFinished();
taskhandler.WaitStop();

shouldUpdtProgress = false;
if( updtProgress.valid() )
Expand Down
2 changes: 1 addition & 1 deletion src/statsutil.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -108,7 +108,7 @@ namespace statsutil
//------------------------------------------------
const string CStatsUtil::Exe_Name = "ppmd_statsutil.exe";
const string CStatsUtil::Title = "Game data importer/exporter";
const string CStatsUtil::Version = "0.23";
const string CStatsUtil::Version = "0.23.1";
const string CStatsUtil::Short_Description = "A utility to export and import various game statistics/data, such as pokemon stats.";
const string CStatsUtil::Long_Description =
"To export game data to XML, you have to append \"-e\" to the\ncommandline, followed with the option corresponding to what to export.\n"
Expand Down
203 changes: 203 additions & 0 deletions src/utils/parallel_tasks.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,203 @@
#include "parallel_tasks.hpp"

using namespace std;

namespace utils
{

//======================================================================================================================================
// TaskQueue
//======================================================================================================================================
const std::chrono::microseconds TaskQueue::WaitForNewTaskTime(100);
/*
Push a task at the back of the queue.
*/
void TaskQueue::Push( TaskQueue::task_t && task )
{
std::lock_guard<std::mutex> lck(m_queuemtx);
m_taskqueue.push_back(std::forward<task_t>(task));
}

/*
Try to pop from the queue. Return false if pop failed, true otherwise.
*/
bool TaskQueue::TryPop( TaskQueue::task_t & out_task )
{
if(!empty())
{
std::lock_guard<std::mutex> lck(m_queuemtx);
out_task = std::move(m_taskqueue.front());
m_taskqueue.pop_front();
return true;
}
return false;
}

/*
Try to pop from the queue, and wait until the delay is reached, or the queue has a new task. Return false if pop failed and/or delay expired, true otherwise.
*/
bool TaskQueue::TryPopWait( TaskQueue::task_t & out_task )
{
if(empty())
{
std::unique_lock<std::mutex> lcknewtask(m_waitfortaskmtx);
m_cvnewtask.wait_for(lcknewtask, WaitForNewTaskTime);
}
//Recheck condition
return TryPop(out_task);
}

//======================================================================================================================================
// Worker
//======================================================================================================================================
#if 0
const std::chrono::microseconds Worker::WaitOnTaskTime(1);
Worker::Worker()
:m_bshoulrun(false), m_ptaskqueue(nullptr)
{}

Worker::Worker( TaskQueue & tq )
:m_bshoulrun(true), m_ptaskqueue(&tq)
{}

Worker::Worker( const Worker & cp )
:m_bshoulrun(cp.m_bshoulrun.load()),
m_ptaskqueue(cp.m_ptaskqueue),
m_excepts(cp.m_excepts)
{
if(cp.m_mythread.joinable())
Start();
}

Worker & Worker::operator=( const Worker & cp )
{
m_bshoulrun = cp.m_bshoulrun.load();
m_ptaskqueue = cp.m_ptaskqueue;
m_excepts = cp.m_excepts;
if(cp.m_mythread.joinable())
Start();
return *this;
}

Worker::~Worker()
{
try
{
Stop(); //Need to stop
TryJoin();
}
catch(...){}
}

/*
*/
inline bool Worker::IsValid()const{return m_ptaskqueue != nullptr;}

/*
Returns whether the worker is working on a task or not
*/
inline bool Worker::IsBusy()const {return m_bisbusy;}

inline void Worker::Start()
{
if(!IsValid())
throw std::runtime_error("Worker::Start(): Worker thread is in an undefined state!");
m_mythread = std::thread(&Worker::Work, this);
}

/*
This is what the worker thread executes.
*/
void Worker::Work()
{
do
{
TaskQueue::task_t mytask;
if( m_ptaskqueue->TryPopWait(mytask) && mytask.valid() )
RunATask(mytask);
else
WaitForTask();
}
while(m_bshoulrun);
}

/*
This tells the thread to stop, and tries to join it, then pops any exceptions.
*/
inline void Worker::Stop()
{
if(!IsValid())
throw std::runtime_error("Worker::Stop(): Worker thread is in an undefined state!");
m_bshoulrun = false;
}

inline void Worker::WaitStop()
{
Stop();
TryJoin();
do
{
TryPopException();
}
while(!m_excepts.empty());
}

bool Worker::TryJoin()
{
if(!IsValid())
throw std::runtime_error("Worker::TryJoin(): Worker thread is in an undefined state!");
if( m_mythread.joinable() )
{
m_mythread.join();
return true;
}
return false;
}

void Worker::TryPopException()
{
if(!IsValid())
throw std::runtime_error("Worker::TryPopException(): Worker thread is in an undefined state!");
if( !m_excepts.empty() )
{
std::lock_guard<std::mutex> lck(m_exceptmtx);
std::exception_ptr eptr = m_excepts.front();
m_excepts.pop_front();
std::rethrow_exception(eptr);
}
}


inline void Worker::PushException( std::exception_ptr ptr )
{
std::lock_guard<std::mutex> lck(m_exceptmtx);
m_excepts.push_back(ptr);
}

inline void Worker::RunATask( TaskQueue::task_t & curtask )
{
try
{
m_bisbusy = true;
curtask();
}
catch(...)
{
PushException(std::current_exception());
}
m_bisbusy= false;
}

inline void Worker::WaitForTask()
{
this_thread::sleep_for(WaitOnTaskTime);
}

#endif


//======================================================================================================================================
//
//======================================================================================================================================

};
Loading

0 comments on commit b9da472

Please sign in to comment.