Mercurial > hg > octave-lojdl
changeset 13985:43cc49c7abd1
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.
author | Michael Goffioul <michael.goffioul@gmail.com> |
---|---|
date | Sat, 03 Dec 2011 15:19:42 +0000 |
parents | 1126c2907878 |
children | 6be49527e4cf |
files | configure.ac liboctave/Array.cc liboctave/Array.h liboctave/Sparse.cc liboctave/Sparse.h liboctave/SparseCmplxQR.h liboctave/SparseQR.h liboctave/dim-vector.h liboctave/oct-mutex.h liboctave/oct-refcount.h liboctave/sparse-base-chol.h src/DLD-FUNCTIONS/urlwrite.cc src/gl-render.cc src/graphics.h.in src/oct-map.h src/oct-stream.h src/ov.h src/symtab.h |
diffstat | 18 files changed, 136 insertions(+), 50 deletions(-) [+] |
line wrap: on
line diff
--- a/configure.ac +++ b/configure.ac @@ -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 <stdint.h> + +/* 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])
--- a/liboctave/Array.cc +++ b/liboctave/Array.cc @@ -84,7 +84,7 @@ void Array<T>::clear (void) { - if (--rep->count <= 0) + if (--rep->count == 0) delete rep; rep = nil_rep (); @@ -99,7 +99,7 @@ void Array<T>::clear (const dim_vector& dv) { - if (--rep->count <= 0) + if (--rep->count == 0) delete rep; rep = new ArrayRep (dv.safe_numel ());
--- a/liboctave/Array.h +++ b/liboctave/Array.h @@ -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;
--- a/liboctave/Sparse.cc +++ b/liboctave/Sparse.cc @@ -667,7 +667,7 @@ template <class T> Sparse<T>::~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;
--- a/liboctave/Sparse.h +++ b/liboctave/Sparse.h @@ -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; } }
--- a/liboctave/SparseCmplxQR.h +++ b/liboctave/SparseCmplxQR.h @@ -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;
--- a/liboctave/SparseQR.h +++ b/liboctave/SparseQR.h @@ -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;
--- a/liboctave/dim-vector.h +++ b/liboctave/dim-vector.h @@ -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;
--- a/liboctave/oct-mutex.h +++ b/liboctave/oct-mutex.h @@ -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<int> count; }; class
--- a/liboctave/oct-refcount.h +++ b/liboctave/oct-refcount.h @@ -23,6 +23,30 @@ #if !defined (octave_refcount_h) #define octave_refcount_h 1 +#ifndef OCTAVE_CONFIG_INCLUDED +# error "The file <octave/config.h> must be included before oct-refcount.h." +#endif + +#if defined (USE_ATOMIC_REFCOUNT) && (defined (_MSC_VER) || defined (__GNUC__)) +# if defined (_MSC_VER) +# include <intrin.h> +# 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 T> 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_type const volatile&> (count); + } private: count_type count;
--- a/liboctave/sparse-base-chol.h +++ b/liboctave/sparse-base-chol.h @@ -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;
--- a/src/DLD-FUNCTIONS/urlwrite.cc +++ b/src/DLD-FUNCTIONS/urlwrite.cc @@ -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<size_t> count; std::string host; bool valid; bool ascii;
--- a/src/gl-render.cc +++ b/src/gl-render.cc @@ -30,6 +30,7 @@ #include <lo-mappers.h> #include "oct-locbuf.h" +#include "oct-refcount.h" #include "gl-render.h" #include "txt-eng.h" #include "txt-eng-ft.h"
--- a/src/graphics.h.in +++ b/src/graphics.h.in @@ -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<int> 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<int> count; private: void gripe_invalid (const std::string& fname) const @@ -2739,7 +2740,7 @@ protected: // A reference count. - int count; + octave_refcount<int> 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<int> count; }; class
--- a/src/oct-map.h +++ b/src/oct-map.h @@ -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; } }
--- a/src/oct-stream.h +++ b/src/oct-stream.h @@ -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<octave_idx_type> count; // The permission bits for the file. Should be some combination of // std::ios::open_mode bits.
--- a/src/ov.h +++ b/src/ov.h @@ -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; } }
--- a/src/symtab.h +++ b/src/symtab.h @@ -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<size_t> count; private: @@ -728,7 +729,7 @@ octave_value built_in_function; - size_t count; + octave_refcount<size_t> count; private: