source: trunk/user/ksh/ksh.c @ 635

Last change on this file since 635 was 635, checked in by alain, 16 months ago

This version is a major evolution: The physical memory allocators,
defined in the kmem.c, ppm.c, and kcm.c files have been modified
to support remote accesses. The RPCs that were previously user
to allocate physical memory in a remote cluster have been removed.
This has been done to cure a dead-lock in case of concurrent page-faults.

This version 2.2 has been tested on a (4 clusters / 2 cores per cluster)
TSAR architecture, for both the "sort" and the "fft" applications.

File size: 38.8 KB
RevLine 
[469]1/////////////////////////////////////////////////////////////////////////////////////////
[407]2// File   :  ksh.c
3// Date   :  October 2017
4// Author :  Alain Greiner
[469]5/////////////////////////////////////////////////////////////////////////////////////////
[457]6// This application implements a minimal shell for ALMOS-MKH.
7//
8// This user KSH process contains two POSIX threads:
[446]9// - the "main" thread contains the infinite loop implementing
[574]10//   the children processes termination monitoring, using the wait() syscall.
[469]11// - the "interactive" thread contains the infinite loop implementing the command
12//   interpreter attached to the TXT terminal, and handling one KSH command
13//   per iteration.
[457]14//
[469]15// The children processes are created by the <load> command, and are
[624]16// attached to the same TXT terminal as the parent KSH process.
[626]17// A child process can be launched in foreground or in background:
[624]18// . when the child process is launched in foreground, the KSH process loses
[469]19//   the TXT terminal ownership, that is transfered to the child process.
[624]20// . when the child process is launched in background, the KSH process keeps
[469]21//   the TXT terminal ownership.
22//
[619]23// We use a semaphore to synchronize the two KSH threads. After each command
24// completion, the interactive thread check the TXT ownership (with a sem_wait),
25// and blocks, if the KSH process loosed the TXT ownership (after a load,
26// or for any other cause). It is unblocked with the following policy:
[469]27// . if the command is "not a load", the semaphore is incremented by the
[619]28//   cmd_***() function when the command is completed, to get the next command
29//   in the while loop.   
[469]30// . if the command is a "load without &", the TXT is given to the NEW process by the
31//   execve() syscall, and is released to the KSH process when NEW process terminates.
32//   The KSH process is notified and the KSH main() function increments the semahore
33//   to allow the KSH interactive() function to handle commands.
34// . if the command is a "load with &", the cmd_load() function returns the TXT
35//   to the KSH process and increment the semaphore, when the parent KSH process
36//   returns from the fork() syscall.
37/////////////////////////////////////////////////////////////////////////////////////////
[230]38
39#include <stdio.h>
40#include <stdlib.h>
41#include <string.h>
[444]42#include <sys/wait.h>
43#include <signal.h>
44#include <unistd.h>
[611]45#include <dirent.h>
[445]46#include <almosmkh.h>
[457]47#include <semaphore.h>
[588]48#include <hal_macros.h>
[596]49#include <sys/stat.h>
50#include <sys/mman.h>
51#include <fcntl.h>
[230]52
[407]53#define CMD_MAX_SIZE   (256)    // max number of characters in one command
[436]54#define LOG_DEPTH      (32)     // max number of registered commands
[407]55#define MAX_ARGS           (32)     // max number of arguments in a command
[625]56#define PATH_MAX_SIZE  (256)    // max number of characters in a pathname
[230]57
[611]58#define DEBUG_MAIN          0
[619]59#define DEBUG_INTER         0
[625]60#define DEBUG_EXECUTE       0
[624]61#define DEBUG_CMD_CAT       0
[611]62#define DEBUG_CMD_CP        0
63#define DEBUG_CMD_LOAD      0
64#define DEBUG_CMD_LS        0
[619]65#define DEBUG_CMD_PS        0
[457]66
[469]67//////////////////////////////////////////////////////////////////////////////////////////
[407]68//         Structures
[469]69//////////////////////////////////////////////////////////////////////////////////////////
[230]70
[407]71// one entry in the registered commands array
72typedef struct log_entry_s
73{
74        char          buf[CMD_MAX_SIZE];
75        unsigned int  count;
76}
77log_entry_t;
[230]78
[407]79// one entry in the supported command types array
80typedef struct ksh_cmd_s
81{
82        char * name;
83        char * desc;
84        void   (*fn)( int , char ** );
85}
86ksh_cmd_t;
87
88
[469]89//////////////////////////////////////////////////////////////////////////////////////////
[230]90//         Global Variables
[469]91//////////////////////////////////////////////////////////////////////////////////////////
[230]92
[625]93ksh_cmd_t       command[];                  // array of supported commands
[230]94
[625]95log_entry_t     log_entries[LOG_DEPTH];     // array of registered commands
[230]96
[625]97unsigned int    ptw;                        // write pointer in log_entries[]
98unsigned int    ptr;                        // read pointer in log_entries[]
[230]99
[625]100pthread_attr_t  attr;                       // interactive thread attributes
[446]101
[625]102sem_t           semaphore;                  // block interactive thread when zero
[457]103
[625]104pthread_t       trdid;                      // interactive thread identifier
105
106char            pathname[PATH_MAX_SIZE];    // pathname for a file
107
108char            pathnew[PATH_MAX_SIZE];     // used by the rename command
[619]109 
[635]110char            string[128];                // used by snprintf() for debug
111
[469]112//////////////////////////////////////////////////////////////////////////////////////////
[230]113//         Shell  Commands
[469]114//////////////////////////////////////////////////////////////////////////////////////////
[230]115
[407]116/////////////////////////////////////////////
117static void cmd_cat( int argc , char **argv )
[230]118{
[611]119    struct stat    st;
[596]120    int            fd;
121    int            size;
122    char         * buf;
[230]123
[619]124#if DEBUG_CMD_CAT
[635]125snprintf( string , 128 , "[ksh] enter %s" , __FUNCTION__);
126display_string( string );
[619]127#endif
128
[407]129        if (argc != 2) 
130    {
[409]131                printf("  usage: cat pathname\n");
[623]132
133        sem_post( &semaphore );
134            return;
[596]135    }
[407]136
[625]137    strcpy( pathname , argv[1] );
[230]138
[635]139#if DEBUG_CMD_CAT
140snprintf( string , 128 , "[ksh] in %s : after strcpy" , __FUNCTION__ );
141display_string( string );
142#endif
143
[596]144    // open the file
[625]145    fd = open( pathname , O_RDONLY , 0 );
[596]146    if (fd < 0) 
147    {
[625]148            printf("  error: cannot open file <%s>\n", pathname );
[623]149
150        sem_post( &semaphore );
151            return;
[596]152    }
[407]153
[611]154#if DEBUG_CMD_CAT
[635]155snprintf( string , 128 , "[ksh] %s : file %s open", __FUNCTION__, pathname );
[619]156display_string( string );
[596]157#endif
158
159    // get file stats
[625]160    if ( stat( pathname , &st ) == -1)
[407]161    {
[625]162            printf("  error: cannot stat <%s>\n", pathname );
[623]163
164            close(fd);
165        sem_post( &semaphore );
166            return;
[596]167    }
[230]168
[596]169        if ( S_ISDIR(st.st_mode) )
[407]170    {
[625]171            printf("  error: <%s> is a directory\n", pathname );
[623]172
173            close(fd);
174        sem_post( &semaphore );
175            return;
[596]176    }
[230]177
[596]178    // get file size
179    size = st.st_size;
[230]180
[611]181#if DEBUG_CMD_CAT
[635]182snprintf( string , 128 , "[ksh] %s : size = %d", __FUNCTION__, size );
[619]183display_string( string );
[596]184#endif
[230]185
[623]186    if( size == 0 )
187    {
[625]188            printf("  error: size = 0 for <%s>\n", pathname );
[623]189
190            close(fd);
191        sem_post( &semaphore );
192            return;
193    }
194
195    // mapping type is MAP_FILE when MAP_ANON and MAP_REMOTE are not specified
[596]196    buf = mmap( NULL , size , PROT_READ|PROT_WRITE , MAP_PRIVATE , fd , 0 );
[230]197
[596]198    if ( buf == NULL )
199    {
[625]200            printf("  error: cannot map file <%s>\n", pathname );
[623]201
202            close(fd);
203        sem_post( &semaphore );
204            return;
[596]205    }
206
[611]207#if DEBUG_CMD_CAT
[635]208snprintf( string , 128 , "[ksh] %s : maped file %d to buffer %x", __FUNCTION__, fd , buf );
[619]209display_string( string );
[596]210#endif
211
212    // display the file content on TXT terminal
213    write( 1 , buf , size );
214
[623]215    // unmap te file
216    if( munmap( buf , size ) )
217    {
[625]218            printf("  error: cannot unmap file <%s>\n", pathname );
[623]219    }
[596]220
[623]221#if DEBUG_CMD_CAT
[635]222snprintf( string , 128 , "[ksh] %s : unmaped file %d from buffer %x", __FUNCTION__, fd , buf );
[623]223display_string( string );
224#endif
[596]225
[623]226    // close the file
227        if( close( fd ) )
228    {
[625]229            printf("  error: cannot close file <%s>\n", pathname );
[623]230    }
[596]231
[457]232    // release semaphore to get next command
233    sem_post( &semaphore );
234
[407]235}   // end cmd_cat()
236
237////////////////////////////////////////////
238static void cmd_cd( int argc , char **argv )
239{
240        if (argc != 2)
241    {
[409]242                printf("  usage: cd pathname\n");
[407]243        }
[596]244    else
245    {
[625]246            strcpy( pathname , argv[1] );
[407]247
[610]248        // call the relevant syscall
[625]249        if( chdir( pathname ) )
[610]250        {
[625]251            printf("  error: cannot found <%s> directory\n", pathname );
[610]252        }
[596]253    }
[407]254
[457]255    // release semaphore to get next command
256    sem_post( &semaphore );
[407]257
258}   // end cmd_cd()
259
260/////////////////////////////////////////
[230]261static void cmd_cp(int argc, char **argv)
262{
[611]263        int          src_fd;
264    int          dst_fd;
265        int          size;          // source file size
266        int          bytes;         // number of transfered bytes
267        char         buf[4096];
268        struct stat  st;
[230]269
[619]270#if DEBUG_CMD_CP
[635]271snprintf( string , 128 , "[ksh] enter %s" , __FUNCTION__);
272display_string( string );
[619]273#endif
274
[407]275        if (argc != 3) 
276    {
[596]277        src_fd = -1;
278        dst_fd = -1;
[409]279                printf("  usage: cp src_pathname dst_pathname\n");
[611]280        goto cmd_cp_exit;
[230]281        }
282
[596]283    // open the src file
[625]284    strcpy( pathname , argv[1] );
285    src_fd = open( pathname , O_RDONLY , 0 );
[230]286
[596]287    if ( src_fd < 0 ) 
288    {
289        dst_fd = -1;
[625]290            printf("  error: cannot open <%s>\n", argv[1] );
[611]291            goto cmd_cp_exit;
[596]292    }
[230]293
[611]294#if DEBUG_CMD_CP
[635]295snprintf( string , 128 , "[ksh] %s : file %s open", __FUNCTION__, argv[1] );
[619]296display_string( string );
[610]297#endif
298
[596]299    // get file stats
[625]300    if ( stat( pathname , &st ) )
[596]301    {
302        dst_fd = -1;
[625]303            printf("  error: cannot stat <%s>\n", argv[1] );
[611]304            goto cmd_cp_exit;
[596]305    }
306
[611]307#if DEBUG_CMD_CP
[635]308snprintf( string , 128 , "[ksh] %s : got stats for %s", __FUNCTION__, argv[1] );
[619]309display_string( string );
[610]310#endif
311
[596]312        if ( S_ISDIR(st.st_mode) )
313    {
314        dst_fd = -1;
[625]315                printf("  error: <%s> is a directory\n", argv[1] );
[611]316                goto cmd_cp_exit;
[230]317        }
[596]318
319    // get src file size
[230]320        size = st.st_size;
321
[407]322        // open the dst file
[625]323    strcpy( pathname , argv[2] );
324        dst_fd = open( pathname , O_CREAT|O_TRUNC|O_RDWR , 0 );
[596]325
326        if ( dst_fd < 0 ) 
327    {
[625]328                printf("  error: cannot open <%s>\n", argv[2] );
[611]329                goto cmd_cp_exit;
[230]330        }
[596]331
[611]332#if DEBUG_CMD_CP
[635]333snprintf( string , 128 , "[ksh] %s : file %s open", __FUNCTION__, argv[2] );
[619]334display_string( string );
[610]335#endif
336
[625]337        if ( stat( pathname , &st ) )
[596]338    {
[625]339                printf("  error: cannot stat <%s>\n", argv[2] );
[611]340                goto cmd_cp_exit;
[230]341        }
[596]342
[611]343#if DEBUG_CMD_CP
[635]344snprintf( string , 128 , "[ksh] %s : got stats for %s", __FUNCTION__, argv[2] );
[619]345display_string( string );
[610]346#endif
347
[596]348        if ( S_ISDIR(st.st_mode ) ) 
349    {
[625]350                printf("  error: <%s> is a directory\n", argv[2] );
[611]351                goto cmd_cp_exit;
[230]352        }
353
[596]354        bytes = 0;
355
356        while (bytes < size)
[230]357        {
[608]358                int len = ((size - bytes) < 4096) ? (size - bytes) : 4096;
[230]359
[407]360                // read the source
[608]361                if ( read( src_fd , buf , len ) != len )
[596]362        {
[625]363                        printf("  error: cannot read from file <%s>\n", argv[1] );
[611]364                        goto cmd_cp_exit;
[230]365                }
366
[611]367#if DEBUG_CMD_CP
[635]368snprintf( string , 128 , "[ksh] %s : read %d bytes from %s", __FUNCTION__, len, argv[1] );
[619]369display_string( string );
[610]370#endif
371
[407]372                // write to the destination
[608]373                if ( write( dst_fd , buf , len ) != len )
[596]374        {
[625]375                        printf("  error: cannot write to file <%s>\n", argv[2] );
[611]376                        goto cmd_cp_exit;
[230]377                }
378
[611]379#if DEBUG_CMD_CP
[635]380snprintf( string , 128 , "[ksh] %s : write %d bytes to %s", __FUNCTION__, len, argv[2] );
[619]381display_string( string );
[610]382#endif
383
[608]384                bytes += len;
[230]385        }
386
[611]387cmd_cp_exit:
[596]388
[407]389        if (src_fd >= 0) close(src_fd);
390        if (dst_fd >= 0) close(dst_fd);
[230]391
[457]392    // release semaphore to get next command
393    sem_post( &semaphore );
394
[407]395}   // end cmd_cp()
396
[436]397/////////////////////////////////////////////////
398static void cmd_display( int argc , char **argv )
399{
[596]400    if( argc < 2 )
[436]401    {
[626]402        printf("  usage: display  vmm      cxy      pid\n"
403               "         display  sched    cxy      lid\n"             
[611]404               "         display  process  cxy\n"             
405               "         display  txt      txtid\n"             
406               "         display  vfs\n"             
407               "         display  chdev\n"             
408               "         display  dqdt\n"             
[626]409               "         display  locks    pid      trdid\n"
[623]410               "         display  barrier  pid\n"
[626]411               "         display  mapper   path     page     nbytes\n"
412               "         display  fat      page     entries\n"
413               "         display  fat      cxy      0\n");
[596]414    }
415    ////////////////////////////////////
416    else if( strcmp( argv[1] , "vmm" ) == 0 )
417    {
[442]418        if( argc != 4 )
[436]419        {
[442]420                    printf("  usage: display vmm cxy pid\n");
[436]421            }
[596]422        else
423        {
424                unsigned int cxy = atoi(argv[2]);
425                unsigned int pid = atoi(argv[3]);
[436]426
[596]427            if( display_vmm( cxy , pid ) )
428            {
429                printf("  error: no process %x in cluster %x\n", pid , cxy );
430            }
[436]431        }
432    }
[596]433    ///////////////////////////////////////////
[436]434    else if( strcmp( argv[1] , "sched" ) == 0 )
435    {
436        if( argc != 4 )
437        {
438                    printf("  usage: display sched cxy lid\n");
439            }
[596]440        else
441        {
442                unsigned int cxy = atoi(argv[2]);
443                unsigned int lid = atoi(argv[3]);
[436]444
[596]445            if( display_sched( cxy , lid ) )
446            {
447                printf("  error: illegal arguments cxy = %x / lid = %d\n", cxy, lid );
448            }
[436]449        }
450    }
[596]451    /////////////////////////////////////////////
[436]452    else if( strcmp( argv[1] , "process" ) == 0 )
453    {
454        if( argc != 3 )
455        {
456                    printf("  usage: display process cxy\n");
457            }
[596]458        else
459        {
460                unsigned int cxy = atoi(argv[2]);
[436]461
[596]462            if( display_cluster_processes( cxy , 0 ) )
463            {
464                printf("  error: illegal argument cxy = %x\n", cxy );
465            }
[436]466        }
467    }
[596]468    /////////////////////////////////////////
[436]469    else if( strcmp( argv[1] , "txt" ) == 0 )
470    {
471        if( argc != 3 )
472        {
473                    printf("  usage: display txt txt_id\n");
474            }
[596]475        else
476        {
477                unsigned int txtid = atoi(argv[2]);
[436]478
[596]479            if( display_txt_processes( txtid ) )
480            {
481                printf("  error: illegal argument txtid = %d\n", txtid );
482            }
[436]483        }
484    }
[596]485    /////////////////////////////////////////
[436]486    else if( strcmp( argv[1] , "vfs" ) == 0 )
487    {
488        if( argc != 2 )
489        {
490                    printf("  usage: display vfs\n");
491            }
[596]492        else
493        {
494            display_vfs();
495        }
[436]496    }
[596]497    //////////////////////////////////////////
[436]498    else if( strcmp( argv[1] , "chdev" ) == 0 )
499    {
500        if( argc != 2 )
501        {
502                    printf("  usage: display chdev\n");
503            }
[596]504        else
505        {
506            display_chdev();
507        }
[436]508    }
[596]509    //////////////////////////////////////////
[445]510    else if( strcmp( argv[1] , "dqdt" ) == 0 )
511    {
512        if( argc != 2 )
513        {
514                    printf("  usage: display dqdt\n");
515            }
[596]516        else
517        {
518            display_dqdt();
519        }
520    }
521    ///////////////////////////////////////////
522    else if( strcmp( argv[1] , "locks" ) == 0 )
523    {
524        if( argc != 4 )
525        {
526                    printf("  usage: display locks pid trdid\n");
527            }
528        else
529        {
530                unsigned int pid   = atoi(argv[2]);
531            unsigned int trdid = atoi(argv[3]);
[445]532
[596]533            if( display_busylocks( pid , trdid ) )
534            {
535                printf("  error: illegal arguments pid = %x / trdid = %x\n", pid, trdid );
536            }
537        }
[445]538    }
[623]539    /////////////////////////////////////////////////
540    else if( strcmp( argv[1] , "barrier" ) == 0 )
541    {
542        if( argc != 3 )
543        {
544                    printf("  usage: display barrier pid\n");
545            }
546        else
547        {
548                unsigned int pid   = atoi(argv[2]);
549
550            if( display_barrier( pid ) )
551            {
552                printf("  error: illegal arguments pid = %x\n", pid );
553            }
554        }
555    }
[611]556    ///////////////////////////////////////////
557    else if( strcmp( argv[1] , "mapper" ) == 0 )
558    {
559        if( argc != 5 )
560        {
561                    printf("  usage: display mapper path page_id nbytes\n");
562            }
563        else
564        {
565                unsigned int page_id   = atoi(argv[3]);
566            unsigned int nbytes    = atoi(argv[4]);
567
568            if( display_mapper( argv[2] , page_id, nbytes ) )
569            {
570                printf("  error: cannot display page %d of mapper %s\n", page_id, argv[2] );
571            }
572        }
573    }
[626]574    ///////////////////////////////////////////
575    else if( strcmp( argv[1] , "fat" ) == 0 )
576    {
577        if( argc != 4 )
578        {
579                    printf("  usage: display fat page_id nb_entries\n");
580            }
581        else
582        {
583                unsigned int page_id    = atoi(argv[2]);
584            unsigned int nb_entries = atoi(argv[3]);
585
586            if( display_fat( page_id, nb_entries ) )
587            {
588                printf("  error: cannot display page %d of fat\n", page_id );
589            }
590        }
591    }
[436]592    else
593    {
[596]594        printf("  error: undefined display request : %s\n", argv[1] ); 
595    }       
[457]596
597    // release semaphore to get next command
598    sem_post( &semaphore );
599
[436]600} // end cmd_display()
601
[427]602/////////////////////////////////////////
603static void cmd_fg(int argc, char **argv)
604{
605        unsigned int pid;
606
607        if (argc != 2) 
608    {
609                printf("  usage: %s pid\n", argv[0]);
610        }
[596]611    else
[427]612    {
[596]613        pid = atoi( argv[1] );   
[427]614
[596]615        if( pid == 0 )
616        { 
617                    printf("  error: PID cannot be 0\n" );
618            }
619        else if( fg( pid ) )
620        {
621                    printf("  error: cannot find process %x\n", pid );
622            }
623    }
[457]624
625    // release semaphore to get next command
626    sem_post( &semaphore );
627
[436]628}  // end cmd_fg()
[427]629
[407]630//////////////////////////////////////////////
631static void cmd_help( int argc , char **argv )
[230]632{
[407]633        unsigned int i;
[230]634
[407]635        if (argc != 1) 
636    {
[409]637                printf("  usage: %s\n", argv[0]);
[230]638        }
[596]639    else
[407]640    {
[619]641        printf("available commands:\n");
642            for (i = 0 ; command[i].name ; i++) 
[596]643        {
[619]644                    printf("\t%s\t : %s\n", command[i].name , command[i].desc);
[596]645            }
646    }
[457]647
648    // release semaphore to get next command
649    sem_post( &semaphore );
650
[407]651}   // end cmd_help()
[230]652
[407]653//////////////////////////////////////////////
654static void cmd_kill( int argc , char **argv )
[230]655{
[407]656        unsigned int pid;
[230]657
[407]658        if (argc != 2) 
659    {
[409]660                printf("  usage: %s pid\n", argv[0]);
[230]661        }
[596]662    else
663    {
664            pid = atoi( argv[1] );
[230]665
[596]666        if( pid == 0 )
667        {
668                    printf("  error: kernel process 0 cannot be killed\n" );
669            }
[230]670
[596]671            else if( kill( pid , SIGKILL ) )
672        {
673                    printf("  error: process %x cannot be killed\n", pid );
674            }
675    }
[427]676
[457]677    // release semaphore to get next command
678    sem_post( &semaphore );
679
[407]680}   // end cmd_kill()
[230]681
[407]682//////////////////////////////////////////////
683static void cmd_load( int argc , char **argv )
[230]684{
[436]685        int                  ret_fork;           // return value from fork
686        int                  ret_exec;           // return value from exec
687    unsigned int         ksh_pid;            // KSH process PID
688    unsigned int         background;         // background execution if non zero
[588]689    unsigned int         placement;          // placement specified if non zero
690    unsigned int         cxy;                // target cluster if placement specified
[407]691
[619]692#if DEBUG_CMD_LOAD
[635]693snprintf( string , 128 , "[ksh] enter %s" , __FUNCTION__);
694display_string( string );
[619]695#endif
696
[588]697        if( (argc < 2) || (argc > 4) ) 
[407]698    {
[588]699                printf("  usage: %s pathname [cxy] [&]\n", argv[0] );
[407]700        }
[596]701    else
702    {
[625]703            strcpy( pathname , argv[1] );
[407]704
[596]705        if( argc == 2 )
[588]706        {
[596]707            background = 0;
[588]708            placement  = 0;
709            cxy        = 0;
710        }
[596]711        else if( argc == 3 )
[588]712        {
[596]713            if( (argv[2][0] == '&') && (argv[2][1] == 0) )
714            {
715                background = 1;
716                placement  = 0;
717                cxy        = 0;
718            }
719            else 
720            {
721                background = 0;
722                placement  = 1;
723                cxy        = atoi( argv[2] );
724            }
725        }
726        else  // argc == 4
727        { 
728            background = ( (argv[3][0] == '&') && (argv[3][1] == 0) );
[588]729            placement  = 1;
730            cxy        = atoi( argv[2] );
731        }
[427]732
[596]733        // get KSH process PID
734        ksh_pid = getpid();
[407]735
[611]736#if DEBUG_CMD_LOAD
[635]737snprintf( string , 128 , "[ksh] %s : <%s> / bg %d / place %d / cxy %x",
738__FUNCTION__, argv[1], background, placement, cxy );
[619]739display_string( string );
[457]740#endif
741
[596]742        // set target cluster if required
743        if( placement ) place_fork( cxy );
[588]744
[596]745        // KSH process fork CHILD process
746            ret_fork = fork();
[434]747
[596]748        if ( ret_fork < 0 )     // it is a failure reported to KSH
749        {
750            printf("  error: ksh process unable to fork\n");
751        }
752        else if (ret_fork == 0) // it is the CHILD process
753        {
[469]754
[611]755#if DEBUG_CMD_LOAD
[635]756snprintf( string , 128 , "[ksh] %s : child (%x) after fork, before exec",
[619]757__FUNCTION__ , getpid() );
758display_string( string );
[469]759#endif
760
[596]761            // CHILD process exec NEW process
762            ret_exec = execve( pathname , NULL , NULL );
[434]763
[611]764#if DEBUG_CMD_LOAD
[635]765snprintf( string , 128 , "[ksh] %s : child (%x) after exec / ret_exec %x",
[619]766__FUNCTION__ , getpid(), ret_exec );
767display_string( string );
[469]768#endif
769
[596]770            // this is only executed in case of exec failure
771            if( ret_exec )
772            {
773                printf("  error: child process unable to exec <%s>\n", pathname );
774                exit( 0 );
775            }   
776            } 
777        else                    // it is the KSH process : ret_fork is the new process PID
[409]778        {
[436]779
[611]780#if DEBUG_CMD_LOAD
[635]781snprintf( string , 128 , "[ksh] %s : ksh (%x) after fork / ret_fork %x",
[619]782__FUNCTION__, getpid(), ret_fork );
783display_string( string );
[457]784#endif
[625]785            // when the new process is launched in background, the KSH process
786            // takes the TXT ownership, and release the semaphore to get the next command.
787            // Otherwise, the child process keep the TXT ownership, and the semaphore will
788            // be released by the KSH main thread when the child process exit
[457]789
[619]790            if( background )    //  KSH must keep TXT ownership
[596]791            {
[619]792                // get back the TXT ownership
[596]793                fg( ksh_pid );
[619]794
795                // release semaphore to get next command
796                sem_post( &semaphore );
[596]797            }
[457]798        }
[436]799    }
[407]800}   // end cmd_load
801
802/////////////////////////////////////////////
803static void cmd_log( int argc , char **argv )
804{
805        unsigned int i;
806
[473]807        if (argc != 1)
808    {
809                printf("  usage: %s\n", argv[0], argc ); 
810        }
[596]811    else
[407]812    {
[596]813            printf("--- registered commands ---\n");
814            for (i = 0; i < LOG_DEPTH; i++) 
815        {
816                    printf(" - %d\t: %s\n", i, &log_entries[i].buf);
817            }
818    }
[230]819
[457]820    // release semaphore to get next command
821    sem_post( &semaphore );
822
823} // end cmd_log()
824
825
[407]826////////////////////////////////////////////
827static void cmd_ls( int argc , char **argv )
[230]828{
[611]829    struct dirent  * entry;
830    DIR            * dir;
[230]831
[619]832#if DEBUG_CMD_LS
[635]833snprintf( string , 128 , "[ksh] enter %s" , __FUNCTION__);
834display_string( string );
[619]835#endif
836
[612]837        if (argc > 2 )
[407]838    {
[596]839                printf("  usage: ls [path]\n");
[407]840        }
[596]841    else
[407]842    {
[612]843        // handle case with no argument
[230]844
[611]845        // get target directory path
[612]846        if ( argc == 1 ) strcpy( pathname , "." );
[625]847        else             strcpy( pathname , argv[1] );
[611]848
849        // open target directory
850            dir = opendir( pathname );
851
852#if DEBUG_CMD_LS
[635]853snprintf( string , 128 , "[ksh] %s : directory <%s> open / DIR %x\n",
[611]854__FUNCTION__, pathname , dir );
[619]855display_string( string );
[611]856#endif
857
858        if( dir == NULL)
859            {
860                    printf("  error : directory <%s> not found\n", pathname );
[623]861
862            sem_post( &semaphore );
863            return;
[611]864            }
865
866        // loop on directory entries   
867        while ( (entry = readdir(dir)) != NULL )
868            {
[612]869                    printf("%s\n", entry->d_name);
[611]870            }
871
872        // close target directory
873            closedir( dir );
874
875#if DEBUG_CMD_LS
[635]876snprintf( string , 128 , "[ksh] %s : directory <%s> closed\n",
[611]877__FUNCTION__, pathname );
[619]878display_string( string );
[611]879#endif
880
[596]881    }
[230]882
[457]883    // release semaphore to get next command
884    sem_post( &semaphore );
885
886} // end cmd_ls()
887
[407]888///////////////////////////////////////////////
889static void cmd_mkdir( int argc , char **argv )
[230]890{
[407]891        if (argc != 2)
892    {
[409]893                printf("  usage: mkdir pathname\n");
[230]894        }
[596]895    else
896    {
[625]897        strcpy( pathname , argv[1] );
[230]898
[610]899        mkdir( pathname , 0x777 );
[596]900    }
[230]901
[457]902    // release semaphore to get next command
903    sem_post( &semaphore );
904
905} // end cmd_mkdir()
906
[407]907////////////////////////////////////////////
908static void cmd_mv( int argc , char **argv )
[230]909{
[610]910        if (argc != 3) 
911    {
912                printf("  usage: mv old_pathname new_pathname\n");
[230]913        }
[596]914    else
915    {
[625]916        strcpy( pathname , argv[1] );
917        strcpy( pathnew  , argv[2] );
[610]918
919        // call the relevant syscall
[625]920        if( rename( pathname , pathnew ) )
[610]921        {
[625]922            printf("  error: unable to rename <%s> to <%s>\n", pathname , pathnew );
[610]923        }
[596]924    }
[610]925
[457]926    // release semaphore to get next command
927    sem_post( &semaphore );
[407]928
[457]929}  // end cmd_mv
[230]930
[588]931
932////////////////////////////////////////////
933static void cmd_ps( int argc , char **argv )
934{
935    unsigned int x_size;
936    unsigned int y_size;
937    unsigned int ncores;
938    unsigned int x;
939    unsigned int y;
940
[619]941#if DEBUG_CMD_PS
[635]942snprintf( string , 128 , "[ksh] enter %s" , __FUNCTION__);
943display_string( string );
[619]944#endif
945
[588]946        if (argc != 1)
947    {
948                printf("  usage: %s\n", argv[0]);
949        }
[596]950    else
951    {
952        // get platform config
953        get_config( &x_size , &y_size , &ncores );
[588]954
[596]955        // scan all clusters
956        for( x = 0 ; x < x_size ; x++ )
[588]957        {
[596]958            for( y = 0 ; y < y_size ; y++ )
959            {
[619]960
961#if DEBUG_CMD_PS
[635]962snprintf( string , 128 , "\n[ksh] %s : call display_cluster_process()", __FUNCTION__ );
[619]963display_string( string );
964#endif
965
[596]966                // display only owned processes
967                display_cluster_processes( HAL_CXY_FROM_XY(x,y), 1 ); 
968            }
[588]969        }
970    }
971
972    // release semaphore to get next command
973    sem_post( &semaphore );
974
975}  // end cmd_ps()
976
[407]977/////////////////////////////////////////////
978static void cmd_pwd( int argc , char **argv )
[230]979{
[407]980        if (argc != 1)
981    {
[473]982                printf("  usage: %s\n", argv[0]);
[407]983        }
984    else 
985    {
[625]986        if ( getcwd( pathname , PATH_MAX_SIZE ) ) 
[596]987        {
988                    printf("  error: unable to get current directory\n");
989            }
990        else 
991        {
[625]992                    printf("%s\n", pathname );
[596]993            }
994    }
[407]995
[457]996    // release semaphore to get next command
997    sem_post( &semaphore );
998
999}  // end cmd_pwd()
1000
[407]1001////////////////////////////////////////////
1002static void cmd_rm( int argc , char **argv )
1003{
1004        if (argc != 2)
1005    {
[473]1006                printf("  usage: %s pathname\n", argv[0]);
[230]1007        }
[596]1008    else
1009    {
[625]1010            strcpy( pathname , argv[1] );
[230]1011
[608]1012        if ( unlink( pathname ) )
1013        {
[611]1014                    printf("  error: unable to remove <%s>\n", pathname );
[608]1015            }
[596]1016    }
[230]1017
[457]1018    // release semaphore to get next command
1019    sem_post( &semaphore );
[230]1020
[457]1021}  // end_cmd_rm()
1022
[407]1023///////////////////////////////////////////////
1024static void cmd_rmdir( int argc , char **argv )
[230]1025{
[457]1026    // same as cmd_rm()
[625]1027        cmd_rm (argc , argv );
[230]1028}
1029
[442]1030///////////////////////////////////////////////
1031static void cmd_trace( int argc , char **argv )
1032{
1033    unsigned int cxy;
1034    unsigned int lid;
1035
1036        if (argc != 3)
1037    {
1038                printf("  usage: trace cxy lid \n");
1039        }
[596]1040    else
1041    {
1042        cxy = atoi(argv[1]);
1043        lid = atoi(argv[2]);
[442]1044
[596]1045        if( trace( 1 , cxy , lid ) )
1046        {
1047            printf("  error: core[%x,%d] not found\n", cxy, lid );
1048        }
[442]1049    }
1050
[457]1051    // release semaphore to get next command
1052    sem_post( &semaphore );
1053
1054}  // end cmd_trace
1055
[442]1056///////////////////////////////////////////////
1057static void cmd_untrace( int argc , char **argv )
1058{
1059    unsigned int cxy;
1060    unsigned int lid;
1061
1062        if (argc != 3)
1063    {
1064                printf("  usage: untrace cxy lid \n");
1065        }
[596]1066    else
1067    {
1068        cxy = atoi(argv[1]);
1069        lid = atoi(argv[2]);
[442]1070
[596]1071        if( trace( 0 , cxy , lid ) )
1072        {
1073            printf("  error: core[%x,%d] not found\n", cxy, lid );
1074        }
[442]1075    }
1076
[457]1077    // release semaphore to get next command
1078    sem_post( &semaphore );
1079
1080}  // end cmd_untrace()
1081
1082///////////////////////////////////////////////////////////////////////////////////
[407]1083// Array of commands
[457]1084///////////////////////////////////////////////////////////////////////////////////
[230]1085
[619]1086ksh_cmd_t command[] =
[230]1087{
[435]1088        { "cat",     "display file content",                            cmd_cat     },
1089        { "cd",      "change current directory",                        cmd_cd      },
1090        { "cp",      "replicate a file in file system",                 cmd_cp      },
1091    { "fg",      "put a process in foreground",                     cmd_fg      },
1092    { "display", "display vmm/sched/process/vfs/chdev/txt",         cmd_display },
1093        { "load",    "load an user application",                        cmd_load    },
1094        { "help",    "list available commands",                         cmd_help    },
[457]1095        { "kill",    "kill a process (all threads)",                    cmd_kill    },
[435]1096        { "log",     "list registered commands",                        cmd_log     },
1097        { "ls",      "list directory entries",                          cmd_ls      },
1098        { "mkdir",   "create a new directory",                          cmd_mkdir   },
1099        { "mv",      "move a file in file system",                      cmd_mv      },
1100        { "pwd",     "print current working directory",                 cmd_pwd     },
[588]1101        { "ps",      "display all processes",                           cmd_ps      },
[435]1102        { "rm",      "remove a file from file system",                  cmd_rm      },
1103        { "rmdir",   "remove a directory from file system",             cmd_rmdir   },
[442]1104        { "trace",   "activate trace for a given core",                 cmd_trace   },
1105        { "untrace", "desactivate trace for a given core",              cmd_untrace },
[435]1106        { NULL,      NULL,                                                                              NULL        }
[230]1107};
1108
[407]1109////////////////////////////////////////////////////////////////////////////////////
[457]1110// This function analyses one command (with arguments), executes it, and returns.
[407]1111////////////////////////////////////////////////////////////////////////////////////
[625]1112static void __attribute__ ((noinline)) execute( char * buf )
[230]1113{
[619]1114        int    argc = 0;
1115        char * argv[MAX_ARGS];
1116        int    i;
1117        int    len = strlen(buf);
[230]1118
[625]1119#if DEBUG_EXECUTE
[635]1120snprintf( string , 128 , "[ksh] enter %s for command <%s>" , __FUNCTION__ , buf );
1121display_string( string );
[619]1122#endif
1123
[230]1124        // build argc/argv
[407]1125        for (i = 0; i < len; i++) 
1126    {
[619]1127        // convert SPACE to NUL
[407]1128                if (buf[i] == ' ') 
1129        {
[230]1130                        buf[i] = '\0';
[407]1131                }
1132        else if (i == 0 || buf[i - 1] == '\0') 
1133        {
1134                        if (argc < MAX_ARGS) 
1135            {
[230]1136                                argv[argc] = &buf[i];
1137                                argc++;
1138                        }
1139                }
1140        }
1141
[625]1142    // check command
1143        if (argc == 0)
1144    {
1145        // release semaphore to get next command
1146        sem_post( &semaphore );
1147    }
1148
1149#if DEBUG_EXECUTE
[635]1150snprintf( string , 128 , "\n[ksh] in %s : argc = %d / arg0 = %s / arg1 = %s\n",
[625]1151__FUNCTION__ , argc , argv[0], argv[1] );
[619]1152#endif
1153
[625]1154    // scan the list of commands to match typed command
1155    int found = 0;
1156    for ( i = 0 ; (command[i].name != NULL) && (found == 0) ; i++ )
[407]1157    {
[625]1158        if (strcmp(argv[0], command[i].name) == 0)
[407]1159        {
[625]1160                        command[i].fn(argc, argv);
1161                        found = 1;
[230]1162                }
[625]1163    }
[230]1164
[625]1165    // check undefined command
1166        if (!found) 
1167    {   
1168        printf("  error : undefined command <%s>\n", argv[0]);
[457]1169
[625]1170        // release semaphore to get next command
1171        sem_post( &semaphore );
[230]1172        }
[625]1173}  // end execute()
[230]1174
[626]1175
1176
[574]1177///////////////////////////////
[503]1178static void interactive( void )
[230]1179{
[469]1180        char           c;                                               // read character
1181    unsigned int   end_command;             // last character found in a command
1182        unsigned int   count;                   // pointer in command buffer
1183        unsigned int   i;                                               // index for loops
1184        unsigned int   state;                   // escape sequence state
[230]1185
[619]1186        char           cmd[CMD_MAX_SIZE];               // buffer for one command
[457]1187
[635]1188/* 1. first direct command
[588]1189if( sem_wait( &semaphore ) )
[469]1190{
[588]1191    printf("\n[ksh error] cannot found semafore\n" );
1192    exit( 1 );
[469]1193}
[588]1194else
1195{
[635]1196    printf("\n[ksh] load bin/user/sort.elf\n");
[588]1197}
[469]1198
[635]1199strcpy( cmd , "load bin/user/sort.elf" );
[625]1200execute( cmd );
[635]1201*/
[625]1202
[628]1203
1204
1205/* 2. second direct command
[625]1206if( sem_wait( &semaphore ) )
1207{
1208    printf("\n[ksh error] cannot found semafore\n" );
1209    exit( 1 );
1210}
1211else
1212{
[635]1213    printf("\n[ksh] load bin/user/fft.elf\n");
[625]1214}
1215
[635]1216strcpy( cmd , "load bin/user/fft.elf" );
[625]1217execute( cmd );
[611]1218*/
[469]1219
[628]1220
1221
[407]1222        enum fsm_states
1223    {
[457]1224                NORMAL = 0,
1225                ESCAPE = 1,
1226                BRAKET = 2,
[230]1227        };
1228
[457]1229        // This lexical analyser writes one command line in the command buffer.
1230        // It is implemented as a 3 states FSM to handle the following escape sequences:
[230]1231        // - ESC [ A : up arrow
1232        // - ESC [ B : down arrow
1233        // - ESC [ C : right arrow
1234        // - ESC [ D : left arrow
[407]1235        // The three states have the following semantic:
[230]1236        // - NORMAL : no (ESC) character has been found
1237        // - ESCAPE : the character (ESC) has been found
1238        // - BRAKET : the wo characters (ESC,[) have been found
[436]1239
[619]1240    // take the semaphore for the first command
1241    if ( sem_wait( &semaphore ) )
1242    {
1243        printf("\n[ksh error] cannot found semafore\n" );
1244        exit( 1 );
1245    }
1246
1247    // display prompt for the first command
1248    printf("\n[ksh] ");
1249
1250    // external loop on the commands / the interactive thread do not exit this loop
[230]1251        while (1)
1252        {
[457]1253            // initialize command buffer
[625]1254            // memset( cmd , 0x20 , sizeof(cmd) );   // TODO useful ?
[619]1255            count       = 0;
1256            state       = NORMAL;
1257        end_command = 0;
[230]1258
[619]1259#if DEBUG_INTER
1260unsigned int pid = getpid();
[635]1261snprintf( string , 128 , "[ksh] %s : request a new command", __FUNCTION__ );
[619]1262display_string( string );
1263#endif
[407]1264
[457]1265        // internal loop on characters in one command
1266        while( end_command == 0 )
1267        {
1268            // get one character from TXT_RX
1269                c = (char)getchar();
1270
1271            if( c == 0 ) continue;
1272
1273                    if( state == NORMAL )  // we are not in an escape sequence
1274                    {
[230]1275                                if ((c == '\b') || (c == 0x7F))  // backspace => remove one character
1276                                {
[457]1277                                    if (count > 0)
1278                    {
1279                                        printf("\b \b");
1280                                        count--;
1281                                    }
[230]1282                                }
[457]1283                                else if (c == '\n')                  // new line => end of command
[230]1284                                {
[457]1285                                    if (count > 0)               // analyse & execute command
1286                                    {
1287                                            // complete command with NUL character
[619]1288                                            cmd[count] = 0;
[457]1289                        count++;
[625]1290#if DEBUG_INTER
[635]1291snprintf( string , 128 , "[ksh] %s : get command <%s>", __FUNCTION__, cmd );
[625]1292display_string( string );
1293display_vmm( 0 , 2 );
1294#endif
1295                        // register command in log_entries[] array
[619]1296                                            strncpy( log_entries[ptw].buf , cmd , count );
[457]1297                                            log_entries[ptw].count = count;
1298                                            ptw = (ptw + 1) % LOG_DEPTH;
1299                                            ptr = ptw;
[230]1300
[619]1301#if DEBUG_INTER
[625]1302snprintf( string , 128 , "[ksh] %s : execute <%s>", __FUNCTION__, cmd );
[619]1303display_string( string );
1304#endif
[457]1305                        // echo character
1306                        putchar( c );
[230]1307
[625]1308                                            // execute command
1309                                            execute( cmd );
[457]1310                                    }
1311                    else                         // no command registered
[441]1312                    {
[457]1313                        // release semaphore to get next command
1314                        sem_post( &semaphore );
[441]1315                    }
[457]1316
1317                    // exit internal loop on characters
1318                    end_command = 1;
1319                }
1320                            else if (c == '\t')             // tabulation => do nothing
1321                                {
1322                            }
1323                            else if (c == (char)0x1B)       // ESC => start an escape sequence
1324                            {
1325                    state = ESCAPE;
1326                            }
1327                            else                                               // normal character
[230]1328                                {
[619]1329                                    if (count < (sizeof(cmd) - 1) )
[457]1330                                    {
1331                        // register character in command buffer
[619]1332                                            cmd[count] = c;
[457]1333                                            count++;
1334
1335                        // echo character
1336                        putchar( c );
[230]1337                                        }
[619]1338                    else
1339                    {
1340                                printf("\none command cannot exceed %d characters\n", sizeof(cmd) );
1341                    }
[230]1342                                }
1343                        }
[457]1344                        else if( state == ESCAPE ) 
[230]1345                        {
1346                                if (c == '[')           //  valid sequence => continue
1347                                {
1348                                        state = BRAKET;
1349                                }
1350                                else                               // invalid sequence => do nothing
1351                                {
1352                                        state = NORMAL;
1353                                }
1354                        }
[457]1355                        else if( state == BRAKET )
[230]1356                        {
[619]1357                                if (c == 'D')   // valid  LEFT sequence => move cmd pointer left
[230]1358                                {
1359                                        if (count > 0)
1360                                        {
1361                                                printf("\b");
1362                                                count--;
1363                                        }
1364
1365                                        // get next user char
1366                                        state = NORMAL;
1367                                }
[619]1368                                else if (c == 'C')   // valid  RIGHT sequence => move cmd pointer right
[230]1369                                {
[619]1370                                        if (count < sizeof(cmd) - 1)
[230]1371                                        {
[619]1372                                                printf("%c", cmd[count]);
[230]1373                                                count++;
1374                                        }
1375
1376                                        // get next user char
1377                                        state = NORMAL;
1378                                }
1379                                else if (c == 'A')   // valid  UP sequence => move log pointer backward
1380                                {
1381                                        // cancel current command
1382                                        for (i = 0; i < count; i++) printf("\b \b");
1383                                        count = 0;
1384
[619]1385                                        // copy log command into cmd
[230]1386                                        ptr = (ptr - 1) % LOG_DEPTH;
[619]1387                                        strcpy(cmd, log_entries[ptr].buf);
[458]1388                                        count = log_entries[ptr].count - 1;
[230]1389
1390                                        // display log command
[619]1391                                        printf("%s", cmd);
[230]1392
1393                                        // get next user char
1394                                        state = NORMAL;
1395                                }
1396                                else if (c == 'B')   // valid  DOWN sequence => move log pointer forward
1397                                {
1398                                        // cancel current command
1399                                        for (i = 0 ; i < count; i++) printf("\b \b");
1400                                        count = 0;
1401
[619]1402                                        // copy log command into cmd
[230]1403                                        ptr = (ptr + 1) % LOG_DEPTH;
[619]1404                                        strcpy(cmd, log_entries[ptr].buf);
[230]1405                                        count = log_entries[ptr].count;
1406
1407                                        // display log command
[619]1408                                        printf("%s", cmd);
[230]1409
1410                                        // get next user char
1411                                        state = NORMAL;
1412                                }
1413                                else                               // other character => do nothing
1414                                {
1415                                        // get next user char
1416                                        state = NORMAL;
1417                                }
1418                        }
[457]1419                }  // end internal while loop on characters
[619]1420
1421#if DEBUG_INTER
[625]1422snprintf( string , 128 , "\n[ksh] %s : complete <%s> command", __FUNCTION__, cmd );
[619]1423display_string( string );
1424#endif
1425
1426        // block interactive thread if KSH loose TXT ownership
1427        if ( sem_wait( &semaphore ) )
1428        {
1429            printf("\n[ksh error] cannot found semafore\n" );
1430            exit( 1 );
1431        }
1432
1433        // display prompt for next command
1434        printf("\n[ksh] ");
1435
[457]1436        }  // end external while loop on commands
[619]1437
[446]1438}  // end interactive()
1439
[574]1440////////////////
[503]1441int main( void )
[446]1442{
1443    unsigned int cxy;             // owner cluster identifier for this KSH process
1444    unsigned int lid;             // core identifier for this KSH main thread
1445    int          status;          // child process termination status
[633]1446    int          parent_pid;      // parent process identifier (i.e. this process)
[457]1447    int          child_pid;       // child process identifier
1448    unsigned int is_owner;        // non-zero if KSH process is TXT owner
[446]1449
1450    // initialize log buffer
1451        memset( &log_entries , 0, sizeof(log_entries));
1452        ptw   = 0;
1453        ptr   = 0;
1454
[457]1455    // get KSH process pid and core
1456    parent_pid = getpid();
[459]1457    get_core( &cxy , &lid );
[457]1458
[611]1459#if DEBUG_MAIN
[635]1460snprintf( string , 128 , "\n[ksh] main thread started on core[%x,%d]\n", cxy , lid ); 
1461display_string( string );
[574]1462#endif
1463   
1464    // initializes the semaphore used to synchronize with interactive thread
[469]1465    if ( sem_init( &semaphore , 0 , 1 ) )
1466    {
1467        printf("\n[KSH ERROR] cannot initialize semaphore\n" );
1468        exit( 1 ); 
1469    }
[457]1470
[611]1471#if DEBUG_MAIN
[635]1472snprintf( string , 128 , "\n[ksh] main initialized semaphore\n" ); 
1473display_string( string );
[574]1474#endif
1475   
[446]1476    // initialize interactive thread attributes
1477    attr.attributes = PT_ATTR_DETACH | PT_ATTR_CLUSTER_DEFINED;
1478    attr.cxy        = cxy;
1479
1480    // lauch the interactive thread
1481    pthread_create( &trdid,
1482                    &attr,
1483                    &interactive,   // entry function
1484                    NULL ); 
[611]1485#if DEBUG_MAIN
[635]1486snprintf( string , 128 , "\n[ksh] main thread launched interactive thread %x\n", trdid ); 
1487display_string( string );
[574]1488#endif
[588]1489
1490    // signal INIT process
1491    kill( 1 , SIGCONT );
[446]1492   
1493    // enter infinite loop monitoring children processes termination
1494    while( 1 )
1495    {
[457]1496        // wait children termination
1497        child_pid = wait( &status );
[446]1498
[633]1499        if( DEBUG_MAIN )
1500        {
1501            if(WIFEXITED  (status)) printf("\n[ksh] child process %x exit\n"   ,child_pid);
1502            if(WIFSIGNALED(status)) printf("\n[ksh] child process %x killed\n" ,child_pid);
1503            if(WIFSTOPPED (status)) printf("\n[ksh] child process %x stopped\n",child_pid);
1504        }
[446]1505
[457]1506        // release semaphore if KSH process is TXT owner, to unblock interactive thread
1507        is_fg( parent_pid , &is_owner );
1508        if( is_owner ) sem_post( &semaphore );
[446]1509    }
[436]1510}  // end main()
[230]1511
[446]1512
Note: See TracBrowser for help on using the repository browser.