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

Last change on this file since 493 was 473, checked in by alain, 6 years ago

Fix several GCC warning related to the -Wextra compilation option.

File size: 27.1 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
48#define CMD_MAX_SIZE   (256)    // max number of characters in one command
49#define LOG_DEPTH      (32)     // max number of registered commands
50#define MAX_ARGS           (32)     // max number of arguments in a command
51#define FIFO_SIZE      (1024)   // FIFO depth for recursive ls
52
53#define KSH_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 ) )
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
469        if( (argc < 2) || (argc > 3) ) 
470    {
471                printf("  usage: %s pathname [&] / argc = %d\n", argv[0], argc );  // @@@
472                return;
473        }
474
475        pathname = argv[1];
476
477    if( argc == 3 ) background = (argv[2][0] == '&');
478    else            background = 0;
479
480    // get KSH process PID
481    ksh_pid = getpid();
482
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 );
488#endif
489
490    // KSH process fork CHILD process
491        ret_fork = fork();
492
493    if ( ret_fork < 0 )     // it is a failure reported to KSH
494    {
495        printf("  error: ksh process unable to fork\n");
496        return;
497    }
498    else if (ret_fork == 0) // it is the CHILD process
499    {
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
507        // CHILD process exec NEW process
508        ret_exec = execve( pathname , NULL , NULL );
509
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
516        // this is only executed in case of exec failure
517        if( ret_exec )
518        {
519            printf("  error: child process unable to exec <%s>\n", pathname );
520            exit( 0 );
521        }   
522        } 
523    else                    // it is the KSH process : ret_fork is the new process PID
524    {
525
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 );
530#endif
531
532        if( background )    // child in background =>  KSH must keep TXT ownership
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        }
540    }
541}   // end cmd_load
542
543/////////////////////////////////////////////
544static void cmd_log( int argc , char **argv )
545{
546        unsigned int i;
547
548        if (argc != 1)
549    {
550                printf("  usage: %s\n", argv[0], argc ); 
551                return;
552        }
553
554        printf("--- registered commands ---\n");
555        for (i = 0; i < LOG_DEPTH; i++) 
556    {
557                printf(" - %d\t: %s\n", i, &log_entries[i].buf);
558        }
559
560    // release semaphore to get next command
561    sem_post( &semaphore );
562
563} // end cmd_log()
564
565
566////////////////////////////////////////////
567static void cmd_ls( int argc , char **argv )
568{
569        char  * path;
570
571//  struct dirent * file;
572//  DIR *dir;
573
574        if (argc == 1)
575    {
576                path = ".";
577        }
578    else if (argc == 2) 
579    {
580                path = argv[1];
581        } 
582    else 
583    {
584                printf("  usage: ls [path]\n");
585                return;
586        }
587
588    printf("  error: not implemented yet\n");
589/*
590        dir = opendir( path );
591        while ((file = readdir(dir)) != NULL)
592        {
593                printf(" %s\n", file->d_name);
594        }
595        closedir(dir);
596*/
597
598    // release semaphore to get next command
599    sem_post( &semaphore );
600
601} // end cmd_ls()
602
603///////////////////////////////////////////////
604static void cmd_mkdir( int argc , char **argv )
605{
606        char * pathname;
607
608        if (argc != 2)
609    {
610                printf("  usage: mkdir pathname\n");
611                return;
612        }
613
614    pathname = argv[1];
615
616    printf("  error: not implemented yet\n");
617
618    // release semaphore to get next command
619    sem_post( &semaphore );
620
621} // end cmd_mkdir()
622
623////////////////////////////////////////////
624static void cmd_mv( int argc , char **argv )
625{
626
627        if (argc < 3)
628        {
629                printf("  usage : %s src_pathname dst_pathname\n", argv[0]);
630                return;
631        }
632
633    printf("  error: not implemented yet\n");
634   
635    // release semaphore to get next command
636    sem_post( &semaphore );
637
638}  // end cmd_mv
639
640/////////////////////////////////////////////
641static void cmd_pwd( int argc , char **argv )
642{
643        char buf[1024];
644
645        if (argc != 1)
646    {
647                printf("  usage: %s\n", argv[0]);
648                return;
649        }
650
651        if ( getcwd( buf , 1024 ) ) 
652    {
653                printf("  error: unable to get current directory\n");
654        }
655    else 
656    {
657                printf("%s\n", buf);
658        }
659
660    // release semaphore to get next command
661    sem_post( &semaphore );
662
663}  // end cmd_pwd()
664
665////////////////////////////////////////////
666static void cmd_rm( int argc , char **argv )
667{
668        char * pathname;
669
670        if (argc != 2)
671    {
672                printf("  usage: %s pathname\n", argv[0]);
673                return;
674        }
675
676        pathname = argv[1];
677
678    printf("  error: not implemented yet\n");
679
680    // release semaphore to get next command
681    sem_post( &semaphore );
682
683}  // end_cmd_rm()
684
685///////////////////////////////////////////////
686static void cmd_rmdir( int argc , char **argv )
687{
688    // same as cmd_rm()
689        cmd_rm(argc, argv);
690}
691
692///////////////////////////////////////////////
693static void cmd_trace( int argc , char **argv )
694{
695    unsigned int cxy;
696    unsigned int lid;
697
698        if (argc != 3)
699    {
700                printf("  usage: trace cxy lid \n");
701                return;
702        }
703
704    cxy = atoi(argv[1]);
705    lid = atoi(argv[2]);
706
707    if( trace( 1 , cxy , lid ) )
708    {
709        printf("  error: core[%x,%d] not found\n", cxy, lid );
710    }
711
712    // release semaphore to get next command
713    sem_post( &semaphore );
714
715}  // end cmd_trace
716
717///////////////////////////////////////////////
718static void cmd_untrace( int argc , char **argv )
719{
720    unsigned int cxy;
721    unsigned int lid;
722
723        if (argc != 3)
724    {
725                printf("  usage: untrace cxy lid \n");
726                return;
727        }
728
729    cxy = atoi(argv[1]);
730    lid = atoi(argv[2]);
731
732    if( trace( 0 , cxy , lid ) )
733    {
734        printf("  error: core[%x,%d] not found\n", cxy, lid );
735    }
736
737    // release semaphore to get next command
738    sem_post( &semaphore );
739
740}  // end cmd_untrace()
741
742///////////////////////////////////////////////////////////////////////////////////
743// Array of commands
744///////////////////////////////////////////////////////////////////////////////////
745
746ksh_cmd_t cmd[] =
747{
748        { "cat",     "display file content",                            cmd_cat     },
749        { "cd",      "change current directory",                        cmd_cd      },
750        { "cp",      "replicate a file in file system",                 cmd_cp      },
751    { "fg",      "put a process in foreground",                     cmd_fg      },
752    { "display", "display vmm/sched/process/vfs/chdev/txt",         cmd_display },
753        { "load",    "load an user application",                        cmd_load    },
754        { "help",    "list available commands",                         cmd_help    },
755        { "kill",    "kill a process (all threads)",                    cmd_kill    },
756        { "log",     "list registered commands",                        cmd_log     },
757        { "ls",      "list directory entries",                          cmd_ls      },
758        { "mkdir",   "create a new directory",                          cmd_mkdir   },
759        { "mv",      "move a file in file system",                      cmd_mv      },
760        { "pwd",     "print current working directory",                 cmd_pwd     },
761        { "rm",      "remove a file from file system",                  cmd_rm      },
762        { "rmdir",   "remove a directory from file system",             cmd_rmdir   },
763        { "trace",   "activate trace for a given core",                 cmd_trace   },
764        { "untrace", "desactivate trace for a given core",              cmd_untrace },
765        { NULL,      NULL,                                                                              NULL        }
766};
767
768////////////////////////////////////////////////////////////////////////////////////
769// This function analyses one command (with arguments), executes it, and returns.
770////////////////////////////////////////////////////////////////////////////////////
771static void __attribute__ ((noinline)) parse( char * buf )
772{
773        int argc = 0;
774        char *argv[MAX_ARGS];
775        int i;
776        int len = strlen(buf);
777
778        // build argc/argv
779        for (i = 0; i < len; i++) 
780    {
781                if (buf[i] == ' ') 
782        {
783                        buf[i] = '\0';
784                }
785        else if (i == 0 || buf[i - 1] == '\0') 
786        {
787                        if (argc < MAX_ARGS) 
788            {
789                                argv[argc] = &buf[i];
790                                argc++;
791                        }
792                }
793        }
794
795    // analyse command type
796        if (argc > 0)
797    {
798                int found = 0;
799
800                argv[argc] = NULL;
801
802                // try to match typed command
803                for (i = 0 ; cmd[i].name ; i++)
804        {
805                        if (strcmp(argv[0], cmd[i].name) == 0)
806            {
807                                cmd[i].fn(argc, argv);
808                                found = 1;
809                                break;
810                        }
811                }
812
813                if (!found)  // undefined command
814        {
815                        printf("  error : undefined command <%s>\n", argv[0]);
816
817            // release semaphore to get next command
818            sem_post( &semaphore );
819                }
820        }
821}  // end parse()
822
823/////////////////////////
824static void interactive()
825{
826        char           c;                                               // read character
827        char           buf[CMD_MAX_SIZE];               // buffer for one command
828    unsigned int   end_command;             // last character found in a command
829        unsigned int   count;                   // pointer in command buffer
830        unsigned int   i;                                               // index for loops
831        unsigned int   state;                   // escape sequence state
832
833/* This can be used to remove interactive mode
834
835for( i=1 ; 1 ; i += 2)
836{
837    if( sem_wait( &semaphore ) )
838    {
839        printf("\n[ksh error] cannot found semafore\n" );
840        exit( 1 );
841    }
842    else
843    {
844        printf("\n[ksh] %d for sort\n", i );
845    }
846    strcpy( buf , "load /bin/user/sort.elf" );
847    parse( buf );
848
849    if( sem_wait( &semaphore ) )
850    {
851        printf("\n[ksh error] cannot found semafore\n" );
852        exit( 1 );
853    }
854    else
855    {
856        printf("\n[ksh] %d for fft\n", i+1 );
857    }
858    strcpy( buf , "load /bin/user/fft.elf" );
859    parse( buf );
860}
861
862*/
863
864        enum fsm_states
865    {
866                NORMAL = 0,
867                ESCAPE = 1,
868                BRAKET = 2,
869        };
870
871        // This lexical analyser writes one command line in the command buffer.
872        // It is implemented as a 3 states FSM to handle the following escape sequences:
873        // - ESC [ A : up arrow
874        // - ESC [ B : down arrow
875        // - ESC [ C : right arrow
876        // - ESC [ D : left arrow
877        // The three states have the following semantic:
878        // - NORMAL : no (ESC) character has been found
879        // - ESCAPE : the character (ESC) has been found
880        // - BRAKET : the wo characters (ESC,[) have been found
881
882    // external loop on the commands
883    // the in teractive thread should not exit this loop
884        while (1)
885        {
886            // initialize command buffer
887            memset( buf, 0x20 , sizeof(buf) );   // TODO useful ?
888            count = 0;
889            state = NORMAL;
890
891        // decrement semaphore, and block if the KSH process is not the TXT owner
892        if ( sem_wait( &semaphore ) )
893        {
894            printf("\n[ksh error] cannot found semafore\n" );
895            exit( 1 );
896        }
897
898        // display prompt on a new line
899        printf("\n[ksh] ");
900 
901        end_command = 0;
902
903        // internal loop on characters in one command
904        while( end_command == 0 )
905        {
906            // get one character from TXT_RX
907                c = (char)getchar();
908
909            if( c == 0 ) continue;
910
911                    if( state == NORMAL )  // we are not in an escape sequence
912                    {
913                                if ((c == '\b') || (c == 0x7F))  // backspace => remove one character
914                                {
915                                    if (count > 0)
916                    {
917                                        printf("\b \b");
918                                        count--;
919                                    }
920                                }
921                                else if (c == '\n')                  // new line => end of command
922                                {
923                                    if (count > 0)               // analyse & execute command
924                                    {
925                                            // complete command with NUL character
926                                            buf[count] = 0;
927                        count++;
928
929                                        // register command in log arrays
930                                            strcpy(log_entries[ptw].buf, buf);
931                                            log_entries[ptw].count = count;
932                                            ptw = (ptw + 1) % LOG_DEPTH;
933                                            ptr = ptw;
934
935                        // echo character
936                        putchar( c );
937
938                                            // call parser to analyse and execute command
939                                            parse( buf );
940                                    }
941                    else                         // no command registered
942                    {
943                        // release semaphore to get next command
944                        sem_post( &semaphore );
945                    }
946
947                    // exit internal loop on characters
948                    end_command = 1;
949                }
950                            else if (c == '\t')             // tabulation => do nothing
951                                {
952                            }
953                            else if (c == (char)0x1B)       // ESC => start an escape sequence
954                            {
955                    state = ESCAPE;
956                            }
957                            else                                               // normal character
958                                {
959                                    if (count < sizeof(buf) - 1)
960                                    {
961                        // register character in command buffer
962                                            buf[count] = c;
963                                            count++;
964
965                        // echo character
966                        putchar( c );
967                                        }
968                                }
969                        }
970                        else if( state == ESCAPE ) 
971                        {
972                                if (c == '[')           //  valid sequence => continue
973                                {
974                                        state = BRAKET;
975                                }
976                                else                               // invalid sequence => do nothing
977                                {
978                                        state = NORMAL;
979                                }
980                        }
981                        else if( state == BRAKET )
982                        {
983                                if (c == 'D')   // valid  LEFT sequence => move buf pointer left
984                                {
985                                        if (count > 0)
986                                        {
987                                                printf("\b");
988                                                count--;
989                                        }
990
991                                        // get next user char
992                                        state = NORMAL;
993                                }
994                                else if (c == 'C')   // valid  RIGHT sequence => move buf pointer right
995                                {
996                                        if (count < sizeof(buf) - 1)
997                                        {
998                                                printf("%c", buf[count]);
999                                                count++;
1000                                        }
1001
1002                                        // get next user char
1003                                        state = NORMAL;
1004                                }
1005                                else if (c == 'A')   // valid  UP sequence => move log pointer backward
1006                                {
1007                                        // cancel current command
1008                                        for (i = 0; i < count; i++) printf("\b \b");
1009                                        count = 0;
1010
1011                                        // copy log command into buf
1012                                        ptr = (ptr - 1) % LOG_DEPTH;
1013                                        strcpy(buf, log_entries[ptr].buf);
1014                                        count = log_entries[ptr].count - 1;
1015
1016                                        // display log command
1017                                        printf("%s", buf);
1018
1019                                        // get next user char
1020                                        state = NORMAL;
1021                                }
1022                                else if (c == 'B')   // valid  DOWN sequence => move log pointer forward
1023                                {
1024                                        // cancel current command
1025                                        for (i = 0 ; i < count; i++) printf("\b \b");
1026                                        count = 0;
1027
1028                                        // copy log command into buf
1029                                        ptr = (ptr + 1) % LOG_DEPTH;
1030                                        strcpy(buf, log_entries[ptr].buf);
1031                                        count = log_entries[ptr].count;
1032
1033                                        // display log command
1034                                        printf("%s", buf);
1035
1036                                        // get next user char
1037                                        state = NORMAL;
1038                                }
1039                                else                               // other character => do nothing
1040                                {
1041                                        // get next user char
1042                                        state = NORMAL;
1043                                }
1044                        }
1045                }  // end internal while loop on characters
1046        }  // end external while loop on commands
1047}  // end interactive()
1048
1049//////////
1050int main()
1051{
1052    unsigned int cxy;             // owner cluster identifier for this KSH process
1053    unsigned int lid;             // core identifier for this KSH main thread
1054    int          status;          // child process termination status
1055    int          child_pid;       // child process identifier
1056    int          parent_pid;      // parent process identifier (i.e. this process)
1057    pthread_t    trdid;           // interactive thread identifier (unused)
1058    unsigned int is_owner;        // non-zero if KSH process is TXT owner
1059
1060    // initialize log buffer
1061        memset( &log_entries , 0, sizeof(log_entries));
1062        ptw   = 0;
1063        ptr   = 0;
1064
1065    // get KSH process pid and core
1066    parent_pid = getpid();
1067    get_core( &cxy , &lid );
1068
1069    // initializes the semaphore used to unblock the interactive thread
1070    if ( sem_init( &semaphore , 0 , 1 ) )
1071    {
1072        printf("\n[KSH ERROR] cannot initialize semaphore\n" );
1073        exit( 1 ); 
1074    }
1075
1076    // initialize interactive thread attributes
1077    attr.attributes = PT_ATTR_DETACH | PT_ATTR_CLUSTER_DEFINED;
1078    attr.cxy        = cxy;
1079
1080    // lauch the interactive thread
1081    pthread_create( &trdid,
1082                    &attr,
1083                    &interactive,   // entry function
1084                    NULL ); 
1085   
1086    // enter infinite loop monitoring children processes termination
1087    while( 1 )
1088    {
1089        // wait children termination
1090        child_pid = wait( &status );
1091
1092#if KSH_DEBUG
1093if( WIFEXITED  (status) ) printf("\n[KSH] child process %x exited\n" , child_pid );
1094if( WIFSIGNALED(status) ) printf("\n[KSH] child process %x killed\n" , child_pid );
1095if( WIFSTOPPED (status) ) printf("\n[KSH] child process %x stopped\n", child_pid );
1096#endif
1097
1098        // release semaphore if KSH process is TXT owner, to unblock interactive thread
1099        is_fg( parent_pid , &is_owner );
1100        if( is_owner ) sem_post( &semaphore );
1101
1102    }
1103}  // end main()
1104
1105
Note: See TracBrowser for help on using the repository browser.