/* Copyright 2005 Chris Thomasson */


#include "../../../include/sys/ac_sys.h"




static ac_i686_this_t *p_this;




int AC_APIDECL
ac_i686_startup
( ac_i686_this_t *_this )
{
  int ret;

  p_this = _this;

  ret = ac_i686_lfgc_smr_startup();
  if ( ret ) { return ac_sys_error( ret ); }

  ac_cpu_stack_mpmc_init( &p_this->node_cache );

  return 0;
}


int AC_APIDECL
ac_i686_shutdown
( void )
{
  int ret = ac_i686_lfgc_smr_shutdown();
  if ( ret ) { return ac_sys_error( ret ); }

  return 0;
}


void AC_APIDECL
ac_i686_node_cache_flush
( void )
{
  ac_i686_node_t *next;

  while ( p_this->node_cache.front )
  {
    next = p_this->node_cache.front->next;
    assert( p_this->node_cache.front->fp_dtor == (ac_fp_dtor_t)0x00000001 );
    ac_free( p_this->node_cache.front );
    --p_this->node_count;
    p_this->node_cache.front = next;
  }

  assert( ! p_this->node_count );  
}


ac_i686_node_t* AC_APIDECL
ac_i686_node_cache_pop
( const void *state )
{
  ac_i686_node_t *node;

  node = np_ac_i686_stack_mpmc_pop_dwcas
          ( &p_this->node_cache );

  if ( ! node )
  {
    node = ac_malloc( sizeof( *node ) );
    if ( ! node ) { ac_sys_error( ENOMEM ); return 0; }

    node->fp_dtor = 0;
  }

  node->next = 0;
  node->lfgc_next = 0;
  node->state = state;

  return node;
}


void AC_APIDECL
ac_i686_node_cache_push
( ac_i686_node_t *node )
{
  if ( p_this->node_count < 50000 || 
       node->fp_dtor == (ac_fp_dtor_t)0x00000001 )
  {
    if ( node->fp_dtor != (ac_fp_dtor_t)0x00000001 )
    {
      node->fp_dtor = (ac_fp_dtor_t)0x00000001;
      ac_atomic_inc_release
        ( &p_this->node_count );
    }

    ac_i686_stack_mpmc_push_cas
      ( &p_this->node_cache, 
        node );
  }

  else
  {
    assert( node->fp_dtor != (ac_fp_dtor_t)0x00000001 );
    ac_free( node );
  }
}


int AC_APIDECL
ac_i686_node_cache_push_no_free
( ac_i686_node_t *node )
{
  if ( p_this->node_count < 50000 || 
       node->fp_dtor == (ac_fp_dtor_t)0x00000001 )
  {
    if ( node->fp_dtor != (ac_fp_dtor_t)0x00000001 )
    {
      node->fp_dtor = (ac_fp_dtor_t)0x00000001;
      ac_atomic_inc_release
        ( &p_this->node_count );
    }

    ac_i686_stack_mpmc_push_cas
      ( &p_this->node_cache, 
        node );
  }

  else
  {
    assert( node->fp_dtor != (ac_fp_dtor_t)0x00000001 );
    return 1;
  }

  return 0;
}


int AC_APIDECL
ac_i686_tls_alloc
( ac_i686_tls_t *_this,
  ac_thread_t *thread )
{
  int ret;

  _this->thread = thread;

  ret = ac_i686_lfgc_smr_alloc( _this );
  if ( ret ) { return ac_sys_error( ret ); }

  return 0;
}


int AC_APIDECL
ac_i686_tls_free
( ac_i686_tls_t *_this )
{
  int ret = ac_i686_lfgc_smr_free( _this );
  if ( ret ) { return ac_sys_error( ret ); }

  return 0;
}