///////////////////////////////////////////////////////////////////////////////////////
// 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), and register the corresponding PIDs
//   in the ksh_pid[] array. Then it calls the wait() function to block.
// - It is reactivated when any child KSH process is terminated by a SIGKILL signal,
//   or stopped by a SIGSTOP signal. In case of SIGKILL, it scan all registered KSH 
//   processes and re-creates each killed KSH process, using a new fork/exec.
// It includes the hard_config.h file to get the NB_TXT_CHANNELS parameter.
///////////////////////////////////////////////////////////////////////////////////////

#include <hard_config.h>

#include <stdlib.h>
#include <stdio.h>
#include <pthread.h>

#define NB_KSH  (NB_TXT_CHANNELS - 1)


//////////
int main()
{
    int     i;
    int     ret;           // fork return value  
    int     child_pid;
    int     status;        // used by the wait function
    char    string[64];

    // check number of TXT channels
    assert( NB_TXT_CHANNELS > 1 );

    // create the KSH processes (one per user terminal)
    for( i = 0 ; i <  NB_KSH ; i++ )
    {
        // INIT process fork process CHILD
        ret = fork();

        if( ret < 0 )                            // error in fork
        {
            // display error message on TXT0 terminal 
            display_string( "init process cannot fork\n" );

            // INIT process exit
            exit( 1 );
        }
        else if( ret > 0 )                     // we are in INIT process
        {
            // INIT display string on kernel TXT0
            snprintf( string , 64 , "INIT created KSH[%d]\n" , i );
            display_string( string );

            // INIT process deschedule
            pthread_yield();
        }
        else                                   // we are in CHILD process
        {
            // CHILD process exec process KSH
            if ( exec( "/bin/user/ksh.elf" , NULL , NULL ) )  // CHILD failure
            {
                // display error message on TXT0 terminal
                display_string( "child process cannot exec process ksh\n" );

                // CHILD process exit
                exit( 1 );
            }
            else                                             // child success
            {
                // CHILD process deschedule
                pthread_yield();
            }
        }
    } 

// @@@
display_string( "@@@  INIT process created all KSH processes\n" );
display_process( 0 );
display_sched( 0 , 0 );
// @@@

    // This blocking loop is only for debug, because KSH[i] processes
    // should never be killed, and INIT should never exit the wait() function.
    while( 1 )
    {
        // block on child process termination
        child_pid = wait( &status ); 

        // build a string to report unexpected KSH process termination
        snprintf( string , 64 , "KSH process %x unexpectedly terminated" , child_pid );

        // display string on kernel TXT0 (INIT has no TXT terminal)
        display_string( string ); 
    }

} // end main()

