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

Last change on this file since 640 was 640, checked in by alain, 4 years ago

Remove all RPCs in page-fault handling.

File size: 38.9 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//
[636]8// This user 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    {
[640]402        printf("  usage: display  vmm      cxy      pid      mapping\n"
[626]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    {
[640]418        if( argc != 5 )
[436]419        {
[640]420                    printf("  usage: display vmm cxy pid mapping\n");
[436]421            }
[596]422        else
423        {
424                unsigned int cxy = atoi(argv[2]);
425                unsigned int pid = atoi(argv[3]);
[640]426                unsigned int map = atoi(argv[4]);
[436]427
[640]428            if( display_vmm( cxy , pid , map ) )
[596]429            {
430                printf("  error: no process %x in cluster %x\n", pid , cxy );
431            }
[436]432        }
433    }
[596]434    ///////////////////////////////////////////
[436]435    else if( strcmp( argv[1] , "sched" ) == 0 )
436    {
437        if( argc != 4 )
438        {
439                    printf("  usage: display sched cxy lid\n");
440            }
[596]441        else
442        {
443                unsigned int cxy = atoi(argv[2]);
444                unsigned int lid = atoi(argv[3]);
[436]445
[596]446            if( display_sched( cxy , lid ) )
447            {
448                printf("  error: illegal arguments cxy = %x / lid = %d\n", cxy, lid );
449            }
[436]450        }
451    }
[596]452    /////////////////////////////////////////////
[436]453    else if( strcmp( argv[1] , "process" ) == 0 )
454    {
455        if( argc != 3 )
456        {
457                    printf("  usage: display process cxy\n");
458            }
[596]459        else
460        {
461                unsigned int cxy = atoi(argv[2]);
[436]462
[596]463            if( display_cluster_processes( cxy , 0 ) )
464            {
465                printf("  error: illegal argument cxy = %x\n", cxy );
466            }
[436]467        }
468    }
[596]469    /////////////////////////////////////////
[436]470    else if( strcmp( argv[1] , "txt" ) == 0 )
471    {
472        if( argc != 3 )
473        {
474                    printf("  usage: display txt txt_id\n");
475            }
[596]476        else
477        {
478                unsigned int txtid = atoi(argv[2]);
[436]479
[596]480            if( display_txt_processes( txtid ) )
481            {
482                printf("  error: illegal argument txtid = %d\n", txtid );
483            }
[436]484        }
485    }
[596]486    /////////////////////////////////////////
[436]487    else if( strcmp( argv[1] , "vfs" ) == 0 )
488    {
489        if( argc != 2 )
490        {
491                    printf("  usage: display vfs\n");
492            }
[596]493        else
494        {
495            display_vfs();
496        }
[436]497    }
[596]498    //////////////////////////////////////////
[436]499    else if( strcmp( argv[1] , "chdev" ) == 0 )
500    {
501        if( argc != 2 )
502        {
503                    printf("  usage: display chdev\n");
504            }
[596]505        else
506        {
507            display_chdev();
508        }
[436]509    }
[596]510    //////////////////////////////////////////
[445]511    else if( strcmp( argv[1] , "dqdt" ) == 0 )
512    {
513        if( argc != 2 )
514        {
515                    printf("  usage: display dqdt\n");
516            }
[596]517        else
518        {
519            display_dqdt();
520        }
521    }
522    ///////////////////////////////////////////
523    else if( strcmp( argv[1] , "locks" ) == 0 )
524    {
525        if( argc != 4 )
526        {
527                    printf("  usage: display locks pid trdid\n");
528            }
529        else
530        {
531                unsigned int pid   = atoi(argv[2]);
532            unsigned int trdid = atoi(argv[3]);
[445]533
[596]534            if( display_busylocks( pid , trdid ) )
535            {
536                printf("  error: illegal arguments pid = %x / trdid = %x\n", pid, trdid );
537            }
538        }
[445]539    }
[623]540    /////////////////////////////////////////////////
541    else if( strcmp( argv[1] , "barrier" ) == 0 )
542    {
543        if( argc != 3 )
544        {
545                    printf("  usage: display barrier pid\n");
546            }
547        else
548        {
549                unsigned int pid   = atoi(argv[2]);
550
551            if( display_barrier( pid ) )
552            {
553                printf("  error: illegal arguments pid = %x\n", pid );
554            }
555        }
556    }
[611]557    ///////////////////////////////////////////
558    else if( strcmp( argv[1] , "mapper" ) == 0 )
559    {
560        if( argc != 5 )
561        {
562                    printf("  usage: display mapper path page_id nbytes\n");
563            }
564        else
565        {
566                unsigned int page_id   = atoi(argv[3]);
567            unsigned int nbytes    = atoi(argv[4]);
568
569            if( display_mapper( argv[2] , page_id, nbytes ) )
570            {
571                printf("  error: cannot display page %d of mapper %s\n", page_id, argv[2] );
572            }
573        }
574    }
[626]575    ///////////////////////////////////////////
576    else if( strcmp( argv[1] , "fat" ) == 0 )
577    {
578        if( argc != 4 )
579        {
580                    printf("  usage: display fat page_id nb_entries\n");
581            }
582        else
583        {
584                unsigned int page_id    = atoi(argv[2]);
585            unsigned int nb_entries = atoi(argv[3]);
586
587            if( display_fat( page_id, nb_entries ) )
588            {
589                printf("  error: cannot display page %d of fat\n", page_id );
590            }
591        }
592    }
[436]593    else
594    {
[596]595        printf("  error: undefined display request : %s\n", argv[1] ); 
596    }       
[457]597
598    // release semaphore to get next command
599    sem_post( &semaphore );
600
[436]601} // end cmd_display()
602
[427]603/////////////////////////////////////////
604static void cmd_fg(int argc, char **argv)
605{
606        unsigned int pid;
607
608        if (argc != 2) 
609    {
610                printf("  usage: %s pid\n", argv[0]);
611        }
[596]612    else
[427]613    {
[596]614        pid = atoi( argv[1] );   
[427]615
[596]616        if( pid == 0 )
617        { 
618                    printf("  error: PID cannot be 0\n" );
619            }
620        else if( fg( pid ) )
621        {
622                    printf("  error: cannot find process %x\n", pid );
623            }
624    }
[457]625
626    // release semaphore to get next command
627    sem_post( &semaphore );
628
[436]629}  // end cmd_fg()
[427]630
[407]631//////////////////////////////////////////////
632static void cmd_help( int argc , char **argv )
[230]633{
[407]634        unsigned int i;
[230]635
[407]636        if (argc != 1) 
637    {
[409]638                printf("  usage: %s\n", argv[0]);
[230]639        }
[596]640    else
[407]641    {
[619]642        printf("available commands:\n");
643            for (i = 0 ; command[i].name ; i++) 
[596]644        {
[619]645                    printf("\t%s\t : %s\n", command[i].name , command[i].desc);
[596]646            }
647    }
[457]648
649    // release semaphore to get next command
650    sem_post( &semaphore );
651
[407]652}   // end cmd_help()
[230]653
[407]654//////////////////////////////////////////////
655static void cmd_kill( int argc , char **argv )
[230]656{
[407]657        unsigned int pid;
[230]658
[407]659        if (argc != 2) 
660    {
[409]661                printf("  usage: %s pid\n", argv[0]);
[230]662        }
[596]663    else
664    {
665            pid = atoi( argv[1] );
[230]666
[596]667        if( pid == 0 )
668        {
669                    printf("  error: kernel process 0 cannot be killed\n" );
670            }
[230]671
[596]672            else if( kill( pid , SIGKILL ) )
673        {
674                    printf("  error: process %x cannot be killed\n", pid );
675            }
676    }
[427]677
[457]678    // release semaphore to get next command
679    sem_post( &semaphore );
680
[407]681}   // end cmd_kill()
[230]682
[407]683//////////////////////////////////////////////
684static void cmd_load( int argc , char **argv )
[230]685{
[436]686        int                  ret_fork;           // return value from fork
687        int                  ret_exec;           // return value from exec
688    unsigned int         ksh_pid;            // KSH process PID
689    unsigned int         background;         // background execution if non zero
[588]690    unsigned int         placement;          // placement specified if non zero
691    unsigned int         cxy;                // target cluster if placement specified
[407]692
[619]693#if DEBUG_CMD_LOAD
[635]694snprintf( string , 128 , "[ksh] enter %s" , __FUNCTION__);
695display_string( string );
[619]696#endif
697
[588]698        if( (argc < 2) || (argc > 4) ) 
[407]699    {
[588]700                printf("  usage: %s pathname [cxy] [&]\n", argv[0] );
[407]701        }
[596]702    else
703    {
[625]704            strcpy( pathname , argv[1] );
[407]705
[596]706        if( argc == 2 )
[588]707        {
[596]708            background = 0;
[588]709            placement  = 0;
710            cxy        = 0;
711        }
[596]712        else if( argc == 3 )
[588]713        {
[596]714            if( (argv[2][0] == '&') && (argv[2][1] == 0) )
715            {
716                background = 1;
717                placement  = 0;
718                cxy        = 0;
719            }
720            else 
721            {
722                background = 0;
723                placement  = 1;
724                cxy        = atoi( argv[2] );
725            }
726        }
727        else  // argc == 4
728        { 
729            background = ( (argv[3][0] == '&') && (argv[3][1] == 0) );
[588]730            placement  = 1;
731            cxy        = atoi( argv[2] );
732        }
[427]733
[596]734        // get KSH process PID
735        ksh_pid = getpid();
[407]736
[611]737#if DEBUG_CMD_LOAD
[635]738snprintf( string , 128 , "[ksh] %s : <%s> / bg %d / place %d / cxy %x",
739__FUNCTION__, argv[1], background, placement, cxy );
[619]740display_string( string );
[457]741#endif
742
[596]743        // set target cluster if required
744        if( placement ) place_fork( cxy );
[588]745
[596]746        // KSH process fork CHILD process
747            ret_fork = fork();
[434]748
[596]749        if ( ret_fork < 0 )     // it is a failure reported to KSH
750        {
751            printf("  error: ksh process unable to fork\n");
752        }
753        else if (ret_fork == 0) // it is the CHILD process
754        {
[469]755
[611]756#if DEBUG_CMD_LOAD
[635]757snprintf( string , 128 , "[ksh] %s : child (%x) after fork, before exec",
[619]758__FUNCTION__ , getpid() );
759display_string( string );
[469]760#endif
761
[596]762            // CHILD process exec NEW process
763            ret_exec = execve( pathname , NULL , NULL );
[434]764
[611]765#if DEBUG_CMD_LOAD
[635]766snprintf( string , 128 , "[ksh] %s : child (%x) after exec / ret_exec %x",
[619]767__FUNCTION__ , getpid(), ret_exec );
768display_string( string );
[469]769#endif
770
[596]771            // this is only executed in case of exec failure
772            if( ret_exec )
773            {
774                printf("  error: child process unable to exec <%s>\n", pathname );
775                exit( 0 );
776            }   
777            } 
778        else                    // it is the KSH process : ret_fork is the new process PID
[409]779        {
[436]780
[611]781#if DEBUG_CMD_LOAD
[635]782snprintf( string , 128 , "[ksh] %s : ksh (%x) after fork / ret_fork %x",
[619]783__FUNCTION__, getpid(), ret_fork );
784display_string( string );
[457]785#endif
[625]786            // when the new process is launched in background, the KSH process
787            // takes the TXT ownership, and release the semaphore to get the next command.
788            // Otherwise, the child process keep the TXT ownership, and the semaphore will
789            // be released by the KSH main thread when the child process exit
[457]790
[619]791            if( background )    //  KSH must keep TXT ownership
[596]792            {
[619]793                // get back the TXT ownership
[596]794                fg( ksh_pid );
[619]795
796                // release semaphore to get next command
797                sem_post( &semaphore );
[596]798            }
[457]799        }
[436]800    }
[407]801}   // end cmd_load
802
803/////////////////////////////////////////////
804static void cmd_log( int argc , char **argv )
805{
806        unsigned int i;
807
[473]808        if (argc != 1)
809    {
810                printf("  usage: %s\n", argv[0], argc ); 
811        }
[596]812    else
[407]813    {
[596]814            printf("--- registered commands ---\n");
815            for (i = 0; i < LOG_DEPTH; i++) 
816        {
817                    printf(" - %d\t: %s\n", i, &log_entries[i].buf);
818            }
819    }
[230]820
[457]821    // release semaphore to get next command
822    sem_post( &semaphore );
823
824} // end cmd_log()
825
826
[407]827////////////////////////////////////////////
828static void cmd_ls( int argc , char **argv )
[230]829{
[611]830    struct dirent  * entry;
831    DIR            * dir;
[230]832
[619]833#if DEBUG_CMD_LS
[635]834snprintf( string , 128 , "[ksh] enter %s" , __FUNCTION__);
835display_string( string );
[619]836#endif
837
[612]838        if (argc > 2 )
[407]839    {
[596]840                printf("  usage: ls [path]\n");
[407]841        }
[596]842    else
[407]843    {
[612]844        // handle case with no argument
[230]845
[611]846        // get target directory path
[612]847        if ( argc == 1 ) strcpy( pathname , "." );
[625]848        else             strcpy( pathname , argv[1] );
[611]849
850        // open target directory
851            dir = opendir( pathname );
852
853#if DEBUG_CMD_LS
[635]854snprintf( string , 128 , "[ksh] %s : directory <%s> open / DIR %x\n",
[611]855__FUNCTION__, pathname , dir );
[619]856display_string( string );
[611]857#endif
858
859        if( dir == NULL)
860            {
861                    printf("  error : directory <%s> not found\n", pathname );
[623]862
863            sem_post( &semaphore );
864            return;
[611]865            }
866
867        // loop on directory entries   
868        while ( (entry = readdir(dir)) != NULL )
869            {
[612]870                    printf("%s\n", entry->d_name);
[611]871            }
872
873        // close target directory
874            closedir( dir );
875
876#if DEBUG_CMD_LS
[635]877snprintf( string , 128 , "[ksh] %s : directory <%s> closed\n",
[611]878__FUNCTION__, pathname );
[619]879display_string( string );
[611]880#endif
881
[596]882    }
[230]883
[457]884    // release semaphore to get next command
885    sem_post( &semaphore );
886
887} // end cmd_ls()
888
[407]889///////////////////////////////////////////////
890static void cmd_mkdir( int argc , char **argv )
[230]891{
[407]892        if (argc != 2)
893    {
[409]894                printf("  usage: mkdir pathname\n");
[230]895        }
[596]896    else
897    {
[625]898        strcpy( pathname , argv[1] );
[230]899
[610]900        mkdir( pathname , 0x777 );
[596]901    }
[230]902
[457]903    // release semaphore to get next command
904    sem_post( &semaphore );
905
906} // end cmd_mkdir()
907
[407]908////////////////////////////////////////////
909static void cmd_mv( int argc , char **argv )
[230]910{
[610]911        if (argc != 3) 
912    {
913                printf("  usage: mv old_pathname new_pathname\n");
[230]914        }
[596]915    else
916    {
[625]917        strcpy( pathname , argv[1] );
918        strcpy( pathnew  , argv[2] );
[610]919
920        // call the relevant syscall
[625]921        if( rename( pathname , pathnew ) )
[610]922        {
[625]923            printf("  error: unable to rename <%s> to <%s>\n", pathname , pathnew );
[610]924        }
[596]925    }
[610]926
[457]927    // release semaphore to get next command
928    sem_post( &semaphore );
[407]929
[457]930}  // end cmd_mv
[230]931
[588]932
933////////////////////////////////////////////
934static void cmd_ps( int argc , char **argv )
935{
936    unsigned int x_size;
937    unsigned int y_size;
938    unsigned int ncores;
939    unsigned int x;
940    unsigned int y;
941
[619]942#if DEBUG_CMD_PS
[635]943snprintf( string , 128 , "[ksh] enter %s" , __FUNCTION__);
944display_string( string );
[619]945#endif
946
[588]947        if (argc != 1)
948    {
949                printf("  usage: %s\n", argv[0]);
950        }
[596]951    else
952    {
953        // get platform config
954        get_config( &x_size , &y_size , &ncores );
[588]955
[596]956        // scan all clusters
957        for( x = 0 ; x < x_size ; x++ )
[588]958        {
[596]959            for( y = 0 ; y < y_size ; y++ )
960            {
[619]961
962#if DEBUG_CMD_PS
[635]963snprintf( string , 128 , "\n[ksh] %s : call display_cluster_process()", __FUNCTION__ );
[619]964display_string( string );
965#endif
966
[596]967                // display only owned processes
968                display_cluster_processes( HAL_CXY_FROM_XY(x,y), 1 ); 
969            }
[588]970        }
971    }
972
973    // release semaphore to get next command
974    sem_post( &semaphore );
975
976}  // end cmd_ps()
977
[407]978/////////////////////////////////////////////
979static void cmd_pwd( int argc , char **argv )
[230]980{
[407]981        if (argc != 1)
982    {
[473]983                printf("  usage: %s\n", argv[0]);
[407]984        }
985    else 
986    {
[625]987        if ( getcwd( pathname , PATH_MAX_SIZE ) ) 
[596]988        {
989                    printf("  error: unable to get current directory\n");
990            }
991        else 
992        {
[625]993                    printf("%s\n", pathname );
[596]994            }
995    }
[407]996
[457]997    // release semaphore to get next command
998    sem_post( &semaphore );
999
1000}  // end cmd_pwd()
1001
[407]1002////////////////////////////////////////////
1003static void cmd_rm( int argc , char **argv )
1004{
1005        if (argc != 2)
1006    {
[473]1007                printf("  usage: %s pathname\n", argv[0]);
[230]1008        }
[596]1009    else
1010    {
[625]1011            strcpy( pathname , argv[1] );
[230]1012
[608]1013        if ( unlink( pathname ) )
1014        {
[611]1015                    printf("  error: unable to remove <%s>\n", pathname );
[608]1016            }
[596]1017    }
[230]1018
[457]1019    // release semaphore to get next command
1020    sem_post( &semaphore );
[230]1021
[457]1022}  // end_cmd_rm()
1023
[407]1024///////////////////////////////////////////////
1025static void cmd_rmdir( int argc , char **argv )
[230]1026{
[457]1027    // same as cmd_rm()
[625]1028        cmd_rm (argc , argv );
[230]1029}
1030
[442]1031///////////////////////////////////////////////
1032static void cmd_trace( int argc , char **argv )
1033{
1034    unsigned int cxy;
1035    unsigned int lid;
1036
1037        if (argc != 3)
1038    {
1039                printf("  usage: trace cxy lid \n");
1040        }
[596]1041    else
1042    {
1043        cxy = atoi(argv[1]);
1044        lid = atoi(argv[2]);
[442]1045
[596]1046        if( trace( 1 , cxy , lid ) )
1047        {
1048            printf("  error: core[%x,%d] not found\n", cxy, lid );
1049        }
[442]1050    }
1051
[457]1052    // release semaphore to get next command
1053    sem_post( &semaphore );
1054
1055}  // end cmd_trace
1056
[442]1057///////////////////////////////////////////////
1058static void cmd_untrace( int argc , char **argv )
1059{
1060    unsigned int cxy;
1061    unsigned int lid;
1062
1063        if (argc != 3)
1064    {
1065                printf("  usage: untrace cxy lid \n");
1066        }
[596]1067    else
1068    {
1069        cxy = atoi(argv[1]);
1070        lid = atoi(argv[2]);
[442]1071
[596]1072        if( trace( 0 , cxy , lid ) )
1073        {
1074            printf("  error: core[%x,%d] not found\n", cxy, lid );
1075        }
[442]1076    }
1077
[457]1078    // release semaphore to get next command
1079    sem_post( &semaphore );
1080
1081}  // end cmd_untrace()
1082
1083///////////////////////////////////////////////////////////////////////////////////
[407]1084// Array of commands
[457]1085///////////////////////////////////////////////////////////////////////////////////
[230]1086
[619]1087ksh_cmd_t command[] =
[230]1088{
[435]1089        { "cat",     "display file content",                            cmd_cat     },
1090        { "cd",      "change current directory",                        cmd_cd      },
1091        { "cp",      "replicate a file in file system",                 cmd_cp      },
1092    { "fg",      "put a process in foreground",                     cmd_fg      },
1093    { "display", "display vmm/sched/process/vfs/chdev/txt",         cmd_display },
1094        { "load",    "load an user application",                        cmd_load    },
1095        { "help",    "list available commands",                         cmd_help    },
[457]1096        { "kill",    "kill a process (all threads)",                    cmd_kill    },
[435]1097        { "log",     "list registered commands",                        cmd_log     },
1098        { "ls",      "list directory entries",                          cmd_ls      },
1099        { "mkdir",   "create a new directory",                          cmd_mkdir   },
1100        { "mv",      "move a file in file system",                      cmd_mv      },
1101        { "pwd",     "print current working directory",                 cmd_pwd     },
[588]1102        { "ps",      "display all processes",                           cmd_ps      },
[435]1103        { "rm",      "remove a file from file system",                  cmd_rm      },
1104        { "rmdir",   "remove a directory from file system",             cmd_rmdir   },
[442]1105        { "trace",   "activate trace for a given core",                 cmd_trace   },
1106        { "untrace", "desactivate trace for a given core",              cmd_untrace },
[435]1107        { NULL,      NULL,                                                                              NULL        }
[230]1108};
1109
[407]1110////////////////////////////////////////////////////////////////////////////////////
[457]1111// This function analyses one command (with arguments), executes it, and returns.
[407]1112////////////////////////////////////////////////////////////////////////////////////
[625]1113static void __attribute__ ((noinline)) execute( char * buf )
[230]1114{
[619]1115        int    argc = 0;
1116        char * argv[MAX_ARGS];
1117        int    i;
1118        int    len = strlen(buf);
[230]1119
[625]1120#if DEBUG_EXECUTE
[635]1121snprintf( string , 128 , "[ksh] enter %s for command <%s>" , __FUNCTION__ , buf );
1122display_string( string );
[619]1123#endif
1124
[230]1125        // build argc/argv
[407]1126        for (i = 0; i < len; i++) 
1127    {
[619]1128        // convert SPACE to NUL
[407]1129                if (buf[i] == ' ') 
1130        {
[230]1131                        buf[i] = '\0';
[407]1132                }
1133        else if (i == 0 || buf[i - 1] == '\0') 
1134        {
1135                        if (argc < MAX_ARGS) 
1136            {
[230]1137                                argv[argc] = &buf[i];
1138                                argc++;
1139                        }
1140                }
1141        }
1142
[625]1143    // check command
1144        if (argc == 0)
1145    {
1146        // release semaphore to get next command
1147        sem_post( &semaphore );
1148    }
1149
1150#if DEBUG_EXECUTE
[635]1151snprintf( string , 128 , "\n[ksh] in %s : argc = %d / arg0 = %s / arg1 = %s\n",
[625]1152__FUNCTION__ , argc , argv[0], argv[1] );
[619]1153#endif
1154
[625]1155    // scan the list of commands to match typed command
1156    int found = 0;
1157    for ( i = 0 ; (command[i].name != NULL) && (found == 0) ; i++ )
[407]1158    {
[625]1159        if (strcmp(argv[0], command[i].name) == 0)
[407]1160        {
[625]1161                        command[i].fn(argc, argv);
1162                        found = 1;
[230]1163                }
[625]1164    }
[230]1165
[625]1166    // check undefined command
1167        if (!found) 
1168    {   
1169        printf("  error : undefined command <%s>\n", argv[0]);
[457]1170
[625]1171        // release semaphore to get next command
1172        sem_post( &semaphore );
[230]1173        }
[625]1174}  // end execute()
[230]1175
[626]1176
1177
[574]1178///////////////////////////////
[503]1179static void interactive( void )
[230]1180{
[469]1181        char           c;                                               // read character
1182    unsigned int   end_command;             // last character found in a command
1183        unsigned int   count;                   // pointer in command buffer
1184        unsigned int   i;                                               // index for loops
1185        unsigned int   state;                   // escape sequence state
[230]1186
[619]1187        char           cmd[CMD_MAX_SIZE];               // buffer for one command
[457]1188
[637]1189/* 1. first direct command
[588]1190if( sem_wait( &semaphore ) )
[469]1191{
[588]1192    printf("\n[ksh error] cannot found semafore\n" );
1193    exit( 1 );
[469]1194}
[588]1195else
1196{
[635]1197    printf("\n[ksh] load bin/user/sort.elf\n");
[588]1198}
[469]1199
[635]1200strcpy( cmd , "load bin/user/sort.elf" );
[625]1201execute( cmd );
[637]1202*/
[625]1203
[628]1204
1205
[638]1206// 2. second direct command
[625]1207if( sem_wait( &semaphore ) )
1208{
1209    printf("\n[ksh error] cannot found semafore\n" );
1210    exit( 1 );
1211}
1212else
1213{
[635]1214    printf("\n[ksh] load bin/user/fft.elf\n");
[625]1215}
1216
[635]1217strcpy( cmd , "load bin/user/fft.elf" );
[625]1218execute( cmd );
[638]1219//
[469]1220
[628]1221
1222
[407]1223        enum fsm_states
1224    {
[457]1225                NORMAL = 0,
1226                ESCAPE = 1,
1227                BRAKET = 2,
[230]1228        };
1229
[457]1230        // This lexical analyser writes one command line in the command buffer.
1231        // It is implemented as a 3 states FSM to handle the following escape sequences:
[230]1232        // - ESC [ A : up arrow
1233        // - ESC [ B : down arrow
1234        // - ESC [ C : right arrow
1235        // - ESC [ D : left arrow
[407]1236        // The three states have the following semantic:
[230]1237        // - NORMAL : no (ESC) character has been found
1238        // - ESCAPE : the character (ESC) has been found
1239        // - BRAKET : the wo characters (ESC,[) have been found
[436]1240
[619]1241    // take the semaphore for the first command
1242    if ( sem_wait( &semaphore ) )
1243    {
1244        printf("\n[ksh error] cannot found semafore\n" );
1245        exit( 1 );
1246    }
1247
1248    // display prompt for the first command
1249    printf("\n[ksh] ");
1250
1251    // external loop on the commands / the interactive thread do not exit this loop
[230]1252        while (1)
1253        {
[457]1254            // initialize command buffer
[625]1255            // memset( cmd , 0x20 , sizeof(cmd) );   // TODO useful ?
[619]1256            count       = 0;
1257            state       = NORMAL;
1258        end_command = 0;
[230]1259
[619]1260#if DEBUG_INTER
1261unsigned int pid = getpid();
[635]1262snprintf( string , 128 , "[ksh] %s : request a new command", __FUNCTION__ );
[619]1263display_string( string );
1264#endif
[407]1265
[457]1266        // internal loop on characters in one command
1267        while( end_command == 0 )
1268        {
1269            // get one character from TXT_RX
1270                c = (char)getchar();
1271
1272            if( c == 0 ) continue;
1273
1274                    if( state == NORMAL )  // we are not in an escape sequence
1275                    {
[230]1276                                if ((c == '\b') || (c == 0x7F))  // backspace => remove one character
1277                                {
[457]1278                                    if (count > 0)
1279                    {
1280                                        printf("\b \b");
1281                                        count--;
1282                                    }
[230]1283                                }
[457]1284                                else if (c == '\n')                  // new line => end of command
[230]1285                                {
[457]1286                                    if (count > 0)               // analyse & execute command
1287                                    {
1288                                            // complete command with NUL character
[619]1289                                            cmd[count] = 0;
[457]1290                        count++;
[625]1291#if DEBUG_INTER
[635]1292snprintf( string , 128 , "[ksh] %s : get command <%s>", __FUNCTION__, cmd );
[625]1293display_string( string );
1294display_vmm( 0 , 2 );
1295#endif
1296                        // register command in log_entries[] array
[619]1297                                            strncpy( log_entries[ptw].buf , cmd , count );
[457]1298                                            log_entries[ptw].count = count;
1299                                            ptw = (ptw + 1) % LOG_DEPTH;
1300                                            ptr = ptw;
[230]1301
[619]1302#if DEBUG_INTER
[625]1303snprintf( string , 128 , "[ksh] %s : execute <%s>", __FUNCTION__, cmd );
[619]1304display_string( string );
1305#endif
[457]1306                        // echo character
1307                        putchar( c );
[230]1308
[625]1309                                            // execute command
1310                                            execute( cmd );
[457]1311                                    }
1312                    else                         // no command registered
[441]1313                    {
[457]1314                        // release semaphore to get next command
1315                        sem_post( &semaphore );
[441]1316                    }
[457]1317
1318                    // exit internal loop on characters
1319                    end_command = 1;
1320                }
1321                            else if (c == '\t')             // tabulation => do nothing
1322                                {
1323                            }
1324                            else if (c == (char)0x1B)       // ESC => start an escape sequence
1325                            {
1326                    state = ESCAPE;
1327                            }
1328                            else                                               // normal character
[230]1329                                {
[619]1330                                    if (count < (sizeof(cmd) - 1) )
[457]1331                                    {
1332                        // register character in command buffer
[619]1333                                            cmd[count] = c;
[457]1334                                            count++;
1335
1336                        // echo character
1337                        putchar( c );
[230]1338                                        }
[619]1339                    else
1340                    {
1341                                printf("\none command cannot exceed %d characters\n", sizeof(cmd) );
1342                    }
[230]1343                                }
1344                        }
[457]1345                        else if( state == ESCAPE ) 
[230]1346                        {
1347                                if (c == '[')           //  valid sequence => continue
1348                                {
1349                                        state = BRAKET;
1350                                }
1351                                else                               // invalid sequence => do nothing
1352                                {
1353                                        state = NORMAL;
1354                                }
1355                        }
[457]1356                        else if( state == BRAKET )
[230]1357                        {
[619]1358                                if (c == 'D')   // valid  LEFT sequence => move cmd pointer left
[230]1359                                {
1360                                        if (count > 0)
1361                                        {
1362                                                printf("\b");
1363                                                count--;
1364                                        }
1365
1366                                        // get next user char
1367                                        state = NORMAL;
1368                                }
[619]1369                                else if (c == 'C')   // valid  RIGHT sequence => move cmd pointer right
[230]1370                                {
[619]1371                                        if (count < sizeof(cmd) - 1)
[230]1372                                        {
[619]1373                                                printf("%c", cmd[count]);
[230]1374                                                count++;
1375                                        }
1376
1377                                        // get next user char
1378                                        state = NORMAL;
1379                                }
1380                                else if (c == 'A')   // valid  UP sequence => move log pointer backward
1381                                {
1382                                        // cancel current command
1383                                        for (i = 0; i < count; i++) printf("\b \b");
1384                                        count = 0;
1385
[619]1386                                        // copy log command into cmd
[230]1387                                        ptr = (ptr - 1) % LOG_DEPTH;
[619]1388                                        strcpy(cmd, log_entries[ptr].buf);
[458]1389                                        count = log_entries[ptr].count - 1;
[230]1390
1391                                        // display log command
[619]1392                                        printf("%s", cmd);
[230]1393
1394                                        // get next user char
1395                                        state = NORMAL;
1396                                }
1397                                else if (c == 'B')   // valid  DOWN sequence => move log pointer forward
1398                                {
1399                                        // cancel current command
1400                                        for (i = 0 ; i < count; i++) printf("\b \b");
1401                                        count = 0;
1402
[619]1403                                        // copy log command into cmd
[230]1404                                        ptr = (ptr + 1) % LOG_DEPTH;
[619]1405                                        strcpy(cmd, log_entries[ptr].buf);
[230]1406                                        count = log_entries[ptr].count;
1407
1408                                        // display log command
[619]1409                                        printf("%s", cmd);
[230]1410
1411                                        // get next user char
1412                                        state = NORMAL;
1413                                }
1414                                else                               // other character => do nothing
1415                                {
1416                                        // get next user char
1417                                        state = NORMAL;
1418                                }
1419                        }
[457]1420                }  // end internal while loop on characters
[619]1421
1422#if DEBUG_INTER
[625]1423snprintf( string , 128 , "\n[ksh] %s : complete <%s> command", __FUNCTION__, cmd );
[619]1424display_string( string );
1425#endif
1426
1427        // block interactive thread if KSH loose TXT ownership
1428        if ( sem_wait( &semaphore ) )
1429        {
1430            printf("\n[ksh error] cannot found semafore\n" );
1431            exit( 1 );
1432        }
1433
1434        // display prompt for next command
1435        printf("\n[ksh] ");
1436
[457]1437        }  // end external while loop on commands
[619]1438
[446]1439}  // end interactive()
1440
[574]1441////////////////
[503]1442int main( void )
[446]1443{
1444    unsigned int cxy;             // owner cluster identifier for this KSH process
1445    unsigned int lid;             // core identifier for this KSH main thread
1446    int          status;          // child process termination status
[633]1447    int          parent_pid;      // parent process identifier (i.e. this process)
[457]1448    int          child_pid;       // child process identifier
1449    unsigned int is_owner;        // non-zero if KSH process is TXT owner
[446]1450
1451    // initialize log buffer
1452        memset( &log_entries , 0, sizeof(log_entries));
1453        ptw   = 0;
1454        ptr   = 0;
1455
[457]1456    // get KSH process pid and core
1457    parent_pid = getpid();
[637]1458    get_core_id( &cxy , &lid );
[457]1459
[611]1460#if DEBUG_MAIN
[635]1461snprintf( string , 128 , "\n[ksh] main thread started on core[%x,%d]\n", cxy , lid ); 
1462display_string( string );
[574]1463#endif
1464   
1465    // initializes the semaphore used to synchronize with interactive thread
[469]1466    if ( sem_init( &semaphore , 0 , 1 ) )
1467    {
1468        printf("\n[KSH ERROR] cannot initialize semaphore\n" );
1469        exit( 1 ); 
1470    }
[457]1471
[611]1472#if DEBUG_MAIN
[635]1473snprintf( string , 128 , "\n[ksh] main initialized semaphore\n" ); 
1474display_string( string );
[574]1475#endif
1476   
[446]1477    // initialize interactive thread attributes
1478    attr.attributes = PT_ATTR_DETACH | PT_ATTR_CLUSTER_DEFINED;
1479    attr.cxy        = cxy;
1480
1481    // lauch the interactive thread
1482    pthread_create( &trdid,
1483                    &attr,
1484                    &interactive,   // entry function
1485                    NULL ); 
[611]1486#if DEBUG_MAIN
[635]1487snprintf( string , 128 , "\n[ksh] main thread launched interactive thread %x\n", trdid ); 
1488display_string( string );
[574]1489#endif
[588]1490
1491    // signal INIT process
1492    kill( 1 , SIGCONT );
[446]1493   
1494    // enter infinite loop monitoring children processes termination
1495    while( 1 )
1496    {
[457]1497        // wait children termination
1498        child_pid = wait( &status );
[446]1499
[633]1500        if( DEBUG_MAIN )
1501        {
1502            if(WIFEXITED  (status)) printf("\n[ksh] child process %x exit\n"   ,child_pid);
1503            if(WIFSIGNALED(status)) printf("\n[ksh] child process %x killed\n" ,child_pid);
1504            if(WIFSTOPPED (status)) printf("\n[ksh] child process %x stopped\n",child_pid);
1505        }
[446]1506
[457]1507        // release semaphore if KSH process is TXT owner, to unblock interactive thread
1508        is_fg( parent_pid , &is_owner );
1509        if( is_owner ) sem_post( &semaphore );
[446]1510    }
[436]1511}  // end main()
[230]1512
[446]1513
Note: See TracBrowser for help on using the repository browser.