Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix locks in TextureLoader class #1147

Open
wants to merge 2 commits into
base: develop
Choose a base branch
from

Conversation

xezon
Copy link
Contributor

@xezon xezon commented Aug 21, 2024

@@ -503,6 +542,7 @@ void TextureLoader::Begin_Load_And_Queue(TextureLoadTaskClass *task)

// If we can't start the load of either a dds or tga for the filename in the task set it to missing.
if (task->Begin_Load()) {
FastCriticalSectionClass::LockClass lock(g_backgroundCritSec);
g_backgroundQueue.Push_Front(task);
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Lock is missing here on write. Could race.

int time = rts::Get_Time();
TextureLoadTaskClass *task;

while ((task = g_foregroundQueue.Pop_Front()) != nullptr) {
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Lock exists before already, but scope can be limited. Optimization.

@@ -385,9 +408,17 @@ void TextureLoader::Request_Foreground_Loading(TextureBaseClass *texture)
*/
bool TextureLoader::Queues_Not_Empty()
{
FastCriticalSectionClass::LockClass lock(g_backgroundCritSec);

return !g_backgroundQueue.Empty() && !g_foregroundQueue.Empty();
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Lock for g_foregroundQueue is missing here on read.

@@ -344,32 +352,47 @@ void TextureLoader::Request_Foreground_Loading(TextureBaseClass *texture)
TextureLoadTaskClass *thumb_task = texture->Get_Thumbnail_Load_Task();

if (!TextureLoader::Is_DX8_Thread()) {
FastCriticalSectionClass::LockClass lock2(g_backgroundCritSec);
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Originally takes both locks at the same time. This can be risky and introduce ABA deadlock problem. This can be avoided by limiting scope.

Could perhaps deadlock with LoaderThreadClass::Thread_Function

@@ -344,32 +352,47 @@ void TextureLoader::Request_Foreground_Loading(TextureBaseClass *texture)
TextureLoadTaskClass *thumb_task = texture->Get_Thumbnail_Load_Task();

if (!TextureLoader::Is_DX8_Thread()) {
FastCriticalSectionClass::LockClass lock2(g_backgroundCritSec);
if (thumb_task != nullptr) {
thumb_task->Set_Load_State(TextureLoadTaskClass::STATE_FOREGROUND_OVERRIDE);
}

if (task != nullptr) {
if (task->Get_Parent() == &g_backgroundQueue) {
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This does not need locking. g_backgroundQueue address never changes.

@@ -312,15 +322,14 @@ void TextureLoader::Request_Thumbnail(TextureBaseClass *texture)
*/
void TextureLoader::Request_Background_Loading(TextureBaseClass *texture)
{
FastCriticalSectionClass::LockClass lock(g_foregroundCritSec);
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Lock scope can be limited. Optimization.

@@ -282,21 +291,22 @@ w3dsurface_t TextureLoader::Load_Surface_Immediate(const StringClass &texture, W
*/
void TextureLoader::Request_Thumbnail(TextureBaseClass *texture)
{
FastCriticalSectionClass::LockClass lock(g_foregroundCritSec);
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Lock scope can be limited. Optimization.

@@ -81,9 +81,18 @@ w3dtexture_t Load_Compressed_Texture(
void LoaderThreadClass::Thread_Function()
{
while (m_isRunning) {
if (!g_backgroundQueue.Empty()) {
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Lock for g_backgroundQueue is missing here on read.

@@ -81,9 +81,18 @@ w3dtexture_t Load_Compressed_Texture(
void LoaderThreadClass::Thread_Function()
{
while (m_isRunning) {
if (!g_backgroundQueue.Empty()) {
bool backgroundQueueEmpty;
{
FastCriticalSectionClass::LockClass background_lock(g_backgroundCritSec);
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Originally takes both locks at the same time. This can be risky and introduce ABA deadlock problem. This can be avoided by limiting scope.

Could perhaps deadlock with TextureLoader::Request_Foreground_Loading.

@xezon xezon added the fixing label Aug 21, 2024
@xezon xezon force-pushed the fix-textureloader-locks branch from e18df69 to 8fbff61 Compare September 21, 2024 05:37
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

w3dview texture crash
1 participant