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

Last change on this file since 469 was 469, checked in by alain, 3 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
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");
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");
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");
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        printf("--- registered commands ---\n");
549        for (i = 0; i < LOG_DEPTH; i++) 
550    {
551                printf(" - %d\t: %s\n", i, &log_entries[i].buf);
552        }
553
554    // release semaphore to get next command
555    sem_post( &semaphore );
556
557} // end cmd_log()
558
559
560////////////////////////////////////////////
561static void cmd_ls( int argc , char **argv )
562{
563        char  * path;
564
565//  struct dirent * file;
566//  DIR *dir;
567
568        if (argc == 1)
569    {
570                path = ".";
571        }
572    else if (argc == 2) 
573    {
574                path = argv[1];
575        } 
576    else 
577    {
578                printf("  usage: ls [path]\n");
579                return;
580        }
581
582    printf("  error: not implemented yet\n");
583/*
584        dir = opendir( path );
585        while ((file = readdir(dir)) != NULL)
586        {
587                printf(" %s\n", file->d_name);
588        }
589        closedir(dir);
590*/
591
592    // release semaphore to get next command
593    sem_post( &semaphore );
594
595} // end cmd_ls()
596
597///////////////////////////////////////////////
598static void cmd_mkdir( int argc , char **argv )
599{
600        char * pathname;
601
602        if (argc != 2)
603    {
604                printf("  usage: mkdir pathname\n");
605                return;
606        }
607
608    pathname = argv[1];
609
610    printf("  error: not implemented yet\n");
611
612    // release semaphore to get next command
613    sem_post( &semaphore );
614
615} // end cmd_mkdir()
616
617////////////////////////////////////////////
618static void cmd_mv( int argc , char **argv )
619{
620
621        if (argc < 3)
622        {
623                printf("  usage : %s src_pathname dst_pathname\n", argv[0]);
624                return;
625        }
626
627    printf("  error: not implemented yet\n");
628   
629    // release semaphore to get next command
630    sem_post( &semaphore );
631
632}  // end cmd_mv
633
634/////////////////////////////////////////////
635static void cmd_pwd( int argc , char **argv )
636{
637        char buf[1024];
638
639        if (argc != 1)
640    {
641                printf("  usage: pwd\n");
642                return;
643        }
644
645        if ( getcwd( buf , 1024 ) ) 
646    {
647                printf("  error: unable to get current directory\n");
648        }
649    else 
650    {
651                printf("%s\n", buf);
652        }
653
654    // release semaphore to get next command
655    sem_post( &semaphore );
656
657}  // end cmd_pwd()
658
659////////////////////////////////////////////
660static void cmd_rm( int argc , char **argv )
661{
662        char * pathname;
663
664        if (argc != 2)
665    {
666                printf("  usage: rm pathname\n");
667                return;
668        }
669
670        pathname = argv[1];
671
672    printf("  error: not implemented yet\n");
673
674    // release semaphore to get next command
675    sem_post( &semaphore );
676
677}  // end_cmd_rm()
678
679///////////////////////////////////////////////
680static void cmd_rmdir( int argc , char **argv )
681{
682    // same as cmd_rm()
683        cmd_rm(argc, argv);
684}
685
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
706    // release semaphore to get next command
707    sem_post( &semaphore );
708
709}  // end cmd_trace
710
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
731    // release semaphore to get next command
732    sem_post( &semaphore );
733
734}  // end cmd_untrace()
735
736///////////////////////////////////////////////////////////////////////////////////
737// Array of commands
738///////////////////////////////////////////////////////////////////////////////////
739
740ksh_cmd_t cmd[] =
741{
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    },
749        { "kill",    "kill a process (all threads)",                    cmd_kill    },
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   },
757        { "trace",   "activate trace for a given core",                 cmd_trace   },
758        { "untrace", "desactivate trace for a given core",              cmd_untrace },
759        { NULL,      NULL,                                                                              NULL        }
760};
761
762////////////////////////////////////////////////////////////////////////////////////
763// This function analyses one command (with arguments), executes it, and returns.
764////////////////////////////////////////////////////////////////////////////////////
765static void __attribute__ ((noinline)) parse( char * buf )
766{
767        int argc = 0;
768        char *argv[MAX_ARGS];
769        int i;
770        int len = strlen(buf);
771
772        // build argc/argv
773        for (i = 0; i < len; i++) 
774    {
775                if (buf[i] == ' ') 
776        {
777                        buf[i] = '\0';
778                }
779        else if (i == 0 || buf[i - 1] == '\0') 
780        {
781                        if (argc < MAX_ARGS) 
782            {
783                                argv[argc] = &buf[i];
784                                argc++;
785                        }
786                }
787        }
788
789    // analyse command type
790        if (argc > 0)
791    {
792                int found = 0;
793
794                argv[argc] = NULL;
795
796                // try to match typed command
797                for (i = 0 ; cmd[i].name ; i++)
798        {
799                        if (strcmp(argv[0], cmd[i].name) == 0)
800            {
801                                cmd[i].fn(argc, argv);
802                                found = 1;
803                                break;
804                        }
805                }
806
807                if (!found)  // undefined command
808        {
809                        printf("  error : undefined command <%s>\n", argv[0]);
810
811            // release semaphore to get next command
812            sem_post( &semaphore );
813                }
814        }
815}  // end parse()
816
817/////////////////////////
818static void interactive()
819{
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
826
827/* This can be used to remove interactive mode
828
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
858        enum fsm_states
859    {
860                NORMAL = 0,
861                ESCAPE = 1,
862                BRAKET = 2,
863        };
864
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:
867        // - ESC [ A : up arrow
868        // - ESC [ B : down arrow
869        // - ESC [ C : right arrow
870        // - ESC [ D : left arrow
871        // The three states have the following semantic:
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
875
876    // external loop on the commands
877    // the in teractive thread should not exit this loop
878        while (1)
879        {
880            // initialize command buffer
881            memset( buf, 0x20 , sizeof(buf) );   // TODO useful ?
882            count = 0;
883            state = NORMAL;
884
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        }
891
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                    {
907                                if ((c == '\b') || (c == 0x7F))  // backspace => remove one character
908                                {
909                                    if (count > 0)
910                    {
911                                        printf("\b \b");
912                                        count--;
913                                    }
914                                }
915                                else if (c == '\n')                  // new line => end of command
916                                {
917                                    if (count > 0)               // analyse & execute command
918                                    {
919                                            // complete command with NUL character
920                                            buf[count] = 0;
921                        count++;
922
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;
928
929                        // echo character
930                        putchar( c );
931
932                                            // call parser to analyse and execute command
933                                            parse( buf );
934                                    }
935                    else                         // no command registered
936                    {
937                        // release semaphore to get next command
938                        sem_post( &semaphore );
939                    }
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
952                                {
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 );
961                                        }
962                                }
963                        }
964                        else if( state == ESCAPE ) 
965                        {
966                                if (c == '[')           //  valid sequence => continue
967                                {
968                                        state = BRAKET;
969                                }
970                                else                               // invalid sequence => do nothing
971                                {
972                                        state = NORMAL;
973                                }
974                        }
975                        else if( state == BRAKET )
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);
1008                                        count = log_entries[ptr].count - 1;
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                        }
1039                }  // end internal while loop on characters
1040        }  // end external while loop on commands
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
1049    int          child_pid;       // child process identifier
1050    int          parent_pid;      // parent process identifier (i.e. this process)
1051    pthread_t    trdid;           // interactive thread identifier (unused)
1052    unsigned int is_owner;        // non-zero if KSH process is TXT owner
1053
1054    // initialize log buffer
1055        memset( &log_entries , 0, sizeof(log_entries));
1056        ptw   = 0;
1057        ptr   = 0;
1058
1059    // get KSH process pid and core
1060    parent_pid = getpid();
1061    get_core( &cxy , &lid );
1062
1063    // initializes the semaphore used to unblock the interactive thread
1064    if ( sem_init( &semaphore , 0 , 1 ) )
1065    {
1066        printf("\n[KSH ERROR] cannot initialize semaphore\n" );
1067        exit( 1 ); 
1068    }
1069
1070printf("\n@@@ in KSH %s : &semaphore = %x\n", __FUNCTION__, &semaphore ); 
1071
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    {
1085        // wait children termination
1086        child_pid = wait( &status );
1087
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 );
1092#endif
1093
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
1098    }
1099}  // end main()
1100
1101
Note: See TracBrowser for help on using the repository browser.