mirror of
https://github.com/thorvg/thorvg.git
synced 2025-06-07 21:23:32 +00:00
common: ++loader thread safety
fortitfy the thread safety in multi-threaded resource loading. issue: https://github.com/thorvg/thorvg/issues/3306
This commit is contained in:
parent
02baa6b462
commit
56d5396b7a
5 changed files with 14 additions and 42 deletions
|
@ -318,9 +318,7 @@ void LottieFont::prepare()
|
||||||
{
|
{
|
||||||
if (!data.b64src || !name) return;
|
if (!data.b64src || !name) return;
|
||||||
|
|
||||||
TaskScheduler::async(false);
|
|
||||||
Text::load(name, data.b64src, data.size, "ttf", false);
|
Text::load(name, data.b64src, data.size, "ttf", false);
|
||||||
TaskScheduler::async(true);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -331,13 +329,9 @@ void LottieImage::prepare()
|
||||||
auto picture = Picture::gen();
|
auto picture = Picture::gen();
|
||||||
|
|
||||||
//force to load a picture on the same thread
|
//force to load a picture on the same thread
|
||||||
TaskScheduler::async(false);
|
|
||||||
|
|
||||||
if (data.size > 0) picture->load((const char*)data.b64Data, data.size, data.mimeType);
|
if (data.size > 0) picture->load((const char*)data.b64Data, data.size, data.mimeType);
|
||||||
else picture->load(data.path);
|
else picture->load(data.path);
|
||||||
|
|
||||||
TaskScheduler::async(true);
|
|
||||||
|
|
||||||
picture->size(data.width, data.height);
|
picture->size(data.width, data.height);
|
||||||
picture->ref();
|
picture->ref();
|
||||||
|
|
||||||
|
@ -348,13 +342,11 @@ void LottieImage::prepare()
|
||||||
void LottieImage::update()
|
void LottieImage::update()
|
||||||
{
|
{
|
||||||
//Update the picture data
|
//Update the picture data
|
||||||
TaskScheduler::async(false);
|
|
||||||
ARRAY_FOREACH(p, pooler) {
|
ARRAY_FOREACH(p, pooler) {
|
||||||
if (data.size > 0) (*p)->load((const char*)data.b64Data, data.size, data.mimeType);
|
if (data.size > 0) (*p)->load((const char*)data.b64Data, data.size, data.mimeType);
|
||||||
else (*p)->load(data.path);
|
else (*p)->load(data.path);
|
||||||
(*p)->size(data.width, data.height);
|
(*p)->size(data.width, data.height);
|
||||||
}
|
}
|
||||||
TaskScheduler::async(true);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -629,8 +629,6 @@ static Paint* _imageBuildHelper(SvgLoaderData& loaderData, SvgNode* node, const
|
||||||
|
|
||||||
auto picture = Picture::gen();
|
auto picture = Picture::gen();
|
||||||
|
|
||||||
TaskScheduler::async(false); //force to load a picture on the same thread
|
|
||||||
|
|
||||||
const char* href = node->node.image.href;
|
const char* href = node->node.image.href;
|
||||||
if (!strncmp(href, "data:", sizeof("data:") - 1)) {
|
if (!strncmp(href, "data:", sizeof("data:") - 1)) {
|
||||||
href += sizeof("data:") - 1;
|
href += sizeof("data:") - 1;
|
||||||
|
@ -642,14 +640,12 @@ static Paint* _imageBuildHelper(SvgLoaderData& loaderData, SvgNode* node, const
|
||||||
auto size = b64Decode(href, strlen(href), &decoded);
|
auto size = b64Decode(href, strlen(href), &decoded);
|
||||||
if (picture->load(decoded, size, mimetype) != Result::Success) {
|
if (picture->load(decoded, size, mimetype) != Result::Success) {
|
||||||
tvg::free(decoded);
|
tvg::free(decoded);
|
||||||
TaskScheduler::async(true);
|
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
auto size = svgUtilURLDecode(href, &decoded);
|
auto size = svgUtilURLDecode(href, &decoded);
|
||||||
if (picture->load(decoded, size, mimetype) != Result::Success) {
|
if (picture->load(decoded, size, mimetype) != Result::Success) {
|
||||||
tvg::free(decoded);
|
tvg::free(decoded);
|
||||||
TaskScheduler::async(true);
|
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -661,7 +657,6 @@ static Paint* _imageBuildHelper(SvgLoaderData& loaderData, SvgNode* node, const
|
||||||
const char *dot = strrchr(href, '.');
|
const char *dot = strrchr(href, '.');
|
||||||
if (dot && !strcmp(dot, ".svg")) {
|
if (dot && !strcmp(dot, ".svg")) {
|
||||||
TVGLOG("SVG", "Embedded svg file is disabled.");
|
TVGLOG("SVG", "Embedded svg file is disabled.");
|
||||||
TaskScheduler::async(true);
|
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
string imagePath = href;
|
string imagePath = href;
|
||||||
|
@ -670,13 +665,10 @@ static Paint* _imageBuildHelper(SvgLoaderData& loaderData, SvgNode* node, const
|
||||||
imagePath = svgPath.substr(0, (last == string::npos ? 0 : last + 1)) + imagePath;
|
imagePath = svgPath.substr(0, (last == string::npos ? 0 : last + 1)) + imagePath;
|
||||||
}
|
}
|
||||||
if (picture->load(imagePath.c_str()) != Result::Success) {
|
if (picture->load(imagePath.c_str()) != Result::Success) {
|
||||||
TaskScheduler::async(true);
|
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
TaskScheduler::async(true);
|
|
||||||
|
|
||||||
float w, h;
|
float w, h;
|
||||||
Matrix m;
|
Matrix m;
|
||||||
if (picture->size(&w, &h) == Result::Success && w > 0 && h > 0) {
|
if (picture->size(&w, &h) == Result::Success && w > 0 && h > 0) {
|
||||||
|
@ -977,9 +969,7 @@ static void _loadFonts(Array<FontFace>& fonts)
|
||||||
|
|
||||||
auto size = b64Decode(p->src + shift, p->srcLen - shift, &p->decoded);
|
auto size = b64Decode(p->src + shift, p->srcLen - shift, &p->decoded);
|
||||||
|
|
||||||
TaskScheduler::async(false);
|
|
||||||
if (Text::load(p->name, p->decoded, size) != Result::Success) TVGERR("SVG", "Error while loading the ttf font named \"%s\".", p->name);
|
if (Text::load(p->name, p->decoded, size) != Result::Success) TVGERR("SVG", "Error while loading the ttf font named \"%s\".", p->name);
|
||||||
TaskScheduler::async(true);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -63,7 +63,7 @@ uintptr_t HASH_KEY(const char* data)
|
||||||
|
|
||||||
ColorSpace ImageLoader::cs = ColorSpace::ARGB8888;
|
ColorSpace ImageLoader::cs = ColorSpace::ARGB8888;
|
||||||
|
|
||||||
static Key key;
|
static Key _key;
|
||||||
static Inlist<LoadModule> _activeLoaders;
|
static Inlist<LoadModule> _activeLoaders;
|
||||||
|
|
||||||
|
|
||||||
|
@ -202,8 +202,7 @@ static LoadModule* _findByType(const char* mimeType)
|
||||||
|
|
||||||
static LoadModule* _findFromCache(const char* filename)
|
static LoadModule* _findFromCache(const char* filename)
|
||||||
{
|
{
|
||||||
ScopedLock lock(key);
|
ScopedLock lock(_key);
|
||||||
|
|
||||||
INLIST_FOREACH(_activeLoaders, loader) {
|
INLIST_FOREACH(_activeLoaders, loader) {
|
||||||
if (loader->cached && loader->hashpath && !strcmp(loader->hashpath, filename)) {
|
if (loader->cached && loader->hashpath && !strcmp(loader->hashpath, filename)) {
|
||||||
++loader->sharing;
|
++loader->sharing;
|
||||||
|
@ -219,9 +218,10 @@ static LoadModule* _findFromCache(const char* data, uint32_t size, const char* m
|
||||||
auto type = _convert(mimeType);
|
auto type = _convert(mimeType);
|
||||||
if (type == FileType::Unknown) return nullptr;
|
if (type == FileType::Unknown) return nullptr;
|
||||||
|
|
||||||
ScopedLock lock(key);
|
|
||||||
auto key = HASH_KEY(data);
|
auto key = HASH_KEY(data);
|
||||||
|
|
||||||
|
ScopedLock lock(_key);
|
||||||
|
|
||||||
INLIST_FOREACH(_activeLoaders, loader) {
|
INLIST_FOREACH(_activeLoaders, loader) {
|
||||||
if (loader->type == type && loader->hashkey == key) {
|
if (loader->type == type && loader->hashkey == key) {
|
||||||
++loader->sharing;
|
++loader->sharing;
|
||||||
|
@ -259,9 +259,9 @@ bool LoaderMgr::term()
|
||||||
bool LoaderMgr::retrieve(LoadModule* loader)
|
bool LoaderMgr::retrieve(LoadModule* loader)
|
||||||
{
|
{
|
||||||
if (!loader) return false;
|
if (!loader) return false;
|
||||||
|
|
||||||
if (loader->close()) {
|
if (loader->close()) {
|
||||||
if (loader->cached) {
|
if (loader->cached) {
|
||||||
ScopedLock lock(key);
|
|
||||||
_activeLoaders.remove(loader);
|
_activeLoaders.remove(loader);
|
||||||
}
|
}
|
||||||
delete(loader);
|
delete(loader);
|
||||||
|
@ -289,7 +289,7 @@ LoadModule* LoaderMgr::loader(const char* filename, bool* invalid)
|
||||||
if (allowCache) {
|
if (allowCache) {
|
||||||
loader->cache(duplicate(filename));
|
loader->cache(duplicate(filename));
|
||||||
{
|
{
|
||||||
ScopedLock lock(key);
|
ScopedLock lock(_key);
|
||||||
_activeLoaders.back(loader);
|
_activeLoaders.back(loader);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -304,7 +304,7 @@ LoadModule* LoaderMgr::loader(const char* filename, bool* invalid)
|
||||||
if (allowCache) {
|
if (allowCache) {
|
||||||
loader->cache(duplicate(filename));
|
loader->cache(duplicate(filename));
|
||||||
{
|
{
|
||||||
ScopedLock lock(key);
|
ScopedLock lock(_key);
|
||||||
_activeLoaders.back(loader);
|
_activeLoaders.back(loader);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -347,7 +347,7 @@ LoadModule* LoaderMgr::loader(const char* data, uint32_t size, const char* mimeT
|
||||||
if (loader->open(data, size, rpath, copy)) {
|
if (loader->open(data, size, rpath, copy)) {
|
||||||
if (allowCache) {
|
if (allowCache) {
|
||||||
loader->cache(HASH_KEY(data));
|
loader->cache(HASH_KEY(data));
|
||||||
ScopedLock lock(key);
|
ScopedLock lock(_key);
|
||||||
_activeLoaders.back(loader);
|
_activeLoaders.back(loader);
|
||||||
}
|
}
|
||||||
return loader;
|
return loader;
|
||||||
|
@ -364,7 +364,7 @@ LoadModule* LoaderMgr::loader(const char* data, uint32_t size, const char* mimeT
|
||||||
if (loader->open(data, size, rpath, copy)) {
|
if (loader->open(data, size, rpath, copy)) {
|
||||||
if (allowCache) {
|
if (allowCache) {
|
||||||
loader->cache(HASH_KEY(data));
|
loader->cache(HASH_KEY(data));
|
||||||
ScopedLock lock(key);
|
ScopedLock lock(_key);
|
||||||
_activeLoaders.back(loader);
|
_activeLoaders.back(loader);
|
||||||
}
|
}
|
||||||
return loader;
|
return loader;
|
||||||
|
@ -390,7 +390,7 @@ LoadModule* LoaderMgr::loader(const uint32_t *data, uint32_t w, uint32_t h, Colo
|
||||||
if (loader->open(data, w, h, cs, copy)) {
|
if (loader->open(data, w, h, cs, copy)) {
|
||||||
if (!copy) {
|
if (!copy) {
|
||||||
loader->cache(HASH_KEY((const char*)data));
|
loader->cache(HASH_KEY((const char*)data));
|
||||||
ScopedLock lock(key);
|
ScopedLock lock(_key);
|
||||||
_activeLoaders.back(loader);
|
_activeLoaders.back(loader);
|
||||||
}
|
}
|
||||||
return loader;
|
return loader;
|
||||||
|
@ -412,7 +412,7 @@ LoadModule* LoaderMgr::loader(const char* name, const char* data, uint32_t size,
|
||||||
if (loader->open(data, size, "", copy)) {
|
if (loader->open(data, size, "", copy)) {
|
||||||
loader->name = duplicate(name);
|
loader->name = duplicate(name);
|
||||||
loader->cached = true; //force it.
|
loader->cached = true; //force it.
|
||||||
ScopedLock lock(key);
|
ScopedLock lock(_key);
|
||||||
_activeLoaders.back(loader);
|
_activeLoaders.back(loader);
|
||||||
return loader;
|
return loader;
|
||||||
}
|
}
|
||||||
|
@ -426,6 +426,7 @@ LoadModule* LoaderMgr::loader(const char* name, const char* data, uint32_t size,
|
||||||
|
|
||||||
LoadModule* LoaderMgr::font(const char* name)
|
LoadModule* LoaderMgr::font(const char* name)
|
||||||
{
|
{
|
||||||
|
ScopedLock lock(_key);
|
||||||
INLIST_FOREACH(_activeLoaders, loader) {
|
INLIST_FOREACH(_activeLoaders, loader) {
|
||||||
if (loader->type != FileType::Ttf) continue;
|
if (loader->type != FileType::Ttf) continue;
|
||||||
if (loader->cached && tvg::equal(name, static_cast<FontLoader*>(loader)->name)) {
|
if (loader->cached && tvg::equal(name, static_cast<FontLoader*>(loader)->name)) {
|
||||||
|
@ -439,6 +440,7 @@ LoadModule* LoaderMgr::font(const char* name)
|
||||||
|
|
||||||
LoadModule* LoaderMgr::anyfont()
|
LoadModule* LoaderMgr::anyfont()
|
||||||
{
|
{
|
||||||
|
ScopedLock lock(_key);
|
||||||
INLIST_FOREACH(_activeLoaders, loader) {
|
INLIST_FOREACH(_activeLoaders, loader) {
|
||||||
if (loader->cached && loader->type == FileType::Ttf) {
|
if (loader->cached && loader->type == FileType::Ttf) {
|
||||||
++loader->sharing;
|
++loader->sharing;
|
||||||
|
|
|
@ -33,8 +33,6 @@ namespace tvg {
|
||||||
|
|
||||||
#ifdef THORVG_THREAD_SUPPORT
|
#ifdef THORVG_THREAD_SUPPORT
|
||||||
|
|
||||||
static thread_local bool _async = true;
|
|
||||||
|
|
||||||
struct TaskQueue {
|
struct TaskQueue {
|
||||||
Inlist<Task> taskDeque;
|
Inlist<Task> taskDeque;
|
||||||
mutex mtx;
|
mutex mtx;
|
||||||
|
@ -150,7 +148,7 @@ struct TaskSchedulerImpl
|
||||||
void request(Task* task)
|
void request(Task* task)
|
||||||
{
|
{
|
||||||
//Async
|
//Async
|
||||||
if (threads.count > 0 && _async) {
|
if (threads.count > 0) {
|
||||||
task->prepare();
|
task->prepare();
|
||||||
auto i = idx++;
|
auto i = idx++;
|
||||||
for (uint32_t n = 0; n < threads.count; ++n) {
|
for (uint32_t n = 0; n < threads.count; ++n) {
|
||||||
|
@ -171,8 +169,6 @@ struct TaskSchedulerImpl
|
||||||
|
|
||||||
#else //THORVG_THREAD_SUPPORT
|
#else //THORVG_THREAD_SUPPORT
|
||||||
|
|
||||||
static bool _async = true;
|
|
||||||
|
|
||||||
struct TaskSchedulerImpl
|
struct TaskSchedulerImpl
|
||||||
{
|
{
|
||||||
TaskSchedulerImpl(TVG_UNUSED uint32_t threadCnt) {}
|
TaskSchedulerImpl(TVG_UNUSED uint32_t threadCnt) {}
|
||||||
|
@ -219,13 +215,6 @@ uint32_t TaskScheduler::threads()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void TaskScheduler::async(bool on)
|
|
||||||
{
|
|
||||||
//toggle async tasking for each thread on/off
|
|
||||||
_async = on;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
bool TaskScheduler::onthread()
|
bool TaskScheduler::onthread()
|
||||||
{
|
{
|
||||||
return _tid != tid();
|
return _tid != tid();
|
||||||
|
|
|
@ -112,7 +112,6 @@ struct TaskScheduler
|
||||||
static void init(uint32_t threads);
|
static void init(uint32_t threads);
|
||||||
static void term();
|
static void term();
|
||||||
static void request(Task* task);
|
static void request(Task* task);
|
||||||
static void async(bool on);
|
|
||||||
static bool onthread(); //figure out whether on worker thread or not
|
static bool onthread(); //figure out whether on worker thread or not
|
||||||
static ThreadID tid();
|
static ThreadID tid();
|
||||||
};
|
};
|
||||||
|
|
Loading…
Add table
Reference in a new issue