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

Last change on this file since 620 was 619, checked in by alain, 5 years ago

1) Fix a bug in KSH : after the "load" command,

the [ksh] prompt is now printed after completion
of the loaded application.

2) Fix a bug in vmm_handle_cow() : the copy-on-write

use now a hal_remote_memcpy() to replicate the page content.


File size: 36.2 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// We use a semaphore to synchronize the two KSH threads. After each command
24// completion, the interactive thread check the TXT ownership (with a sem_wait),
25// and blocks, if the KSH process loosed the TXT ownership (after a load,
26// or for any other cause). It is unblocked 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 get the next command
29//   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 <dirent.h>
46#include <almosmkh.h>
47#include <semaphore.h>
48#include <hal_macros.h>
49#include <sys/stat.h>
50#include <sys/mman.h>
51#include <fcntl.h>
52
53#define CMD_MAX_SIZE   (256)    // max number of characters in one command
54#define LOG_DEPTH      (32)     // max number of registered commands
55#define MAX_ARGS           (32)     // max number of arguments in a command
56
57#define DEBUG_MAIN          0
58#define DEBUG_INTER         0
59#define DEBUG_PARSE         0
60#define DEBUG_CMD_CAT       0
61#define DEBUG_CMD_CP        0
62#define DEBUG_CMD_LOAD      0
63#define DEBUG_CMD_LS        0
64#define DEBUG_CMD_PS        0
65
66//////////////////////////////////////////////////////////////////////////////////////////
67//         Structures
68//////////////////////////////////////////////////////////////////////////////////////////
69
70// one entry in the registered commands array
71typedef struct log_entry_s
72{
73        char          buf[CMD_MAX_SIZE];
74        unsigned int  count;
75}
76log_entry_t;
77
78// one entry in the supported command types array
79typedef struct ksh_cmd_s
80{
81        char * name;
82        char * desc;
83        void   (*fn)( int , char ** );
84}
85ksh_cmd_t;
86
87
88//////////////////////////////////////////////////////////////////////////////////////////
89//         Global Variables
90//////////////////////////////////////////////////////////////////////////////////////////
91
92ksh_cmd_t       command[];                // array of supported commands
93
94log_entry_t     log_entries[LOG_DEPTH];   // array of registered commands
95
96unsigned int    ptw;                      // write pointer in log_entries[]
97unsigned int    ptr;                      // read pointer in log_entries[]
98
99pthread_attr_t  attr;                     // interactive thread attributes
100
101sem_t           semaphore;                // block interactive thread when zero
102
103pthread_t       trdid;                    // interactive thread identifier
104 
105//////////////////////////////////////////////////////////////////////////////////////////
106//         Shell  Commands
107//////////////////////////////////////////////////////////////////////////////////////////
108
109/////////////////////////////////////////////
110static void cmd_cat( int argc , char **argv )
111{
112        char         * path;
113    struct stat    st;
114    int            fd;
115    int            size;
116    char         * buf;
117
118#if DEBUG_CMD_CAT
119char string[64];
120#endif
121
122        if (argc != 2) 
123    {
124        fd   = -1;
125        buf  = NULL;
126        size = 0;
127                printf("  usage: cat pathname\n");
128            goto cmd_cat_exit;
129    }
130
131    path = argv[1];
132
133    // open the file
134    fd = open( path , O_RDONLY , 0 );
135    if (fd < 0) 
136    {
137        buf  = NULL;
138        size = 0;
139            printf("  error: cannot open file <%s>\n", path);
140            goto cmd_cat_exit;
141    }
142
143#if DEBUG_CMD_CAT
144snprintf( string , 64 , "[KSH] %s : file %s open", __FUNCTION__, path );
145display_string( string );
146#endif
147
148    // get file stats
149    if ( stat( path , &st ) == -1)
150    {
151        buf  = NULL;
152        size = 0;
153            printf("  error: cannot stat <%s>\n", path);
154            goto cmd_cat_exit;
155    }
156
157        if ( S_ISDIR(st.st_mode) )
158    {
159        buf  = NULL;
160        size = 0;
161            printf("  error: <%s> is a directory\n", path);
162            goto cmd_cat_exit;
163    }
164
165    // get file size
166    size = st.st_size;
167
168#if DEBUG_CMD_CAT
169snprintf( string , 64 , "[KSH] %s : get size = %d", __FUNCTION__, size );
170display_string( string );
171#endif
172
173    // MAP_FILE is default type when MAP_ANON and MAP_REMOTE are not specified
174    buf = mmap( NULL , size , PROT_READ|PROT_WRITE , MAP_PRIVATE , fd , 0 );
175
176    if ( buf == NULL )
177    {
178            printf("  error: cannot map file <%s>\n", path );
179            goto cmd_cat_exit;
180    }
181
182#if DEBUG_CMD_CAT
183snprintf( string , 64 , "[KSH] %s : map file %d to buffer %x", __FUNCTION__, fd , buf );
184display_string( string );
185display_vmm( 0 , getpid() );
186#endif
187
188    // display the file content on TXT terminal
189    write( 1 , buf , size );
190
191    // release semaphore to get next command
192    sem_post( &semaphore );
193
194    return;
195
196cmd_cat_exit:
197
198        if (buf != NULL) munmap(buf, size);
199        if (fd >= 0) close(fd);
200
201    // release semaphore to get next command
202    sem_post( &semaphore );
203
204}   // end cmd_cat()
205
206////////////////////////////////////////////
207static void cmd_cd( int argc , char **argv )
208{
209        char * path;
210
211        if (argc != 2)
212    {
213                printf("  usage: cd pathname\n");
214        }
215    else
216    {
217            path = argv[1];
218
219        // call the relevant syscall
220        if( chdir( path ) )
221        {
222            printf("  error: cannot found <%s> directory\n", path );
223        }
224    }
225
226    // release semaphore to get next command
227    sem_post( &semaphore );
228
229}   // end cmd_cd()
230
231/////////////////////////////////////////
232static void cmd_cp(int argc, char **argv)
233{
234        int          src_fd;
235    int          dst_fd;
236        char       * srcpath;
237    char       * dstpath;
238        int          size;          // source file size
239        int          bytes;         // number of transfered bytes
240        char         buf[4096];
241        struct stat  st;
242
243#if DEBUG_CMD_CP
244char string[64];
245#endif
246
247        if (argc != 3) 
248    {
249        src_fd = -1;
250        dst_fd = -1;
251                printf("  usage: cp src_pathname dst_pathname\n");
252        goto cmd_cp_exit;
253        }
254
255    srcpath = argv[1];
256    dstpath = argv[2];
257
258    // open the src file
259    src_fd = open( srcpath , O_RDONLY , 0 );
260
261    if ( src_fd < 0 ) 
262    {
263        dst_fd = -1;
264            printf("  error: cannot open <%s>\n", srcpath );
265            goto cmd_cp_exit;
266    }
267
268#if DEBUG_CMD_CP
269snprintf( string , 64 , "[KSH] %s : file %s open", __FUNCTION__, srcpath );
270display_string( string );
271#endif
272
273    // get file stats
274    if ( stat( srcpath , &st ) )
275    {
276        dst_fd = -1;
277            printf("  error: cannot stat <%s>\n", srcpath);
278            goto cmd_cp_exit;
279    }
280
281#if DEBUG_CMD_CP
282snprintf( string , 64 , "[KSH] %s : got stats for %s", __FUNCTION__, srcpath );
283display_string( string );
284#endif
285
286        if ( S_ISDIR(st.st_mode) )
287    {
288        dst_fd = -1;
289                printf("  error: <%s> is a directory\n", srcpath);
290                goto cmd_cp_exit;
291        }
292
293    // get src file size
294        size = st.st_size;
295
296        // open the dst file
297        dst_fd = open( dstpath , O_CREAT|O_TRUNC|O_RDWR , 0 );
298
299        if ( dst_fd < 0 ) 
300    {
301                printf("  error: cannot open <%s>\n", dstpath );
302                goto cmd_cp_exit;
303        }
304
305#if DEBUG_CMD_CP
306snprintf( string , 64 , "[KSH] %s : file %s open", __FUNCTION__, dstpath );
307display_string( string );
308#endif
309
310        if ( stat( dstpath , &st ) )
311    {
312                printf("  error: cannot stat <%s>\n", dstpath );
313                goto cmd_cp_exit;
314        }
315
316#if DEBUG_CMD_CP
317snprintf( string , 64 , "[KSH] %s : got stats for %s", __FUNCTION__, dstpath );
318display_string( string );
319#endif
320
321        if ( S_ISDIR(st.st_mode ) ) 
322    {
323                printf("  error: <%s> is a directory\n", dstpath );
324                goto cmd_cp_exit;
325        }
326
327        bytes = 0;
328
329        while (bytes < size)
330        {
331                int len = ((size - bytes) < 4096) ? (size - bytes) : 4096;
332
333                // read the source
334                if ( read( src_fd , buf , len ) != len )
335        {
336                        printf("  error: cannot read from file <%s>\n", srcpath);
337                        goto cmd_cp_exit;
338                }
339
340#if DEBUG_CMD_CP
341snprintf( string , 64 , "[KSH] %s : read %d bytes from %s", __FUNCTION__, len, srcpath );
342display_string( string );
343#endif
344
345                // write to the destination
346                if ( write( dst_fd , buf , len ) != len )
347        {
348                        printf("  error: cannot write to file <%s>\n", dstpath);
349                        goto cmd_cp_exit;
350                }
351
352#if DEBUG_CMD_CP
353snprintf( string , 64 , "[KSH] %s : write %d bytes to %s", __FUNCTION__, len, dstpath );
354display_string( string );
355#endif
356
357                bytes += len;
358        }
359
360cmd_cp_exit:
361
362        if (src_fd >= 0) close(src_fd);
363        if (dst_fd >= 0) close(dst_fd);
364
365    // release semaphore to get next command
366    sem_post( &semaphore );
367
368}   // end cmd_cp()
369
370/////////////////////////////////////////////////
371static void cmd_display( int argc , char **argv )
372{
373    if( argc < 2 )
374    {
375        printf("  usage: display  vmm      cxy    pid\n"
376               "         display  sched    cxy    lid\n"             
377               "         display  process  cxy\n"             
378               "         display  txt      txtid\n"             
379               "         display  vfs\n"             
380               "         display  chdev\n"             
381               "         display  dqdt\n"             
382               "         display  locks    pid    trdid\n"
383               "         display  mapper   path   page_id  nbytes\n");
384    }
385    ////////////////////////////////////
386    else if( strcmp( argv[1] , "vmm" ) == 0 )
387    {
388        if( argc != 4 )
389        {
390                    printf("  usage: display vmm cxy pid\n");
391            }
392        else
393        {
394                unsigned int cxy = atoi(argv[2]);
395                unsigned int pid = atoi(argv[3]);
396
397            if( display_vmm( cxy , pid ) )
398            {
399                printf("  error: no process %x in cluster %x\n", pid , cxy );
400            }
401        }
402    }
403    ///////////////////////////////////////////
404    else if( strcmp( argv[1] , "sched" ) == 0 )
405    {
406        if( argc != 4 )
407        {
408                    printf("  usage: display sched cxy lid\n");
409            }
410        else
411        {
412                unsigned int cxy = atoi(argv[2]);
413                unsigned int lid = atoi(argv[3]);
414
415            if( display_sched( cxy , lid ) )
416            {
417                printf("  error: illegal arguments cxy = %x / lid = %d\n", cxy, lid );
418            }
419        }
420    }
421    /////////////////////////////////////////////
422    else if( strcmp( argv[1] , "process" ) == 0 )
423    {
424        if( argc != 3 )
425        {
426                    printf("  usage: display process cxy\n");
427            }
428        else
429        {
430                unsigned int cxy = atoi(argv[2]);
431
432            if( display_cluster_processes( cxy , 0 ) )
433            {
434                printf("  error: illegal argument cxy = %x\n", cxy );
435            }
436        }
437    }
438    /////////////////////////////////////////
439    else if( strcmp( argv[1] , "txt" ) == 0 )
440    {
441        if( argc != 3 )
442        {
443                    printf("  usage: display txt txt_id\n");
444            }
445        else
446        {
447                unsigned int txtid = atoi(argv[2]);
448
449            if( display_txt_processes( txtid ) )
450            {
451                printf("  error: illegal argument txtid = %d\n", txtid );
452            }
453        }
454    }
455    /////////////////////////////////////////
456    else if( strcmp( argv[1] , "vfs" ) == 0 )
457    {
458        if( argc != 2 )
459        {
460                    printf("  usage: display vfs\n");
461            }
462        else
463        {
464            display_vfs();
465        }
466    }
467    //////////////////////////////////////////
468    else if( strcmp( argv[1] , "chdev" ) == 0 )
469    {
470        if( argc != 2 )
471        {
472                    printf("  usage: display chdev\n");
473            }
474        else
475        {
476            display_chdev();
477        }
478    }
479    //////////////////////////////////////////
480    else if( strcmp( argv[1] , "dqdt" ) == 0 )
481    {
482        if( argc != 2 )
483        {
484                    printf("  usage: display dqdt\n");
485            }
486        else
487        {
488            display_dqdt();
489        }
490    }
491    ///////////////////////////////////////////
492    else if( strcmp( argv[1] , "locks" ) == 0 )
493    {
494        if( argc != 4 )
495        {
496                    printf("  usage: display locks pid trdid\n");
497            }
498        else
499        {
500                unsigned int pid   = atoi(argv[2]);
501            unsigned int trdid = atoi(argv[3]);
502
503            if( display_busylocks( pid , trdid ) )
504            {
505                printf("  error: illegal arguments pid = %x / trdid = %x\n", pid, trdid );
506            }
507        }
508    }
509    ///////////////////////////////////////////
510    else if( strcmp( argv[1] , "mapper" ) == 0 )
511    {
512        if( argc != 5 )
513        {
514                    printf("  usage: display mapper path page_id nbytes\n");
515            }
516        else
517        {
518                unsigned int page_id   = atoi(argv[3]);
519            unsigned int nbytes    = atoi(argv[4]);
520
521            if( display_mapper( argv[2] , page_id, nbytes ) )
522            {
523                printf("  error: cannot display page %d of mapper %s\n", page_id, argv[2] );
524            }
525        }
526    }
527    else
528    {
529        printf("  error: undefined display request : %s\n", argv[1] ); 
530    }       
531
532    // release semaphore to get next command
533    sem_post( &semaphore );
534
535} // end cmd_display()
536
537/////////////////////////////////////////
538static void cmd_fg(int argc, char **argv)
539{
540        unsigned int pid;
541
542        if (argc != 2) 
543    {
544                printf("  usage: %s pid\n", argv[0]);
545        }
546    else
547    {
548        pid = atoi( argv[1] );   
549
550        if( pid == 0 )
551        { 
552                    printf("  error: PID cannot be 0\n" );
553            }
554        else if( fg( pid ) )
555        {
556                    printf("  error: cannot find process %x\n", pid );
557            }
558    }
559
560    // release semaphore to get next command
561    sem_post( &semaphore );
562
563}  // end cmd_fg()
564
565//////////////////////////////////////////////
566static void cmd_help( int argc , char **argv )
567{
568        unsigned int i;
569
570        if (argc != 1) 
571    {
572                printf("  usage: %s\n", argv[0]);
573        }
574    else
575    {
576        printf("available commands:\n");
577            for (i = 0 ; command[i].name ; i++) 
578        {
579                    printf("\t%s\t : %s\n", command[i].name , command[i].desc);
580            }
581    }
582
583    // release semaphore to get next command
584    sem_post( &semaphore );
585
586}   // end cmd_help()
587
588//////////////////////////////////////////////
589static void cmd_kill( int argc , char **argv )
590{
591        unsigned int pid;
592
593        if (argc != 2) 
594    {
595                printf("  usage: %s pid\n", argv[0]);
596        }
597    else
598    {
599            pid = atoi( argv[1] );
600
601        if( pid == 0 )
602        {
603                    printf("  error: kernel process 0 cannot be killed\n" );
604            }
605
606            else if( kill( pid , SIGKILL ) )
607        {
608                    printf("  error: process %x cannot be killed\n", pid );
609            }
610    }
611
612    // release semaphore to get next command
613    sem_post( &semaphore );
614
615}   // end cmd_kill()
616
617//////////////////////////////////////////////
618static void cmd_load( int argc , char **argv )
619{
620        int                  ret_fork;           // return value from fork
621        int                  ret_exec;           // return value from exec
622    unsigned int         ksh_pid;            // KSH process PID
623        char               * pathname;           // path to .elf file
624    unsigned int         background;         // background execution if non zero
625    unsigned int         placement;          // placement specified if non zero
626    unsigned int         cxy;                // target cluster if placement specified
627
628#if DEBUG_CMD_LOAD
629char string[64];
630#endif
631
632        if( (argc < 2) || (argc > 4) ) 
633    {
634                printf("  usage: %s pathname [cxy] [&]\n", argv[0] );
635        }
636    else
637    {
638            pathname = argv[1];
639
640        if( argc == 2 )
641        {
642            background = 0;
643            placement  = 0;
644            cxy        = 0;
645        }
646        else if( argc == 3 )
647        {
648            if( (argv[2][0] == '&') && (argv[2][1] == 0) )
649            {
650                background = 1;
651                placement  = 0;
652                cxy        = 0;
653            }
654            else 
655            {
656                background = 0;
657                placement  = 1;
658                cxy        = atoi( argv[2] );
659            }
660        }
661        else  // argc == 4
662        { 
663            background = ( (argv[3][0] == '&') && (argv[3][1] == 0) );
664            placement  = 1;
665            cxy        = atoi( argv[2] );
666        }
667
668/*
669        // take semaphore to block the interactive thread
670        if ( sem_wait( &semaphore ) )
671        {
672            printf("\n[ksh error] cannot found semafore\n" );
673            exit( 1 );
674        }
675*/
676        // get KSH process PID
677        ksh_pid = getpid();
678
679#if DEBUG_CMD_LOAD
680snprintf( string , 64 , "[KSH] %s : ksh_pid %x / path %s / bg %d / place %d (%x)\n",
681__FUNCTION__, ksh_pid, argv[1], background, placement, cxy );
682display_string( string );
683#endif
684
685        // set target cluster if required
686        if( placement ) place_fork( cxy );
687
688        // KSH process fork CHILD process
689            ret_fork = fork();
690
691        if ( ret_fork < 0 )     // it is a failure reported to KSH
692        {
693            printf("  error: ksh process unable to fork\n");
694        }
695        else if (ret_fork == 0) // it is the CHILD process
696        {
697
698#if DEBUG_CMD_LOAD
699snprintf( string , 64 , "[KSH] %s : child_pid %x after fork, before exec\n",
700__FUNCTION__ , getpid() );
701display_string( string );
702#endif
703
704            // CHILD process exec NEW process
705            ret_exec = execve( pathname , NULL , NULL );
706
707#if DEBUG_CMD_LOAD
708snprintf( string , 64 , "[KSH] %s : child_pid %x after exec / ret_exec %x\n",
709__FUNCTION__ , getpid(), ret_exec );
710display_string( string );
711#endif
712
713            // this is only executed in case of exec failure
714            if( ret_exec )
715            {
716                printf("  error: child process unable to exec <%s>\n", pathname );
717                exit( 0 );
718            }   
719            } 
720        else                    // it is the KSH process : ret_fork is the new process PID
721        {
722
723#if DEBUG_CMD_LOAD
724snprintf( string , 64 , "[KSH] %s : ksh_pid %x after fork / ret_fork %x\n",
725__FUNCTION__, getpid(), ret_fork );
726display_string( string );
727#endif
728
729            if( background )    //  KSH must keep TXT ownership
730            {
731                // get back the TXT ownership
732                fg( ksh_pid );
733
734                // release semaphore to get next command
735                sem_post( &semaphore );
736            }
737            else                // KSH loosed TXT ownership
738            {
739                // semaphore will be released by the KSH main thread
740                // when the loaded process exit
741            }
742        }
743    }
744}   // end cmd_load
745
746/////////////////////////////////////////////
747static void cmd_log( int argc , char **argv )
748{
749        unsigned int i;
750
751        if (argc != 1)
752    {
753                printf("  usage: %s\n", argv[0], argc ); 
754        }
755    else
756    {
757            printf("--- registered commands ---\n");
758            for (i = 0; i < LOG_DEPTH; i++) 
759        {
760                    printf(" - %d\t: %s\n", i, &log_entries[i].buf);
761            }
762    }
763
764    // release semaphore to get next command
765    sem_post( &semaphore );
766
767} // end cmd_log()
768
769
770////////////////////////////////////////////
771static void cmd_ls( int argc , char **argv )
772{
773        char           * pathname = NULL;
774    struct dirent  * entry;
775    DIR            * dir;
776
777#if DEBUG_CMD_LS
778char string[64];
779#endif
780
781        if (argc > 2 )
782    {
783                printf("  usage: ls [path]\n");
784        }
785    else
786    {
787        // handle case with no argument
788
789        // get target directory path
790        if ( argc == 1 ) strcpy( pathname , "." );
791        else             pathname = argv[1];
792
793        // open target directory
794            dir = opendir( pathname );
795
796#if DEBUG_CMD_LS
797snprintf( string , 64 , "[KSH] %s : directory <%s> open / DIR %x\n",
798__FUNCTION__, pathname , dir );
799display_string( string );
800#endif
801
802        if( dir == NULL)
803            {
804                    printf("  error : directory <%s> not found\n", pathname );
805            goto cmd_ls_exit;
806            }
807
808        // loop on directory entries   
809        while ( (entry = readdir(dir)) != NULL )
810            {
811                    printf("%s\n", entry->d_name);
812            }
813
814        // close target directory
815            closedir( dir );
816
817#if DEBUG_CMD_LS
818snprintf( string , 64 , "[KSH] %s : directory <%s> closed\n",
819__FUNCTION__, pathname );
820display_string( string );
821#endif
822
823    }
824
825cmd_ls_exit:
826
827    // release semaphore to get next command
828    sem_post( &semaphore );
829
830} // end cmd_ls()
831
832///////////////////////////////////////////////
833static void cmd_mkdir( int argc , char **argv )
834{
835        char * pathname;
836
837        if (argc != 2)
838    {
839                printf("  usage: mkdir pathname\n");
840        }
841    else
842    {
843        pathname = argv[1];
844
845        mkdir( pathname , 0x777 );
846    }
847
848    // release semaphore to get next command
849    sem_post( &semaphore );
850
851} // end cmd_mkdir()
852
853////////////////////////////////////////////
854static void cmd_mv( int argc , char **argv )
855{
856        char * old_path;
857    char * new_path;
858
859        if (argc != 3) 
860    {
861                printf("  usage: mv old_pathname new_pathname\n");
862        }
863    else
864    {
865        old_path = argv[1];
866        new_path = argv[2];
867
868        // call the relevant syscall
869        if( rename( old_path , new_path ) )
870        {
871            printf("  error: unable to rename <%s> to <%s>\n", old_path, new_path );
872        }
873    }
874
875    // release semaphore to get next command
876    sem_post( &semaphore );
877
878}  // end cmd_mv
879
880
881////////////////////////////////////////////
882static void cmd_ps( int argc , char **argv )
883{
884    unsigned int x_size;
885    unsigned int y_size;
886    unsigned int ncores;
887    unsigned int x;
888    unsigned int y;
889
890#if DEBUG_CMD_PS
891char string[64];
892#endif
893
894        if (argc != 1)
895    {
896                printf("  usage: %s\n", argv[0]);
897        }
898    else
899    {
900        // get platform config
901        get_config( &x_size , &y_size , &ncores );
902
903        // scan all clusters
904        for( x = 0 ; x < x_size ; x++ )
905        {
906            for( y = 0 ; y < y_size ; y++ )
907            {
908
909#if DEBUG_CMD_PS
910snprintf( string , 64 , "\n[KSH] %s : call display_cluster_process()", __FUNCTION__ );
911display_string( string );
912#endif
913
914                // display only owned processes
915                display_cluster_processes( HAL_CXY_FROM_XY(x,y), 1 ); 
916            }
917        }
918    }
919
920    // release semaphore to get next command
921    sem_post( &semaphore );
922
923}  // end cmd_ps()
924
925/////////////////////////////////////////////
926static void cmd_pwd( int argc , char **argv )
927{
928        char buf[1024];
929
930        if (argc != 1)
931    {
932                printf("  usage: %s\n", argv[0]);
933        }
934    else 
935    {
936        if ( getcwd( buf , 1024 ) ) 
937        {
938                    printf("  error: unable to get current directory\n");
939            }
940        else 
941        {
942                    printf("%s\n", buf);
943            }
944    }
945
946    // release semaphore to get next command
947    sem_post( &semaphore );
948
949}  // end cmd_pwd()
950
951////////////////////////////////////////////
952static void cmd_rm( int argc , char **argv )
953{
954        char * pathname;
955
956        if (argc != 2)
957    {
958                printf("  usage: %s pathname\n", argv[0]);
959        }
960    else
961    {
962            pathname = argv[1];
963
964        if ( unlink( pathname ) )
965        {
966                    printf("  error: unable to remove <%s>\n", pathname );
967            }
968    }
969
970    // release semaphore to get next command
971    sem_post( &semaphore );
972
973}  // end_cmd_rm()
974
975///////////////////////////////////////////////
976static void cmd_rmdir( int argc , char **argv )
977{
978    // same as cmd_rm()
979        cmd_rm(argc, argv);
980}
981
982///////////////////////////////////////////////
983static void cmd_trace( int argc , char **argv )
984{
985    unsigned int cxy;
986    unsigned int lid;
987
988        if (argc != 3)
989    {
990                printf("  usage: trace cxy lid \n");
991        }
992    else
993    {
994        cxy = atoi(argv[1]);
995        lid = atoi(argv[2]);
996
997        if( trace( 1 , cxy , lid ) )
998        {
999            printf("  error: core[%x,%d] not found\n", cxy, lid );
1000        }
1001    }
1002
1003    // release semaphore to get next command
1004    sem_post( &semaphore );
1005
1006}  // end cmd_trace
1007
1008///////////////////////////////////////////////
1009static void cmd_untrace( int argc , char **argv )
1010{
1011    unsigned int cxy;
1012    unsigned int lid;
1013
1014        if (argc != 3)
1015    {
1016                printf("  usage: untrace cxy lid \n");
1017        }
1018    else
1019    {
1020        cxy = atoi(argv[1]);
1021        lid = atoi(argv[2]);
1022
1023        if( trace( 0 , cxy , lid ) )
1024        {
1025            printf("  error: core[%x,%d] not found\n", cxy, lid );
1026        }
1027    }
1028
1029    // release semaphore to get next command
1030    sem_post( &semaphore );
1031
1032}  // end cmd_untrace()
1033
1034///////////////////////////////////////////////////////////////////////////////////
1035// Array of commands
1036///////////////////////////////////////////////////////////////////////////////////
1037
1038ksh_cmd_t command[] =
1039{
1040        { "cat",     "display file content",                            cmd_cat     },
1041        { "cd",      "change current directory",                        cmd_cd      },
1042        { "cp",      "replicate a file in file system",                 cmd_cp      },
1043    { "fg",      "put a process in foreground",                     cmd_fg      },
1044    { "display", "display vmm/sched/process/vfs/chdev/txt",         cmd_display },
1045        { "load",    "load an user application",                        cmd_load    },
1046        { "help",    "list available commands",                         cmd_help    },
1047        { "kill",    "kill a process (all threads)",                    cmd_kill    },
1048        { "log",     "list registered commands",                        cmd_log     },
1049        { "ls",      "list directory entries",                          cmd_ls      },
1050        { "mkdir",   "create a new directory",                          cmd_mkdir   },
1051        { "mv",      "move a file in file system",                      cmd_mv      },
1052        { "pwd",     "print current working directory",                 cmd_pwd     },
1053        { "ps",      "display all processes",                           cmd_ps      },
1054        { "rm",      "remove a file from file system",                  cmd_rm      },
1055        { "rmdir",   "remove a directory from file system",             cmd_rmdir   },
1056        { "trace",   "activate trace for a given core",                 cmd_trace   },
1057        { "untrace", "desactivate trace for a given core",              cmd_untrace },
1058        { NULL,      NULL,                                                                              NULL        }
1059};
1060
1061////////////////////////////////////////////////////////////////////////////////////
1062// This function analyses one command (with arguments), executes it, and returns.
1063////////////////////////////////////////////////////////////////////////////////////
1064static void __attribute__ ((noinline)) parse( char * buf )
1065{
1066        int    argc = 0;
1067        char * argv[MAX_ARGS];
1068        int    i;
1069        int    len = strlen(buf);
1070
1071#if DEBUG_PARSE
1072char string[64];
1073snprintf( string , 64 , "\n[KSH] %s : <%s>", __FUNCTION__ , buf );
1074display_string( string );
1075#endif
1076
1077        // build argc/argv
1078        for (i = 0; i < len; i++) 
1079    {
1080        // convert SPACE to NUL
1081                if (buf[i] == ' ') 
1082        {
1083                        buf[i] = '\0';
1084                }
1085        else if (i == 0 || buf[i - 1] == '\0') 
1086        {
1087                        if (argc < MAX_ARGS) 
1088            {
1089                                argv[argc] = &buf[i];
1090                                argc++;
1091                        }
1092                }
1093        }
1094
1095#if DEBUG_PARSE
1096snprintf( string , 64 , "\n[KSH] %s : argc = %d for <%s>", __FUNCTION__ , argc , argv[0] );
1097display_string( string );
1098#endif
1099
1100    // analyse command type
1101        if (argc > 0)
1102    {
1103                int found = 0;
1104
1105                // try to match typed command
1106                for ( i = 0 ; command[i].name ; i++ )
1107        {
1108                        if (strcmp(argv[0], command[i].name) == 0)
1109            {
1110                                command[i].fn(argc, argv);
1111                                found = 1;
1112                                break;
1113                        }
1114                }
1115
1116                if (!found)  // undefined command
1117        {
1118                        printf("  error : undefined command <%s>\n", argv[0]);
1119
1120            // release semaphore to get next command
1121            sem_post( &semaphore );
1122                }
1123        }
1124}  // end parse()
1125
1126///////////////////////////////
1127static void interactive( void )
1128{
1129        char           c;                                               // read character
1130    unsigned int   end_command;             // last character found in a command
1131        unsigned int   count;                   // pointer in command buffer
1132        unsigned int   i;                                               // index for loops
1133        unsigned int   state;                   // escape sequence state
1134
1135        char           cmd[CMD_MAX_SIZE];               // buffer for one command
1136
1137#if DEBUG_INTER
1138char string[64];
1139#endif
1140
1141/* To lauch one command without interactive mode
1142if( sem_wait( &semaphore ) )
1143{
1144    printf("\n[ksh error] cannot found semafore\n" );
1145    exit( 1 );
1146}
1147else
1148{
1149    printf("\n[ksh] load bin/user/sort.elf\n");
1150}
1151
1152strcpy( cmd , "load bin/user/sort.elf" );
1153parse( cmd );
1154*/
1155
1156        enum fsm_states
1157    {
1158                NORMAL = 0,
1159                ESCAPE = 1,
1160                BRAKET = 2,
1161        };
1162
1163        // This lexical analyser writes one command line in the command buffer.
1164        // It is implemented as a 3 states FSM to handle the following escape sequences:
1165        // - ESC [ A : up arrow
1166        // - ESC [ B : down arrow
1167        // - ESC [ C : right arrow
1168        // - ESC [ D : left arrow
1169        // The three states have the following semantic:
1170        // - NORMAL : no (ESC) character has been found
1171        // - ESCAPE : the character (ESC) has been found
1172        // - BRAKET : the wo characters (ESC,[) have been found
1173
1174    // take the semaphore for the first command
1175    if ( sem_wait( &semaphore ) )
1176    {
1177        printf("\n[ksh error] cannot found semafore\n" );
1178        exit( 1 );
1179    }
1180
1181    // display prompt for the first command
1182    printf("\n[ksh] ");
1183
1184    // external loop on the commands / the interactive thread do not exit this loop
1185        while (1)
1186        {
1187            // initialize command buffer
1188            memset( cmd, 0x20 , sizeof(cmd) );   // TODO useful ?
1189            count       = 0;
1190            state       = NORMAL;
1191        end_command = 0;
1192
1193#if DEBUG_INTER
1194unsigned int pid = getpid();
1195snprintf( string , 64 , "\n[KSH] %s : request a new command", __FUNCTION__ );
1196display_string( string );
1197#endif
1198
1199        // internal loop on characters in one command
1200        while( end_command == 0 )
1201        {
1202            // get one character from TXT_RX
1203                c = (char)getchar();
1204
1205            if( c == 0 ) continue;
1206
1207                    if( state == NORMAL )  // we are not in an escape sequence
1208                    {
1209                                if ((c == '\b') || (c == 0x7F))  // backspace => remove one character
1210                                {
1211                                    if (count > 0)
1212                    {
1213                                        printf("\b \b");
1214                                        count--;
1215                                    }
1216                                }
1217                                else if (c == '\n')                  // new line => end of command
1218                                {
1219                                    if (count > 0)               // analyse & execute command
1220                                    {
1221                                            // complete command with NUL character
1222                                            cmd[count] = 0;
1223                        count++;
1224
1225                        // register command in log
1226                                            strncpy( log_entries[ptw].buf , cmd , count );
1227                                            log_entries[ptw].count = count;
1228                                            ptw = (ptw + 1) % LOG_DEPTH;
1229                                            ptr = ptw;
1230
1231#if DEBUG_INTER
1232snprintf( string , 64 , "[KSH] %s : parse and execute <%s>", __FUNCTION__, cmd );
1233display_string( string );
1234#endif
1235                        // echo character
1236                        putchar( c );
1237
1238                                            // call parser to analyse and execute command
1239                                            parse( cmd );
1240                                    }
1241                    else                         // no command registered
1242                    {
1243                        // release semaphore to get next command
1244                        sem_post( &semaphore );
1245                    }
1246
1247                    // exit internal loop on characters
1248                    end_command = 1;
1249                }
1250                            else if (c == '\t')             // tabulation => do nothing
1251                                {
1252                            }
1253                            else if (c == (char)0x1B)       // ESC => start an escape sequence
1254                            {
1255                    state = ESCAPE;
1256                            }
1257                            else                                               // normal character
1258                                {
1259                                    if (count < (sizeof(cmd) - 1) )
1260                                    {
1261                        // register character in command buffer
1262                                            cmd[count] = c;
1263                                            count++;
1264
1265                        // echo character
1266                        putchar( c );
1267                                        }
1268                    else
1269                    {
1270                                printf("\none command cannot exceed %d characters\n", sizeof(cmd) );
1271                    }
1272                                }
1273                        }
1274                        else if( state == ESCAPE ) 
1275                        {
1276                                if (c == '[')           //  valid sequence => continue
1277                                {
1278                                        state = BRAKET;
1279                                }
1280                                else                               // invalid sequence => do nothing
1281                                {
1282                                        state = NORMAL;
1283                                }
1284                        }
1285                        else if( state == BRAKET )
1286                        {
1287                                if (c == 'D')   // valid  LEFT sequence => move cmd pointer left
1288                                {
1289                                        if (count > 0)
1290                                        {
1291                                                printf("\b");
1292                                                count--;
1293                                        }
1294
1295                                        // get next user char
1296                                        state = NORMAL;
1297                                }
1298                                else if (c == 'C')   // valid  RIGHT sequence => move cmd pointer right
1299                                {
1300                                        if (count < sizeof(cmd) - 1)
1301                                        {
1302                                                printf("%c", cmd[count]);
1303                                                count++;
1304                                        }
1305
1306                                        // get next user char
1307                                        state = NORMAL;
1308                                }
1309                                else if (c == 'A')   // valid  UP sequence => move log pointer backward
1310                                {
1311                                        // cancel current command
1312                                        for (i = 0; i < count; i++) printf("\b \b");
1313                                        count = 0;
1314
1315                                        // copy log command into cmd
1316                                        ptr = (ptr - 1) % LOG_DEPTH;
1317                                        strcpy(cmd, log_entries[ptr].buf);
1318                                        count = log_entries[ptr].count - 1;
1319
1320                                        // display log command
1321                                        printf("%s", cmd);
1322
1323                                        // get next user char
1324                                        state = NORMAL;
1325                                }
1326                                else if (c == 'B')   // valid  DOWN sequence => move log pointer forward
1327                                {
1328                                        // cancel current command
1329                                        for (i = 0 ; i < count; i++) printf("\b \b");
1330                                        count = 0;
1331
1332                                        // copy log command into cmd
1333                                        ptr = (ptr + 1) % LOG_DEPTH;
1334                                        strcpy(cmd, log_entries[ptr].buf);
1335                                        count = log_entries[ptr].count;
1336
1337                                        // display log command
1338                                        printf("%s", cmd);
1339
1340                                        // get next user char
1341                                        state = NORMAL;
1342                                }
1343                                else                               // other character => do nothing
1344                                {
1345                                        // get next user char
1346                                        state = NORMAL;
1347                                }
1348                        }
1349                }  // end internal while loop on characters
1350
1351#if DEBUG_INTER
1352snprintf( string , 64 , "\n[KSH] %s : complete <%s> command", __FUNCTION__, cmd );
1353display_string( string );
1354#endif
1355
1356        // block interactive thread if KSH loose TXT ownership
1357        if ( sem_wait( &semaphore ) )
1358        {
1359            printf("\n[ksh error] cannot found semafore\n" );
1360            exit( 1 );
1361        }
1362
1363        // display prompt for next command
1364        printf("\n[ksh] ");
1365
1366        }  // end external while loop on commands
1367
1368}  // end interactive()
1369
1370////////////////
1371int main( void )
1372{
1373    unsigned int cxy;             // owner cluster identifier for this KSH process
1374    unsigned int lid;             // core identifier for this KSH main thread
1375    int          status;          // child process termination status
1376    int          child_pid;       // child process identifier
1377    int          parent_pid;      // parent process identifier (i.e. this process)
1378    unsigned int is_owner;        // non-zero if KSH process is TXT owner
1379
1380    // initialize log buffer
1381        memset( &log_entries , 0, sizeof(log_entries));
1382        ptw   = 0;
1383        ptr   = 0;
1384
1385    // get KSH process pid and core
1386    parent_pid = getpid();
1387    get_core( &cxy , &lid );
1388
1389#if DEBUG_MAIN
1390printf("\n[ksh] main thread started on core[%x,%d]\n", cxy , lid ); 
1391#endif
1392   
1393    // initializes the semaphore used to synchronize with interactive thread
1394    if ( sem_init( &semaphore , 0 , 1 ) )
1395    {
1396        printf("\n[KSH ERROR] cannot initialize semaphore\n" );
1397        exit( 1 ); 
1398    }
1399
1400#if DEBUG_MAIN
1401printf("\n[ksh] main initialized semaphore\n" ); 
1402#endif
1403   
1404    // initialize interactive thread attributes
1405    attr.attributes = PT_ATTR_DETACH | PT_ATTR_CLUSTER_DEFINED;
1406    attr.cxy        = cxy;
1407
1408    // lauch the interactive thread
1409    pthread_create( &trdid,
1410                    &attr,
1411                    &interactive,   // entry function
1412                    NULL ); 
1413#if DEBUG_MAIN
1414printf("\n[ksh] main thread launched interactive thread %x\n", trdid ); 
1415#endif
1416
1417    // signal INIT process
1418    kill( 1 , SIGCONT );
1419   
1420    // enter infinite loop monitoring children processes termination
1421    while( 1 )
1422    {
1423        // wait children termination
1424        child_pid = wait( &status );
1425
1426#if DEBUG_MAIN
1427if( WIFEXITED  (status) ) printf("\n[ksh] child process %x exit\n"   , child_pid );
1428if( WIFSIGNALED(status) ) printf("\n[ksh] child process %x killed\n" , child_pid );
1429if( WIFSTOPPED (status) ) printf("\n[ksh] child process %x stopped\n", child_pid );
1430#endif
1431
1432        // release semaphore if KSH process is TXT owner, to unblock interactive thread
1433        is_fg( parent_pid , &is_owner );
1434        if( is_owner ) sem_post( &semaphore );
1435    }
1436}  // end main()
1437
1438
Note: See TracBrowser for help on using the repository browser.