/* Copyright 2005 Chris Thomasson */


#ifndef AC_EVENTCOUNT_ALGO1_H
#define AC_EVENTCOUNT_ALGO1_H


#ifdef __cplusplus
extern "C"
{
#endif


typedef ac_intword_t ac_eventcount_cmp_t;


#ifdef _MSC_VER 
/* 4324: structure was padded due to _declspec(align()) */
#pragma warning ( disable : 4324 )
#pragma pack(1) 
#endif


typedef struct
AC_DECLSPEC_PACKED
ac_eventcount_algo1_shared_
{
  ac_eventcount_cmp_t ec;
  ac_intword_t waiters;

} ac_eventcount_algo1_shared_t;

typedef struct 
AC_DECLSPEC_PACKED_ALIGN_CACHE_LINE 
ac_eventcount_algo1_shared_padded_
{
  ac_eventcount_algo1_shared_t _this;

} ac_eventcount_algo1_shared_padded_t;


#ifdef _MSC_VER 
#pragma pack() 
/* 4324: structure was padded due to _declspec(align()) */
#pragma warning ( default : 4324 )
#endif


typedef struct ac_eventcount_algo1_
{
  ac_eventcount_algo1_shared_t *shared;

  pthread_cond_t cond;
  pthread_mutex_t mutex;

  /* read-only */
  void *shared_mem;

} ac_eventcount_algo1_t;




/* critical test compile time assertion */
AC_BUILD_DBG_ASSERT
( eventcount_algo1,
  sizeof( ac_eventcount_algo1_shared_padded_t ) == AC_CPU_CACHE_LINE );




AC_APIEXPORT int AC_APIDECL
ac_eventcount_algo1_alloc
( ac_eventcount_algo1_t*,
  ac_eventcount_algo1_shared_t* );


AC_APIEXPORT int AC_APIDECL
ac_eventcount_algo1_free
( ac_eventcount_algo1_t* );


AC_APIEXPORT int AC_APIDECL
ac_prv_eventcount_algo1_signal
( ac_eventcount_algo1_t* );


AC_APIEXPORT int AC_APIDECL
ac_eventcount_algo1_timedwait
( ac_eventcount_algo1_t*,
  ac_thread_t*,
  ac_eventcount_cmp_t,
  ac_timeout_t );




AC_DECLSPEC_INLINE ac_eventcount_cmp_t AC_APIDECL
ac_eventcount_algo1_get
( ac_eventcount_algo1_t *_this )
{
  ac_eventcount_cmp_t cmp, old;

  old = _this->shared->ec;

  do
  {
    cmp = old;
    old = ac_atomic_cas_acquire
            ( &_this->shared->ec,
              cmp,
              cmp | 0x80000000 );
  }
  while ( cmp != old );

  return old & 0x7FFFFFFF;
}


AC_DECLSPEC_INLINE int AC_APIDECL
ac_eventcount_algo1_signal_naked
( ac_eventcount_algo1_t *_this )
{
  return ( (ac_eventcount_cmp_t)ac_mb_load_naked
            ( &_this->shared->ec ) & 0x80000000 ) ?
            ac_prv_eventcount_algo1_signal( _this ) : 0;
}


AC_DECLSPEC_INLINE int AC_APIDECL
ac_eventcount_algo1_signal_fence
( ac_eventcount_algo1_t *_this )
{
  ac_mb_fence();
  ac_eventcount_algo1_signal_naked(_this);
}


#define ac_eventcount_algo1_signal \
  ac_eventcount_algo1_signal_fence




#ifdef __cplusplus
}
#endif


#endif