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

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

Remove all RPCs in page-fault handling.

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