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

Last change on this file since 625 was 625, checked in by alain, 5 years ago

Fix a bug in the vmm_remove_vseg() function: the physical pages
associated to an user DATA vseg were released to the kernel when
the target process descriptor was in the reference cluster.
This physical pages release should be done only when the page
forks counter value is zero.
All other modifications are cosmetic.

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