Upgrade to Bonanza 6.0
[bonanza.git] / thread.c
index c88461a..f170edd 100644 (file)
--- a/thread.c
+++ b/thread.c
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
+#include <assert.h>
+#include <stdarg.h>
 #if defined(_WIN32)
 #  include <process.h>
 #else
+#  include <arpa/inet.h>
+#  include <sys/types.h>
+#  include <unistd.h>
 #  include <sched.h>
 #endif
 #include "shogi.h"
 
+
+#if defined(TLP) || defined(DFPN_CLIENT)
+int CONV
+lock_init( lock_t *plock )
+{
+#  if defined(_MSC_VER)
+  *plock = 0;
+#  elif defined(__GNUC__) && ( defined(__i386__) || defined(__x86_64__) )
+  *plock = 0;
+#  else
+  if ( pthread_mutex_init( plock, 0 ) )
+    {
+      str_error = "pthread_mutex_init() failed.";
+      return -1;
+    }
+#  endif
+  return 1;
+}
+
+
+int CONV
+lock_free( lock_t *plock )
+{
+#  if defined(_MSC_VER)
+  *plock = 0;
+#  elif defined(__GNUC__) && ( defined(__i386__) || defined(__x86_64__) )
+  *plock = 0;
+#  else
+  if ( pthread_mutex_destroy( plock ) )
+    {
+      str_error = "pthread_mutex_destroy() failed.";
+      return -1;
+    }
+#  endif
+  return 1;
+}
+
+
+void CONV
+unlock( lock_t *plock )
+{
+#  if defined(_MSC_VER)
+  *plock = 0;
+#  elif defined(__GNUC__) && ( defined(__i386__) || defined(__x86_64__) )
+  *plock = 0;
+#  else
+  pthread_mutex_unlock( plock );
+#  endif
+}
+
+
+void CONV
+lock( lock_t *plock )
+{
+#  if defined(_MSC_VER)
+  while ( _InterlockedExchange( (void *)plock, 1 ) )
+    {
+      while ( *plock ) { tlp_yield();}
+    }
+#  elif defined(__GNUC__) && ( defined(__i386__) || defined(__x86_64__) )
+  int itemp;
+
+  for ( ;; )
+    {
+      asm ( "1:   movl     $1,  %1 \n\t"
+           "     xchgl   (%0), %1 \n\t"
+           : "=g" (plock), "=r" (itemp) : "0" (plock) );
+      if ( ! itemp ) { return; }
+      while ( *plock ) { tlp_yield();}
+    }
+#  else
+  pthread_mutex_lock( plock );
+#  endif
+}
+
+
+void
+tlp_yield( void )
+{
+#if defined(_WIN32)
+  Sleep( 0 );
+#else
+  sched_yield();
+#endif
+}
+#endif /* TLP || DFPN_CLIENT */
+
+
+#if defined(DFPN_CLIENT)
+
+static int CONV proce_line( char *line_buf );
+#  if defined(_WIN32)
+static unsigned int __stdcall dfpn_client_receiver( void *arg );
+#  else
+static void *dfpn_client_receiver( void *arg );
+#  endif
+
+void CONV
+dfpn_client_start( const tree_t * restrict ptree )
+{
+  if ( root_turn != min_posi_no_handicap.turn_to_move
+       || HAND_B != min_posi_no_handicap.hand_black
+       || HAND_W != min_posi_no_handicap.hand_white
+       || memcmp( BOARD, min_posi_no_handicap.asquare, nsquare ) )
+    {
+      sckt_shutdown( dfpn_client_sckt );
+      dfpn_client_sckt = SCKT_NULL;
+      return;
+    }
+
+  if ( dfpn_client_sckt        != SCKT_NULL ) { return; }
+  if ( dfpn_client_str_addr[0] == '\0' )      { return; }
+
+  dfpn_client_sckt = sckt_connect( dfpn_client_str_addr, dfpn_client_port );
+  if ( dfpn_client_sckt == SCKT_NULL )
+    {
+      out_warning( "Connection to DFPN server failed." );
+      return;
+    }
+  else {
+    Out( "New connection to DFPN server: %s %d\n",
+        dfpn_client_str_addr, dfpn_client_port );
+  }
+
+#  if defined(_WIN32)
+  if ( ! _beginthreadex( 0, 0, &dfpn_client_receiver, NULL, 0, 0 ) )
+    {
+      sckt_shutdown( dfpn_client_sckt );
+      dfpn_client_sckt = SCKT_NULL;
+      out_warning( "_beginthreadex() failed." );
+    }
+#  else
+  {
+    pthread_t pt;
+    if ( pthread_create( &pt, &pthread_attr, &dfpn_client_receiver, NULL ) )
+      {
+       sckt_shutdown( dfpn_client_sckt );
+       dfpn_client_sckt = SCKT_NULL;
+       out_warning( "_beginthreadex() failed." );
+      }
+  }
+#  endif
+
+  dfpn_client_out( "Client: anonymous\n" );
+}
+
+
+#  if defined(_MSC_VER)
+#    pragma warning(disable:4100)
+#  elif defined(__ICC)
+#    pragma warning(disable:869)
+#  endif
+
+#  if defined(_MSC_VER)
+static unsigned int __stdcall dfpn_client_receiver( void *arg )
+#  else
+static void *dfpn_client_receiver( void *arg )
+#endif
+{
+#define SIZE_RECV_BUF ( 1024 * 16 )
+#define SIZE_LINE_BUF 1024
+  char recv_buf[ SIZE_RECV_BUF ];
+  char line_buf[ SIZE_LINE_BUF ];
+  char *str_end, *str_line_end;
+  size_t size;
+  int len_recv_buf;
+  struct timeval tv;
+  fd_set readfds;
+  int iret;
+
+  recv_buf[0] = '\0';
+
+  /* recv loop */
+  for ( ;; ) {
+
+    /* select loop */
+    for ( ;; ) {
+      tv.tv_sec  = SEC_KEEP_ALIVE;
+      tv.tv_usec = 0;
+      FD_ZERO( &readfds );
+#  if defined(_MSC_VER)
+#    pragma warning(disable:4127)
+#  endif
+      FD_SET( dfpn_client_sckt, &readfds );
+#  if defined(_MSC_VER)
+#    pragma warning(default:4127)
+#  endif
+      
+      iret = select( (int)dfpn_client_sckt+1, &readfds, NULL, NULL, &tv );
+      if ( iret == SOCKET_ERROR )
+       {
+         out_warning( "%s", str_error );
+         goto dfpn_client_receiver_shutdown;
+       }
+
+      /* message arrived */
+      if ( iret ) { break; }
+
+      /* timeout and keepalive */
+      lock( &dfpn_client_lock);
+      iret = dfpn_client_out( "ping\n" );
+      unlock( &dfpn_client_lock);
+      if ( iret < 0 ) { return 0; }
+    }
+
+    /* read messages */
+    len_recv_buf = (int)strlen( recv_buf );
+    str_end      = recv_buf + len_recv_buf;
+
+    iret = recv( dfpn_client_sckt, str_end, SIZE_RECV_BUF-1-len_recv_buf, 0 );
+    if ( iret == SOCKET_ERROR )
+      {
+       str_error = str_WSAError( "recv() failed:" );
+       out_warning( "%s", str_error );
+       goto dfpn_client_receiver_shutdown;
+      }
+    if ( ! iret ) { goto dfpn_client_receiver_shutdown; }
+    recv_buf[ len_recv_buf + iret ] = '\0';
+
+    /* take each line */
+    lock( &dfpn_client_lock );
+    for ( ;; ) {
+
+      str_line_end = strchr( recv_buf, '\n' );
+      if ( str_line_end == NULL )
+       {
+         if ( iret + len_recv_buf + 1 >= SIZE_RECV_BUF )
+           {
+             unlock( &dfpn_client_lock );
+             out_warning( "%s", str_ovrflw_line );
+             goto dfpn_client_receiver_shutdown;
+           }
+         break;
+       }
+
+      size = str_line_end - recv_buf;
+      if ( size + 1 >= SIZE_LINE_BUF )
+       {
+         unlock( &dfpn_client_lock );
+         out_warning( "%s", str_ovrflw_line );
+         goto dfpn_client_receiver_shutdown;
+       }
+      
+      memcpy( line_buf, recv_buf, size );
+      memmove( recv_buf, str_line_end+1, strlen(str_line_end+1) + 1 );
+
+      line_buf[size] = '\0';
+
+      if ( proce_line( line_buf ) < 0 )
+       {
+         unlock( &dfpn_client_lock );
+         out_warning( "invalid messages from DFPN server" );
+         goto dfpn_client_receiver_shutdown;
+       }
+    }
+    unlock( &dfpn_client_lock );
+  }
+
+ dfpn_client_receiver_shutdown:
+  sckt_shutdown( dfpn_client_sckt );
+  dfpn_client_sckt = SCKT_NULL;
+  out_warning( "A connection to DFPN server is down." );
+
+  return 0;
+}
+#  if defined(_MSC_VER)
+#    pragma warning(default:4100)
+#  elif defined(__ICC)
+#    pragma warning(default:869)
+#endif
+
+
+static int CONV proce_line( char *line_buf )
+{
+  const char *token;
+  volatile dfpn_client_cresult_t *pcresult;
+  char *last;
+
+  token = strtok_r( line_buf, str_delimiters, &last );
+  if ( token == NULL ) { return -1; }
+
+  /* check signature */
+  if ( strcmp( token, (const char *)dfpn_client_signature ) ) { return 1; }
+
+  token = strtok_r( NULL, str_delimiters, &last );
+  if ( token == NULL ) { return -1; }
+
+  /* root node */
+  if ( ! strcmp( token, "WIN" ) )
+    {
+      token = strtok_r( NULL, str_delimiters, &last );
+      if ( token == NULL || ! is_move( token ) ) { return -1; }
+      dfpn_client_rresult   = dfpn_client_win;
+      dfpn_client_flag_read = 1;
+      memcpy( (char *)dfpn_client_str_move, token, 7 );
+      return 1;
+    }
+
+  if ( ! strcmp( token, "LOSE" ) )
+    {
+      dfpn_client_rresult   = dfpn_client_lose;
+      dfpn_client_flag_read = 1;
+      return 1;
+    }
+
+  if ( ! strcmp( token, "UNSOLVED" ) )
+    {
+      dfpn_client_rresult   = dfpn_client_misc;
+      dfpn_client_flag_read = 1;
+      return 1;
+    }
+
+  /* child node */
+  if ( ! is_move( token ) ) { return -1; }
+  if ( MAX_LEGAL_MOVES <= dfpn_client_num_cresult ) { return -1; }
+  pcresult = &dfpn_client_cresult[dfpn_client_num_cresult];
+  memcpy( (char *)pcresult->str_move, token, 7 );
+
+  token = strtok_r( NULL, str_delimiters, &last );
+  if ( token == NULL ) { return -1; }
+  
+  if ( ! strcmp( token, "WIN" ) )
+    {
+      pcresult->result         = dfpn_client_win;
+      dfpn_client_flag_read    = 1;
+      dfpn_client_num_cresult += 1;
+      return 1;
+    }
+
+  if ( ! strcmp( token, "LOSE" ) )
+    {
+      pcresult->result         = dfpn_client_lose;
+      dfpn_client_flag_read    = 1;
+      dfpn_client_num_cresult += 1;
+      return 1;
+    }
+
+  if ( ! strcmp( token, "UNSOLVED" ) )
+    {
+      pcresult->result         = dfpn_client_misc;
+      dfpn_client_flag_read    = 1;
+      dfpn_client_num_cresult += 1;
+      return 1;
+    }
+
+  return -1;
+}
+
+#endif /* DFPN_CLINET */
+
+
 #if defined(TLP)
 
 #  if defined(_WIN32)
@@ -138,7 +494,7 @@ tlp_set_abort( tree_t * restrict ptree )
 }
 
 
-#if defined(MNJ_LAN)
+#if defined(MNJ_LAN) || defined(USI)
 uint64_t
 tlp_count_node( tree_t * restrict ptree )
 {
@@ -169,95 +525,6 @@ tlp_is_descendant( const tree_t * restrict ptree, int slot_ancestor )
 }
 
 
-int
-lock_init( lock_t *plock )
-{
-#  if defined(_MSC_VER)
-  *plock = 0;
-#  elif defined(__GNUC__) && ( defined(__i386__) || defined(__x86_64__) )
-  *plock = 0;
-#  else
-  if ( pthread_mutex_init( plock, 0 ) )
-    {
-      str_error = "pthread_mutex_init() failed.";
-      return -1;
-    }
-#  endif
-  return 1;
-}
-
-
-int
-lock_free( lock_t *plock )
-{
-#  if defined(_MSC_VER)
-  *plock = 0;
-#  elif defined(__GNUC__) && ( defined(__i386__) || defined(__x86_64__) )
-  *plock = 0;
-#  else
-  if ( pthread_mutex_destroy( plock ) )
-    {
-      str_error = "pthread_mutex_destroy() failed.";
-      return -1;
-    }
-#  endif
-  return 1;
-}
-
-
-void
-unlock( lock_t *plock )
-{
-#  if defined(_MSC_VER)
-  *plock = 0;
-#  elif defined(__GNUC__) && ( defined(__i386__) || defined(__x86_64__) )
-  *plock = 0;
-#  else
-  pthread_mutex_unlock( plock );
-#  endif
-}
-
-
-void
-lock( lock_t *plock )
-{
-#  if defined(_MSC_VER)
-  long l;
-
-  for ( ;; )
-    {
-      l = _InterlockedExchange( (void *)plock, 1 );
-      if ( ! l ) { return; }
-      while ( *plock );
-    }
-#  elif defined(__GNUC__) && ( defined(__i386__) || defined(__x86_64__) )
-  int itemp;
-
-  for ( ;; )
-    {
-      asm ( "1:   movl     $1,  %1 \n\t"
-           "     xchgl   (%0), %1 \n\t"
-           : "=g" (plock), "=r" (itemp) : "0" (plock) );
-      if ( ! itemp ) { return; }
-      while ( *plock );
-    }
-#  else
-  pthread_mutex_lock( plock );
-#  endif
-}
-
-
-void
-tlp_yield( void )
-{
-#if defined(_WIN32)
-  Sleep( 0 );
-#else
-  sched_yield();
-#endif
-}
-
-
 #  if defined(_MSC_VER)
 static unsigned int __stdcall start_address( void *arg )
 #  else
