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

Last change on this file since 471 was 469, checked in by alain, 6 years ago

1) Introduce the libsemaphore library.
2) Introduce a small libmath library, required by the "fft" application..
3) Introduce the multithreaded "fft" application.
4) Fix a bad synchronisation bug in the Copy-On-Write mechanism.

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