source: trunk/user/ksh/ksh.c

Last change on this file was 682, checked in by alain, 3 years ago

Introduce three new applications:

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