/////////////////////////////////////////////////////////////////////////////////////// // 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 terminal). // Then calls the wait() function to block, and reactivate any child KSH process // that has been deleted, using a new fork/exec. // It includes the hard_config.h file to get th NB_TXT_CHANNELS parameter. /////////////////////////////////////////////////////////////////////////////////////// #include #include #include #include #define DEBUG_PROCESS_INIT 0 // TODO make the cxy computation portable [AG] #define CXY_FROM_XY( x , y ) ((x<<4) + y) ////////// int main() { 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 // check number of TXT channels assert( NB_TXT_CHANNELS > 1 ); // create the KSH processes (one per user terminal) for( i = 1 ; i < NB_TXT_CHANNELS ; i++ ) { // INIT process fork process CHILD[i] ret_fork = fork(); if( ret_fork < 0 ) // error in fork { // INIT display error message snprintf( string , 64 , "[INIT] cannot fork child[%d] => suicide" , i ); display_string( string ); // INIT suicide exit( 0 ); } else if( ret_fork == 0 ) // we are in CHILD[i] process { // CHILD[i] process exec process KSH[i] ret_exec = exec( "/bin/user/ksh.elf" , NULL , NULL ); if ( ret_exec ) // error in exec { // CHILD[i] display error message snprintf( string , 64 , "[INIT ERROR] CHILD[%d] cannot exec KSH / ret_exec = %d" , i , ret_exec ); display_string( string ); } } else // we are in INIT process { // INIT display CHILD[i] process PID snprintf( string , 64 , "[INIT] created KSH[%d] / pid = %x", i , ret_fork ); display_string( string ); } } #if DEBUG_PROCESS_INIT unsigned int x_size; // number of clusters in a row unsigned int y_size; // number of clusters in a column unsigned int ncores; // number of cores per cluster unsigned int x; // cluster x coordinate unsigned int y; // cluster y coordinate unsigned int cxy; // cluster identifier unsigned int lid; // core local index // get hardware config get_config( &x_size , &y_size , &ncores ); // INIT displays processes and threads in all clusters for( x = 0 ; x < x_size ; x++ ) { for( y = 0 ; y < y_size ; y++ ) { cxy = CXY_FROM_XY( x , y ); display_cluster_processes( cxy ); 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 = exec( "/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 #if DEBUG_PROCESS_INIT // INIT displays processes and threads in all clusters for( x = 0 ; x < x_size ; x++ ) { for( y = 0 ; y < y_size ; y++ ) { cxy = CXY_FROM_XY( x , y ); display_cluster_processes( cxy ); for( lid = 0 ; lid < ncores ; lid++ ) { display_sched( cxy , lid ); } } } #endif } // end while waiting KSH[i] termination } // end main()