# HG changeset patch # User John W. Eaton # Date 1569448628 14400 # Wed Sep 25 17:57:08 2019 -0400 # Node ID 5785028d203288d27c4d8f31408fb11e3ee1f44f # Parent 160930a3e5eed20b6daee5d82403b1dbcb388451 use std::atomic to implement refcount class * oct-atomic.h, oct-atomic.c: New files. * liboctave/util/module.mk: Update. * dim-vector.h (dim_vector::increment_count, dim_vector::decrement_count): New functions. Use them instead of OCTAVE_ATOMIC_INCREMENT and OCTAVE_ATOMIC_DECREMENT macros. * Array.h (Array::jit_ref_count): Return int, not pointer. Change all uses. * jit-typeinfo.h, jit-typeinfo.cc (jit_array::m_ref_count): Store integer, not pointer. Change all uses. * oct-refcount.h (OCTAVE_ATOMIC_INCREMENT, OCTAVE_ATOMIC_DECREMENT, OCTAVE_ATOMIC_POST_INCREMENT, OCTAVE_ATOMIC_POST_DECREMENT): Delete macros. (refcount::m_count): Now std::atomic instead of T. (class refcount): Provide assignment operator and copy constructor. (refcount::operator++, refcount::operator--): Define using std::atomic operators instead of increment macros. (refcound::get): Delete. diff --git a/libinterp/parse-tree/jit-typeinfo.cc b/libinterp/parse-tree/jit-typeinfo.cc --- a/libinterp/parse-tree/jit-typeinfo.cc +++ b/libinterp/parse-tree/jit-typeinfo.cc @@ -298,7 +298,7 @@ namespace octave bool done = false; // optimize for the simple case (no resizing and no errors) - if (*array->jit_ref_count () == 1 + if (array->jit_ref_count () == 1 && index->all_elements_are_ints ()) { // this code is similar to idx_vector::fill, but we avoid allocating an diff --git a/libinterp/parse-tree/jit-typeinfo.h b/libinterp/parse-tree/jit-typeinfo.h --- a/libinterp/parse-tree/jit-typeinfo.h +++ b/libinterp/parse-tree/jit-typeinfo.h @@ -102,7 +102,7 @@ namespace octave return *m_array; } - int *m_ref_count; + int m_ref_count; U *m_slice_data; octave_idx_type m_slice_len; diff --git a/liboctave/array/Array.h b/liboctave/array/Array.h --- a/liboctave/array/Array.h +++ b/liboctave/array/Array.h @@ -839,7 +839,7 @@ public: //@{ //! WARNING: Only call these functions from jit - int * jit_ref_count (void) { return rep->count.get (); } + int jit_ref_count (void) { return rep->count.value (); } T * jit_slice_data (void) const { return slice_data; } diff --git a/liboctave/array/dim-vector.h b/liboctave/array/dim-vector.h --- a/liboctave/array/dim-vector.h +++ b/liboctave/array/dim-vector.h @@ -32,6 +32,7 @@ along with Octave; see the file COPYING. #include #include +#include "oct-atomic.h" #include "oct-refcount.h" template class Array; @@ -94,6 +95,16 @@ private: octave_idx_type& count (void) const { return rep[-2]; } + octave_idx_type increment_count (void) + { + return octave_atomic_increment (&(count ())); + } + + octave_idx_type decrement_count (void) + { + return octave_atomic_decrement (&(count ())); + } + //! Construct a new rep with count = 1 and ndims given. static octave_idx_type * newrep (int ndims) @@ -153,7 +164,7 @@ private: { octave_idx_type *new_rep = clonerep (); - if (OCTAVE_ATOMIC_DECREMENT (&(count ())) == 0) + if (decrement_count () == 0) freerep (); rep = new_rep; @@ -253,10 +264,10 @@ public: static octave_idx_type dim_max (void); explicit dim_vector (void) : rep (nil_rep ()) - { OCTAVE_ATOMIC_INCREMENT (&(count ())); } + { increment_count (); } dim_vector (const dim_vector& dv) : rep (dv.rep) - { OCTAVE_ATOMIC_INCREMENT (&(count ())); } + { increment_count (); } dim_vector (dim_vector&& dv) : rep (dv.rep) { dv.rep = nullptr; } @@ -272,11 +283,11 @@ public: { if (&dv != this) { - if (OCTAVE_ATOMIC_DECREMENT (&(count ())) == 0) + if (decrement_count () == 0) freerep (); rep = dv.rep; - OCTAVE_ATOMIC_INCREMENT (&(count ())); + increment_count (); } return *this; @@ -290,7 +301,7 @@ public: // operator, rep may be a nullptr here. We should only need to // protect the destructor in a similar way. - if (rep && OCTAVE_ATOMIC_DECREMENT (&(count ())) == 0) + if (rep && decrement_count () == 0) freerep (); rep = dv.rep; @@ -306,7 +317,7 @@ public: // operator, rep may be a nullptr here. We should only need to // protect the move assignment operator in a similar way. - if (rep && OCTAVE_ATOMIC_DECREMENT (&(count ())) == 0) + if (rep && decrement_count () == 0) freerep (); } @@ -339,7 +350,7 @@ public: { octave_idx_type *r = resizerep (n, fill_value); - if (OCTAVE_ATOMIC_DECREMENT (&(count ())) == 0) + if (decrement_count () == 0) freerep (); rep = r; diff --git a/liboctave/util/module.mk b/liboctave/util/module.mk --- a/liboctave/util/module.mk +++ b/liboctave/util/module.mk @@ -19,6 +19,7 @@ UTIL_INC = \ %reldir%/lo-error.h \ %reldir%/octave-preserve-stream-state.h \ %reldir%/quit.h \ + %reldir%/oct-atomic.h \ %reldir%/oct-base64.h \ %reldir%/oct-binmap.h \ %reldir%/oct-cmplx.h \ @@ -74,6 +75,7 @@ UTIL_SRC = \ %reldir%/lo-regexp.cc \ %reldir%/lo-utils.cc \ %reldir%/quit.cc \ + %reldir%/oct-atomic.c \ %reldir%/oct-base64.cc \ %reldir%/oct-glob.cc \ %reldir%/oct-inttypes.cc \ diff --git a/liboctave/util/oct-atomic.c b/liboctave/util/oct-atomic.c new file mode 100644 --- /dev/null +++ b/liboctave/util/oct-atomic.c @@ -0,0 +1,45 @@ +/* + +Copyright (C) 2019 John W. Eaton + +This file is part of Octave. + +Octave is free software: you can redistribute it and/or modify it +under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +Octave 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 General Public License for more details. + +You should have received a copy of the GNU General Public License +along with Octave; see the file COPYING. If not, see +. + +*/ + +#if defined (HAVE_CONFIG_H) +# include "config.h" +#endif + +#include "oct-atomic.h" + +#include + +octave_idx_type +octave_atomic_increment (octave_idx_type *x) +{ + atomic_fetch_add (x, 1); + + return *x; +} + +octave_idx_type +octave_atomic_decrement (octave_idx_type *x) +{ + atomic_fetch_sub (x, 1); + + return *x; +} diff --git a/liboctave/util/oct-atomic.h b/liboctave/util/oct-atomic.h new file mode 100644 --- /dev/null +++ b/liboctave/util/oct-atomic.h @@ -0,0 +1,40 @@ +/* + +Copyright (C) 2019 John W. Eaton + +This file is part of Octave. + +Octave is free software: you can redistribute it and/or modify it +under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +Octave 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 General Public License for more details. + +You should have received a copy of the GNU General Public License +along with Octave; see the file COPYING. If not, see +. + +*/ + +#if ! defined (octave_oct_atomic_h) +#define octave_oct_atomic_h 1 + +#include "octave-config.h" + +#if defined __cplusplus +extern "C" { +#endif + +extern octave_idx_type octave_atomic_increment (octave_idx_type *x); + + extern octave_idx_type octave_atomic_decrement (octave_idx_type *x); + +#if defined __cplusplus +} +#endif + +#endif diff --git a/liboctave/util/oct-refcount.h b/liboctave/util/oct-refcount.h --- a/liboctave/util/oct-refcount.h +++ b/liboctave/util/oct-refcount.h @@ -25,48 +25,10 @@ along with Octave; see the file COPYING. #include "octave-config.h" -#if (defined (OCTAVE_ENABLE_ATOMIC_REFCOUNT) \ - && (defined (__GNUC__) || defined (_MSC_VER))) - -# if defined (__GNUC__) - -# define OCTAVE_ATOMIC_INCREMENT(x) __sync_add_and_fetch (x, 1) -# define OCTAVE_ATOMIC_DECREMENT(x) __sync_add_and_fetch (x, -1) -# define OCTAVE_ATOMIC_POST_INCREMENT(x) __sync_fetch_and_add (x, 1) -# define OCTAVE_ATOMIC_POST_DECREMENT(x) __sync_fetch_and_add (x, -1) - -# elif defined (_MSC_VER) - -# include - -# define OCTAVE_ATOMIC_INCREMENT(x) \ - _InterlockedIncrement (static_cast (x)) - -# define OCTAVE_ATOMIC_DECREMENT(x) \ - _InterlockedDecrement (static_cast (x)) - -# define OCTAVE_ATOMIC_POST_INCREMENT(x) \ - _InterlockedExchangeAdd (static_cast (x)) - -# define OCTAVE_ATOMIC_POST_DECREMENT(x) \ - _InterlockedExchangeAdd (static_cast (x)) - -# endif - -#else - -// Generic non-locking versions - -# define OCTAVE_ATOMIC_INCREMENT(x) ++(*(x)) -# define OCTAVE_ATOMIC_DECREMENT(x) --(*(x)) -# define OCTAVE_ATOMIC_POST_INCREMENT(x) (*(x))++ -# define OCTAVE_ATOMIC_POST_DECREMENT(x) (*(x))-- - -#endif +#include namespace octave { - // Encapsulates a reference counter. template @@ -80,30 +42,41 @@ namespace octave : m_count (initial_count) { } + refcount (const refcount& count) + : m_count (count.value ()) + { } + + refcount& operator = (count_type value) + { + m_count.store (value); + + return *this; + } + // Increment/Decrement. int is postfix. count_type operator++ (void) { - return OCTAVE_ATOMIC_INCREMENT (&m_count); + return ++m_count; } count_type operator++ (int) { - return OCTAVE_ATOMIC_POST_INCREMENT (&m_count); + return m_count++; } count_type operator-- (void) { - return OCTAVE_ATOMIC_DECREMENT (&m_count); + return --m_count; } count_type operator-- (int) { - return OCTAVE_ATOMIC_POST_DECREMENT (&m_count); + return m_count--; } count_type value (void) const { - return static_cast (m_count); + return m_count.load (); } operator count_type (void) const @@ -111,14 +84,9 @@ namespace octave return value (); } - count_type * get (void) - { - return &m_count; - } - private: - count_type m_count; + std::atomic m_count; }; }