/////////////////////////////////////////////////////////////////////////////////////// // File : init.c // Date : January 2018 // Author : Alain Greiner /////////////////////////////////////////////////////////////////////////////////////// // This single thread application implement the "init" process for ALMOS-MKH. // It uses the fork/exec syscalls to create N KSH child processes // (one child process per user TXT terminal). // Then it calls the wait() function to block, and recreate any child KSH process // that has been deleted, using a new fork/exec. /////////////////////////////////////////////////////////////////////////////////////// #include #include #include #include #include #include #include #include #define DEBUG_PROCESS_INIT 0 //////////////// int main( void ) { unsigned int i; int ret_fork; // fork return value int ret_exec; // exec return value int rcv_pid; // pid received from the wait syscall int status; // used by the wait syscall char string[64]; // log messages on kernel TXT0 unsigned int cxy; // target cluster identifier #if DEBUG_PROCESS_INIT display_string("[init] process enters"); #endif // get number of TXT channels and number of clusters hard_config_t config; get_config( &config ); unsigned int txt_channels = config.txt_channels; unsigned int x_size = config.x_size; unsigned int y_size = config.y_size; unsigned int n_clusters = x_size * y_size; // check number of TXT channels if( txt_channels < 2 ) { snprintf( string , 64 , "\n[init ERROR] number of TXT channels must be larger than 1"); display_string( string ); exit( EXIT_FAILURE ); } cxy = 0; // create the KSH processes (one per user terminal) for( i = 1 ; i < txt_channels ; i++ ) { // compute target cluster cxy = (cxy + 1) % n_clusters; // select target cluster if( place_fork( cxy ) ) { // INIT display error message snprintf( string , 64 , "\n[init ERROR] cannot place fork for child[%d] => suicide" , i ); display_string( string ); // INIT suicide exit( EXIT_FAILURE ); } // INIT process fork process CHILD[i] ret_fork = fork(); if( ret_fork < 0 ) // error in fork { // INIT display error message snprintf( string , 64 , "\n[init ERROR] cannot fork child[%d] => suicide" , i ); display_string( string ); // INIT suicide exit( EXIT_FAILURE ); } else if( ret_fork == 0 ) // we are in CHILD[i] process { #if DEBUG_PROCESS_INIT snprintf( string , 64 , "\n[init] CHILD[%d] process forked / call execve", i ); display_string( string ); #endif // CHILD[i] process exec process KSH[i] ret_exec = execve( "/bin/user/ksh.elf" , NULL , NULL ); if ( ret_exec ) // error in exec { // CHILD[i] display error message snprintf( string , 64 , "\n[init ERROR] CHILD[%d] cannot exec KSH" , i ); display_string( string ); // CHILD[i] suicide exit( EXIT_FAILURE ); } } else // we are in INIT process { // INIT display CHILD[i] process PID snprintf( string , 64 , "[init] (pid 0x1) create ksh[%d] (pid %x)", i , ret_fork ); display_string( string ); } } #if DEBUG_PROCESS_INIT { // keep blocked for 2 seconds // to allow all KSH[i] process // to be launched before display sleep( 2 ); unsigned int x; // cluster x coordinate unsigned int y; // cluster y coordinate unsigned int cxy; // cluster identifier unsigned int lid; // core local index unsigned int x_size = config.x_size; unsigned int y_size = config.y_size; unsigned int ncores = config.ncores; // INIT displays processes and threads in all clusters for( x = 0 ; x < x_size ; x++ ) { for( y = 0 ; y < y_size ; y++ ) { cxy = HAL_CXY_FROM_XY( x , y ); display_cluster_processes( cxy , 0 ); for( lid = 0 ; lid < ncores ; lid++ ) { display_sched( cxy , lid ); } } } } #endif // This loop detects the termination of the KSH[i] processes, // and recreate a new KSH[i] process when required. while( 1 ) { // block on child processes termination rcv_pid = wait( &status ); if( WIFSTOPPED( status ) ) // stopped => unblock it { // display string to report unexpected KSH process block snprintf( string , 64 , "[init] KSH process %x stopped => unblock it" , rcv_pid ); display_string( string ); // TODO : unblock KSH [AG] } // end KSH stopped handling if( WIFSIGNALED( status ) || WIFEXITED( status ) ) // killed => recreate it { // display string to report KSH process termination snprintf( string , 64 , "[init] KSH process %x terminated => recreate", rcv_pid ); display_string( string ); // INIT process fork a new CHILD process ret_fork = fork(); if( ret_fork < 0 ) // error in fork { // INIT display error message snprintf( string , 64 , "[init ERROR] cannot fork child => suicide"); display_string( string ); // INIT suicide exit( 0 ); } else if( ret_fork == 0 ) // we are in CHILD process { // CHILD process exec process KSH ret_exec = execve( "/bin/user/ksh.elf" , NULL , NULL ); if ( ret_exec ) // error in exec { // CHILD display error message on TXT0 terminal snprintf( string , 64 , "[init ERROR] CHILD cannot exec KSH" ); display_string( string ); } } else // we are in INIT process { // INIT display new KSH process PID snprintf( string , 64 , "[init] re-created KSH / pid = %x", ret_fork ); display_string( string ); } } // end KSH kill handling } // end while waiting KSH[i] termination } // end main()