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

Last change on this file since 635 was 635, checked in by alain, 5 months ago

This version is a major evolution: The physical memory allocators,
defined in the kmem.c, ppm.c, and kcm.c files have been modified
to support remote accesses. The RPCs that were previously user
to allocate physical memory in a remote cluster have been removed.
This has been done to cure a dead-lock in case of concurrent page-faults.

This version 2.2 has been tested on a (4 clusters / 2 cores per cluster)
TSAR architecture, for both the "sort" and the "fft" applications.

File size: 38.8 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 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\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 != 4 )
419        {
420                    printf("  usage: display vmm cxy pid\n");
421            }
422        else
423        {
424                unsigned int cxy = atoi(argv[2]);
425                unsigned int pid = atoi(argv[3]);
426
427            if( display_vmm( cxy , pid ) )
428            {
429                printf("  error: no process %x in cluster %x\n", pid , cxy );
430            }
431        }
432    }
433    ///////////////////////////////////////////
434    else if( strcmp( argv[1] , "sched" ) == 0 )
435    {
436        if( argc != 4 )
437        {
438                    printf("  usage: display sched cxy lid\n");
439            }
440        else
441        {
442                unsigned int cxy = atoi(argv[2]);
443                unsigned int lid = atoi(argv[3]);
444
445            if( display_sched( cxy , lid ) )
446            {
447                printf("  error: illegal arguments cxy = %x / lid = %d\n", cxy, lid );
448            }
449        }
450    }
451    /////////////////////////////////////////////
452    else if( strcmp( argv[1] , "process" ) == 0 )
453    {
454        if( argc != 3 )
455        {
456                    printf("  usage: display process cxy\n");
457            }
458        else
459        {
460                unsigned int cxy = atoi(argv[2]);
461
462            if( display_cluster_processes( cxy , 0 ) )
463            {
464                printf("  error: illegal argument cxy = %x\n", cxy );
465            }
466        }
467    }
468    /////////////////////////////////////////
469    else if( strcmp( argv[1] , "txt" ) == 0 )
470    {
471        if( argc != 3 )
472        {
473                    printf("  usage: display txt txt_id\n");
474            }
475        else
476        {
477                unsigned int txtid = atoi(argv[2]);
478
479            if( display_txt_processes( txtid ) )
480            {
481                printf("  error: illegal argument txtid = %d\n", txtid );
482            }
483        }
484    }
485    /////////////////////////////////////////
486    else if( strcmp( argv[1] , "vfs" ) == 0 )
487    {
488        if( argc != 2 )
489        {
490                    printf("  usage: display vfs\n");
491            }
492        else
493        {
494            display_vfs();
495        }
496    }
497    //////////////////////////////////////////
498    else if( strcmp( argv[1] , "chdev" ) == 0 )
499    {
500        if( argc != 2 )
501        {
502                    printf("  usage: display chdev\n");
503            }
504        else
505        {
506            display_chdev();
507        }
508    }
509    //////////////////////////////////////////
510    else if( strcmp( argv[1] , "dqdt" ) == 0 )
511    {
512        if( argc != 2 )
513        {
514                    printf("  usage: display dqdt\n");
515            }
516        else
517        {
518            display_dqdt();
519        }
520    }
521    ///////////////////////////////////////////
522    else if( strcmp( argv[1] , "locks" ) == 0 )
523    {
524        if( argc != 4 )
525        {
526                    printf("  usage: display locks pid trdid\n");
527            }
528        else
529        {
530                unsigned int pid   = atoi(argv[2]);
531            unsigned int trdid = atoi(argv[3]);
532
533            if( display_busylocks( pid , trdid ) )
534            {
535                printf("  error: illegal arguments pid = %x / trdid = %x\n", pid, trdid );
536            }
537        }
538    }
539    /////////////////////////////////////////////////
540    else if( strcmp( argv[1] , "barrier" ) == 0 )
541    {
542        if( argc != 3 )
543        {
544                    printf("  usage: display barrier pid\n");
545            }
546        else
547        {
548                unsigned int pid   = atoi(argv[2]);
549
550            if( display_barrier( pid ) )
551            {
552                printf("  error: illegal arguments pid = %x\n", pid );
553            }
554        }
555    }
556    ///////////////////////////////////////////
557    else if( strcmp( argv[1] , "mapper" ) == 0 )
558    {
559        if( argc != 5 )
560        {
561                    printf("  usage: display mapper path page_id nbytes\n");
562            }
563        else
564        {
565                unsigned int page_id   = atoi(argv[3]);
566            unsigned int nbytes    = atoi(argv[4]);
567
568            if( display_mapper( argv[2] , page_id, nbytes ) )
569            {
570                printf("  error: cannot display page %d of mapper %s\n", page_id, argv[2] );
571            }
572        }
573    }
574    ///////////////////////////////////////////
575    else if( strcmp( argv[1] , "fat" ) == 0 )
576    {
577        if( argc != 4 )
578        {
579                    printf("  usage: display fat page_id nb_entries\n");
580            }
581        else
582        {
583                unsigned int page_id    = atoi(argv[2]);
584            unsigned int nb_entries = atoi(argv[3]);
585
586            if( display_fat( page_id, nb_entries ) )
587            {
588                printf("  error: cannot display page %d of fat\n", page_id );
589            }
590        }
591    }
592    else
593    {
594        printf("  error: undefined display request : %s\n", argv[1] ); 
595    }       
596
597    // release semaphore to get next command
598    sem_post( &semaphore );
599
600} // end cmd_display()
601
602/////////////////////////////////////////
603static void cmd_fg(int argc, char **argv)
604{
605        unsigned int pid;
606
607        if (argc != 2) 
608    {
609                printf("  usage: %s pid\n", argv[0]);
610        }
611    else
612    {
613        pid = atoi( argv[1] );   
614
615        if( pid == 0 )
616        { 
617                    printf("  error: PID cannot be 0\n" );
618            }
619        else if( fg( pid ) )
620        {
621                    printf("  error: cannot find process %x\n", pid );
622            }
623    }
624
625    // release semaphore to get next command
626    sem_post( &semaphore );
627
628}  // end cmd_fg()
629
630//////////////////////////////////////////////
631static void cmd_help( int argc , char **argv )
632{
633        unsigned int i;
634
635        if (argc != 1) 
636    {
637                printf("  usage: %s\n", argv[0]);
638        }
639    else
640    {
641        printf("available commands:\n");
642            for (i = 0 ; command[i].name ; i++) 
643        {
644                    printf("\t%s\t : %s\n", command[i].name , command[i].desc);
645            }
646    }
647
648    // release semaphore to get next command
649    sem_post( &semaphore );
650
651}   // end cmd_help()
652
653//////////////////////////////////////////////
654static void cmd_kill( int argc , char **argv )
655{
656        unsigned int pid;
657
658        if (argc != 2) 
659    {
660                printf("  usage: %s pid\n", argv[0]);
661        }
662    else
663    {
664            pid = atoi( argv[1] );
665
666        if( pid == 0 )
667        {
668                    printf("  error: kernel process 0 cannot be killed\n" );
669            }
670
671            else if( kill( pid , SIGKILL ) )
672        {
673                    printf("  error: process %x cannot be killed\n", pid );
674            }
675    }
676
677    // release semaphore to get next command
678    sem_post( &semaphore );
679
680}   // end cmd_kill()
681
682//////////////////////////////////////////////
683static void cmd_load( int argc , char **argv )
684{
685        int                  ret_fork;           // return value from fork
686        int                  ret_exec;           // return value from exec
687    unsigned int         ksh_pid;            // KSH process PID
688    unsigned int         background;         // background execution if non zero
689    unsigned int         placement;          // placement specified if non zero
690    unsigned int         cxy;                // target cluster if placement specified
691
692#if DEBUG_CMD_LOAD
693snprintf( string , 128 , "[ksh] enter %s" , __FUNCTION__);
694display_string( string );
695#endif
696
697        if( (argc < 2) || (argc > 4) ) 
698    {
699                printf("  usage: %s pathname [cxy] [&]\n", argv[0] );
700        }
701    else
702    {
703            strcpy( pathname , argv[1] );
704
705        if( argc == 2 )
706        {
707            background = 0;
708            placement  = 0;
709            cxy        = 0;
710        }
711        else if( argc == 3 )
712        {
713            if( (argv[2][0] == '&') && (argv[2][1] == 0) )
714            {
715                background = 1;
716                placement  = 0;
717                cxy        = 0;
718            }
719            else 
720            {
721                background = 0;
722                placement  = 1;
723                cxy        = atoi( argv[2] );
724            }
725        }
726        else  // argc == 4
727        { 
728            background = ( (argv[3][0] == '&') && (argv[3][1] == 0) );
729            placement  = 1;
730            cxy        = atoi( argv[2] );
731        }
732
733        // get KSH process PID
734        ksh_pid = getpid();
735
736#if DEBUG_CMD_LOAD
737snprintf( string , 128 , "[ksh] %s : <%s> / bg %d / place %d / cxy %x",
738__FUNCTION__, argv[1], background, placement, cxy );
739display_string( string );
740#endif
741
742        // set target cluster if required
743        if( placement ) place_fork( cxy );
744
745        // KSH process fork CHILD process
746            ret_fork = fork();
747
748        if ( ret_fork < 0 )     // it is a failure reported to KSH
749        {
750            printf("  error: ksh process unable to fork\n");
751        }
752        else if (ret_fork == 0) // it is the CHILD process
753        {
754
755#if DEBUG_CMD_LOAD
756snprintf( string , 128 , "[ksh] %s : child (%x) after fork, before exec",
757__FUNCTION__ , getpid() );
758display_string( string );
759#endif
760
761            // CHILD process exec NEW process
762            ret_exec = execve( pathname , NULL , NULL );
763
764#if DEBUG_CMD_LOAD
765snprintf( string , 128 , "[ksh] %s : child (%x) after exec / ret_exec %x",
766__FUNCTION__ , getpid(), ret_exec );
767display_string( string );
768#endif
769
770            // this is only executed in case of exec failure
771            if( ret_exec )
772            {
773                printf("  error: child process unable to exec <%s>\n", pathname );
774                exit( 0 );
775            }   
776            } 
777        else                    // it is the KSH process : ret_fork is the new process PID
778        {
779
780#if DEBUG_CMD_LOAD
781snprintf( string , 128 , "[ksh] %s : ksh (%x) after fork / ret_fork %x",
782__FUNCTION__, getpid(), ret_fork );
783display_string( string );
784#endif
785            // when the new process is launched in background, the KSH process
786            // takes the TXT ownership, and release the semaphore to get the next command.
787            // Otherwise, the child process keep the TXT ownership, and the semaphore will
788            // be released by the KSH main thread when the child process exit
789
790            if( background )    //  KSH must keep TXT ownership
791            {
792                // get back the TXT ownership
793                fg( ksh_pid );
794
795                // release semaphore to get next command
796                sem_post( &semaphore );
797            }
798        }
799    }
800}   // end cmd_load
801
802/////////////////////////////////////////////
803static void cmd_log( int argc , char **argv )
804{
805        unsigned int i;
806
807        if (argc != 1)
808    {
809                printf("  usage: %s\n", argv[0], argc ); 
810        }
811    else
812    {
813            printf("--- registered commands ---\n");
814            for (i = 0; i < LOG_DEPTH; i++) 
815        {
816                    printf(" - %d\t: %s\n", i, &log_entries[i].buf);
817            }
818    }
819
820    // release semaphore to get next command
821    sem_post( &semaphore );
822
823} // end cmd_log()
824
825
826////////////////////////////////////////////
827static void cmd_ls( int argc , char **argv )
828{
829    struct dirent  * entry;
830    DIR            * dir;
831
832#if DEBUG_CMD_LS
833snprintf( string , 128 , "[ksh] enter %s" , __FUNCTION__);
834display_string( string );
835#endif
836
837        if (argc > 2 )
838    {
839                printf("  usage: ls [path]\n");
840        }
841    else
842    {
843        // handle case with no argument
844
845        // get target directory path
846        if ( argc == 1 ) strcpy( pathname , "." );
847        else             strcpy( pathname , argv[1] );
848
849        // open target directory
850            dir = opendir( pathname );
851
852#if DEBUG_CMD_LS
853snprintf( string , 128 , "[ksh] %s : directory <%s> open / DIR %x\n",
854__FUNCTION__, pathname , dir );
855display_string( string );
856#endif
857
858        if( dir == NULL)
859            {
860                    printf("  error : directory <%s> not found\n", pathname );
861
862            sem_post( &semaphore );
863            return;
864            }
865
866        // loop on directory entries   
867        while ( (entry = readdir(dir)) != NULL )
868            {
869                    printf("%s\n", entry->d_name);
870            }
871
872        // close target directory
873            closedir( dir );
874
875#if DEBUG_CMD_LS
876snprintf( string , 128 , "[ksh] %s : directory <%s> closed\n",
877__FUNCTION__, pathname );
878display_string( string );
879#endif
880
881    }
882
883    // release semaphore to get next command
884    sem_post( &semaphore );
885
886} // end cmd_ls()
887
888///////////////////////////////////////////////
889static void cmd_mkdir( int argc , char **argv )
890{
891        if (argc != 2)
892    {
893                printf("  usage: mkdir pathname\n");
894        }
895    else
896    {
897        strcpy( pathname , argv[1] );
898
899        mkdir( pathname , 0x777 );
900    }
901
902    // release semaphore to get next command
903    sem_post( &semaphore );
904
905} // end cmd_mkdir()
906
907////////////////////////////////////////////
908static void cmd_mv( int argc , char **argv )
909{
910        if (argc != 3) 
911    {
912                printf("  usage: mv old_pathname new_pathname\n");
913        }
914    else
915    {
916        strcpy( pathname , argv[1] );
917        strcpy( pathnew  , argv[2] );
918
919        // call the relevant syscall
920        if( rename( pathname , pathnew ) )
921        {
922            printf("  error: unable to rename <%s> to <%s>\n", pathname , pathnew );
923        }
924    }
925
926    // release semaphore to get next command
927    sem_post( &semaphore );
928
929}  // end cmd_mv
930
931
932////////////////////////////////////////////
933static void cmd_ps( int argc , char **argv )
934{
935    unsigned int x_size;
936    unsigned int y_size;
937    unsigned int ncores;
938    unsigned int x;
939    unsigned int y;
940
941#if DEBUG_CMD_PS
942snprintf( string , 128 , "[ksh] enter %s" , __FUNCTION__);
943display_string( string );
944#endif
945
946        if (argc != 1)
947    {
948                printf("  usage: %s\n", argv[0]);
949        }
950    else
951    {
952        // get platform config
953        get_config( &x_size , &y_size , &ncores );
954
955        // scan all clusters
956        for( x = 0 ; x < x_size ; x++ )
957        {
958            for( y = 0 ; y < y_size ; y++ )
959            {
960
961#if DEBUG_CMD_PS
962snprintf( string , 128 , "\n[ksh] %s : call display_cluster_process()", __FUNCTION__ );
963display_string( string );
964#endif
965
966                // display only owned processes
967                display_cluster_processes( HAL_CXY_FROM_XY(x,y), 1 ); 
968            }
969        }
970    }
971
972    // release semaphore to get next command
973    sem_post( &semaphore );
974
975}  // end cmd_ps()
976
977/////////////////////////////////////////////
978static void cmd_pwd( int argc , char **argv )
979{
980        if (argc != 1)
981    {
982                printf("  usage: %s\n", argv[0]);
983        }
984    else 
985    {
986        if ( getcwd( pathname , PATH_MAX_SIZE ) ) 
987        {
988                    printf("  error: unable to get current directory\n");
989            }
990        else 
991        {
992                    printf("%s\n", pathname );
993            }
994    }
995
996    // release semaphore to get next command
997    sem_post( &semaphore );
998
999}  // end cmd_pwd()
1000
1001////////////////////////////////////////////
1002static void cmd_rm( int argc , char **argv )
1003{
1004        if (argc != 2)
1005    {
1006                printf("  usage: %s pathname\n", argv[0]);
1007        }
1008    else
1009    {
1010            strcpy( pathname , argv[1] );
1011
1012        if ( unlink( pathname ) )
1013        {
1014                    printf("  error: unable to remove <%s>\n", pathname );
1015            }
1016    }
1017
1018    // release semaphore to get next command
1019    sem_post( &semaphore );
1020
1021}  // end_cmd_rm()
1022
1023///////////////////////////////////////////////
1024static void cmd_rmdir( int argc , char **argv )
1025{
1026    // same as cmd_rm()
1027        cmd_rm (argc , argv );
1028}
1029
1030///////////////////////////////////////////////
1031static void cmd_trace( int argc , char **argv )
1032{
1033    unsigned int cxy;
1034    unsigned int lid;
1035
1036        if (argc != 3)
1037    {
1038                printf("  usage: trace cxy lid \n");
1039        }
1040    else
1041    {
1042        cxy = atoi(argv[1]);
1043        lid = atoi(argv[2]);
1044
1045        if( trace( 1 , cxy , lid ) )
1046        {
1047            printf("  error: core[%x,%d] not found\n", cxy, lid );
1048        }
1049    }
1050
1051    // release semaphore to get next command
1052    sem_post( &semaphore );
1053
1054}  // end cmd_trace
1055
1056///////////////////////////////////////////////
1057static void cmd_untrace( int argc , char **argv )
1058{
1059    unsigned int cxy;
1060    unsigned int lid;
1061
1062        if (argc != 3)
1063    {
1064                printf("  usage: untrace cxy lid \n");
1065        }
1066    else
1067    {
1068        cxy = atoi(argv[1]);
1069        lid = atoi(argv[2]);
1070
1071        if( trace( 0 , cxy , lid ) )
1072        {
1073            printf("  error: core[%x,%d] not found\n", cxy, lid );
1074        }
1075    }
1076
1077    // release semaphore to get next command
1078    sem_post( &semaphore );
1079
1080}  // end cmd_untrace()
1081
1082///////////////////////////////////////////////////////////////////////////////////
1083// Array of commands
1084///////////////////////////////////////////////////////////////////////////////////
1085
1086ksh_cmd_t command[] =
1087{
1088        { "cat",     "display file content",                            cmd_cat     },
1089        { "cd",      "change current directory",                        cmd_cd      },
1090        { "cp",      "replicate a file in file system",                 cmd_cp      },
1091    { "fg",      "put a process in foreground",                     cmd_fg      },
1092    { "display", "display vmm/sched/process/vfs/chdev/txt",         cmd_display },
1093        { "load",    "load an user application",                        cmd_load    },
1094        { "help",    "list available commands",                         cmd_help    },
1095        { "kill",    "kill a process (all threads)",                    cmd_kill    },
1096        { "log",     "list registered commands",                        cmd_log     },
1097        { "ls",      "list directory entries",                          cmd_ls      },
1098        { "mkdir",   "create a new directory",                          cmd_mkdir   },
1099        { "mv",      "move a file in file system",                      cmd_mv      },
1100        { "pwd",     "print current working directory",                 cmd_pwd     },
1101        { "ps",      "display all processes",                           cmd_ps      },
1102        { "rm",      "remove a file from file system",                  cmd_rm      },
1103        { "rmdir",   "remove a directory from file system",             cmd_rmdir   },
1104        { "trace",   "activate trace for a given core",                 cmd_trace   },
1105        { "untrace", "desactivate trace for a given core",              cmd_untrace },
1106        { NULL,      NULL,                                                                              NULL        }
1107};
1108
1109////////////////////////////////////////////////////////////////////////////////////
1110// This function analyses one command (with arguments), executes it, and returns.
1111////////////////////////////////////////////////////////////////////////////////////
1112static void __attribute__ ((noinline)) execute( char * buf )
1113{
1114        int    argc = 0;
1115        char * argv[MAX_ARGS];
1116        int    i;
1117        int    len = strlen(buf);
1118
1119#if DEBUG_EXECUTE
1120snprintf( string , 128 , "[ksh] enter %s for command <%s>" , __FUNCTION__ , buf );
1121display_string( string );
1122#endif
1123
1124        // build argc/argv
1125        for (i = 0; i < len; i++) 
1126    {
1127        // convert SPACE to NUL
1128                if (buf[i] == ' ') 
1129        {
1130                        buf[i] = '\0';
1131                }
1132        else if (i == 0 || buf[i - 1] == '\0') 
1133        {
1134                        if (argc < MAX_ARGS) 
1135            {
1136                                argv[argc] = &buf[i];
1137                                argc++;
1138                        }
1139                }
1140        }
1141
1142    // check command
1143        if (argc == 0)
1144    {
1145        // release semaphore to get next command
1146        sem_post( &semaphore );
1147    }
1148
1149#if DEBUG_EXECUTE
1150snprintf( string , 128 , "\n[ksh] in %s : argc = %d / arg0 = %s / arg1 = %s\n",
1151__FUNCTION__ , argc , argv[0], argv[1] );
1152#endif
1153
1154    // scan the list of commands to match typed command
1155    int found = 0;
1156    for ( i = 0 ; (command[i].name != NULL) && (found == 0) ; i++ )
1157    {
1158        if (strcmp(argv[0], command[i].name) == 0)
1159        {
1160                        command[i].fn(argc, argv);
1161                        found = 1;
1162                }
1163    }
1164
1165    // check undefined command
1166        if (!found) 
1167    {   
1168        printf("  error : undefined command <%s>\n", argv[0]);
1169
1170        // release semaphore to get next command
1171        sem_post( &semaphore );
1172        }
1173}  // end execute()
1174
1175
1176
1177///////////////////////////////
1178static void interactive( void )
1179{
1180        char           c;                                               // read character
1181    unsigned int   end_command;             // last character found in a command
1182        unsigned int   count;                   // pointer in command buffer
1183        unsigned int   i;                                               // index for loops
1184        unsigned int   state;                   // escape sequence state
1185
1186        char           cmd[CMD_MAX_SIZE];               // buffer for one command
1187
1188/* 1. first direct command
1189if( sem_wait( &semaphore ) )
1190{
1191    printf("\n[ksh error] cannot found semafore\n" );
1192    exit( 1 );
1193}
1194else
1195{
1196    printf("\n[ksh] load bin/user/sort.elf\n");
1197}
1198
1199strcpy( cmd , "load bin/user/sort.elf" );
1200execute( cmd );
1201*/
1202
1203
1204
1205/* 2. second direct command
1206if( sem_wait( &semaphore ) )
1207{
1208    printf("\n[ksh error] cannot found semafore\n" );
1209    exit( 1 );
1210}
1211else
1212{
1213    printf("\n[ksh] load bin/user/fft.elf\n");
1214}
1215
1216strcpy( cmd , "load bin/user/fft.elf" );
1217execute( cmd );
1218*/
1219
1220
1221
1222        enum fsm_states
1223    {
1224                NORMAL = 0,
1225                ESCAPE = 1,
1226                BRAKET = 2,
1227        };
1228
1229        // This lexical analyser writes one command line in the command buffer.
1230        // It is implemented as a 3 states FSM to handle the following escape sequences:
1231        // - ESC [ A : up arrow
1232        // - ESC [ B : down arrow
1233        // - ESC [ C : right arrow
1234        // - ESC [ D : left arrow
1235        // The three states have the following semantic:
1236        // - NORMAL : no (ESC) character has been found
1237        // - ESCAPE : the character (ESC) has been found
1238        // - BRAKET : the wo characters (ESC,[) have been found
1239
1240    // take the semaphore for the first command
1241    if ( sem_wait( &semaphore ) )
1242    {
1243        printf("\n[ksh error] cannot found semafore\n" );
1244        exit( 1 );
1245    }
1246
1247    // display prompt for the first command
1248    printf("\n[ksh] ");
1249
1250    // external loop on the commands / the interactive thread do not exit this loop
1251        while (1)
1252        {
1253            // initialize command buffer
1254            // memset( cmd , 0x20 , sizeof(cmd) );   // TODO useful ?
1255            count       = 0;
1256            state       = NORMAL;
1257        end_command = 0;
1258
1259#if DEBUG_INTER
1260unsigned int pid = getpid();
1261snprintf( string , 128 , "[ksh] %s : request a new command", __FUNCTION__ );
1262display_string( string );
1263#endif
1264
1265        // internal loop on characters in one command
1266        while( end_command == 0 )
1267        {
1268            // get one character from TXT_RX
1269                c = (char)getchar();
1270
1271            if( c == 0 ) continue;
1272
1273                    if( state == NORMAL )  // we are not in an escape sequence
1274                    {
1275                                if ((c == '\b') || (c == 0x7F))  // backspace => remove one character
1276                                {
1277                                    if (count > 0)
1278                    {
1279                                        printf("\b \b");
1280                                        count--;
1281                                    }
1282                                }
1283                                else if (c == '\n')                  // new line => end of command
1284                                {
1285                                    if (count > 0)               // analyse & execute command
1286                                    {
1287                                            // complete command with NUL character
1288                                            cmd[count] = 0;
1289                        count++;
1290#if DEBUG_INTER
1291snprintf( string , 128 , "[ksh] %s : get command <%s>", __FUNCTION__, cmd );
1292display_string( string );
1293display_vmm( 0 , 2 );
1294#endif
1295                        // register command in log_entries[] array
1296                                            strncpy( log_entries[ptw].buf , cmd , count );
1297                                            log_entries[ptw].count = count;
1298                                            ptw = (ptw + 1) % LOG_DEPTH;
1299                                            ptr = ptw;
1300
1301#if DEBUG_INTER
1302snprintf( string , 128 , "[ksh] %s : execute <%s>", __FUNCTION__, cmd );
1303display_string( string );
1304#endif
1305                        // echo character
1306                        putchar( c );
1307
1308                                            // execute command
1309                                            execute( cmd );
1310                                    }
1311                    else                         // no command registered
1312                    {
1313                        // release semaphore to get next command
1314                        sem_post( &semaphore );
1315                    }
1316
1317                    // exit internal loop on characters
1318                    end_command = 1;
1319                }
1320                            else if (c == '\t')             // tabulation => do nothing
1321                                {
1322                            }
1323                            else if (c == (char)0x1B)       // ESC => start an escape sequence
1324                            {
1325                    state = ESCAPE;
1326                            }
1327                            else                                               // normal character
1328                                {
1329                                    if (count < (sizeof(cmd) - 1) )
1330                                    {
1331                        // register character in command buffer
1332                                            cmd[count] = c;
1333                                            count++;
1334
1335                        // echo character
1336                        putchar( c );
1337                                        }
1338                    else
1339                    {
1340                                printf("\none command cannot exceed %d characters\n", sizeof(cmd) );
1341                    }
1342                                }
1343                        }
1344                        else if( state == ESCAPE ) 
1345                        {
1346                                if (c == '[')           //  valid sequence => continue
1347                                {
1348                                        state = BRAKET;
1349                                }
1350                                else                               // invalid sequence => do nothing
1351                                {
1352                                        state = NORMAL;
1353                                }
1354                        }
1355                        else if( state == BRAKET )
1356                        {
1357                                if (c == 'D')   // valid  LEFT sequence => move cmd pointer left
1358                                {
1359                                        if (count > 0)
1360                                        {
1361                                                printf("\b");
1362                                                count--;
1363                                        }
1364
1365                                        // get next user char
1366                                        state = NORMAL;
1367                                }
1368                                else if (c == 'C')   // valid  RIGHT sequence => move cmd pointer right
1369                                {
1370                                        if (count < sizeof(cmd) - 1)
1371                                        {
1372                                                printf("%c", cmd[count]);
1373                                                count++;
1374                                        }
1375
1376                                        // get next user char
1377                                        state = NORMAL;
1378                                }
1379                                else if (c == 'A')   // valid  UP sequence => move log pointer backward
1380                                {
1381                                        // cancel current command
1382                                        for (i = 0; i < count; i++) printf("\b \b");
1383                                        count = 0;
1384
1385                                        // copy log command into cmd
1386                                        ptr = (ptr - 1) % LOG_DEPTH;
1387                                        strcpy(cmd, log_entries[ptr].buf);
1388                                        count = log_entries[ptr].count - 1;
1389
1390                                        // display log command
1391                                        printf("%s", cmd);
1392
1393                                        // get next user char
1394                                        state = NORMAL;
1395                                }
1396                                else if (c == 'B')   // valid  DOWN sequence => move log pointer forward
1397                                {
1398                                        // cancel current command
1399                                        for (i = 0 ; i < count; i++) printf("\b \b");
1400                                        count = 0;
1401
1402                                        // copy log command into cmd
1403                                        ptr = (ptr + 1) % LOG_DEPTH;
1404                                        strcpy(cmd, log_entries[ptr].buf);
1405                                        count = log_entries[ptr].count;
1406
1407                                        // display log command
1408                                        printf("%s", cmd);
1409
1410                                        // get next user char
1411                                        state = NORMAL;
1412                                }
1413                                else                               // other character => do nothing
1414                                {
1415                                        // get next user char
1416                                        state = NORMAL;
1417                                }
1418                        }
1419                }  // end internal while loop on characters
1420
1421#if DEBUG_INTER
1422snprintf( string , 128 , "\n[ksh] %s : complete <%s> command", __FUNCTION__, cmd );
1423display_string( string );
1424#endif
1425
1426        // block interactive thread if KSH loose TXT ownership
1427        if ( sem_wait( &semaphore ) )
1428        {
1429            printf("\n[ksh error] cannot found semafore\n" );
1430            exit( 1 );
1431        }
1432
1433        // display prompt for next command
1434        printf("\n[ksh] ");
1435
1436        }  // end external while loop on commands
1437
1438}  // end interactive()
1439
1440////////////////
1441int main( void )
1442{
1443    unsigned int cxy;             // owner cluster identifier for this KSH process
1444    unsigned int lid;             // core identifier for this KSH main thread
1445    int          status;          // child process termination status
1446    int          parent_pid;      // parent process identifier (i.e. this process)
1447    int          child_pid;       // child process identifier
1448    unsigned int is_owner;        // non-zero if KSH process is TXT owner
1449
1450    // initialize log buffer
1451        memset( &log_entries , 0, sizeof(log_entries));
1452        ptw   = 0;
1453        ptr   = 0;
1454
1455    // get KSH process pid and core
1456    parent_pid = getpid();
1457    get_core( &cxy , &lid );
1458
1459#if DEBUG_MAIN
1460snprintf( string , 128 , "\n[ksh] main thread started on core[%x,%d]\n", cxy , lid ); 
1461display_string( string );
1462#endif
1463   
1464    // initializes the semaphore used to synchronize with interactive thread
1465    if ( sem_init( &semaphore , 0 , 1 ) )
1466    {
1467        printf("\n[KSH ERROR] cannot initialize semaphore\n" );
1468        exit( 1 ); 
1469    }
1470
1471#if DEBUG_MAIN
1472snprintf( string , 128 , "\n[ksh] main initialized semaphore\n" ); 
1473display_string( string );
1474#endif
1475   
1476    // initialize interactive thread attributes
1477    attr.attributes = PT_ATTR_DETACH | PT_ATTR_CLUSTER_DEFINED;
1478    attr.cxy        = cxy;
1479
1480    // lauch the interactive thread
1481    pthread_create( &trdid,
1482                    &attr,
1483                    &interactive,   // entry function
1484                    NULL ); 
1485#if DEBUG_MAIN
1486snprintf( string , 128 , "\n[ksh] main thread launched interactive thread %x\n", trdid ); 
1487display_string( string );
1488#endif
1489
1490    // signal INIT process
1491    kill( 1 , SIGCONT );
1492   
1493    // enter infinite loop monitoring children processes termination
1494    while( 1 )
1495    {
1496        // wait children termination
1497        child_pid = wait( &status );
1498
1499        if( DEBUG_MAIN )
1500        {
1501            if(WIFEXITED  (status)) printf("\n[ksh] child process %x exit\n"   ,child_pid);
1502            if(WIFSIGNALED(status)) printf("\n[ksh] child process %x killed\n" ,child_pid);
1503            if(WIFSTOPPED (status)) printf("\n[ksh] child process %x stopped\n",child_pid);
1504        }
1505
1506        // release semaphore if KSH process is TXT owner, to unblock interactive thread
1507        is_fg( parent_pid , &is_owner );
1508        if( is_owner ) sem_post( &semaphore );
1509    }
1510}  // end main()
1511
1512
Note: See TracBrowser for help on using the repository browser.