# HG changeset patch # User Michael Goffioul # Date 1322925582 0 # Node ID 43cc49c7abd19d256c3baa06fa00e54a78157260 # Parent 1126c29078787c0b4842cd3a94e145fa4a5e7713 Use thread-safe atomic reference counting (GCC and MSVC). * configure.ac: New --enable-atomic-refcount argument. (octave_allocator): Fix USE_OCTAVE_ALLOCATOR variable assignment. (OCTAVE_CONFIG_INCLUDED): New macro in config.h. * oct-refcount.h (OCTREFCOUNT_ATOMIC_INCREMENT, OCTREFCOUNT_ATOMIC_INCREMENT_POST, OCTREFCOUNT_ATOMIC_DECREMENT, OCTREFCOUNT_ATOMIC_DECREMENT_POST): New macro, defined for MSVC and GCC when USE_ATOMIC_REFCOUNT is defined. (octave_refcount:operator++, octave_refcount::operator--): Use them. (octave_refcount::operator count_type): Cast returned value to volatile. (octave_refcount::direct): Remove unsafe member. * Array.h (Array::make_unique): Delete rep if refcount reaches 0. * Sparse.h (Sparse::make_unique): Delete rep if refcount reaches 0. * Array.h (Array:~Array, Array::operator=): Delete rep only when refcount is excatly 0. * Array.cc (Array::clear): Likewise. * Sparse.cc (Sparse::~Sparse, Sparse::operator=): Likewise. * SparseCmplxQR.h (SparseCmplxQR::~SparseCmplxQR, SparseCmplxQR::operator=): Likewise. * SparseQR.h (SparseQR::~SparseQR, SparseQR::operator=): Likewise. * sparse-base-chol.h (sparse_base_chol::~sparse_base_chol, sparse_base_chol::operator): Likewise. * dim-vector.h (oct-refcount.h): New included header. (dim_vector::make_unique, dim_vector::resize): Use OCTREFCOUNT_ATOMIC_DECREMENT macro and delete rep when refcount reaches 0. (dim_vector::dim_vector): Use OCTREFCOUNT_ATOMIC_INCREMENT. (dim_vector::operator=): Use OCTREFCOUNT_ATOMIC_INCREMENT and OCTREFCOUNT_ATOMIC_DECREMENT. (dim_vector::~dim_vector): Use OCTREFCOUNT_ATOMIC_DECREMENT. * oct-mutex.h (oct-refcount.h): New included header. (octave_base_mutex::count): Use octave_refcount class. * gl-render.cc (oct-refcount.h): New included header. * graphics.h.in (oct-refcount.h): Likewise. (base_property::count, base_graphics_toolkit::count, base_graphics_object::count, base_graphics_event::count): Use octave_refcount. (property::~property, property::operator=): Delete rep only when refcountn is excatly 0. * oct-map.h (octave_fields::make_unique): Delete rep when refcount reaches 0. * oct-stream.h (oct-refcount.h): New included header. (octave_base_stream::count): Use octave_refcount class. * ov.h (octave_value::make_unique): Delete rep when refcount reaches 0. * symtab.h (oct-refcount.h): New included header. (symbol_record_rep::count, fcn_info_rep::count): Use octave_refcount class. * DLD-FUNCTIONS/urlwrite.cc (oct-refcount.h): New included header. (curl_handle_rep::count): Use octave_refcount class. diff -r 1126c2907878 -r 43cc49c7abd1 configure.ac --- a/configure.ac Sat Dec 03 05:23:52 2011 -0500 +++ b/configure.ac Sat Dec 03 15:19:42 2011 +0000 @@ -171,11 +171,20 @@ AC_ARG_ENABLE(octave-allocator, [AS_HELP_STRING([--enable-octave-allocator], [use the obsolete octave_allocator class for many of Octave's objects (mostly octave_value types). You probably do NOT want to enable this feature. (default is no)])], - [if test "$enableval" = yes; then USE_ALLOCATOR=true; fi], []) + [if test "$enableval" = yes; then USE_OCTAVE_ALLOCATOR=true; fi], []) if $USE_OCTAVE_ALLOCATOR; then AC_DEFINE(USE_OCTAVE_ALLOCATOR, 1, [Define to use octave_allocator class.]) fi +USE_ATOMIC_REFCOUNT=false +AC_ARG_ENABLE(atomic-refcount, + [AS_HELP_STRING([--enable-atomic-refcount], + [use atomic operations for internal reference counting. This is required for thread-safe behavior. (default is no)])], + [if test "$enableval" = yes; then USE_ATOMIC_REFCOUNT=true; fi], []) +if $USE_ATOMIC_REFCOUNT; then + AC_DEFINE(USE_ATOMIC_REFCOUNT, 1, [Define to use atomic operations for reference counting.]) +fi + ### Make it possible to disable running Make in the doc directory. ### Useful for building on systems without TeX, for example. DOCDIR=doc @@ -2089,6 +2098,9 @@ typedef OCTAVE_IDX_TYPE octave_idx_type; #include + +/* Tag indicating octave config.h has been included */ +#define OCTAVE_CONFIG_INCLUDED 1 ]) ### Do the substitutions in all the Makefiles. @@ -2465,6 +2477,22 @@ warn_msg_printed=true fi +if $USE_ATOMIC_REFCOUNT; then + AC_MSG_WARN([]) + AC_MSG_WARN([Using atomic reference counting.]) + AC_MSG_WARN([This feature allows to access octave data safely from]) + AC_MSG_WARN([another thread, for instance from a GUI. However this]) + AC_MSG_WARN([results in a small performance penalty in the octave]) + AC_MSG_WARN([interpreter.]) + AC_MSG_WARN([]) + if $USE_OCTAVE_ALLOCATOR; then + AC_MSG_WARN([Thread-safe behavior is not guaranteed unless you also]) + AC_MSG_WARN([disable the use of the octave_allocator class.]) + AC_MSG_WARN([]) + fi + warn_msg_printed=true +fi + if $warn_msg_printed; then AC_MSG_NOTICE([]) AC_MSG_NOTICE([NOTE: libraries may be skipped if a library is not found OR]) diff -r 1126c2907878 -r 43cc49c7abd1 liboctave/Array.cc --- a/liboctave/Array.cc Sat Dec 03 05:23:52 2011 -0500 +++ b/liboctave/Array.cc Sat Dec 03 15:19:42 2011 +0000 @@ -84,7 +84,7 @@ void Array::clear (void) { - if (--rep->count <= 0) + if (--rep->count == 0) delete rep; rep = nil_rep (); @@ -99,7 +99,7 @@ void Array::clear (const dim_vector& dv) { - if (--rep->count <= 0) + if (--rep->count == 0) delete rep; rep = new ArrayRep (dv.safe_numel ()); diff -r 1126c2907878 -r 43cc49c7abd1 liboctave/Array.h --- a/liboctave/Array.h Sat Dec 03 05:23:52 2011 -0500 +++ b/liboctave/Array.h Sat Dec 03 15:19:42 2011 +0000 @@ -110,8 +110,12 @@ { if (rep->count > 1) { - --rep->count; - rep = new ArrayRep (slice_data, slice_len); + ArrayRep *r = new ArrayRep (slice_data, slice_len); + + if (--rep->count == 0) + delete rep; + + rep = r; slice_data = rep->data; } } @@ -225,7 +229,7 @@ ~Array (void) { - if (--rep->count <= 0) + if (--rep->count == 0) delete rep; } @@ -233,7 +237,7 @@ { if (this != &a) { - if (--rep->count <= 0) + if (--rep->count == 0) delete rep; rep = a.rep; diff -r 1126c2907878 -r 43cc49c7abd1 liboctave/Sparse.cc --- a/liboctave/Sparse.cc Sat Dec 03 05:23:52 2011 -0500 +++ b/liboctave/Sparse.cc Sat Dec 03 15:19:42 2011 +0000 @@ -667,7 +667,7 @@ template Sparse::~Sparse (void) { - if (--rep->count <= 0) + if (--rep->count == 0) delete rep; } @@ -677,7 +677,7 @@ { if (this != &a) { - if (--rep->count <= 0) + if (--rep->count == 0) delete rep; rep = a.rep; diff -r 1126c2907878 -r 43cc49c7abd1 liboctave/Sparse.h --- a/liboctave/Sparse.h Sat Dec 03 05:23:52 2011 -0500 +++ b/liboctave/Sparse.h Sat Dec 03 15:19:42 2011 +0000 @@ -147,8 +147,12 @@ { if (rep->count > 1) { - --rep->count; - rep = new SparseRep (*rep); + SparseRep *r = new SparseRep (*rep); + + if (--rep->count == 0) + delete rep; + + rep = r; } } diff -r 1126c2907878 -r 43cc49c7abd1 liboctave/SparseCmplxQR.h --- a/liboctave/SparseCmplxQR.h Sat Dec 03 05:23:52 2011 -0500 +++ b/liboctave/SparseCmplxQR.h Sat Dec 03 15:19:42 2011 +0000 @@ -96,7 +96,7 @@ ~SparseComplexQR (void) { - if (--rep->count <= 0) + if (--rep->count == 0) delete rep; } @@ -104,7 +104,7 @@ { if (this != &a) { - if (--rep->count <= 0) + if (--rep->count == 0) delete rep; rep = a.rep; diff -r 1126c2907878 -r 43cc49c7abd1 liboctave/SparseQR.h --- a/liboctave/SparseQR.h Sat Dec 03 05:23:52 2011 -0500 +++ b/liboctave/SparseQR.h Sat Dec 03 15:19:42 2011 +0000 @@ -98,7 +98,7 @@ ~SparseQR (void) { - if (--rep->count <= 0) + if (--rep->count == 0) delete rep; } @@ -106,7 +106,7 @@ { if (this != &a) { - if (--rep->count <= 0) + if (--rep->count == 0) delete rep; rep = a.rep; diff -r 1126c2907878 -r 43cc49c7abd1 liboctave/dim-vector.h --- a/liboctave/dim-vector.h Sat Dec 03 05:23:52 2011 -0500 +++ b/liboctave/dim-vector.h Sat Dec 03 15:19:42 2011 +0000 @@ -32,6 +32,7 @@ #include "lo-error.h" #include "lo-macros.h" +#include "oct-refcount.h" // Rationale: This implementation is more tricky than Array, but the // big plus is that dim_vector requires only one allocation instead of @@ -128,8 +129,12 @@ { if (count () > 1) { - --count(); - rep = clonerep (); + octave_idx_type *new_rep = clonerep (); + + if (OCTREFCOUNT_ATOMIC_DECREMENT(&(count())) == 0) + freerep (); + + rep = new_rep; } } @@ -222,9 +227,11 @@ static octave_idx_type dim_max (void); - explicit dim_vector (void) : rep (nil_rep ()) { count()++; } + explicit dim_vector (void) : rep (nil_rep ()) + { OCTREFCOUNT_ATOMIC_INCREMENT (&(count())); } - dim_vector (const dim_vector& dv) : rep (dv.rep) { count()++; } + dim_vector (const dim_vector& dv) : rep (dv.rep) + { OCTREFCOUNT_ATOMIC_INCREMENT (&(count())); } static dim_vector alloc (int n) { @@ -235,11 +242,11 @@ { if (&dv != this) { - if (--count() <= 0) + if (OCTREFCOUNT_ATOMIC_DECREMENT (&(count())) == 0) freerep (); rep = dv.rep; - count()++; + OCTREFCOUNT_ATOMIC_INCREMENT (&(count())); } return *this; @@ -247,7 +254,7 @@ ~dim_vector (void) { - if (--count() <= 0) + if (OCTREFCOUNT_ATOMIC_DECREMENT (&(count())) == 0) freerep (); } @@ -265,7 +272,7 @@ { octave_idx_type *r = resizerep (n, fill_value); - if (--count() <= 0) + if (OCTREFCOUNT_ATOMIC_DECREMENT (&(count())) == 0) freerep (); rep = r; diff -r 1126c2907878 -r 43cc49c7abd1 liboctave/oct-mutex.h --- a/liboctave/oct-mutex.h Sat Dec 03 05:23:52 2011 -0500 +++ b/liboctave/oct-mutex.h Sat Dec 03 15:19:42 2011 +0000 @@ -23,6 +23,8 @@ #if !defined (octave_octave_mutex_h) #define octave_octave_mutex_h 1 +#include "oct-refcount.h" + class octave_mutex; class @@ -42,7 +44,7 @@ virtual bool try_lock (void); private: - int count; + octave_refcount count; }; class diff -r 1126c2907878 -r 43cc49c7abd1 liboctave/oct-refcount.h --- a/liboctave/oct-refcount.h Sat Dec 03 05:23:52 2011 -0500 +++ b/liboctave/oct-refcount.h Sat Dec 03 15:19:42 2011 +0000 @@ -23,6 +23,30 @@ #if !defined (octave_refcount_h) #define octave_refcount_h 1 +#ifndef OCTAVE_CONFIG_INCLUDED +# error "The file must be included before oct-refcount.h." +#endif + +#if defined (USE_ATOMIC_REFCOUNT) && (defined (_MSC_VER) || defined (__GNUC__)) +# if defined (_MSC_VER) +# include +# define OCTREFCOUNT_ATOMIC_INCREMENT(x) _InterlockedIncrement((long*)x) +# define OCTREFCOUNT_ATOMIC_DECREMENT(x) _InterlockedDecrement((long*)x) +# define OCTREFCOUNT_ATOMIC_INCREMENT_POST(x) _InterlockedExchangeAdd((long*)x, 1) +# define OCTREFCOUNT_ATOMIC_DECREMENT_POST(x) _InterlockedExchangeAdd((long*)x, -1) +# elif defined (__GNUC__) +# define OCTREFCOUNT_ATOMIC_INCREMENT(x) __sync_add_and_fetch(x, 1) +# define OCTREFCOUNT_ATOMIC_DECREMENT(x) __sync_add_and_fetch(x, -1) +# define OCTREFCOUNT_ATOMIC_INCREMENT_POST(x) __sync_fetch_and_add(x, 1) +# define OCTREFCOUNT_ATOMIC_DECREMENT_POST(x) __sync_fetch_and_add(x, -1) +# endif +#else // Generic non-locking versions +# define OCTREFCOUNT_ATOMIC_INCREMENT(x) ++(*(x)) +# define OCTREFCOUNT_ATOMIC_DECREMENT(x) --(*(x)) +# define OCTREFCOUNT_ATOMIC_INCREMENT_POST(x) (*(x))++ +# define OCTREFCOUNT_ATOMIC_DECREMENT_POST(x) (*(x))-- +#endif + // Encapsulates a reference counter. template class octave_refcount @@ -35,28 +59,28 @@ // Increment/Decrement. int is postfix. count_type operator++(void) { - return ++count; + return OCTREFCOUNT_ATOMIC_INCREMENT (&count); } count_type operator++(int) { - return count++; + return OCTREFCOUNT_ATOMIC_INCREMENT_POST (&count); } count_type operator--(void) { - return --count; + return OCTREFCOUNT_ATOMIC_DECREMENT (&count); } count_type operator--(int) { - return count--; + return OCTREFCOUNT_ATOMIC_DECREMENT_POST (&count); } - operator count_type (void) const { return count; } - - // For low-level optimizations only. - count_type& direct (void) const { return count; } + operator count_type (void) const + { + return static_cast (count); + } private: count_type count; diff -r 1126c2907878 -r 43cc49c7abd1 liboctave/sparse-base-chol.h --- a/liboctave/sparse-base-chol.h Sat Dec 03 05:23:52 2011 -0500 +++ b/liboctave/sparse-base-chol.h Sat Dec 03 15:19:42 2011 +0000 @@ -178,7 +178,7 @@ virtual ~sparse_base_chol (void) { - if (--rep->count <= 0) + if (--rep->count == 0) delete rep; } @@ -186,7 +186,7 @@ { if (this != &a) { - if (--rep->count <= 0) + if (--rep->count == 0) delete rep; rep = a.rep; diff -r 1126c2907878 -r 43cc49c7abd1 src/DLD-FUNCTIONS/urlwrite.cc --- a/src/DLD-FUNCTIONS/urlwrite.cc Sat Dec 03 05:23:52 2011 -0500 +++ b/src/DLD-FUNCTIONS/urlwrite.cc Sat Dec 03 15:19:42 2011 +0000 @@ -46,6 +46,7 @@ #include "ov-cell.h" #include "pager.h" #include "oct-map.h" +#include "oct-refcount.h" #include "unwind-prot.h" #ifdef HAVE_CURL @@ -141,7 +142,7 @@ return !ascii; } - size_t count; + octave_refcount count; std::string host; bool valid; bool ascii; diff -r 1126c2907878 -r 43cc49c7abd1 src/gl-render.cc --- a/src/gl-render.cc Sat Dec 03 05:23:52 2011 -0500 +++ b/src/gl-render.cc Sat Dec 03 15:19:42 2011 +0000 @@ -30,6 +30,7 @@ #include #include "oct-locbuf.h" +#include "oct-refcount.h" #include "gl-render.h" #include "txt-eng.h" #include "txt-eng-ft.h" diff -r 1126c2907878 -r 43cc49c7abd1 src/graphics.h.in --- a/src/graphics.h.in Sat Dec 03 05:23:52 2011 -0500 +++ b/src/graphics.h.in Sat Dec 03 15:19:42 2011 +0000 @@ -42,6 +42,7 @@ #include "gripes.h" #include "oct-map.h" #include "oct-mutex.h" +#include "oct-refcount.h" #include "ov.h" #include "txt-eng-ft.h" @@ -482,7 +483,7 @@ private: int id; - int count; + octave_refcount count; std::string name; graphics_handle parent; bool hidden; @@ -1910,7 +1911,7 @@ ~property (void) { - if (--rep->count <= 0) + if (--rep->count == 0) delete rep; } @@ -1965,7 +1966,7 @@ property& operator = (const property& p) { - if (rep && --rep->count <= 0) + if (rep && --rep->count == 0) delete rep; rep = p.rep; @@ -2133,7 +2134,7 @@ private: std::string name; - int count; + octave_refcount count; private: void gripe_invalid (const std::string& fname) const @@ -2739,7 +2740,7 @@ protected: // A reference count. - int count; + octave_refcount count; // A flag telling whether this object is a valid object // in the backend context. @@ -5097,7 +5098,7 @@ virtual void execute (void) = 0; private: - int count; + octave_refcount count; }; class diff -r 1126c2907878 -r 43cc49c7abd1 src/oct-map.h --- a/src/oct-map.h Sat Dec 03 05:23:52 2011 -0500 +++ b/src/oct-map.h Sat Dec 03 15:19:42 2011 +0000 @@ -73,8 +73,12 @@ { if (rep->count > 1) { - --rep->count; - rep = new fields_rep (*rep); + fields_rep *r = new fields_rep (*rep); + + if (--rep->count == 0) + delete rep; + + rep = r; } } diff -r 1126c2907878 -r 43cc49c7abd1 src/oct-stream.h --- a/src/oct-stream.h Sat Dec 03 05:23:52 2011 -0500 +++ b/src/oct-stream.h Sat Dec 03 15:19:42 2011 +0000 @@ -37,6 +37,7 @@ #include "data-conv.h" #include "lo-utils.h" #include "mach-info.h" +#include "oct-refcount.h" class OCTINTERP_API @@ -427,7 +428,7 @@ private: // A reference count. - octave_idx_type count; + octave_refcount count; // The permission bits for the file. Should be some combination of // std::ios::open_mode bits. diff -r 1126c2907878 -r 43cc49c7abd1 src/ov.h --- a/src/ov.h Sat Dec 03 05:23:52 2011 -0500 +++ b/src/ov.h Sat Dec 03 15:19:42 2011 +0000 @@ -315,8 +315,12 @@ { if (rep->count > 1) { - --rep->count; - rep = rep->unique_clone (); + octave_base_value *r = rep->unique_clone (); + + if (--rep->count == 0) + delete rep; + + rep = r; } } @@ -327,8 +331,12 @@ { if (rep->count > obsolete_copies + 1) { - --rep->count; - rep = rep->unique_clone (); + octave_base_value *r = rep->unique_clone (); + + if (--rep->count == 0) + delete rep; + + rep = r; } } diff -r 1126c2907878 -r 43cc49c7abd1 src/symtab.h --- a/src/symtab.h Sat Dec 03 05:23:52 2011 -0500 +++ b/src/symtab.h Sat Dec 03 15:19:42 2011 +0000 @@ -37,6 +37,7 @@ class octave_user_function; #include "oct-obj.h" +#include "oct-refcount.h" #include "ov.h" class @@ -387,7 +388,7 @@ fcn_info *finfo; - size_t count; + octave_refcount count; private: @@ -728,7 +729,7 @@ octave_value built_in_function; - size_t count; + octave_refcount count; private: