text: /**CFile****************************************************************
  
    FileName    [cmdStarter.c]
  
    SystemName  [ABC: Logic synthesis and verification system.]
  
    PackageName [Command processing package.]
  
    Synopsis    [Command to start many instances of ABC in parallel.]
  
    Author      [Alan Mishchenko]
    
    Affiliation [UC Berkeley]
  
    Date        [Ver. 1.0. Started - June 20, 2005.]
  
    Revision    [$Id: cmdStarter.c,v 1.00 2005/06/20 00:00:00 alanmi Exp $]
  
  ***********************************************************************/
  
  #include <stdio.h>
  #include <stdlib.h>
  #include <string.h>
  #include <assert.h>
  #include "misc/util/abc_global.h"
  #include "misc/extra/extra.h"
  
  #ifdef ABC_USE_PTHREADS
  
  #ifdef _WIN32
  #include "../lib/pthread.h"
  #else
  #include <pthread.h>
  #include <unistd.h>
  #endif
  
  #endif
  
  ABC_NAMESPACE_IMPL_START
   
  ////////////////////////////////////////////////////////////////////////
  ///                        DECLARATIONS                              ///
  ////////////////////////////////////////////////////////////////////////
  
  #ifndef ABC_USE_PTHREADS
  
  void Cmd_RunStarter( char * pFileName, char * pBinary, char * pCommand, int nCores ) {}
  
  #else // pthreads are used
  
  // the number of concurrently running threads
  static volatile int nThreadsRunning = 0;
  
  // mutex to control access to the number of threads
  pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
  
  ////////////////////////////////////////////////////////////////////////
  ///                     FUNCTION DEFINITIONS                         ///
  ////////////////////////////////////////////////////////////////////////
  
  /**Function*************************************************************
  
    Synopsis    [This procedures executes one call to system().]
  
    Description []
                 
    SideEffects []
  
    SeeAlso     []
  
  ***********************************************************************/
  void * Abc_RunThread( void * pCommand )
  {
      int status;
      // perform the call
      if ( system( (char *)pCommand ) )
      {
          fprintf( stderr, "The following command has returned non-zero exit status:\n" );
          fprintf( stderr, "\"%s\"\n\n", (char *)pCommand );
          fflush( stdout );
      }
      free( pCommand );
  
      // decrement the number of threads runining 
      status = pthread_mutex_lock(&mutex);   assert(status == 0);
      nThreadsRunning--;
      status = pthread_mutex_unlock(&mutex); assert(status == 0);
  
      // quit this thread
  	//printf("...Finishing %s\n", (char *)Command);
  	pthread_exit( NULL );
  	assert(0);
  	return NULL;
  }
  
  /**Function*************************************************************
  
    Synopsis    [Takes file with commands to be executed and the number of CPUs.]
  
    Description []
                 
    SideEffects []
  
    SeeAlso     []
  
  ***********************************************************************/
  void Cmd_RunStarter( char * pFileName, char * pBinary, char * pCommand, int nCores )
  {
      FILE * pFile, * pFileTemp;
  	pthread_t * pThreadIds;
      char * BufferCopy, * Buffer;
      int nLines, LineMax, Line, Len;
  	int i, c, status, Counter;
      abctime clk = Abc_Clock();
  
      // check the number of cores
      if ( nCores < 2 )
      {
          fprintf( stdout, "The number of cores (%d) should be more than 1.\n", nCores ); 
          return; 
      }
  
      // open the file and make sure it is available
      pFile = fopen( pFileName, "rb" );
      if ( pFile == NULL )
      { 
          fprintf( stdout, "Input file \"%s\" cannot be opened.\n", pFileName ); 
          return; 
      }
  
      // count the number of lines and the longest line
      nLines = LineMax = Line = 0;
      while ( (c = fgetc(pFile)) != EOF )
      {
          Line++;
          if ( c != '\n' )
              continue;
          nLines++;
          LineMax = Abc_MaxInt( LineMax, Line );
          Line = 0;       
      }
      nLines += 10;
      LineMax += LineMax + 100;
      LineMax += pBinary  ? strlen(pBinary) : 0;
      LineMax += pCommand ? strlen(pCommand) : 0;
  
      // allocate storage
      Buffer = ABC_ALLOC( char, LineMax );
      pThreadIds = ABC_ALLOC( pthread_t, nLines );
  
      // check if all files can be opened
      if ( pCommand != NULL )
      {
          // read file names
          rewind( pFile );
          for ( i = 0; fgets( Buffer, LineMax, pFile ) != NULL; i++ )
          {
              // remove trailing spaces
              for ( Len = strlen(Buffer) - 1; Len >= 0; Len-- )
                  if ( Buffer[Len] == '\n' || Buffer[Len] == '\r' || Buffer[Len] == '\t' || Buffer[Len] == ' ' )
                      Buffer[Len] = 0;
                  else
                      break;
  
              // get command from file
              if ( Buffer[0] == 0 || Buffer[0] == '\n' || Buffer[0] == '\r' || Buffer[0] == '\t' || Buffer[0] == ' ' || Buffer[0] == '#' )
                  continue;
  
              // try to open the file
              pFileTemp = fopen( Buffer, "rb" );
              if ( pFileTemp == NULL )
              {
                  fprintf( stdout, "Starter cannot open file \"%s\".\n", Buffer );
                  fflush( stdout );
                  ABC_FREE( pThreadIds );
                  ABC_FREE( Buffer );
                  fclose( pFile );
                  return;
              }    
          }
      } 
   
      // read commands and execute at most <num> of them at a time
      rewind( pFile );
      for ( i = 0; fgets( Buffer, LineMax, pFile ) != NULL; i++ )
      {
          // remove trailing spaces
          for ( Len = strlen(Buffer) - 1; Len >= 0; Len-- )
              if ( Buffer[Len] == '\n' || Buffer[Len] == '\r' || Buffer[Len] == '\t' || Buffer[Len] == ' ' )
                  Buffer[Len] = 0;
              else
                  break;
  
          // get command from file
          if ( Buffer[0] == 0 || Buffer[0] == '\n' || Buffer[0] == '\r' || Buffer[0] == '\t' || Buffer[0] == ' ' || Buffer[0] == '#' )
              continue;
  
          // create command
          if ( pCommand != NULL )
          {
              BufferCopy = ABC_ALLOC( char, LineMax );
              sprintf( BufferCopy, "%s -c \"%s; %s\" > %s", pBinary, Buffer, pCommand, Extra_FileNameGenericAppend(Buffer, ".txt") );
          }
          else
              BufferCopy = Abc_UtilStrsav( Buffer );
          fprintf( stdout, "Calling:  %s\n", (char *)BufferCopy );  
          fflush( stdout );
  
          // wait till there is an empty thread
          while ( 1 )
          {
              status = pthread_mutex_lock(&mutex);   assert(status == 0);
              Counter = nThreadsRunning;
              status = pthread_mutex_unlock(&mutex); assert(status == 0);
              if ( Counter < nCores - 1 )
                  break;
  //            Sleep( 100 );
          }
  
          // increament the number of threads running
          status = pthread_mutex_lock(&mutex);   assert(status == 0);
          nThreadsRunning++;
          status = pthread_mutex_unlock(&mutex); assert(status == 0);
  
          // create thread to execute this command
          status = pthread_create( &pThreadIds[i], NULL, Abc_RunThread, (void *)BufferCopy );  assert(status == 0);
          assert( i < nLines );
      }
      ABC_FREE( pThreadIds );
      ABC_FREE( Buffer );
      fclose( pFile );
  
      // wait for all the threads to finish
      while ( 1 )
      {
          status = pthread_mutex_lock(&mutex);   assert(status == 0);
          Counter = nThreadsRunning;
          status = pthread_mutex_unlock(&mutex); assert(status == 0);
          if ( Counter == 0 )
              break;
      }
  
      // cleanup
  //    status = pthread_mutex_destroy(&mutex);   assert(status == 0);
  //    mutex = PTHREAD_MUTEX_INITIALIZER;
      fprintf( stdout, "Finished processing commands in file \"%s\".  ", pFileName );
      Abc_PrintTime( 1, "Total wall time", Abc_Clock() - clk );
      fflush( stdout );
  }
  
  #endif // pthreads are used
  
  ////////////////////////////////////////////////////////////////////////
  ///                       END OF FILE                                ///
  ////////////////////////////////////////////////////////////////////////
  
  
  ABC_NAMESPACE_IMPL_END
  
  