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

Last change on this file since 576 was 574, checked in by alain, 6 years ago

Cosmetic.

File size: 27.1 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
[457]16// attached to the same TXT terminal as the KSH process itself.
[469]17// A child process can be lauched in foreground or in background:
18// . when the child process is running in foreground, the KSH process loses
19//   the TXT terminal ownership, that is transfered to the child process.
20// . when the child process is running in background: the KSH process keeps
21//   the TXT terminal ownership.
22//
23// A semaphore is used to synchronize the two KSH threads. At each iteration,
24// the interactive thread check the semaphore (with a sem_wait). It blocks
25// and deschedules, if the KSH process loosed the TXT ownership (after a load,
26// or for any other cause. It unblocks with the following policy:
27// . if the command is "not a load", the semaphore is incremented by the
28//   cmd_***() function when the command is completed, to allow the KSH interactive()
29//   function to get the next command in the while loop.   
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>
[445]45#include <almosmkh.h>
[457]46#include <semaphore.h>
[230]47
[407]48#define CMD_MAX_SIZE   (256)    // max number of characters in one command
[436]49#define LOG_DEPTH      (32)     // max number of registered commands
[407]50#define MAX_ARGS           (32)     // max number of arguments in a command
[230]51
[574]52#define MAIN_DEBUG          0
[469]53#define CMD_LOAD_DEBUG      0
[457]54
[469]55//////////////////////////////////////////////////////////////////////////////////////////
[407]56//         Structures
[469]57//////////////////////////////////////////////////////////////////////////////////////////
[230]58
[407]59// one entry in the registered commands array
60typedef struct log_entry_s
61{
62        char          buf[CMD_MAX_SIZE];
63        unsigned int  count;
64}
65log_entry_t;
[230]66
[407]67// one entry in the supported command types array
68typedef struct ksh_cmd_s
69{
70        char * name;
71        char * desc;
72        void   (*fn)( int , char ** );
73}
74ksh_cmd_t;
75
76
[469]77//////////////////////////////////////////////////////////////////////////////////////////
[230]78//         Global Variables
[469]79//////////////////////////////////////////////////////////////////////////////////////////
[230]80
[407]81ksh_cmd_t       cmd[];                    // array of supported commands
[230]82
[407]83log_entry_t     log_entries[LOG_DEPTH];   // array of registered commands
[230]84
[407]85unsigned int    ptw;                      // write pointer in log_entries[]
86unsigned int    ptr;                      // read pointer in log_entries[]
[230]87
[457]88pthread_attr_t  attr;                     // interactive thread attributes
[446]89
[457]90sem_t           semaphore;                // block interactive thread when zero
91
[469]92//////////////////////////////////////////////////////////////////////////////////////////
[230]93//         Shell  Commands
[469]94//////////////////////////////////////////////////////////////////////////////////////////
[230]95
[407]96/////////////////////////////////////////////
97static void cmd_cat( int argc , char **argv )
[230]98{
[407]99        char         * path;
[230]100
[407]101        if (argc != 2) 
102    {
[409]103                printf("  usage: cat pathname\n");
[230]104                return;
105        }
[407]106
[230]107        path = argv[1];
108
[473]109    printf("  error: not implemented yet\n", argc, argv );
[407]110
111/*
112        // open the file
113        fd = open( path , O_RDONLY , 0 );
114        if (fd < 0)
115    {
[409]116                printf("  error: cannot open %s\n", path);
[230]117                goto exit;
118        }
119
[407]120        // get file size
121        if (stat(path, &st) == -1)
122    {
[409]123                printf("  error: cannot stat %s\n", path);
[230]124                goto exit;
125        }
126        if (S_ISDIR(st.st_mode)) {
[409]127                printf("  error: %s is a directory\n", path);
[230]128                goto exit;
129        }
130        size = st.st_size;
131
[407]132        // mmap the file
[230]133        buf = mmap(NULL, size, PROT_READ|PROT_WRITE, MAP_PRIVATE, fd, 0);
134        if (buf == NULL || buf == (char *)-1) {
[409]135                printf("  error: cannot map %s\n", path);
[230]136                goto exit;
137        }
138
[446]139        // set terminating '0'
[230]140        buf[size-1] = 0;
141
[407]142        // display the file content
[230]143        printf("%s", buf);
144
145exit:
[407]146        if (buf != NULL) munmap(buf, size);
147        if (fd >= 0) close(fd);
148*/
[230]149
[457]150    // release semaphore to get next command
151    sem_post( &semaphore );
152
[407]153}   // end cmd_cat()
154
155////////////////////////////////////////////
156static void cmd_cd( int argc , char **argv )
157{
158        char * path;
159
160        if (argc != 2)
161    {
[409]162                printf("  usage: cd pathname\n");
[407]163                return;
164        }
165
166        path = argv[1];
167
[473]168    printf("  error: not implemented yet\n", argc, argv );
[407]169
[457]170    // release semaphore to get next command
171    sem_post( &semaphore );
[407]172
173}   // end cmd_cd()
174
175/////////////////////////////////////////
[230]176static void cmd_cp(int argc, char **argv)
177{
[407]178//      int src_fd = -1, dst_fd = -1;
179//      char *srcpath, *dstpath;
180//      struct stat st;
181//      size_t size, i;
182//      char buf[1024];
[230]183
[407]184        if (argc != 3) 
185    {
[409]186                printf("  usage: cp src_pathname dst_pathname\n");
[230]187                return;
188        }
189
[473]190    printf("  error: not implemented yet\n", argc, argv );
[407]191
192/*
[230]193        srcpath = argv[1];
194        dstpath = argv[2];
195
[407]196        // open the src file
[230]197        src_fd = open(srcpath, O_RDONLY, 0);
198        if (src_fd < 0) {
[409]199                printf("  error: cannot open %s / err = %d\n", srcpath, errno);
[230]200                goto exit;
201        }
202
[407]203        // get file size
[230]204        if (stat(srcpath, &st) == -1) {
[409]205                printf("  error: cannot stat %s\n", srcpath);
[230]206                goto exit;
207        }
208        if (S_ISDIR(st.st_mode)) {
[409]209                printf("  error: %s is a directory\n", srcpath);
[230]210                goto exit;
211        }
212        size = st.st_size;
213
[407]214        // open the dst file
[230]215        dst_fd = open(dstpath, O_CREAT|O_TRUNC|O_RDWR, 0);
216        if (dst_fd < 0) {
[409]217                printf("  error: cannot open %s / err = %d\n", dstpath, errno);
[230]218                goto exit;
219        }
220        if (stat(dstpath, &st) == -1) {
[409]221                printf("  error: cannot stat %s\n", dstpath);
[230]222                goto exit;
223        }
224        if (S_ISDIR(st.st_mode)) {
[409]225                printf("  error: %s is a directory\n", dstpath);
[230]226                goto exit;
227        }
228
229        i = 0;
230        while (i < size)
231        {
232                size_t rlen = (size - i < 1024 ? size - i : 1024);
233                size_t wlen;
234                ssize_t ret;
235
[407]236                // read the source
[230]237                ret = read(src_fd, buf, rlen);
238                if (ret == -1) {
[409]239                        printf("  error: cannot read from file %s\n", srcpath);
[230]240                        goto exit;
241                }
242                rlen = (size_t)ret;
243
[407]244                // write to the destination
[230]245                ret = write(dst_fd, buf, rlen);
246                if (ret == -1) {
[409]247                        printf("  error: cannot write to file %s\n", dstpath);
[230]248                        goto exit;
249                }
250                wlen = (size_t)ret;
251
[407]252                // check
[230]253                if (wlen != rlen) {
[409]254                        printf("  error: cannot write on device\n");
[230]255                        goto exit;
256                }
257
258                i += rlen;
259        }
260
261exit:
[407]262        if (src_fd >= 0) close(src_fd);
263        if (dst_fd >= 0) close(dst_fd);
264*/
[230]265
[457]266    // release semaphore to get next command
267    sem_post( &semaphore );
268
[407]269}   // end cmd_cp()
270
[436]271/////////////////////////////////////////////////
272static void cmd_display( int argc , char **argv )
273{
274    unsigned int  cxy;
275    unsigned int  lid;
276    unsigned int  pid;
277    unsigned int  txt_id;
278
279    if( strcmp( argv[1] , "vmm" ) == 0 )
280    {
[442]281        if( argc != 4 )
[436]282        {
[442]283                    printf("  usage: display vmm cxy pid\n");
[436]284                    return;
285            }
286
[442]287            cxy = atoi(argv[2]);
288            pid = atoi(argv[3]);
[436]289
[442]290        if( display_vmm( cxy , pid ) )
[436]291        {
[442]292            printf("  error: no process %x in cluster %x\n", pid , cxy );
[436]293        }
294    }
295    else if( strcmp( argv[1] , "sched" ) == 0 )
296    {
297        if( argc != 4 )
298        {
299                    printf("  usage: display sched cxy lid\n");
300                    return;
301            }
302
303            cxy = atoi(argv[2]);
304            lid = atoi(argv[3]);
305
306        if( display_sched( cxy , lid ) )
307        {
308            printf("  error: illegal arguments cxy = %x / lid = %d\n", cxy, lid );
309        }
310    }
311    else if( strcmp( argv[1] , "process" ) == 0 )
312    {
313        if( argc != 3 )
314        {
315                    printf("  usage: display process cxy\n");
316                    return;
317            }
318
319            cxy = atoi(argv[2]);
320
321        if( display_cluster_processes( cxy ) )
322        {
323            printf("  error: illegal argument cxy = %x\n", cxy );
324        }
325    }
326    else if( strcmp( argv[1] , "txt" ) == 0 )
327    {
328        if( argc != 3 )
329        {
330                    printf("  usage: display txt txt_id\n");
331                    return;
332            }
333
334            txt_id = atoi(argv[2]);
335
336        if( display_txt_processes( txt_id ) )
337        {
[458]338            printf("  error: illegal argument txt_id = %d\n", txt_id );
[436]339        }
340    }
341    else if( strcmp( argv[1] , "vfs" ) == 0 )
342    {
343        if( argc != 2 )
344        {
345                    printf("  usage: display vfs\n");
346                    return;
347            }
348
349        display_vfs();
350    }
351    else if( strcmp( argv[1] , "chdev" ) == 0 )
352    {
353        if( argc != 2 )
354        {
355                    printf("  usage: display chdev\n");
356                    return;
357            }
358
359        display_chdev();
360    }
[445]361    else if( strcmp( argv[1] , "dqdt" ) == 0 )
362    {
363        if( argc != 2 )
364        {
365                    printf("  usage: display dqdt\n");
366                    return;
367            }
368
369        display_dqdt();
370    }
[436]371    else
372    {
373        printf("  usage: display (vmm/sched/process/vfs/chdev/txt) [arg2] [arg3]\n");
374    }
[457]375
376    // release semaphore to get next command
377    sem_post( &semaphore );
378
[436]379} // end cmd_display()
380
[427]381/////////////////////////////////////////
382static void cmd_fg(int argc, char **argv)
383{
384        unsigned int pid;
385
386        if (argc != 2) 
387    {
388                printf("  usage: %s pid\n", argv[0]);
389                return;
390        }
391
392    pid = atoi( argv[1] );   
393
394    if( pid == 0 )
395    {
[442]396                printf("  error: PID cannot be 0\n" );
[427]397        }
398
399    if( fg( pid ) )
400    {
401                printf("  error: cannot find process %x\n", pid );
402        }
[457]403
404    // release semaphore to get next command
405    sem_post( &semaphore );
406
[436]407}  // end cmd_fg()
[427]408
[407]409//////////////////////////////////////////////
410static void cmd_help( int argc , char **argv )
[230]411{
[407]412        unsigned int i;
[230]413
[407]414        if (argc != 1) 
415    {
[409]416                printf("  usage: %s\n", argv[0]);
[230]417                return;
418        }
419
420        printf("available commands:\n");
[407]421        for (i = 0 ; cmd[i].name ; i++) 
422    {
[230]423                printf("\t%s\t : %s\n", cmd[i].name , cmd[i].desc);
424        }
[457]425
426    // release semaphore to get next command
427    sem_post( &semaphore );
428
[407]429}   // end cmd_help()
[230]430
[407]431//////////////////////////////////////////////
432static void cmd_kill( int argc , char **argv )
[230]433{
[407]434        unsigned int pid;
[230]435
[407]436        if (argc != 2) 
437    {
[409]438                printf("  usage: %s pid\n", argv[0]);
[230]439                return;
440        }
441
[427]442        pid = atoi( argv[1] );
[230]443
[427]444    if( pid == 0 )
445    {
[440]446                printf("  error: kernel process 0 cannot be killed\n" );
[427]447        }
448
[416]449        if( kill( pid , SIGKILL ) )
[407]450    {
[440]451                printf("  error: process %x cannot be killed\n", pid );
[230]452        }
[457]453
454    // release semaphore to get next command
455    sem_post( &semaphore );
456
[407]457}   // end cmd_kill()
[230]458
[407]459//////////////////////////////////////////////
460static void cmd_load( int argc , char **argv )
[230]461{
[436]462        int                  ret_fork;           // return value from fork
463        int                  ret_exec;           // return value from exec
464    unsigned int         ksh_pid;            // KSH process PID
465        char               * pathname;           // path to .elf file
466    unsigned int         background;         // background execution if non zero
[407]467
[427]468        if( (argc < 2) || (argc > 3) ) 
[407]469    {
[469]470                printf("  usage: %s pathname [&] / argc = %d\n", argv[0], argc );  // @@@
[407]471                return;
472        }
473
474        pathname = argv[1];
475
[427]476    if( argc == 3 ) background = (argv[2][0] == '&');
[434]477    else            background = 0;
[427]478
[434]479    // get KSH process PID
480    ksh_pid = getpid();
[407]481
[469]482#if CMD_LOAD_DEBUG
483long long unsigned cycle;
484get_cycle( &cycle );
485printf("\n@@@ %s : KSH PID %x before fork / path %s / background %d / cycle %d\n",
486__FUNCTION__, ksh_pid, argv[1], background, (int)cycle );
[457]487#endif
488
[434]489    // KSH process fork CHILD process
[436]490        ret_fork = fork();
[434]491
[457]492    if ( ret_fork < 0 )     // it is a failure reported to KSH
[407]493    {
[434]494        printf("  error: ksh process unable to fork\n");
[440]495        return;
[434]496    }
[457]497    else if (ret_fork == 0) // it is the CHILD process
[434]498    {
[469]499
500#if CMD_LOAD_DEBUG
501get_cycle( &cycle );
502printf("\n@@@ %s : CHILD_PID %x after fork, before exec / cycle %d\n",
503__FUNCTION__ , getpid(), (int)cycle );
504#endif
505
[434]506        // CHILD process exec NEW process
[444]507        ret_exec = execve( pathname , NULL , NULL );
[434]508
[469]509#if CMD_LOAD_DEBUG
510get_cycle( &cycle );
511printf("\n@@@ %s : CHILD_PID %x after exec / ret_exec %d / cycle %d\n",
512__FUNCTION__ , getpid(), ret_exec, (int)cycle );
513#endif
514
[441]515        // this is only executed in case of exec failure
[436]516        if( ret_exec )
[409]517        {
[441]518            printf("  error: child process unable to exec <%s>\n", pathname );
519            exit( 0 );
[436]520        }   
521        } 
[457]522    else                    // it is the KSH process : ret_fork is the new process PID
[436]523    {
524
[469]525#if CMD_LOAD_DEBUG
526get_cycle( &cycle );
527printf("\n@@@ %s : KSH_PID %x after fork / ret_fork %x / cycle %d\n",
528__FUNCTION__, getpid(), ret_fork, (int)cycle );
[457]529#endif
530
[469]531        if( background )    // child in background =>  KSH must keep TXT ownership
[457]532        {
533            // execve() tranfered TXT ownership to child => give it back to KSH
534            fg( ksh_pid );
535
536            // release semaphore to get next command
537            sem_post( &semaphore );
538        }
[436]539    }
[407]540}   // end cmd_load
541
542/////////////////////////////////////////////
543static void cmd_log( int argc , char **argv )
544{
545        unsigned int i;
546
[473]547        if (argc != 1)
548    {
549                printf("  usage: %s\n", argv[0], argc ); 
550                return;
551        }
552
[230]553        printf("--- registered commands ---\n");
[407]554        for (i = 0; i < LOG_DEPTH; i++) 
555    {
[436]556                printf(" - %d\t: %s\n", i, &log_entries[i].buf);
[230]557        }
558
[457]559    // release semaphore to get next command
560    sem_post( &semaphore );
561
562} // end cmd_log()
563
564
[407]565////////////////////////////////////////////
566static void cmd_ls( int argc , char **argv )
[230]567{
[407]568        char  * path;
[230]569
[407]570//  struct dirent * file;
571//  DIR *dir;
572
573        if (argc == 1)
574    {
[230]575                path = ".";
[407]576        }
577    else if (argc == 2) 
578    {
[230]579                path = argv[1];
[407]580        } 
581    else 
582    {
[409]583                printf("  usage: ls [path]\n");
[230]584                return;
585        }
586
[409]587    printf("  error: not implemented yet\n");
[407]588/*
589        dir = opendir( path );
[230]590        while ((file = readdir(dir)) != NULL)
591        {
592                printf(" %s\n", file->d_name);
593        }
594        closedir(dir);
[407]595*/
[230]596
[457]597    // release semaphore to get next command
598    sem_post( &semaphore );
599
600} // end cmd_ls()
601
[407]602///////////////////////////////////////////////
603static void cmd_mkdir( int argc , char **argv )
[230]604{
[407]605        char * pathname;
[230]606
[407]607        if (argc != 2)
608    {
[409]609                printf("  usage: mkdir pathname\n");
[230]610                return;
611        }
612
[407]613    pathname = argv[1];
[230]614
[409]615    printf("  error: not implemented yet\n");
[230]616
[457]617    // release semaphore to get next command
618    sem_post( &semaphore );
619
620} // end cmd_mkdir()
621
[407]622////////////////////////////////////////////
623static void cmd_mv( int argc , char **argv )
[230]624{
[407]625
[230]626        if (argc < 3)
627        {
628                printf("  usage : %s src_pathname dst_pathname\n", argv[0]);
629                return;
630        }
631
[409]632    printf("  error: not implemented yet\n");
[407]633   
[457]634    // release semaphore to get next command
635    sem_post( &semaphore );
[407]636
[457]637}  // end cmd_mv
[230]638
[407]639/////////////////////////////////////////////
640static void cmd_pwd( int argc , char **argv )
[230]641{
[407]642        char buf[1024];
[230]643
[407]644        if (argc != 1)
645    {
[473]646                printf("  usage: %s\n", argv[0]);
[407]647                return;
648        }
649
650        if ( getcwd( buf , 1024 ) ) 
651    {
[409]652                printf("  error: unable to get current directory\n");
[407]653        }
654    else 
655    {
656                printf("%s\n", buf);
657        }
658
[457]659    // release semaphore to get next command
660    sem_post( &semaphore );
661
662}  // end cmd_pwd()
663
[407]664////////////////////////////////////////////
665static void cmd_rm( int argc , char **argv )
666{
667        char * pathname;
668
669        if (argc != 2)
670    {
[473]671                printf("  usage: %s pathname\n", argv[0]);
[230]672                return;
673        }
674
[407]675        pathname = argv[1];
[230]676
[409]677    printf("  error: not implemented yet\n");
[407]678
[457]679    // release semaphore to get next command
680    sem_post( &semaphore );
[230]681
[457]682}  // end_cmd_rm()
683
[407]684///////////////////////////////////////////////
685static void cmd_rmdir( int argc , char **argv )
[230]686{
[457]687    // same as cmd_rm()
[230]688        cmd_rm(argc, argv);
689}
690
[442]691///////////////////////////////////////////////
692static void cmd_trace( int argc , char **argv )
693{
694    unsigned int cxy;
695    unsigned int lid;
696
697        if (argc != 3)
698    {
699                printf("  usage: trace cxy lid \n");
700                return;
701        }
702
703    cxy = atoi(argv[1]);
704    lid = atoi(argv[2]);
705
706    if( trace( 1 , cxy , lid ) )
707    {
708        printf("  error: core[%x,%d] not found\n", cxy, lid );
709    }
710
[457]711    // release semaphore to get next command
712    sem_post( &semaphore );
713
714}  // end cmd_trace
715
[442]716///////////////////////////////////////////////
717static void cmd_untrace( int argc , char **argv )
718{
719    unsigned int cxy;
720    unsigned int lid;
721
722        if (argc != 3)
723    {
724                printf("  usage: untrace cxy lid \n");
725                return;
726        }
727
728    cxy = atoi(argv[1]);
729    lid = atoi(argv[2]);
730
731    if( trace( 0 , cxy , lid ) )
732    {
733        printf("  error: core[%x,%d] not found\n", cxy, lid );
734    }
735
[457]736    // release semaphore to get next command
737    sem_post( &semaphore );
738
739}  // end cmd_untrace()
740
741///////////////////////////////////////////////////////////////////////////////////
[407]742// Array of commands
[457]743///////////////////////////////////////////////////////////////////////////////////
[230]744
[407]745ksh_cmd_t cmd[] =
[230]746{
[435]747        { "cat",     "display file content",                            cmd_cat     },
748        { "cd",      "change current directory",                        cmd_cd      },
749        { "cp",      "replicate a file in file system",                 cmd_cp      },
750    { "fg",      "put a process in foreground",                     cmd_fg      },
751    { "display", "display vmm/sched/process/vfs/chdev/txt",         cmd_display },
752        { "load",    "load an user application",                        cmd_load    },
753        { "help",    "list available commands",                         cmd_help    },
[457]754        { "kill",    "kill a process (all threads)",                    cmd_kill    },
[435]755        { "log",     "list registered commands",                        cmd_log     },
756        { "ls",      "list directory entries",                          cmd_ls      },
757        { "mkdir",   "create a new directory",                          cmd_mkdir   },
758        { "mv",      "move a file in file system",                      cmd_mv      },
759        { "pwd",     "print current working directory",                 cmd_pwd     },
760        { "rm",      "remove a file from file system",                  cmd_rm      },
761        { "rmdir",   "remove a directory from file system",             cmd_rmdir   },
[442]762        { "trace",   "activate trace for a given core",                 cmd_trace   },
763        { "untrace", "desactivate trace for a given core",              cmd_untrace },
[435]764        { NULL,      NULL,                                                                              NULL        }
[230]765};
766
[407]767////////////////////////////////////////////////////////////////////////////////////
[457]768// This function analyses one command (with arguments), executes it, and returns.
[407]769////////////////////////////////////////////////////////////////////////////////////
[469]770static void __attribute__ ((noinline)) parse( char * buf )
[230]771{
772        int argc = 0;
773        char *argv[MAX_ARGS];
774        int i;
775        int len = strlen(buf);
776
777        // build argc/argv
[407]778        for (i = 0; i < len; i++) 
779    {
780                if (buf[i] == ' ') 
781        {
[230]782                        buf[i] = '\0';
[407]783                }
784        else if (i == 0 || buf[i - 1] == '\0') 
785        {
786                        if (argc < MAX_ARGS) 
787            {
[230]788                                argv[argc] = &buf[i];
789                                argc++;
790                        }
791                }
792        }
793
[469]794    // analyse command type
[407]795        if (argc > 0)
796    {
[230]797                int found = 0;
798
799                argv[argc] = NULL;
800
[407]801                // try to match typed command
[469]802                for (i = 0 ; cmd[i].name ; i++)
[407]803        {
804                        if (strcmp(argv[0], cmd[i].name) == 0)
805            {
[230]806                                cmd[i].fn(argc, argv);
807                                found = 1;
808                                break;
809                        }
810                }
811
[457]812                if (!found)  // undefined command
[407]813        {
[457]814                        printf("  error : undefined command <%s>\n", argv[0]);
815
816            // release semaphore to get next command
817            sem_post( &semaphore );
[230]818                }
819        }
[446]820}  // end parse()
[230]821
[574]822///////////////////////////////
[503]823static void interactive( void )
[230]824{
[469]825        char           c;                                               // read character
826        char           buf[CMD_MAX_SIZE];               // buffer for one command
827    unsigned int   end_command;             // last character found in a command
828        unsigned int   count;                   // pointer in command buffer
829        unsigned int   i;                                               // index for loops
830        unsigned int   state;                   // escape sequence state
[230]831
[574]832/* This can be used to simplify debug, as it avoids interactive mode
[457]833
[574]834for( i=1 ; 1 ; i++ )
[469]835{
836    if( sem_wait( &semaphore ) )
837    {
838        printf("\n[ksh error] cannot found semafore\n" );
839        exit( 1 );
840    }
841    else
842    {
[574]843        printf("\n[ksh] %d for fft\n", i );
[469]844    }
845    strcpy( buf , "load /bin/user/fft.elf" );
846    parse( buf );
847}
848
849*/
850
[407]851        enum fsm_states
852    {
[457]853                NORMAL = 0,
854                ESCAPE = 1,
855                BRAKET = 2,
[230]856        };
857
[457]858        // This lexical analyser writes one command line in the command buffer.
859        // It is implemented as a 3 states FSM to handle the following escape sequences:
[230]860        // - ESC [ A : up arrow
861        // - ESC [ B : down arrow
862        // - ESC [ C : right arrow
863        // - ESC [ D : left arrow
[407]864        // The three states have the following semantic:
[230]865        // - NORMAL : no (ESC) character has been found
866        // - ESCAPE : the character (ESC) has been found
867        // - BRAKET : the wo characters (ESC,[) have been found
[436]868
[457]869    // external loop on the commands
870    // the in teractive thread should not exit this loop
[230]871        while (1)
872        {
[457]873            // initialize command buffer
874            memset( buf, 0x20 , sizeof(buf) );   // TODO useful ?
875            count = 0;
876            state = NORMAL;
[230]877
[469]878        // decrement semaphore, and block if the KSH process is not the TXT owner
879        if ( sem_wait( &semaphore ) )
880        {
881            printf("\n[ksh error] cannot found semafore\n" );
882            exit( 1 );
883        }
[407]884
[457]885        // display prompt on a new line
886        printf("\n[ksh] ");
887 
888        end_command = 0;
889
890        // internal loop on characters in one command
891        while( end_command == 0 )
892        {
893            // get one character from TXT_RX
894                c = (char)getchar();
895
896            if( c == 0 ) continue;
897
898                    if( state == NORMAL )  // we are not in an escape sequence
899                    {
[230]900                                if ((c == '\b') || (c == 0x7F))  // backspace => remove one character
901                                {
[457]902                                    if (count > 0)
903                    {
904                                        printf("\b \b");
905                                        count--;
906                                    }
[230]907                                }
[457]908                                else if (c == '\n')                  // new line => end of command
[230]909                                {
[457]910                                    if (count > 0)               // analyse & execute command
911                                    {
912                                            // complete command with NUL character
913                                            buf[count] = 0;
914                        count++;
[230]915
[457]916                                        // register command in log arrays
917                                            strcpy(log_entries[ptw].buf, buf);
918                                            log_entries[ptw].count = count;
919                                            ptw = (ptw + 1) % LOG_DEPTH;
920                                            ptr = ptw;
[230]921
[457]922                        // echo character
923                        putchar( c );
[230]924
[457]925                                            // call parser to analyse and execute command
926                                            parse( buf );
927                                    }
928                    else                         // no command registered
[441]929                    {
[457]930                        // release semaphore to get next command
931                        sem_post( &semaphore );
[441]932                    }
[457]933
934                    // exit internal loop on characters
935                    end_command = 1;
936                }
937                            else if (c == '\t')             // tabulation => do nothing
938                                {
939                            }
940                            else if (c == (char)0x1B)       // ESC => start an escape sequence
941                            {
942                    state = ESCAPE;
943                            }
944                            else                                               // normal character
[230]945                                {
[457]946                                    if (count < sizeof(buf) - 1)
947                                    {
948                        // register character in command buffer
949                                            buf[count] = c;
950                                            count++;
951
952                        // echo character
953                        putchar( c );
[230]954                                        }
955                                }
956                        }
[457]957                        else if( state == ESCAPE ) 
[230]958                        {
959                                if (c == '[')           //  valid sequence => continue
960                                {
961                                        state = BRAKET;
962                                }
963                                else                               // invalid sequence => do nothing
964                                {
965                                        state = NORMAL;
966                                }
967                        }
[457]968                        else if( state == BRAKET )
[230]969                        {
970                                if (c == 'D')   // valid  LEFT sequence => move buf pointer left
971                                {
972                                        if (count > 0)
973                                        {
974                                                printf("\b");
975                                                count--;
976                                        }
977
978                                        // get next user char
979                                        state = NORMAL;
980                                }
981                                else if (c == 'C')   // valid  RIGHT sequence => move buf pointer right
982                                {
983                                        if (count < sizeof(buf) - 1)
984                                        {
985                                                printf("%c", buf[count]);
986                                                count++;
987                                        }
988
989                                        // get next user char
990                                        state = NORMAL;
991                                }
992                                else if (c == 'A')   // valid  UP sequence => move log pointer backward
993                                {
994                                        // cancel current command
995                                        for (i = 0; i < count; i++) printf("\b \b");
996                                        count = 0;
997
998                                        // copy log command into buf
999                                        ptr = (ptr - 1) % LOG_DEPTH;
1000                                        strcpy(buf, log_entries[ptr].buf);
[458]1001                                        count = log_entries[ptr].count - 1;
[230]1002
1003                                        // display log command
1004                                        printf("%s", buf);
1005
1006                                        // get next user char
1007                                        state = NORMAL;
1008                                }
1009                                else if (c == 'B')   // valid  DOWN sequence => move log pointer forward
1010                                {
1011                                        // cancel current command
1012                                        for (i = 0 ; i < count; i++) printf("\b \b");
1013                                        count = 0;
1014
1015                                        // copy log command into buf
1016                                        ptr = (ptr + 1) % LOG_DEPTH;
1017                                        strcpy(buf, log_entries[ptr].buf);
1018                                        count = log_entries[ptr].count;
1019
1020                                        // display log command
1021                                        printf("%s", buf);
1022
1023                                        // get next user char
1024                                        state = NORMAL;
1025                                }
1026                                else                               // other character => do nothing
1027                                {
1028                                        // get next user char
1029                                        state = NORMAL;
1030                                }
1031                        }
[457]1032                }  // end internal while loop on characters
1033        }  // end external while loop on commands
[446]1034}  // end interactive()
1035
[574]1036////////////////
[503]1037int main( void )
[446]1038{
1039    unsigned int cxy;             // owner cluster identifier for this KSH process
1040    unsigned int lid;             // core identifier for this KSH main thread
1041    int          status;          // child process termination status
[457]1042    int          child_pid;       // child process identifier
[469]1043    int          parent_pid;      // parent process identifier (i.e. this process)
1044    pthread_t    trdid;           // interactive thread identifier (unused)
[457]1045    unsigned int is_owner;        // non-zero if KSH process is TXT owner
[446]1046
1047    // initialize log buffer
1048        memset( &log_entries , 0, sizeof(log_entries));
1049        ptw   = 0;
1050        ptr   = 0;
1051
[457]1052    // get KSH process pid and core
1053    parent_pid = getpid();
[459]1054    get_core( &cxy , &lid );
[457]1055
[574]1056#if MAIN_DEBUG
1057printf("\n[ksh] main started on core[%x,%d]\n", cxy , lid ); 
1058#endif
1059   
1060    // initializes the semaphore used to synchronize with interactive thread
[469]1061    if ( sem_init( &semaphore , 0 , 1 ) )
1062    {
1063        printf("\n[KSH ERROR] cannot initialize semaphore\n" );
1064        exit( 1 ); 
1065    }
[457]1066
[574]1067#if MAIN_DEBUG
1068printf("\n[ksh] main initialized semaphore\n" ); 
1069#endif
1070   
[446]1071    // initialize interactive thread attributes
1072    attr.attributes = PT_ATTR_DETACH | PT_ATTR_CLUSTER_DEFINED;
1073    attr.cxy        = cxy;
1074
1075    // lauch the interactive thread
1076    pthread_create( &trdid,
1077                    &attr,
1078                    &interactive,   // entry function
1079                    NULL ); 
[574]1080#if MAIN_DEBUG
1081printf("\n[ksh] main launched interactive thread => wait children termination\n" ); 
1082#endif
[446]1083   
1084    // enter infinite loop monitoring children processes termination
1085    while( 1 )
1086    {
[457]1087        // wait children termination
1088        child_pid = wait( &status );
[446]1089
[574]1090#if MAIN_DEBUG
1091if( WIFEXITED  (status) ) printf("\n[ksh] child process %x exit\n"   , child_pid );
1092if( WIFSIGNALED(status) ) printf("\n[ksh] child process %x killed\n" , child_pid );
1093if( WIFSTOPPED (status) ) printf("\n[ksh] child process %x stopped\n", child_pid );
[446]1094#endif
1095
[457]1096        // release semaphore if KSH process is TXT owner, to unblock interactive thread
1097        is_fg( parent_pid , &is_owner );
1098        if( is_owner ) sem_post( &semaphore );
1099
[446]1100    }
[436]1101}  // end main()
[230]1102
[446]1103
Note: See TracBrowser for help on using the repository browser.