tsan: fix data race in o3tl::cow_wrapper
where the use_count() call was happening without any kind of synchronisation - switch to use std::atomic which does the right thing for us Change-Id: I79a6452f42bd425ea494bb0298dc134de5678813 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/170217 Reviewed-by: Noel Grandin <noel.grandin@collabora.co.uk> Tested-by: Jenkins
This commit is contained in:
@@ -20,8 +20,7 @@
|
|||||||
#ifndef INCLUDED_O3TL_COW_WRAPPER_HXX
|
#ifndef INCLUDED_O3TL_COW_WRAPPER_HXX
|
||||||
#define INCLUDED_O3TL_COW_WRAPPER_HXX
|
#define INCLUDED_O3TL_COW_WRAPPER_HXX
|
||||||
|
|
||||||
#include <osl/interlck.h>
|
#include <atomic>
|
||||||
|
|
||||||
#include <optional>
|
#include <optional>
|
||||||
#include <cstddef>
|
#include <cstddef>
|
||||||
|
|
||||||
@@ -38,6 +37,7 @@ namespace o3tl
|
|||||||
typedef std::size_t ref_count_t;
|
typedef std::size_t ref_count_t;
|
||||||
static void incrementCount( ref_count_t& rCount ) { ++rCount; }
|
static void incrementCount( ref_count_t& rCount ) { ++rCount; }
|
||||||
static bool decrementCount( ref_count_t& rCount ) { return --rCount != 0; }
|
static bool decrementCount( ref_count_t& rCount ) { return --rCount != 0; }
|
||||||
|
static std::size_t getCount( ref_count_t& rCount) { return rCount; }
|
||||||
};
|
};
|
||||||
|
|
||||||
/** Thread-safe refcounting
|
/** Thread-safe refcounting
|
||||||
@@ -47,12 +47,13 @@ namespace o3tl
|
|||||||
*/
|
*/
|
||||||
struct ThreadSafeRefCountingPolicy
|
struct ThreadSafeRefCountingPolicy
|
||||||
{
|
{
|
||||||
typedef oslInterlockedCount ref_count_t;
|
typedef std::atomic<int> ref_count_t;
|
||||||
static void incrementCount( ref_count_t& rCount ) { osl_atomic_increment(&rCount); }
|
static void incrementCount( ref_count_t& rCount ) { rCount++; }
|
||||||
static bool decrementCount( ref_count_t& rCount )
|
static bool decrementCount( ref_count_t& rCount )
|
||||||
{
|
{
|
||||||
return osl_atomic_decrement(&rCount) != 0;
|
return (--rCount) != 0;
|
||||||
}
|
}
|
||||||
|
static std::size_t getCount( ref_count_t& rCount) { return rCount; }
|
||||||
};
|
};
|
||||||
|
|
||||||
/** Copy-on-write wrapper.
|
/** Copy-on-write wrapper.
|
||||||
@@ -315,9 +316,9 @@ int cow_wrapper_client::queryUnmodified() const
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// return number of shared instances (1 for unique object)
|
/// return number of shared instances (1 for unique object)
|
||||||
typename MTPolicy::ref_count_t use_count() const // nothrow
|
size_t use_count() const // nothrow
|
||||||
{
|
{
|
||||||
return m_pimpl ? m_pimpl->m_ref_count : 0;
|
return m_pimpl ? MTPolicy::getCount(m_pimpl->m_ref_count) : 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void swap(cow_wrapper& r) // never throws
|
void swap(cow_wrapper& r) // never throws
|
||||||
|
@@ -93,7 +93,7 @@ bool cow_wrapper_client2::is_unique() const
|
|||||||
{
|
{
|
||||||
return maImpl.is_unique();
|
return maImpl.is_unique();
|
||||||
}
|
}
|
||||||
oslInterlockedCount cow_wrapper_client2::use_count() const
|
int cow_wrapper_client2::use_count() const
|
||||||
{
|
{
|
||||||
return maImpl.use_count();
|
return maImpl.use_count();
|
||||||
}
|
}
|
||||||
@@ -171,7 +171,7 @@ bool cow_wrapper_client3::is_unique() const
|
|||||||
{
|
{
|
||||||
return maImpl.is_unique();
|
return maImpl.is_unique();
|
||||||
}
|
}
|
||||||
oslInterlockedCount cow_wrapper_client3::use_count() const
|
int cow_wrapper_client3::use_count() const
|
||||||
{
|
{
|
||||||
return maImpl.use_count();
|
return maImpl.use_count();
|
||||||
}
|
}
|
||||||
|
@@ -20,6 +20,7 @@
|
|||||||
#ifndef INCLUDED_O3TL_QA_COW_WRAPPER_CLIENTS_HXX
|
#ifndef INCLUDED_O3TL_QA_COW_WRAPPER_CLIENTS_HXX
|
||||||
#define INCLUDED_O3TL_QA_COW_WRAPPER_CLIENTS_HXX
|
#define INCLUDED_O3TL_QA_COW_WRAPPER_CLIENTS_HXX
|
||||||
|
|
||||||
|
#include <sal/types.h>
|
||||||
#include <o3tl/cow_wrapper.hxx>
|
#include <o3tl/cow_wrapper.hxx>
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
@@ -45,7 +46,7 @@ public:
|
|||||||
|
|
||||||
void makeUnique() { maImpl.make_unique(); }
|
void makeUnique() { maImpl.make_unique(); }
|
||||||
bool is_unique() const { return maImpl.is_unique(); }
|
bool is_unique() const { return maImpl.is_unique(); }
|
||||||
oslInterlockedCount use_count() const { return maImpl.use_count(); }
|
int use_count() const { return maImpl.use_count(); }
|
||||||
void swap( cow_wrapper_client1& r ) { o3tl::swap(maImpl, r.maImpl); }
|
void swap( cow_wrapper_client1& r ) { o3tl::swap(maImpl, r.maImpl); }
|
||||||
|
|
||||||
bool operator==( const cow_wrapper_client1& rRHS ) const { return maImpl == rRHS.maImpl; }
|
bool operator==( const cow_wrapper_client1& rRHS ) const { return maImpl == rRHS.maImpl; }
|
||||||
@@ -79,7 +80,7 @@ public:
|
|||||||
|
|
||||||
void makeUnique();
|
void makeUnique();
|
||||||
bool is_unique() const;
|
bool is_unique() const;
|
||||||
oslInterlockedCount use_count() const;
|
int use_count() const;
|
||||||
void swap( cow_wrapper_client2& r );
|
void swap( cow_wrapper_client2& r );
|
||||||
|
|
||||||
bool operator==( const cow_wrapper_client2& rRHS ) const;
|
bool operator==( const cow_wrapper_client2& rRHS ) const;
|
||||||
@@ -110,7 +111,7 @@ public:
|
|||||||
|
|
||||||
void makeUnique();
|
void makeUnique();
|
||||||
bool is_unique() const;
|
bool is_unique() const;
|
||||||
oslInterlockedCount use_count() const;
|
int use_count() const;
|
||||||
void swap( cow_wrapper_client3& r );
|
void swap( cow_wrapper_client3& r );
|
||||||
|
|
||||||
bool operator==( const cow_wrapper_client3& rRHS ) const;
|
bool operator==( const cow_wrapper_client3& rRHS ) const;
|
||||||
@@ -172,6 +173,7 @@ struct BogusRefCountPolicy
|
|||||||
}
|
}
|
||||||
return rCount != 0;
|
return rCount != 0;
|
||||||
}
|
}
|
||||||
|
static std::size_t getCount( ref_count_t& rCount) { return rCount; }
|
||||||
};
|
};
|
||||||
|
|
||||||
class cow_wrapper_client5
|
class cow_wrapper_client5
|
||||||
|
Reference in New Issue
Block a user