Changeset 457 for trunk/user/ksh/ksh.c
- Timestamp:
- Aug 2, 2018, 11:47:13 AM (6 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/user/ksh/ksh.c
r446 r457 4 4 // Author : Alain Greiner 5 5 /////////////////////////////////////////////////////////////////////////////// 6 // This applications implement a minimal shell for ALMOS-MKH. 7 // This user process contains two POSIX threads: 6 // This application implements a minimal shell for ALMOS-MKH. 7 // 8 // This user KSH process contains two POSIX threads: 8 9 // - the "main" thread contains the infinite loop implementing 9 // the children processes termination monitoring (children processes 10 // are created by the <load> command and attached to the KSH TXT terminal). 10 // the children processes termination monitoring using the wait syscall. 11 11 // - the "interactive" thread contains the infinite loop implementing 12 12 // the command interpreter attached to the TXT terminal. 13 // This "interactive" thread block and deschedules when the KSH process 14 // loses the TXT terminal ownership. It is reactivated when the KSH 15 // process returns in background. 16 // 17 // Note: the children processes are created by the <load> command, and are 18 // attached to the same TXT terminal as the KSH process itself. 19 // . A child process can be lauched in foreground: the KSH process loses 20 // the TXT terminal ownership, that is transfered to the new process. 21 // . A child process can be lauched in background: the KSH process keeps 22 // the TXT terminal ownership. that is transfered to the new process. 13 23 /////////////////////////////////////////////////////////////////////////////// 14 24 … … 20 30 #include <unistd.h> 21 31 #include <almosmkh.h> 32 #include <semaphore.h> 22 33 23 34 #define CMD_MAX_SIZE (256) // max number of characters in one command … … 25 36 #define MAX_ARGS (32) // max number of arguments in a command 26 37 #define FIFO_SIZE (1024) // FIFO depth for recursive ls 38 39 #define KSH_DEBUG 0 27 40 28 41 //////////////////////////////////////////////////////////////////////////////// … … 59 72 unsigned int ptr; // read pointer in log_entries[] 60 73 61 pthread_attr_t attr; // monitor thread attributes 74 pthread_attr_t attr; // interactive thread attributes 75 76 sem_t semaphore; // block interactive thread when zero 62 77 63 78 //////////////////////////////////////////////////////////////////////////////// … … 119 134 */ 120 135 136 // release semaphore to get next command 137 sem_post( &semaphore ); 138 121 139 } // end cmd_cat() 122 140 … … 135 153 136 154 printf(" error: not implemented yet\n"); 137 /* 138 path = argv[1]; 139 140 if (chdir(path) == -1) 141 { 142 printf(" error: cannot cd to %s\n", path); 143 } 144 */ 155 156 // release semaphore to get next command 157 sem_post( &semaphore ); 145 158 146 159 } // end cmd_cd() … … 237 250 */ 238 251 252 // release semaphore to get next command 253 sem_post( &semaphore ); 254 239 255 } // end cmd_cp() 240 256 … … 343 359 printf(" usage: display (vmm/sched/process/vfs/chdev/txt) [arg2] [arg3]\n"); 344 360 } 361 362 // release semaphore to get next command 363 sem_post( &semaphore ); 364 345 365 } // end cmd_display() 346 366 … … 367 387 printf(" error: cannot find process %x\n", pid ); 368 388 } 389 390 // release semaphore to get next command 391 sem_post( &semaphore ); 392 369 393 } // end cmd_fg() 370 394 … … 385 409 printf("\t%s\t : %s\n", cmd[i].name , cmd[i].desc); 386 410 } 411 412 // release semaphore to get next command 413 sem_post( &semaphore ); 414 387 415 } // end cmd_help() 388 416 … … 409 437 printf(" error: process %x cannot be killed\n", pid ); 410 438 } 439 440 // release semaphore to get next command 441 sem_post( &semaphore ); 442 411 443 } // end cmd_kill() 412 444 … … 419 451 char * pathname; // path to .elf file 420 452 unsigned int background; // background execution if non zero 421 int status; // new process exit status422 453 423 454 if( (argc < 2) || (argc > 3) ) … … 435 466 ksh_pid = getpid(); 436 467 468 #if KSH_DEBUG 469 printf("\n[KSH_DEBUG] in %s : ksh PID %x / path %s / background %d\n", 470 __FUNCTION__, ksh_pid, argv[1], background ); 471 #endif 472 437 473 // KSH process fork CHILD process 438 474 ret_fork = fork(); 439 475 440 if ( ret_fork < 0 ) 476 if ( ret_fork < 0 ) // it is a failure reported to KSH 441 477 { 442 478 printf(" error: ksh process unable to fork\n"); 443 479 return; 444 480 } 445 else if (ret_fork == 0) 481 else if (ret_fork == 0) // it is the CHILD process 446 482 { 447 483 // CHILD process exec NEW process … … 455 491 } 456 492 } 457 else // it is the parent KSH : ret_fork is the new process PID 458 { 459 // give back terminal ownership to KSH 460 // when new process created in background 461 if( background ) fg( ksh_pid ); 462 463 // return to command interpreter 464 return; 493 else // it is the KSH process : ret_fork is the new process PID 494 { 495 496 #if KSH_DEBUG 497 int sem_value; 498 sem_getvalue( &semaphore , &sem_value ); 499 printf("\n[KSH_DEBUG] in %s : child PID %x / background %d / sem_value %d\n", 500 ret_fork, background, sem_value ); 501 #endif 502 503 if( background ) // child in background => KSH keeps TXT ownership 504 { 505 // execve() tranfered TXT ownership to child => give it back to KSH 506 fg( ksh_pid ); 507 508 // release semaphore to get next command 509 sem_post( &semaphore ); 510 } 465 511 } 466 512 } // end cmd_load … … 476 522 printf(" - %d\t: %s\n", i, &log_entries[i].buf); 477 523 } 478 } 524 525 // release semaphore to get next command 526 sem_post( &semaphore ); 527 528 } // end cmd_log() 529 479 530 480 531 //////////////////////////////////////////// … … 509 560 closedir(dir); 510 561 */ 511 } 562 563 // release semaphore to get next command 564 sem_post( &semaphore ); 565 566 } // end cmd_ls() 512 567 513 568 /////////////////////////////////////////////// … … 525 580 526 581 printf(" error: not implemented yet\n"); 527 /* 528 if ( mkdir( path, 0x700) == -1 ) 529 { 530 printf(" error: cannot create directory %s\n", path); 531 } 532 */ 533 } 582 583 // release semaphore to get next command 584 sem_post( &semaphore ); 585 586 } // end cmd_mkdir() 534 587 535 588 //////////////////////////////////////////// … … 545 598 printf(" error: not implemented yet\n"); 546 599 547 /* 548 int ret = giet_fat_rename(argv[1], argv[2]); 549 if (ret < 0) 550 { 551 printf(" error : cannot move %s to %s / err = %d\n", argv[1], argv[2], ret ); 552 } 553 */ 554 555 } 600 // release semaphore to get next command 601 sem_post( &semaphore ); 602 603 } // end cmd_mv 556 604 557 605 ///////////////////////////////////////////// … … 574 622 printf("%s\n", buf); 575 623 } 576 } 624 625 // release semaphore to get next command 626 sem_post( &semaphore ); 627 628 } // end cmd_pwd() 577 629 578 630 //////////////////////////////////////////// … … 590 642 591 643 printf(" error: not implemented yet\n"); 592 /* 593 if (remove(path) == -1) 594 { 595 printf(" error: cannot remove %s\n", path); 596 } 597 */ 598 599 } 644 645 // release semaphore to get next command 646 sem_post( &semaphore ); 647 648 } // end_cmd_rm() 600 649 601 650 /////////////////////////////////////////////// 602 651 static void cmd_rmdir( int argc , char **argv ) 603 652 { 653 // same as cmd_rm() 604 654 cmd_rm(argc, argv); 605 655 } … … 624 674 printf(" error: core[%x,%d] not found\n", cxy, lid ); 625 675 } 626 } 676 677 // release semaphore to get next command 678 sem_post( &semaphore ); 679 680 } // end cmd_trace 627 681 628 682 /////////////////////////////////////////////// … … 645 699 printf(" error: core[%x,%d] not found\n", cxy, lid ); 646 700 } 647 } 648 649 ////////////////////////////////////////////////////////////////// 701 702 // release semaphore to get next command 703 sem_post( &semaphore ); 704 705 } // end cmd_untrace() 706 707 /////////////////////////////////////////////////////////////////////////////////// 650 708 // Array of commands 651 ////////////////////////////////////////////////////////////////// 709 /////////////////////////////////////////////////////////////////////////////////// 652 710 653 711 ksh_cmd_t cmd[] = … … 660 718 { "load", "load an user application", cmd_load }, 661 719 { "help", "list available commands", cmd_help }, 662 { "kill", "kill a n application (all threads)",cmd_kill },720 { "kill", "kill a process (all threads)", cmd_kill }, 663 721 { "log", "list registered commands", cmd_log }, 664 722 { "ls", "list directory entries", cmd_ls }, … … 674 732 675 733 //////////////////////////////////////////////////////////////////////////////////// 676 // This function analyses one command (with arguments), execute it, and return.734 // This function analyses one command (with arguments), executes it, and returns. 677 735 //////////////////////////////////////////////////////////////////////////////////// 678 static void parse( char *buf)736 static void parse( char * buf ) 679 737 { 680 738 int argc = 0; … … 717 775 } 718 776 719 if (!found) 720 { 721 printf(" undefined command <%s>\n", argv[0]); 777 if (!found) // undefined command 778 { 779 printf(" error : undefined command <%s>\n", argv[0]); 780 781 // release semaphore to get next command 782 sem_post( &semaphore ); 722 783 } 723 784 } … … 729 790 char c; // read character 730 791 char buf[CMD_MAX_SIZE]; // buffer for one command 731 unsigned int count; // pointer in buf 792 unsigned int end_command; // last character found in a command 793 unsigned int count; // pointer in command buffer 732 794 unsigned int i; // index for loops 795 unsigned int state; // escape sequence state 796 797 char string[80]; 733 798 734 799 enum fsm_states 735 800 { 736 NORMAL ,737 ESCAPE ,738 BRAKET ,801 NORMAL = 0, 802 ESCAPE = 1, 803 BRAKET = 2, 739 804 }; 740 805 741 // initialize command buffer 742 memset( buf, 0x20 , sizeof(buf) ); 743 count = 0; 744 745 // display first prompt 746 printf("# "); 747 748 // This lexical analyser writes one command line in the buf buffer. 749 // It is implemented as a 3 states FSM to handle the following sequences: 806 // This lexical analyser writes one command line in the command buffer. 807 // It is implemented as a 3 states FSM to handle the following escape sequences: 750 808 // - ESC [ A : up arrow 751 809 // - ESC [ B : down arrow … … 757 815 // - BRAKET : the wo characters (ESC,[) have been found 758 816 759 unsigned int state = NORMAL; 760 761 // @@@ 762 parse("load /bin/user/idbg.elf"); 763 // @@@ 764 817 // external loop on the commands 818 // the in teractive thread should not exit this loop 765 819 while (1) 766 820 { 767 c = (char)getchar(); 768 769 if( c == 0 ) continue; 770 771 switch (state) 772 { 773 case NORMAL: 774 { 821 // initialize command buffer 822 memset( buf, 0x20 , sizeof(buf) ); // TODO useful ? 823 count = 0; 824 state = NORMAL; 825 826 // block if the KSH process is not the TXT owner 827 // - if the command is not a "load" 828 // the semaphore must be released by the cmd_***() 829 // - if the command is a load, it depends on 830 // the "background" argument 831 sem_wait( &semaphore ); 832 833 // display prompt on a new line 834 printf("\n[ksh] "); 835 836 end_command = 0; 837 838 // internal loop on characters in one command 839 while( end_command == 0 ) 840 { 841 // get one character from TXT_RX 842 c = (char)getchar(); 843 844 if( c == 0 ) continue; 845 846 if( state == NORMAL ) // we are not in an escape sequence 847 { 775 848 if ((c == '\b') || (c == 0x7F)) // backspace => remove one character 776 849 { 777 if (count > 0) { 778 printf("\b \b"); 779 count--; 850 if (count > 0) 851 { 852 printf("\b \b"); 853 count--; 854 } 855 } 856 else if (c == '\n') // new line => end of command 857 { 858 if (count > 0) // analyse & execute command 859 { 860 // complete command with NUL character 861 buf[count] = 0; 862 count++; 863 864 // register command in log arrays 865 strcpy(log_entries[ptw].buf, buf); 866 log_entries[ptw].count = count; 867 ptw = (ptw + 1) % LOG_DEPTH; 868 ptr = ptw; 869 870 // echo character 871 putchar( c ); 872 873 // call parser to analyse and execute command 874 parse( buf ); 875 } 876 else // no command registered 877 { 878 // release semaphore to get next command 879 sem_post( &semaphore ); 880 } 881 882 // exit internal loop on characters 883 end_command = 1; 884 } 885 else if (c == '\t') // tabulation => do nothing 886 { 887 } 888 else if (c == (char)0x1B) // ESC => start an escape sequence 889 { 890 state = ESCAPE; 891 } 892 else // normal character 893 { 894 if (count < sizeof(buf) - 1) 895 { 896 // register character in command buffer 897 buf[count] = c; 898 count++; 899 900 // echo character 901 putchar( c ); 780 902 } 781 903 } 782 else if (c == '\n') // new line => call parser to execute command783 {784 if (count > 0)785 {786 // complete command787 buf[count] = '\0';788 789 // register command in log arrays790 strcpy(log_entries[ptw].buf, buf);791 log_entries[ptw].count = count;792 ptw = (ptw + 1) % LOG_DEPTH;793 ptr = ptw;794 795 // execute command796 printf("\n");797 parse((char *)&buf);798 799 // reinitialise buffer and display prompt800 for ( i = 0 ; i < sizeof(buf) ; i++ ) buf[i] = 0x20;801 count = 0;802 printf("# ");803 }804 else805 {806 printf("\n# ");807 }808 }809 else if (c == '\t') // tabulation => do nothing810 {811 }812 else if (c == (char)0x1B) // ESC => start an escape sequence813 {814 state = ESCAPE;815 }816 else // register character in command buffer817 {818 if (count < sizeof(buf) - 1)819 {820 putchar( c );821 buf[count] = c;822 count++;823 }824 }825 break;826 904 } 827 case ESCAPE:905 else if( state == ESCAPE ) 828 906 { 829 907 if (c == '[') // valid sequence => continue … … 835 913 state = NORMAL; 836 914 } 837 break;838 915 } 839 case BRAKET:916 else if( state == BRAKET ) 840 917 { 841 918 if (c == 'D') // valid LEFT sequence => move buf pointer left … … 900 977 state = NORMAL; 901 978 } 902 break;903 979 } 904 } 905 } 980 } // end internal while loop on characters 981 } // end external while loop on commands 906 982 } // end interactive() 907 983 … … 912 988 unsigned int lid; // core identifier for this KSH main thread 913 989 int status; // child process termination status 914 int pid; // chils process identifier 990 int child_pid; // child process identifier 991 int parent_pid; // parent process identifier 915 992 pthread_t trdid; // kernel allocated index for interactive thread 993 unsigned int is_owner; // non-zero if KSH process is TXT owner 916 994 917 995 // initialize log buffer … … 920 998 ptr = 0; 921 999 1000 // get KSH process pid and core 1001 parent_pid = getpid(); 922 1002 get_core( &cxy , & lid ); 1003 923 1004 printf( "\n\n~~~ KSH on core[%x,%d] ~~~\n\n", cxy , lid ); 1005 1006 // initializes the semaphore used to unblock the interactive thread 1007 sem_init( &semaphore , 0 , 1 ); 924 1008 925 1009 // initialize interactive thread attributes … … 936 1020 while( 1 ) 937 1021 { 938 pid = wait( &status );939 940 #if 0 941 if ( WIFEXITED (status) ) printf("\n[KSH] process %x exited\n" , pid ); 942 else if( WIFSIGNALED(status) ) printf("\n[KSH] process %x killed\n" ,pid );943 else if( WIFSTOPPED (status) ) printf("\n[KSH] process %x stopped\n",pid );944 else printf("\n[KSH] process %x strange\n", pid ); 1022 // wait children termination 1023 child_pid = wait( &status ); 1024 1025 #if KSH_DEBUG 1026 if( WIFEXITED (status) ) printf("\n[KSH] child process %x exited\n" , child_pid ); 1027 if( WIFSIGNALED(status) ) printf("\n[KSH] child process %x killed\n" , child_pid ); 1028 if( WIFSTOPPED (status) ) printf("\n[KSH] child process %x stopped\n", child_pid ); 945 1029 #endif 946 1030 1031 // release semaphore if KSH process is TXT owner, to unblock interactive thread 1032 is_fg( parent_pid , &is_owner ); 1033 if( is_owner ) sem_post( &semaphore ); 1034 947 1035 } 948 1036 } // end main()
Note: See TracChangeset
for help on using the changeset viewer.