@@ -361,8 +628,6 @@ init_state( const tree_t * restrict parent, tree_t * restrict child )
   child->nperpetual_check      = 0;
   child->nsuperior_rep         = 0;
   child->nrep_tried            = 0;
-  child->nreject_tried         = 0;
-  child->nreject_done          = 0;
   child->ntrans_always_hit     = 0;
   child->ntrans_prefer_hit     = 0;
   child->ntrans_probe          = 0;
@@ -381,15 +646,16 @@ init_state( const tree_t * restrict parent, tree_t * restrict child )
   child->anext_move[ply].move_cap2  = parent->anext_move[ply].move_cap2;
 
   child->move_last[ply]        = child->amove;
-  child->stand_pat[ply]        = parent->stand_pat[ply];
+  child->save_eval[ply]        = parent->save_eval[ply];
   child->current_move[ply-1]   = parent->current_move[ply-1];
   child->nsuc_check[ply-1]     = parent->nsuc_check[ply-1];
   child->nsuc_check[ply]       = parent->nsuc_check[ply];
+  child->nrep                  = parent->nrep;
 
   memcpy( child->hist_good,  parent->hist_good,  sizeof(parent->hist_good) );
   memcpy( child->hist_tried, parent->hist_tried, sizeof(parent->hist_tried) );
 
