[WTF] Add DataMutex and MainThreadData wrappers
https://bugs.webkit.org/show_bug.cgi?id=199831
Reviewed by Alex Christensen.
Source/WTF:
This patch adds two new wrapper classes:
DataMutex<T> stores an instance of T in a private member along with a
mutex. In order to use its fields, users need to instantiate a
DataMutex<T>::LockedWrapper instance in the stack. This class uses
RAII to lock and unlock the mutex in construction and destruction
respectively, and by using the arrow operator lets the user access T's
members.
This way, DataMutex<T> prevents most instances of accidental access to
data fields that should only be read and modified in an atomic matter.
Still, both the Lock and the LockHolder are exposed once the user has
taken the lock so that special cases such as waiting for a condition
variable or performing an early unlock are doable.
MainThreadData<T> is another wrapper class, in this case for data
fields that should only be accessed from the main thread. In this
case, it works similar to a smart pointer, except that (1) there is no
actual memory indirection, T is stored directly inside
MainThreadData<T> and (2) attempts to use the -> or * operator have an
isMainThread() assertion.
Together, these two wrapper classes make it easier to write
multi-threaded code in a safer, more self-documented way by letting
the author group data into structures that have certain access safety
requirements.
These structures were originally part of the new GStreamer
WebKitMediaSrc rework patch: https://bugs.webkit.org/show_bug.cgi?id=199719
* wtf/CMakeLists.txt:
* wtf/DataMutex.h: Added.
(WTF::DataMutex::DataMutex):
(WTF::DataMutex::LockedWrapper::LockedWrapper):
(WTF::DataMutex::LockedWrapper::operator->):
(WTF::DataMutex::LockedWrapper::operator*):
(WTF::DataMutex::LockedWrapper::mutex):
(WTF::DataMutex::LockedWrapper::lockHolder):
* wtf/MainThreadData.h: Added.
(WTF::MainThreadData::MainThreadData):
(WTF::MainThreadData::operator->):
(WTF::MainThreadData::operator*):
Tools:
Added a very simple test that checks that DataMutex<T> indeed takes
the lock and indeed holds data.
* TestWebKitAPI/CMakeLists.txt:
* TestWebKitAPI/Tests/WTF/DataMutex.cpp: Added.
(TestWebKitAPI::TEST):
Canonical link: https://commits.webkit.org/213882@main
git-svn-id: https://svn.webkit.org/repository/webkit/trunk@247723 268f45cc-cd09-0410-ab3c-d52691b4dbfc
2019-07-23 14:51:29 +00:00
|
|
|
/*
|
|
|
|
* Copyright (C) 2019 Igalia, S.L.
|
|
|
|
* Copyright (C) 2019 Metrological Group B.V.
|
|
|
|
*
|
|
|
|
* This library is free software; you can redistribute it and/or
|
|
|
|
* modify it under the terms of the GNU Library General Public
|
|
|
|
* License as published by the Free Software Foundation; either
|
|
|
|
* version 2 of the License, or (at your option) any later version.
|
|
|
|
*
|
|
|
|
* This library is distributed in the hope that it will be useful,
|
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
|
|
* Library General Public License for more details.
|
|
|
|
*
|
|
|
|
* You should have received a copy of the GNU Library General Public License
|
|
|
|
* aint with this library; see the file COPYING.LIB. If not, write to
|
|
|
|
* the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
|
|
|
|
* Boston, MA 02110-1301, USA.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#pragma once
|
|
|
|
|
|
|
|
#include <wtf/Lock.h>
|
2020-04-10 16:46:49 +00:00
|
|
|
#include <wtf/Threading.h>
|
[WTF] Add DataMutex and MainThreadData wrappers
https://bugs.webkit.org/show_bug.cgi?id=199831
Reviewed by Alex Christensen.
Source/WTF:
This patch adds two new wrapper classes:
DataMutex<T> stores an instance of T in a private member along with a
mutex. In order to use its fields, users need to instantiate a
DataMutex<T>::LockedWrapper instance in the stack. This class uses
RAII to lock and unlock the mutex in construction and destruction
respectively, and by using the arrow operator lets the user access T's
members.
This way, DataMutex<T> prevents most instances of accidental access to
data fields that should only be read and modified in an atomic matter.
Still, both the Lock and the LockHolder are exposed once the user has
taken the lock so that special cases such as waiting for a condition
variable or performing an early unlock are doable.
MainThreadData<T> is another wrapper class, in this case for data
fields that should only be accessed from the main thread. In this
case, it works similar to a smart pointer, except that (1) there is no
actual memory indirection, T is stored directly inside
MainThreadData<T> and (2) attempts to use the -> or * operator have an
isMainThread() assertion.
Together, these two wrapper classes make it easier to write
multi-threaded code in a safer, more self-documented way by letting
the author group data into structures that have certain access safety
requirements.
These structures were originally part of the new GStreamer
WebKitMediaSrc rework patch: https://bugs.webkit.org/show_bug.cgi?id=199719
* wtf/CMakeLists.txt:
* wtf/DataMutex.h: Added.
(WTF::DataMutex::DataMutex):
(WTF::DataMutex::LockedWrapper::LockedWrapper):
(WTF::DataMutex::LockedWrapper::operator->):
(WTF::DataMutex::LockedWrapper::operator*):
(WTF::DataMutex::LockedWrapper::mutex):
(WTF::DataMutex::LockedWrapper::lockHolder):
* wtf/MainThreadData.h: Added.
(WTF::MainThreadData::MainThreadData):
(WTF::MainThreadData::operator->):
(WTF::MainThreadData::operator*):
Tools:
Added a very simple test that checks that DataMutex<T> indeed takes
the lock and indeed holds data.
* TestWebKitAPI/CMakeLists.txt:
* TestWebKitAPI/Tests/WTF/DataMutex.cpp: Added.
(TestWebKitAPI::TEST):
Canonical link: https://commits.webkit.org/213882@main
git-svn-id: https://svn.webkit.org/repository/webkit/trunk@247723 268f45cc-cd09-0410-ab3c-d52691b4dbfc
2019-07-23 14:51:29 +00:00
|
|
|
|
|
|
|
namespace WTF {
|
|
|
|
|
2020-04-10 16:46:49 +00:00
|
|
|
// By default invalid access checks are only done in Debug builds.
|
|
|
|
#if !defined(ENABLE_DATA_MUTEX_CHECKS)
|
|
|
|
#if defined(NDEBUG)
|
|
|
|
#define ENABLE_DATA_MUTEX_CHECKS 0
|
|
|
|
#else
|
|
|
|
#define ENABLE_DATA_MUTEX_CHECKS 1
|
|
|
|
#endif
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#if ENABLE_DATA_MUTEX_CHECKS
|
|
|
|
#define DATA_MUTEX_CHECK(expr) RELEASE_ASSERT(expr)
|
|
|
|
#else
|
|
|
|
#define DATA_MUTEX_CHECK(expr)
|
|
|
|
#endif
|
|
|
|
|
2021-05-30 05:22:59 +00:00
|
|
|
template <typename T> class DataMutexLocker;
|
|
|
|
|
|
|
|
template<typename T>
|
|
|
|
class DataMutex {
|
|
|
|
WTF_MAKE_FAST_ALLOCATED;
|
|
|
|
WTF_MAKE_NONCOPYABLE(DataMutex);
|
|
|
|
public:
|
|
|
|
template<typename ...Args>
|
|
|
|
explicit DataMutex(Args&&... args)
|
|
|
|
: m_data(std::forward<Args>(args)...)
|
|
|
|
{ }
|
|
|
|
|
|
|
|
private:
|
|
|
|
friend class DataMutexLocker<T>;
|
|
|
|
|
|
|
|
Lock m_mutex;
|
|
|
|
T m_data WTF_GUARDED_BY_LOCK(m_mutex);
|
2021-06-16 15:41:15 +00:00
|
|
|
#if ENABLE_DATA_MUTEX_CHECKS
|
|
|
|
Thread* m_currentMutexHolder { nullptr };
|
|
|
|
#endif
|
2021-05-30 05:22:59 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
template <typename T>
|
|
|
|
class WTF_CAPABILITY_SCOPED_LOCK DataMutexLocker {
|
2020-04-10 16:46:49 +00:00
|
|
|
public:
|
2021-05-30 05:22:59 +00:00
|
|
|
explicit DataMutexLocker(DataMutex<T>& dataMutex) WTF_ACQUIRES_LOCK(m_dataMutex.m_mutex)
|
|
|
|
: m_dataMutex(dataMutex)
|
2020-04-10 16:46:49 +00:00
|
|
|
{
|
2021-06-16 15:41:15 +00:00
|
|
|
lock();
|
2020-04-10 16:46:49 +00:00
|
|
|
}
|
|
|
|
|
2021-06-07 11:45:59 +00:00
|
|
|
~DataMutexLocker() WTF_RELEASES_LOCK()
|
2020-04-10 16:46:49 +00:00
|
|
|
{
|
2021-06-07 11:45:59 +00:00
|
|
|
if (m_isLocked) {
|
2021-06-16 15:41:15 +00:00
|
|
|
unlock();
|
2021-06-07 11:45:59 +00:00
|
|
|
}
|
2020-04-10 16:46:49 +00:00
|
|
|
}
|
|
|
|
|
2021-05-30 05:22:59 +00:00
|
|
|
T* operator->()
|
2020-04-10 16:46:49 +00:00
|
|
|
{
|
2021-06-07 11:45:59 +00:00
|
|
|
DATA_MUTEX_CHECK(m_isLocked && mutex().isHeld());
|
2021-05-30 05:22:59 +00:00
|
|
|
assertIsHeld(m_dataMutex.m_mutex);
|
|
|
|
return &m_dataMutex.m_data;
|
2020-04-10 16:46:49 +00:00
|
|
|
}
|
|
|
|
|
2021-05-30 05:22:59 +00:00
|
|
|
T& operator*()
|
2020-04-10 16:46:49 +00:00
|
|
|
{
|
2021-06-07 11:45:59 +00:00
|
|
|
DATA_MUTEX_CHECK(m_isLocked && mutex().isHeld());
|
2021-05-30 05:22:59 +00:00
|
|
|
assertIsHeld(m_dataMutex.m_mutex);
|
|
|
|
return m_dataMutex.m_data;
|
2020-04-10 16:46:49 +00:00
|
|
|
}
|
|
|
|
|
2021-05-30 05:22:59 +00:00
|
|
|
Lock& mutex() WTF_RETURNS_LOCK(m_dataMutex.m_mutex)
|
|
|
|
{
|
|
|
|
return m_dataMutex.m_mutex;
|
|
|
|
}
|
2020-04-10 16:46:49 +00:00
|
|
|
|
2021-06-07 11:45:59 +00:00
|
|
|
// Note: DataMutexLocker shouldn't be used after this. Due to limitations of clang thread safety analysis this can't
|
|
|
|
// currently be staticly checked (adding WTF_REQUIRES_LOCK() to operator->() doesn't work.)
|
|
|
|
// Run-time checks are still performed if enabled.
|
2021-05-30 05:22:59 +00:00
|
|
|
void unlockEarly() WTF_RELEASES_LOCK(m_dataMutex.m_mutex)
|
|
|
|
{
|
2021-06-16 15:41:15 +00:00
|
|
|
assertIsHeld(m_dataMutex.m_mutex);
|
|
|
|
unlock();
|
2021-05-30 05:22:59 +00:00
|
|
|
}
|
[WTF] Add DataMutex and MainThreadData wrappers
https://bugs.webkit.org/show_bug.cgi?id=199831
Reviewed by Alex Christensen.
Source/WTF:
This patch adds two new wrapper classes:
DataMutex<T> stores an instance of T in a private member along with a
mutex. In order to use its fields, users need to instantiate a
DataMutex<T>::LockedWrapper instance in the stack. This class uses
RAII to lock and unlock the mutex in construction and destruction
respectively, and by using the arrow operator lets the user access T's
members.
This way, DataMutex<T> prevents most instances of accidental access to
data fields that should only be read and modified in an atomic matter.
Still, both the Lock and the LockHolder are exposed once the user has
taken the lock so that special cases such as waiting for a condition
variable or performing an early unlock are doable.
MainThreadData<T> is another wrapper class, in this case for data
fields that should only be accessed from the main thread. In this
case, it works similar to a smart pointer, except that (1) there is no
actual memory indirection, T is stored directly inside
MainThreadData<T> and (2) attempts to use the -> or * operator have an
isMainThread() assertion.
Together, these two wrapper classes make it easier to write
multi-threaded code in a safer, more self-documented way by letting
the author group data into structures that have certain access safety
requirements.
These structures were originally part of the new GStreamer
WebKitMediaSrc rework patch: https://bugs.webkit.org/show_bug.cgi?id=199719
* wtf/CMakeLists.txt:
* wtf/DataMutex.h: Added.
(WTF::DataMutex::DataMutex):
(WTF::DataMutex::LockedWrapper::LockedWrapper):
(WTF::DataMutex::LockedWrapper::operator->):
(WTF::DataMutex::LockedWrapper::operator*):
(WTF::DataMutex::LockedWrapper::mutex):
(WTF::DataMutex::LockedWrapper::lockHolder):
* wtf/MainThreadData.h: Added.
(WTF::MainThreadData::MainThreadData):
(WTF::MainThreadData::operator->):
(WTF::MainThreadData::operator*):
Tools:
Added a very simple test that checks that DataMutex<T> indeed takes
the lock and indeed holds data.
* TestWebKitAPI/CMakeLists.txt:
* TestWebKitAPI/Tests/WTF/DataMutex.cpp: Added.
(TestWebKitAPI::TEST):
Canonical link: https://commits.webkit.org/213882@main
git-svn-id: https://svn.webkit.org/repository/webkit/trunk@247723 268f45cc-cd09-0410-ab3c-d52691b4dbfc
2019-07-23 14:51:29 +00:00
|
|
|
|
2021-05-30 05:22:59 +00:00
|
|
|
// Used to avoid excessive brace scoping when only small parts of the code need to be run unlocked.
|
|
|
|
// Please be mindful that accessing the wrapped data from the callback is unsafe and will fail on assertions.
|
|
|
|
// It's helpful to use a minimal lambda capture to be conscious of what data you're having access to in these sections.
|
2021-06-07 11:45:59 +00:00
|
|
|
void runUnlocked(const Function<void()>& callback) WTF_IGNORES_THREAD_SAFETY_ANALYSIS
|
2021-05-30 05:22:59 +00:00
|
|
|
{
|
2021-06-16 15:41:15 +00:00
|
|
|
unlock();
|
2021-05-30 05:22:59 +00:00
|
|
|
callback();
|
2021-06-16 15:41:15 +00:00
|
|
|
lock();
|
2021-05-30 05:22:59 +00:00
|
|
|
}
|
[WTF] Add DataMutex and MainThreadData wrappers
https://bugs.webkit.org/show_bug.cgi?id=199831
Reviewed by Alex Christensen.
Source/WTF:
This patch adds two new wrapper classes:
DataMutex<T> stores an instance of T in a private member along with a
mutex. In order to use its fields, users need to instantiate a
DataMutex<T>::LockedWrapper instance in the stack. This class uses
RAII to lock and unlock the mutex in construction and destruction
respectively, and by using the arrow operator lets the user access T's
members.
This way, DataMutex<T> prevents most instances of accidental access to
data fields that should only be read and modified in an atomic matter.
Still, both the Lock and the LockHolder are exposed once the user has
taken the lock so that special cases such as waiting for a condition
variable or performing an early unlock are doable.
MainThreadData<T> is another wrapper class, in this case for data
fields that should only be accessed from the main thread. In this
case, it works similar to a smart pointer, except that (1) there is no
actual memory indirection, T is stored directly inside
MainThreadData<T> and (2) attempts to use the -> or * operator have an
isMainThread() assertion.
Together, these two wrapper classes make it easier to write
multi-threaded code in a safer, more self-documented way by letting
the author group data into structures that have certain access safety
requirements.
These structures were originally part of the new GStreamer
WebKitMediaSrc rework patch: https://bugs.webkit.org/show_bug.cgi?id=199719
* wtf/CMakeLists.txt:
* wtf/DataMutex.h: Added.
(WTF::DataMutex::DataMutex):
(WTF::DataMutex::LockedWrapper::LockedWrapper):
(WTF::DataMutex::LockedWrapper::operator->):
(WTF::DataMutex::LockedWrapper::operator*):
(WTF::DataMutex::LockedWrapper::mutex):
(WTF::DataMutex::LockedWrapper::lockHolder):
* wtf/MainThreadData.h: Added.
(WTF::MainThreadData::MainThreadData):
(WTF::MainThreadData::operator->):
(WTF::MainThreadData::operator*):
Tools:
Added a very simple test that checks that DataMutex<T> indeed takes
the lock and indeed holds data.
* TestWebKitAPI/CMakeLists.txt:
* TestWebKitAPI/Tests/WTF/DataMutex.cpp: Added.
(TestWebKitAPI::TEST):
Canonical link: https://commits.webkit.org/213882@main
git-svn-id: https://svn.webkit.org/repository/webkit/trunk@247723 268f45cc-cd09-0410-ab3c-d52691b4dbfc
2019-07-23 14:51:29 +00:00
|
|
|
|
|
|
|
private:
|
2021-05-30 05:22:59 +00:00
|
|
|
DataMutex<T>& m_dataMutex;
|
|
|
|
bool m_isLocked { false };
|
2021-06-16 15:41:15 +00:00
|
|
|
|
|
|
|
void lock() WTF_ACQUIRES_LOCK(m_dataMutex.m_mutex)
|
|
|
|
{
|
|
|
|
DATA_MUTEX_CHECK(m_dataMutex.m_currentMutexHolder != &Thread::current()); // Thread attempted recursive lock on non-recursive lock.
|
|
|
|
mutex().lock();
|
|
|
|
m_isLocked = true;
|
|
|
|
#if ENABLE_DATA_MUTEX_CHECKS
|
|
|
|
m_dataMutex.m_currentMutexHolder = &Thread::current();
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
void unlock() WTF_RELEASES_LOCK(m_dataMutex.m_mutex)
|
|
|
|
{
|
|
|
|
DATA_MUTEX_CHECK(mutex().isHeld());
|
|
|
|
assertIsHeld(m_dataMutex.m_mutex);
|
|
|
|
#if ENABLE_DATA_MUTEX_CHECKS
|
|
|
|
m_dataMutex.m_currentMutexHolder = nullptr;
|
|
|
|
#endif
|
|
|
|
m_isLocked = false;
|
|
|
|
mutex().unlock();
|
|
|
|
}
|
[WTF] Add DataMutex and MainThreadData wrappers
https://bugs.webkit.org/show_bug.cgi?id=199831
Reviewed by Alex Christensen.
Source/WTF:
This patch adds two new wrapper classes:
DataMutex<T> stores an instance of T in a private member along with a
mutex. In order to use its fields, users need to instantiate a
DataMutex<T>::LockedWrapper instance in the stack. This class uses
RAII to lock and unlock the mutex in construction and destruction
respectively, and by using the arrow operator lets the user access T's
members.
This way, DataMutex<T> prevents most instances of accidental access to
data fields that should only be read and modified in an atomic matter.
Still, both the Lock and the LockHolder are exposed once the user has
taken the lock so that special cases such as waiting for a condition
variable or performing an early unlock are doable.
MainThreadData<T> is another wrapper class, in this case for data
fields that should only be accessed from the main thread. In this
case, it works similar to a smart pointer, except that (1) there is no
actual memory indirection, T is stored directly inside
MainThreadData<T> and (2) attempts to use the -> or * operator have an
isMainThread() assertion.
Together, these two wrapper classes make it easier to write
multi-threaded code in a safer, more self-documented way by letting
the author group data into structures that have certain access safety
requirements.
These structures were originally part of the new GStreamer
WebKitMediaSrc rework patch: https://bugs.webkit.org/show_bug.cgi?id=199719
* wtf/CMakeLists.txt:
* wtf/DataMutex.h: Added.
(WTF::DataMutex::DataMutex):
(WTF::DataMutex::LockedWrapper::LockedWrapper):
(WTF::DataMutex::LockedWrapper::operator->):
(WTF::DataMutex::LockedWrapper::operator*):
(WTF::DataMutex::LockedWrapper::mutex):
(WTF::DataMutex::LockedWrapper::lockHolder):
* wtf/MainThreadData.h: Added.
(WTF::MainThreadData::MainThreadData):
(WTF::MainThreadData::operator->):
(WTF::MainThreadData::operator*):
Tools:
Added a very simple test that checks that DataMutex<T> indeed takes
the lock and indeed holds data.
* TestWebKitAPI/CMakeLists.txt:
* TestWebKitAPI/Tests/WTF/DataMutex.cpp: Added.
(TestWebKitAPI::TEST):
Canonical link: https://commits.webkit.org/213882@main
git-svn-id: https://svn.webkit.org/repository/webkit/trunk@247723 268f45cc-cd09-0410-ab3c-d52691b4dbfc
2019-07-23 14:51:29 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
} // namespace WTF
|
2021-05-30 05:22:59 +00:00
|
|
|
|
|
|
|
using WTF::DataMutex;
|
|
|
|
using WTF::DataMutexLocker;
|