158 lines
3.3 KiB
C++
158 lines
3.3 KiB
C++
// This file is part of Noggit3, licensed under GNU General Public License (version 3).
|
|
|
|
#include <noggit/AsyncLoader.h>
|
|
#include <noggit/errorHandling.h>
|
|
|
|
#include <QtCore/QSettings>
|
|
|
|
#include <algorithm>
|
|
#include <list>
|
|
|
|
bool AsyncLoader::is_loading()
|
|
{
|
|
std::lock_guard<std::mutex> const lock (_guard);
|
|
if (_currently_loading.empty())
|
|
{
|
|
return false;
|
|
}
|
|
else
|
|
{
|
|
for (auto async_obj : _currently_loading)
|
|
{
|
|
if (!async_obj->loading_failed() && async_obj->filename.length()) // the filename check is a hack
|
|
{
|
|
return true;
|
|
}
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
void AsyncLoader::process()
|
|
{
|
|
AsyncObject* object = nullptr;
|
|
|
|
QSettings settings;
|
|
bool additional_log = settings.value("additional_file_loading_log", false).toBool();
|
|
|
|
while (!_stop)
|
|
{
|
|
{
|
|
std::unique_lock<std::mutex> lock (_guard);
|
|
|
|
_state_changed.wait
|
|
( lock
|
|
, [&]
|
|
{
|
|
return !!_stop || std::any_of ( _to_load.begin(), _to_load.end()
|
|
, [](auto const& to_load) { return !to_load.empty(); }
|
|
);
|
|
}
|
|
);
|
|
|
|
if (_stop)
|
|
{
|
|
return;
|
|
}
|
|
|
|
for (auto& to_load : _to_load)
|
|
{
|
|
if (to_load.empty())
|
|
{
|
|
continue;
|
|
}
|
|
|
|
object = to_load.front();
|
|
_currently_loading.emplace_back (object);
|
|
to_load.pop_front();
|
|
|
|
break;
|
|
}
|
|
}
|
|
|
|
try
|
|
{
|
|
if (additional_log)
|
|
{
|
|
std::lock_guard<std::mutex> const lock(_guard);
|
|
LogDebug << "Loading '" << object->filename << "'" << std::endl;
|
|
}
|
|
|
|
object->finishLoading();
|
|
|
|
if (additional_log)
|
|
{
|
|
std::lock_guard<std::mutex> const lock(_guard);
|
|
LogDebug << "Loaded '" << object->filename << "'" << std::endl;
|
|
}
|
|
|
|
{
|
|
std::lock_guard<std::mutex> const lock (_guard);
|
|
_currently_loading.remove (object);
|
|
_state_changed.notify_all();
|
|
}
|
|
}
|
|
catch (...)
|
|
{
|
|
std::lock_guard<std::mutex> const lock(_guard);
|
|
object->error_on_loading();
|
|
|
|
if (object->is_required_when_saving())
|
|
{
|
|
_important_object_failed_loading = true;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void AsyncLoader::queue_for_load (AsyncObject* object)
|
|
{
|
|
std::lock_guard<std::mutex> const lock (_guard);
|
|
_to_load[(size_t)object->loading_priority()].push_back (object);
|
|
_state_changed.notify_one();
|
|
}
|
|
|
|
void AsyncLoader::ensure_deletable (AsyncObject* object)
|
|
{
|
|
std::unique_lock<std::mutex> lock (_guard);
|
|
_state_changed.wait
|
|
( lock
|
|
, [&]
|
|
{
|
|
auto& to_load = _to_load[(size_t)object->loading_priority()];
|
|
auto const& it = std::find (to_load.begin(), to_load.end(), object);
|
|
|
|
// don't load it if it's just to delete it afterward
|
|
if (it != to_load.end())
|
|
{
|
|
to_load.erase(it);
|
|
return true;
|
|
}
|
|
else
|
|
{
|
|
return std::find (_currently_loading.begin(), _currently_loading.end(), object) == _currently_loading.end();
|
|
}
|
|
}
|
|
);
|
|
}
|
|
|
|
AsyncLoader::AsyncLoader(int numThreads)
|
|
: _stop (false)
|
|
{
|
|
for (int i = 0; i < numThreads; ++i)
|
|
{
|
|
_threads.emplace_back (&AsyncLoader::process, this);
|
|
}
|
|
}
|
|
|
|
AsyncLoader::~AsyncLoader()
|
|
{
|
|
_stop = true;
|
|
_state_changed.notify_all();
|
|
|
|
for (auto& thread : _threads)
|
|
{
|
|
thread.join();
|
|
}
|
|
}
|