-  for ( i = 0; i < root_nrep + ply - 1; i++ )
+  for ( i = 0; i < child->nrep + ply - 1; i++ )
     {
       child->rep_board_list[i] = parent->rep_board_list[i];
       child->rep_hand_list[i]  = parent->rep_hand_list[i];
@@ -424,8 +690,6 @@ copy_state( tree_t * restrict parent, const tree_t * restrict child,
   parent->nfour_fold_rep       += child->nfour_fold_rep;
   parent->nperpetual_check     += child->nperpetual_check;
   parent->nsuperior_rep        += child->nsuperior_rep;
-  parent->nreject_tried        += child->nreject_tried;
-  parent->nreject_done         += child->nreject_done;
   parent->ntrans_always_hit    += child->ntrans_always_hit;
   parent->ntrans_prefer_hit    += child->ntrans_prefer_hit;
   parent->ntrans_probe         += child->ntrans_probe;
@@ -439,19 +703,20 @@ copy_state( tree_t * restrict parent, const tree_t * restrict child,
 
   if ( child->tlp_abort || value <= parent->tlp_best ) { return; }
 
-  ply                       = parent->tlp_ply;
-  parent->tlp_best          = (short)value;
-  parent->pv[ply]           = child->pv[ply];
+  ply              = parent->tlp_ply;
+  parent->tlp_best = (short)value;
+  parent->pv[ply]  = child->pv[ply];
+
+  lock( &parent->tlp_lock );
   parent->current_move[ply] = child->current_move[ply];
-  
   memcpy( parent->hist_tried, child->hist_tried, sizeof(child->hist_tried) );
   memcpy( parent->hist_good,  child->hist_good,  sizeof(child->hist_good) );
-
   for ( i = ply; i < PLY_MAX; i++ ) 
     {
       parent->amove_killer[i] = child->amove_killer[i];
       parent->killers[i]      = child->killers[i];
     }
+  unlock( &parent->tlp_lock );
 }