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

Last change on this file since 588 was 588, checked in by alain, 3 years ago

Introduce a signal based synchro between INIT and KSH processes
to sequencialize multiple KSH[i] processes creation.

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