#ifndef AC_I686_LFGC_REFCOUNT_H
#define AC_I686_LFGC_REFCOUNT_H
#ifdef __cplusplus
extern "C"
{
#endif
#ifdef _MSC_VER
#pragma warning ( disable : 4324 )
#endif
typedef struct
AC_DECLSPEC_PACKED
ac_i686_lfgc_refcount_
{
ac_intword_t refs;
ac_i686_node_t *lfgc_next;
ac_fp_dtor_t fp_dtor;
const void *state;
} ac_i686_lfgc_refcount_t;
#ifdef _MSC_VER
#pragma warning ( default : 4324 )
#endif
AC_BUILD_DBG_ASSERT
( lfgc_refcount,
sizeof( ac_i686_lfgc_refcount_t ) == sizeof( ac_i686_node_t ) );
#define ac_i686_lfgc_refcount_get( ac_macro_this ) \
( (void*)(ac_macro_this)->state )
#define ac_i686_mb_lfgc_refcount_get( ac_macro_this ) \
( ac_mb_loadptr_depends( &(ac_macro_this)->state ) )
AC_DECLSPEC_INLINE int AC_APIDECL
ac_i686_lfgc_refcount_alloc
( ac_thread_t *_tls,
ac_i686_lfgc_refcount_t **_pthis,
ac_fp_dtor_t fp_dtor,
const void *state )
{
ac_i686_lfgc_refcount_t *_this;
if ( ! _tls ) { _tls = ac_thread_self(); }
_this = (ac_i686_lfgc_refcount_t*)
ac_thread_cpu_node_cache_pop( _tls, state );
if ( ! _this ) { return ac_sys_error( ENOMEM ); }
_this->refs = 1;
if ( _this->fp_dtor == (ac_fp_dtor_t)0x00000001 )
{ _this->refs |= 0x80000000;
}
_this->fp_dtor = fp_dtor;
*_pthis = _this;
return 0;
}
AC_DECLSPEC_INLINE void AC_APIDECL
ac_i686_lfgc_refcount_release
( ac_i686_lfgc_refcount_t *_this )
{
if ( _this &&
! ( ac_atomic_dec_release
( &_this->refs ) & 0x7FFFFFFF ) )
{ ac_thread_t *_tls = ac_thread_self();
_this->fp_dtor( (void*)_this->state );
_this->fp_dtor =
( _this->refs & 0x80000000 ) ? (ac_fp_dtor_t)0x00000001 : 0;
ac_lfgc_smr_collect( _tls, 0, (ac_i686_node_t*)_this );
}
}
AC_DECLSPEC_INLINE ac_i686_lfgc_refcount_t* AC_APIDECL
ac_i686_lfgc_refcount_addref
( ac_thread_t *_tls,
ac_i686_lfgc_refcount_t **pdest )
{
ac_intword_t refs, refs_cmp;
ac_lfgc_smr_hazard_t hazard;
ac_i686_lfgc_refcount_t *dest;
if ( ! _tls ) { _tls = ac_thread_self(); };
hazard = ac_lfgc_smr_get( _tls, 0 );
for( ;; )
{ dest = (ac_i686_lfgc_refcount_t*)
ac_i686_lfgc_smr_activate
( hazard,
(ac_i686_node_t**)pdest );
if ( ! dest ) { break; }
refs = dest->refs;
while( ( refs & 0x7FFFFFFF ) > 0 )
{ refs_cmp = refs;
refs = ac_atomic_cas_acquire
( &dest->refs,
refs_cmp,
refs_cmp + 1 );
if ( refs == refs_cmp )
{ ac_i686_lfgc_smr_deactivate( hazard );
return dest;
}
}
}
return 0;
}
AC_DECLSPEC_INLINE void AC_APIDECL
ac_i686_lfgc_refcount_null
( ac_i686_lfgc_refcount_t **pdest )
{
ac_i686_lfgc_refcount_release
( (ac_i686_lfgc_refcount_t*)
ac_atomic_xchgptr_release
( pdest,
0 ) );
}
AC_DECLSPEC_INLINE void AC_APIDECL
ac_i686_lfgc_refcount_copy_local
( ac_i686_lfgc_refcount_t **pdest,
ac_i686_lfgc_refcount_t *src )
{
ac_i686_lfgc_refcount_t *old =
(ac_i686_lfgc_refcount_t*)ac_mb_loadptr_depends( pdest );
if ( src ) { ac_atomic_inc_acquire( &src->refs ); }
ac_mb_storeptr_release( pdest, src );
ac_i686_lfgc_refcount_release( old );
}
AC_DECLSPEC_INLINE void AC_APIDECL
ac_i686_lfgc_refcount_copy_shared
( ac_thread_t *_tls,
ac_i686_lfgc_refcount_t **pdest,
ac_i686_lfgc_refcount_t **psrc )
{
ac_i686_lfgc_refcount_release
( (ac_i686_lfgc_refcount_t*)
ac_atomic_xchgptr_release
( pdest,
ac_i686_lfgc_refcount_addref
( _tls,
psrc ) ) );
}
AC_DECLSPEC_INLINE ac_i686_lfgc_refcount_t* AC_APIDECL
ac_i686_lfgc_refcount_xchg
( ac_i686_lfgc_refcount_t **pdest,
ac_i686_lfgc_refcount_t *src )
{
if ( src ) { ac_atomic_inc_acquire( &src->refs ); }
return (ac_i686_lfgc_refcount_t*)
ac_atomic_xchgptr_release
( pdest,
src );
}
AC_DECLSPEC_INLINE int AC_APIDECL
ac_i686_lfgc_refcount_cas
( ac_i686_lfgc_refcount_t **pdest,
ac_i686_lfgc_refcount_t *cmp,
ac_i686_lfgc_refcount_t *xchg )
{
if ( xchg ) { ac_atomic_inc_acquire( &xchg->refs ); }
if ( ac_atomic_casptr_release
( pdest,
cmp,
xchg ) != cmp )
{ ac_i686_lfgc_refcount_release( xchg );
return 1;
}
ac_i686_lfgc_refcount_release( cmp );
return 0;
}
typedef ac_i686_lfgc_refcount_t ac_lfgc_refcount_t;
#define ac_lfgc_refcount_alloc ac_i686_lfgc_refcount_alloc
#define ac_lfgc_refcount_get ac_i686_lfgc_refcount_get
#define ac_mb_lfgc_refcount_get ac_i686_mb_lfgc_refcount_get
#define ac_lfgc_refcount_null ac_i686_lfgc_refcount_null
#define ac_lfgc_refcount_cas ac_i686_lfgc_refcount_cas
#define ac_lfgc_refcount_xchg ac_i686_lfgc_refcount_xchg
#define ac_lfgc_refcount_release ac_i686_lfgc_refcount_release
#define ac_lfgc_refcount_copy_shared ac_i686_lfgc_refcount_copy_shared
#define ac_lfgc_refcount_copy_local ac_i686_lfgc_refcount_copy_local
#ifdef __cplusplus
}
#endif
#endif