/* Copyright 2005 Chris Thomasson */


#ifndef AC_THREAD_H
#define AC_THREAD_H


#ifdef __cplusplus
extern "C"
{
#endif




#define AC_PRV_TLS_NODE_CACHE_MAX_DEPTH 5000
#define AC_PRV_TLS_LOCK_RECURSE_MAX_DEPTH 6




typedef void* ( AC_CDECL *ac_fp_thread_entry_t ) ( void* );


typedef struct ac_thread_cfg_
{
  ac_flags_t flags;

} ac_thread_cfg_t;


typedef struct ac_thread_shared_recurse_
{
  void *lock;
  ac_intword_t count;

} ac_thread_shared_recurse_t;


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


typedef struct 
AC_DECLSPEC_ALIGN_CACHE_LINE
ac_thread_shared_
{
  ac_intword_t refs;

} ac_thread_shared_t;


struct 
AC_DECLSPEC_ALIGN_CACHE_LINE
ac_thread_
{
  ac_thread_shared_t shared;

  /* thread-local */
  ac_cpu_node_t *local_cache;
  ac_intword_t cache_count;
  ac_thread_shared_recurse_t recurse[AC_PRV_TLS_LOCK_RECURSE_MAX_DEPTH];
  ac_intword_t recurse_index;
  ac_cpu_node_t node;

  /* read-only */
  ac_cpu_tls_t cpu_atomic;
  ac_thread_cfg_t cfg;
  ac_fp_thread_entry_t fp_entry;
  const void *state;
  ac_uintword_t id;
  pthread_t thread;
  void *this_mem;
};


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




AC_APIEXPORT int AC_APIDECL
ac_thread_alloc
( ac_thread_t**,
  ac_thread_cfg_t*,
  ac_fp_thread_entry_t,
  const void* );


AC_APIEXPORT int AC_APIDECL
ac_thread_join
( ac_thread_t*,
  void** );


AC_APIEXPORT ac_thread_t* AC_APIDECL
ac_thread_self
( void );


AC_DECLSPEC_INLINE void AC_APIDECL
ac_sys_thread_recurse_locked
( ac_thread_t *_this,
  void *lock )
{
  ac_intword_t recurse = ++_this->recurse_index;
  assert( ! _this->recurse[recurse].count );
  _this->recurse[recurse].lock = lock;
}


AC_DECLSPEC_INLINE int AC_APIDECL
ac_sys_thread_recurse_inc
( ac_thread_t *_this,
  void *lock )
{
  ac_intword_t recurse = _this->recurse_index;

  if ( recurse > -1 && _this->recurse[recurse].lock == lock )
  {
    ++_this->recurse[recurse].count;
    return 0;    
  }

  return 1;
}


AC_DECLSPEC_INLINE int AC_APIDECL
ac_sys_thread_recurse_dec
( ac_thread_t *_this,
  void *lock )
{
  ac_intword_t recurse = _this->recurse_index,
               count = _this->recurse[recurse].count;

  if ( _this->recurse[recurse].lock != lock )
  {
    assert( _this->recurse[recurse].lock == lock );
    return ac_sys_error( AC_ECORRUPTED );
  }

  if ( count )
  {
    _this->recurse[recurse].count = count - 1;
    return 0;
  }

  _this->recurse_index = recurse - 1;

  return 1;
}


AC_DECLSPEC_INLINE ac_cpu_node_t* AC_APIDECL
ac_thread_cpu_node_cache_pop
( ac_thread_t *_this,
  const void *state )
{
  ac_cpu_node_t *node = _this->local_cache;

  if ( node )
  {
    --_this->cache_count;
    _this->local_cache = node->next;
    node->next = 0;
    node->lfgc_next = 0;
    node->state = state;
  }

  else
  {
    node = ac_cpu_node_cache_pop( state );
  }

  return node;
}


AC_DECLSPEC_INLINE void AC_APIDECL
ac_thread_cpu_node_cache_push
( ac_thread_t *_this,
  ac_cpu_node_t *node )
{
  if ( _this->cache_count < AC_PRV_TLS_NODE_CACHE_MAX_DEPTH )
  {
    ++_this->cache_count;
    node->next = _this->local_cache;
    _this->local_cache = node;
  }

  else
  {
    ac_cpu_node_cache_push( node );
  }
}


AC_DECLSPEC_INLINE int AC_APIDECL
ac_thread_cpu_node_cache_push_no_free
( ac_thread_t *_this,
  ac_cpu_node_t *node )
{
  if ( _this && node->fp_dtor == (ac_fp_dtor_t)0x00000001 )
  {
    ++_this->cache_count;
    node->next = _this->local_cache;
    _this->local_cache = node;
  }

  else
  {
    return ac_cpu_node_cache_push_no_free( node );
  }

  return 0;
}




#ifdef __cplusplus
}
#endif


#endif