/* Copyright 2005 Chris Thomasson */


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




/* undef to remove expensive allocation counting */
#define AC_DBG_MALLOC_COUNTER


#ifdef AC_DBG_MALLOC_COUNTER
static ac_intword_t dbg_refs = 0;
#endif




static ac_sys_this_t *p_this;




int AC_APIDECL
ac_startup
( void )
{
  int ret;
  void *this_mem;

  p_this = ac_calloc_aligned
            ( &this_mem,
              1,
              sizeof( *p_this ),
              AC_CPU_CACHE_LINE );

  if ( ! p_this ) { return ac_sys_error( ENOMEM ); }

  p_this->this_mem = this_mem;

  ret = ac_sys_thread_startup( &p_this->sys_thread );
  if ( ret ) { return ac_sys_error( ret ); }

  ret = ac_cpu_startup( &p_this->cpu );
  if ( ret ) { return ac_sys_error( ret ); }

  printf( "%p::appcore - ctor\n\n", (void*)p_this );

  return 0;
}


int AC_APIDECL
ac_shutdown
( void )
{
  int ret;

  ac_sys_thread_tls_shutdown();

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

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

  ac_sys_thread_cache_flush();
  ac_cpu_node_cache_flush();

  ac_free( p_this->this_mem );

#ifdef AC_DBG_MALLOC_COUNTER
  if ( dbg_refs ) 
  { 
    printf( "ac - memory leak %d\n", dbg_refs );
    assert( ! dbg_refs );
    abort(); 
  }
#endif

  printf( "\n%p::appcore - dtor\n\n", (void*)p_this );

  return 0;
}


int AC_APIDECL
ac_sys_error
( int err )
{
  if ( err == AC_ECORRUPTED ) { abort(); }
  assert( ! err );
  return err;
}


void* AC_CDECL
ac_malloc
( size_t s )
{
#ifdef AC_DBG_MALLOC_COUNTER
  ac_atomic_inc_acquire( &dbg_refs );
#endif

  return malloc( s );
}


void* AC_CDECL
ac_calloc
( size_t n,
  size_t s )
{
#ifdef AC_DBG_MALLOC_COUNTER
  ac_atomic_inc_acquire( &dbg_refs );
#endif

  return calloc( n, s );
}


void* AC_APIDECL
ac_malloc_aligned
( void **thismem, 
  size_t s,
  size_t a )
{
  void *_aligned;

  if ( s % a )
  {
    ac_sys_error( EFAULT);
    return 0;     
  }

  *thismem = ac_malloc( s + ( a - 1 ) );
  if ( ! *thismem )
  {
    ac_sys_error( ENOMEM );
    return 0;
  }

  _aligned = (void*)((((ptrdiff_t)*thismem) + (a - 1)) & -((ptrdiff_t)a) );

  if ( ( ((ptrdiff_t)_aligned) % a ) )
  {
    ac_free( *thismem );
    ac_sys_error( EFAULT);
    return 0;     
  }

  return _aligned;
}


void* AC_APIDECL
ac_calloc_aligned
( void **thismem, 
  size_t n,
  size_t s,
  size_t a )
{
  void *_aligned;

  if ( ( s * n ) % a )
  {
    ac_sys_error( EFAULT);
    return 0;     
  }

  *thismem = ac_calloc( 1, ( s * n ) + ( a - 1 ) );
  if ( ! *thismem )
  {
    ac_sys_error( ENOMEM );
    return 0;
  }

  _aligned = (void*)((((ptrdiff_t)*thismem) + (a - 1)) & -((ptrdiff_t)a) );

  if ( ( ((ptrdiff_t)_aligned) % a ) )
  {
    ac_free( *thismem );
    ac_sys_error( EFAULT);
    return 0;     
  }

  return _aligned;
}


void AC_CDECL
ac_free
( void *m )
{
  if ( m ) 
  { 
    free( m ); 
     
#ifdef AC_DBG_MALLOC_COUNTER
    ac_atomic_dec_release( &dbg_refs ); 
#endif

  }
}