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

Investigate thread safety of rust-sfml #228

Open
crumblingstatue opened this issue Sep 10, 2020 · 5 comments
Open

Investigate thread safety of rust-sfml #228

crumblingstatue opened this issue Sep 10, 2020 · 5 comments

Comments

@crumblingstatue
Copy link
Collaborator

So far most of the effort has been to make the library safe to use in a single-threaded context, but there haven't been much investigation on how it behaves when multiple threads are involved.

Related/sub issues:

@memoryleak47
Copy link
Contributor

Context::new() also doesn't seem to be thread safe.

@memoryleak47
Copy link
Contributor

The following may be the root issue:
"That's because a window (more precisely its OpenGL context) cannot be active in more than one thread at the same time." - https://www.sfml-dev.org/tutorials/2.5/graphics-draw.php

Hence possibly all subclasses of sf::GlResource are not thread safe.
(see https://www.sfml-dev.org/documentation/2.5.1/classsf_1_1GlResource.php#details)

@crumblingstatue
Copy link
Collaborator Author

Thank you, that's useful information!

@datMaffin
Copy link
Contributor

datMaffin commented Sep 27, 2020

I noticed an implementation detail that may be relevant for thread safety:

In Transformable the function fn transform(&self) -> Transform looks like it would be thread safe. (self is not mut).
However, the C++ implementation is not:

const Transform& Transformable::getTransform() const
{
    // Recompute the combined transform if needed
    if (m_transformNeedUpdate)
    {
        ...

        m_transform = Transform( sxc, sys, tx,
                                -sxs, syc, ty,
                                 0.f, 0.f, 1.f);
        m_transformNeedUpdate = false;
    }

    return m_transform;
}

Changing m_transform and m_transformNeedUpdate is possible because they are declared as mutable:

class SFML_GRAPHICS_API Transformable
{
...

private:

    ////////////////////////////////////////////////////////////
    // Member data
    ////////////////////////////////////////////////////////////
    ...
    mutable Transform m_transform;                  //!< Combined transformation of the object
    mutable bool      m_transformNeedUpdate;        //!< Does the transform need to be recomputed?
    mutable Transform m_inverseTransform;           //!< Combined transformation of the object
    mutable bool      m_inverseTransformNeedUpdate; //!< Does the transform need to be recomputed?
};

The same would probably be true for other getter that are using caching as well.

I guess it would be possible to mark all such functions with an additional mut in the function signature fn func(&mut self,... such that the rust compiler is able to ensure memory safety.

(I am NOT 100% sure if this really is an issue...)
(I thought about it a little more: I think it is possible that a dangerous race condition is going to occur if the cache of those parallel threads is incoherent, which should be possible; there is no flush or anything similar. For example the second thread could see m_transformNeedUpdate = true while still holding old Transform data therfore old Transform data is getting (falsely) returned.)

@crumblingstatue
Copy link
Collaborator Author

Thank you, that's very useful information!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

3 participants