| [469] | 1 | ///////////////////////////////////////////////////////////////////////////////////////// | 
|---|
| [407] | 2 | // File   :  ksh.c | 
|---|
 | 3 | // Date   :  October 2017 | 
|---|
 | 4 | // Author :  Alain Greiner | 
|---|
| [469] | 5 | ///////////////////////////////////////////////////////////////////////////////////////// | 
|---|
| [457] | 6 | // This application implements a minimal shell for ALMOS-MKH. | 
|---|
 | 7 | // | 
|---|
 | 8 | // This user KSH process contains two POSIX threads: | 
|---|
| [446] | 9 | // - the "main" thread contains the infinite loop implementing | 
|---|
| [574] | 10 | //   the children processes termination monitoring, using the wait() syscall. | 
|---|
| [469] | 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.  | 
|---|
| [457] | 14 | // | 
|---|
| [469] | 15 | // The children processes are created by the <load> command, and are | 
|---|
| [457] | 16 | // attached to the same TXT terminal as the KSH process itself. | 
|---|
| [469] | 17 | // A child process can be lauched in foreground or in background:  | 
|---|
 | 18 | // . when the child process is running in foreground, the KSH process loses | 
|---|
 | 19 | //   the TXT terminal ownership, that is transfered to the child process. | 
|---|
 | 20 | // . when the child process is running in background: the KSH process keeps | 
|---|
 | 21 | //   the TXT terminal ownership. | 
|---|
 | 22 | // | 
|---|
 | 23 | // A semaphore is used to synchronize the two KSH threads. At each iteration,  | 
|---|
 | 24 | // the interactive thread check the semaphore (with a sem_wait). It blocks  | 
|---|
 | 25 | // and deschedules, if the KSH process loosed the TXT ownership (after a load, | 
|---|
 | 26 | // or for any other cause. It unblocks 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 allow the KSH interactive() | 
|---|
 | 29 | //   function to get the next command 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 | ///////////////////////////////////////////////////////////////////////////////////////// | 
|---|
| [230] | 38 |  | 
|---|
 | 39 | #include <stdio.h> | 
|---|
 | 40 | #include <stdlib.h> | 
|---|
 | 41 | #include <string.h> | 
|---|
| [444] | 42 | #include <sys/wait.h> | 
|---|
 | 43 | #include <signal.h> | 
|---|
 | 44 | #include <unistd.h> | 
|---|
| [445] | 45 | #include <almosmkh.h> | 
|---|
| [457] | 46 | #include <semaphore.h> | 
|---|
| [230] | 47 |  | 
|---|
| [407] | 48 | #define CMD_MAX_SIZE   (256)    // max number of characters in one command | 
|---|
| [436] | 49 | #define LOG_DEPTH      (32)     // max number of registered commands  | 
|---|
| [407] | 50 | #define MAX_ARGS           (32)     // max number of arguments in a command | 
|---|
| [230] | 51 |  | 
|---|
| [574] | 52 | #define MAIN_DEBUG          0 | 
|---|
| [469] | 53 | #define CMD_LOAD_DEBUG      0 | 
|---|
| [457] | 54 |  | 
|---|
| [469] | 55 | ////////////////////////////////////////////////////////////////////////////////////////// | 
|---|
| [407] | 56 | //         Structures | 
|---|
| [469] | 57 | ////////////////////////////////////////////////////////////////////////////////////////// | 
|---|
| [230] | 58 |  | 
|---|
| [407] | 59 | // one entry in the registered commands array | 
|---|
 | 60 | typedef struct log_entry_s  | 
|---|
 | 61 | { | 
|---|
 | 62 |         char          buf[CMD_MAX_SIZE]; | 
|---|
 | 63 |         unsigned int  count; | 
|---|
 | 64 | } | 
|---|
 | 65 | log_entry_t; | 
|---|
| [230] | 66 |  | 
|---|
| [407] | 67 | // one entry in the supported command types array | 
|---|
 | 68 | typedef struct ksh_cmd_s  | 
|---|
 | 69 | { | 
|---|
 | 70 |         char * name; | 
|---|
 | 71 |         char * desc; | 
|---|
 | 72 |         void   (*fn)( int , char ** ); | 
|---|
 | 73 | } | 
|---|
 | 74 | ksh_cmd_t; | 
|---|
 | 75 |  | 
|---|
 | 76 |  | 
|---|
| [469] | 77 | ////////////////////////////////////////////////////////////////////////////////////////// | 
|---|
| [230] | 78 | //         Global Variables | 
|---|
| [469] | 79 | ////////////////////////////////////////////////////////////////////////////////////////// | 
|---|
| [230] | 80 |  | 
|---|
| [407] | 81 | ksh_cmd_t       cmd[];                    // array of supported commands | 
|---|
| [230] | 82 |  | 
|---|
| [407] | 83 | log_entry_t     log_entries[LOG_DEPTH];   // array of registered commands | 
|---|
| [230] | 84 |  | 
|---|
| [407] | 85 | unsigned int    ptw;                      // write pointer in log_entries[] | 
|---|
 | 86 | unsigned int    ptr;                      // read pointer in log_entries[] | 
|---|
| [230] | 87 |  | 
|---|
| [457] | 88 | pthread_attr_t  attr;                     // interactive thread attributes | 
|---|
| [446] | 89 |  | 
|---|
| [457] | 90 | sem_t           semaphore;                // block interactive thread when zero | 
|---|
 | 91 |  | 
|---|
| [469] | 92 | ////////////////////////////////////////////////////////////////////////////////////////// | 
|---|
| [230] | 93 | //         Shell  Commands | 
|---|
| [469] | 94 | ////////////////////////////////////////////////////////////////////////////////////////// | 
|---|
| [230] | 95 |  | 
|---|
| [407] | 96 | ///////////////////////////////////////////// | 
|---|
 | 97 | static void cmd_cat( int argc , char **argv ) | 
|---|
| [230] | 98 | { | 
|---|
| [407] | 99 |         char         * path; | 
|---|
| [230] | 100 |  | 
|---|
| [407] | 101 |         if (argc != 2)  | 
|---|
 | 102 |     { | 
|---|
| [409] | 103 |                 printf("  usage: cat pathname\n"); | 
|---|
| [230] | 104 |                 return; | 
|---|
 | 105 |         } | 
|---|
| [407] | 106 |  | 
|---|
| [230] | 107 |         path = argv[1]; | 
|---|
 | 108 |  | 
|---|
| [473] | 109 |     printf("  error: not implemented yet\n", argc, argv ); | 
|---|
| [407] | 110 |  | 
|---|
 | 111 | /* | 
|---|
 | 112 |         // open the file | 
|---|
 | 113 |         fd = open( path , O_RDONLY , 0 ); | 
|---|
 | 114 |         if (fd < 0)  | 
|---|
 | 115 |     { | 
|---|
| [409] | 116 |                 printf("  error: cannot open %s\n", path); | 
|---|
| [230] | 117 |                 goto exit; | 
|---|
 | 118 |         } | 
|---|
 | 119 |  | 
|---|
| [407] | 120 |         // get file size  | 
|---|
 | 121 |         if (stat(path, &st) == -1) | 
|---|
 | 122 |     { | 
|---|
| [409] | 123 |                 printf("  error: cannot stat %s\n", path); | 
|---|
| [230] | 124 |                 goto exit; | 
|---|
 | 125 |         } | 
|---|
 | 126 |         if (S_ISDIR(st.st_mode)) { | 
|---|
| [409] | 127 |                 printf("  error: %s is a directory\n", path); | 
|---|
| [230] | 128 |                 goto exit; | 
|---|
 | 129 |         } | 
|---|
 | 130 |         size = st.st_size; | 
|---|
 | 131 |  | 
|---|
| [407] | 132 |         // mmap the file  | 
|---|
| [230] | 133 |         buf = mmap(NULL, size, PROT_READ|PROT_WRITE, MAP_PRIVATE, fd, 0); | 
|---|
 | 134 |         if (buf == NULL || buf == (char *)-1) { | 
|---|
| [409] | 135 |                 printf("  error: cannot map %s\n", path); | 
|---|
| [230] | 136 |                 goto exit; | 
|---|
 | 137 |         } | 
|---|
 | 138 |  | 
|---|
| [446] | 139 |         // set terminating '0' | 
|---|
| [230] | 140 |         buf[size-1] = 0; | 
|---|
 | 141 |  | 
|---|
| [407] | 142 |         // display the file content | 
|---|
| [230] | 143 |         printf("%s", buf); | 
|---|
 | 144 |  | 
|---|
 | 145 | exit: | 
|---|
| [407] | 146 |         if (buf != NULL) munmap(buf, size); | 
|---|
 | 147 |         if (fd >= 0) close(fd); | 
|---|
 | 148 | */ | 
|---|
| [230] | 149 |  | 
|---|
| [457] | 150 |     // release semaphore to get next command | 
|---|
 | 151 |     sem_post( &semaphore ); | 
|---|
 | 152 |  | 
|---|
| [407] | 153 | }   // end cmd_cat() | 
|---|
 | 154 |  | 
|---|
 | 155 | //////////////////////////////////////////// | 
|---|
 | 156 | static void cmd_cd( int argc , char **argv ) | 
|---|
 | 157 | { | 
|---|
 | 158 |         char * path; | 
|---|
 | 159 |  | 
|---|
 | 160 |         if (argc != 2) | 
|---|
 | 161 |     { | 
|---|
| [409] | 162 |                 printf("  usage: cd pathname\n"); | 
|---|
| [407] | 163 |                 return; | 
|---|
 | 164 |         } | 
|---|
 | 165 |  | 
|---|
 | 166 |         path = argv[1]; | 
|---|
 | 167 |  | 
|---|
| [473] | 168 |     printf("  error: not implemented yet\n", argc, argv ); | 
|---|
| [407] | 169 |  | 
|---|
| [457] | 170 |     // release semaphore to get next command | 
|---|
 | 171 |     sem_post( &semaphore ); | 
|---|
| [407] | 172 |  | 
|---|
 | 173 | }   // end cmd_cd() | 
|---|
 | 174 |  | 
|---|
 | 175 | ///////////////////////////////////////// | 
|---|
| [230] | 176 | static void cmd_cp(int argc, char **argv) | 
|---|
 | 177 | { | 
|---|
| [407] | 178 | //      int src_fd = -1, dst_fd = -1; | 
|---|
 | 179 | //      char *srcpath, *dstpath; | 
|---|
 | 180 | //      struct stat st; | 
|---|
 | 181 | //      size_t size, i; | 
|---|
 | 182 | //      char buf[1024]; | 
|---|
| [230] | 183 |  | 
|---|
| [407] | 184 |         if (argc != 3)  | 
|---|
 | 185 |     { | 
|---|
| [409] | 186 |                 printf("  usage: cp src_pathname dst_pathname\n"); | 
|---|
| [230] | 187 |                 return; | 
|---|
 | 188 |         } | 
|---|
 | 189 |  | 
|---|
| [473] | 190 |     printf("  error: not implemented yet\n", argc, argv ); | 
|---|
| [407] | 191 |  | 
|---|
 | 192 | /* | 
|---|
| [230] | 193 |         srcpath = argv[1]; | 
|---|
 | 194 |         dstpath = argv[2]; | 
|---|
 | 195 |  | 
|---|
| [407] | 196 |         // open the src file  | 
|---|
| [230] | 197 |         src_fd = open(srcpath, O_RDONLY, 0); | 
|---|
 | 198 |         if (src_fd < 0) { | 
|---|
| [409] | 199 |                 printf("  error: cannot open %s / err = %d\n", srcpath, errno); | 
|---|
| [230] | 200 |                 goto exit; | 
|---|
 | 201 |         } | 
|---|
 | 202 |  | 
|---|
| [407] | 203 |         // get file size  | 
|---|
| [230] | 204 |         if (stat(srcpath, &st) == -1) { | 
|---|
| [409] | 205 |                 printf("  error: cannot stat %s\n", srcpath); | 
|---|
| [230] | 206 |                 goto exit; | 
|---|
 | 207 |         } | 
|---|
 | 208 |         if (S_ISDIR(st.st_mode)) { | 
|---|
| [409] | 209 |                 printf("  error: %s is a directory\n", srcpath); | 
|---|
| [230] | 210 |                 goto exit; | 
|---|
 | 211 |         } | 
|---|
 | 212 |         size = st.st_size; | 
|---|
 | 213 |  | 
|---|
| [407] | 214 |         // open the dst file  | 
|---|
| [230] | 215 |         dst_fd = open(dstpath, O_CREAT|O_TRUNC|O_RDWR, 0); | 
|---|
 | 216 |         if (dst_fd < 0) { | 
|---|
| [409] | 217 |                 printf("  error: cannot open %s / err = %d\n", dstpath, errno); | 
|---|
| [230] | 218 |                 goto exit; | 
|---|
 | 219 |         } | 
|---|
 | 220 |         if (stat(dstpath, &st) == -1) { | 
|---|
| [409] | 221 |                 printf("  error: cannot stat %s\n", dstpath); | 
|---|
| [230] | 222 |                 goto exit; | 
|---|
 | 223 |         } | 
|---|
 | 224 |         if (S_ISDIR(st.st_mode)) { | 
|---|
| [409] | 225 |                 printf("  error: %s is a directory\n", dstpath); | 
|---|
| [230] | 226 |                 goto exit; | 
|---|
 | 227 |         } | 
|---|
 | 228 |  | 
|---|
 | 229 |         i = 0; | 
|---|
 | 230 |         while (i < size) | 
|---|
 | 231 |         { | 
|---|
 | 232 |                 size_t rlen = (size - i < 1024 ? size - i : 1024); | 
|---|
 | 233 |                 size_t wlen; | 
|---|
 | 234 |                 ssize_t ret; | 
|---|
 | 235 |  | 
|---|
| [407] | 236 |                 // read the source  | 
|---|
| [230] | 237 |                 ret = read(src_fd, buf, rlen); | 
|---|
 | 238 |                 if (ret == -1) { | 
|---|
| [409] | 239 |                         printf("  error: cannot read from file %s\n", srcpath); | 
|---|
| [230] | 240 |                         goto exit; | 
|---|
 | 241 |                 } | 
|---|
 | 242 |                 rlen = (size_t)ret; | 
|---|
 | 243 |  | 
|---|
| [407] | 244 |                 // write to the destination  | 
|---|
| [230] | 245 |                 ret = write(dst_fd, buf, rlen); | 
|---|
 | 246 |                 if (ret == -1) { | 
|---|
| [409] | 247 |                         printf("  error: cannot write to file %s\n", dstpath); | 
|---|
| [230] | 248 |                         goto exit; | 
|---|
 | 249 |                 } | 
|---|
 | 250 |                 wlen = (size_t)ret; | 
|---|
 | 251 |  | 
|---|
| [407] | 252 |                 // check  | 
|---|
| [230] | 253 |                 if (wlen != rlen) { | 
|---|
| [409] | 254 |                         printf("  error: cannot write on device\n"); | 
|---|
| [230] | 255 |                         goto exit; | 
|---|
 | 256 |                 } | 
|---|
 | 257 |  | 
|---|
 | 258 |                 i += rlen; | 
|---|
 | 259 |         } | 
|---|
 | 260 |  | 
|---|
 | 261 | exit: | 
|---|
| [407] | 262 |         if (src_fd >= 0) close(src_fd); | 
|---|
 | 263 |         if (dst_fd >= 0) close(dst_fd); | 
|---|
 | 264 | */ | 
|---|
| [230] | 265 |  | 
|---|
| [457] | 266 |     // release semaphore to get next command | 
|---|
 | 267 |     sem_post( &semaphore ); | 
|---|
 | 268 |  | 
|---|
| [407] | 269 | }   // end cmd_cp() | 
|---|
 | 270 |  | 
|---|
| [436] | 271 | ///////////////////////////////////////////////// | 
|---|
 | 272 | static void cmd_display( int argc , char **argv ) | 
|---|
 | 273 | { | 
|---|
 | 274 |     unsigned int  cxy; | 
|---|
 | 275 |     unsigned int  lid; | 
|---|
 | 276 |     unsigned int  pid; | 
|---|
 | 277 |     unsigned int  txt_id; | 
|---|
 | 278 |  | 
|---|
 | 279 |     if( strcmp( argv[1] , "vmm" ) == 0 ) | 
|---|
 | 280 |     { | 
|---|
| [442] | 281 |         if( argc != 4 ) | 
|---|
| [436] | 282 |         { | 
|---|
| [442] | 283 |                     printf("  usage: display vmm cxy pid\n"); | 
|---|
| [436] | 284 |                     return; | 
|---|
 | 285 |             } | 
|---|
 | 286 |  | 
|---|
| [442] | 287 |             cxy = atoi(argv[2]); | 
|---|
 | 288 |             pid = atoi(argv[3]); | 
|---|
| [436] | 289 |  | 
|---|
| [442] | 290 |         if( display_vmm( cxy , pid ) ) | 
|---|
| [436] | 291 |         { | 
|---|
| [442] | 292 |             printf("  error: no process %x in cluster %x\n", pid , cxy ); | 
|---|
| [436] | 293 |         } | 
|---|
 | 294 |     } | 
|---|
 | 295 |     else if( strcmp( argv[1] , "sched" ) == 0 ) | 
|---|
 | 296 |     { | 
|---|
 | 297 |         if( argc != 4 ) | 
|---|
 | 298 |         { | 
|---|
 | 299 |                     printf("  usage: display sched cxy lid\n"); | 
|---|
 | 300 |                     return; | 
|---|
 | 301 |             } | 
|---|
 | 302 |  | 
|---|
 | 303 |             cxy = atoi(argv[2]); | 
|---|
 | 304 |             lid = atoi(argv[3]); | 
|---|
 | 305 |  | 
|---|
 | 306 |         if( display_sched( cxy , lid ) ) | 
|---|
 | 307 |         { | 
|---|
 | 308 |             printf("  error: illegal arguments cxy = %x / lid = %d\n", cxy, lid ); | 
|---|
 | 309 |         } | 
|---|
 | 310 |     } | 
|---|
 | 311 |     else if( strcmp( argv[1] , "process" ) == 0 ) | 
|---|
 | 312 |     { | 
|---|
 | 313 |         if( argc != 3 ) | 
|---|
 | 314 |         { | 
|---|
 | 315 |                     printf("  usage: display process cxy\n"); | 
|---|
 | 316 |                     return; | 
|---|
 | 317 |             } | 
|---|
 | 318 |  | 
|---|
 | 319 |             cxy = atoi(argv[2]); | 
|---|
 | 320 |  | 
|---|
 | 321 |         if( display_cluster_processes( cxy ) ) | 
|---|
 | 322 |         { | 
|---|
 | 323 |             printf("  error: illegal argument cxy = %x\n", cxy ); | 
|---|
 | 324 |         } | 
|---|
 | 325 |     } | 
|---|
 | 326 |     else if( strcmp( argv[1] , "txt" ) == 0 ) | 
|---|
 | 327 |     { | 
|---|
 | 328 |         if( argc != 3 ) | 
|---|
 | 329 |         { | 
|---|
 | 330 |                     printf("  usage: display txt txt_id\n"); | 
|---|
 | 331 |                     return; | 
|---|
 | 332 |             } | 
|---|
 | 333 |  | 
|---|
 | 334 |             txt_id = atoi(argv[2]); | 
|---|
 | 335 |  | 
|---|
 | 336 |         if( display_txt_processes( txt_id ) ) | 
|---|
 | 337 |         { | 
|---|
| [458] | 338 |             printf("  error: illegal argument txt_id = %d\n", txt_id ); | 
|---|
| [436] | 339 |         } | 
|---|
 | 340 |     } | 
|---|
 | 341 |     else if( strcmp( argv[1] , "vfs" ) == 0 ) | 
|---|
 | 342 |     { | 
|---|
 | 343 |         if( argc != 2 ) | 
|---|
 | 344 |         { | 
|---|
 | 345 |                     printf("  usage: display vfs\n"); | 
|---|
 | 346 |                     return; | 
|---|
 | 347 |             } | 
|---|
 | 348 |  | 
|---|
 | 349 |         display_vfs(); | 
|---|
 | 350 |     } | 
|---|
 | 351 |     else if( strcmp( argv[1] , "chdev" ) == 0 ) | 
|---|
 | 352 |     { | 
|---|
 | 353 |         if( argc != 2 ) | 
|---|
 | 354 |         { | 
|---|
 | 355 |                     printf("  usage: display chdev\n"); | 
|---|
 | 356 |                     return; | 
|---|
 | 357 |             } | 
|---|
 | 358 |  | 
|---|
 | 359 |         display_chdev(); | 
|---|
 | 360 |     } | 
|---|
| [445] | 361 |     else if( strcmp( argv[1] , "dqdt" ) == 0 ) | 
|---|
 | 362 |     { | 
|---|
 | 363 |         if( argc != 2 ) | 
|---|
 | 364 |         { | 
|---|
 | 365 |                     printf("  usage: display dqdt\n"); | 
|---|
 | 366 |                     return; | 
|---|
 | 367 |             } | 
|---|
 | 368 |  | 
|---|
 | 369 |         display_dqdt(); | 
|---|
 | 370 |     } | 
|---|
| [436] | 371 |     else | 
|---|
 | 372 |     { | 
|---|
 | 373 |         printf("  usage: display (vmm/sched/process/vfs/chdev/txt) [arg2] [arg3]\n"); | 
|---|
 | 374 |     } | 
|---|
| [457] | 375 |  | 
|---|
 | 376 |     // release semaphore to get next command | 
|---|
 | 377 |     sem_post( &semaphore ); | 
|---|
 | 378 |  | 
|---|
| [436] | 379 | } // end cmd_display() | 
|---|
 | 380 |  | 
|---|
| [427] | 381 | ///////////////////////////////////////// | 
|---|
 | 382 | static void cmd_fg(int argc, char **argv) | 
|---|
 | 383 | { | 
|---|
 | 384 |         unsigned int pid; | 
|---|
 | 385 |  | 
|---|
 | 386 |         if (argc != 2)  | 
|---|
 | 387 |     { | 
|---|
 | 388 |                 printf("  usage: %s pid\n", argv[0]); | 
|---|
 | 389 |                 return; | 
|---|
 | 390 |         } | 
|---|
 | 391 |  | 
|---|
 | 392 |     pid = atoi( argv[1] );    | 
|---|
 | 393 |  | 
|---|
 | 394 |     if( pid == 0 ) | 
|---|
 | 395 |     { | 
|---|
| [442] | 396 |                 printf("  error: PID cannot be 0\n" ); | 
|---|
| [427] | 397 |         } | 
|---|
 | 398 |  | 
|---|
 | 399 |     if( fg( pid ) ) | 
|---|
 | 400 |     { | 
|---|
 | 401 |                 printf("  error: cannot find process %x\n", pid ); | 
|---|
 | 402 |         } | 
|---|
| [457] | 403 |  | 
|---|
 | 404 |     // release semaphore to get next command | 
|---|
 | 405 |     sem_post( &semaphore ); | 
|---|
 | 406 |  | 
|---|
| [436] | 407 | }  // end cmd_fg() | 
|---|
| [427] | 408 |  | 
|---|
| [407] | 409 | ////////////////////////////////////////////// | 
|---|
 | 410 | static void cmd_help( int argc , char **argv ) | 
|---|
| [230] | 411 | { | 
|---|
| [407] | 412 |         unsigned int i; | 
|---|
| [230] | 413 |  | 
|---|
| [407] | 414 |         if (argc != 1)  | 
|---|
 | 415 |     { | 
|---|
| [409] | 416 |                 printf("  usage: %s\n", argv[0]); | 
|---|
| [230] | 417 |                 return; | 
|---|
 | 418 |         } | 
|---|
 | 419 |  | 
|---|
 | 420 |         printf("available commands:\n"); | 
|---|
| [407] | 421 |         for (i = 0 ; cmd[i].name ; i++)  | 
|---|
 | 422 |     { | 
|---|
| [230] | 423 |                 printf("\t%s\t : %s\n", cmd[i].name , cmd[i].desc); | 
|---|
 | 424 |         } | 
|---|
| [457] | 425 |  | 
|---|
 | 426 |     // release semaphore to get next command | 
|---|
 | 427 |     sem_post( &semaphore ); | 
|---|
 | 428 |  | 
|---|
| [407] | 429 | }   // end cmd_help() | 
|---|
| [230] | 430 |  | 
|---|
| [407] | 431 | ////////////////////////////////////////////// | 
|---|
 | 432 | static void cmd_kill( int argc , char **argv ) | 
|---|
| [230] | 433 | { | 
|---|
| [407] | 434 |         unsigned int pid; | 
|---|
| [230] | 435 |  | 
|---|
| [407] | 436 |         if (argc != 2)  | 
|---|
 | 437 |     { | 
|---|
| [409] | 438 |                 printf("  usage: %s pid\n", argv[0]); | 
|---|
| [230] | 439 |                 return; | 
|---|
 | 440 |         } | 
|---|
 | 441 |  | 
|---|
| [427] | 442 |         pid = atoi( argv[1] ); | 
|---|
| [230] | 443 |  | 
|---|
| [427] | 444 |     if( pid == 0 ) | 
|---|
 | 445 |     { | 
|---|
| [440] | 446 |                 printf("  error: kernel process 0 cannot be killed\n" ); | 
|---|
| [427] | 447 |         } | 
|---|
 | 448 |  | 
|---|
| [416] | 449 |         if( kill( pid , SIGKILL ) ) | 
|---|
| [407] | 450 |     { | 
|---|
| [440] | 451 |                 printf("  error: process %x cannot be killed\n", pid ); | 
|---|
| [230] | 452 |         } | 
|---|
| [457] | 453 |  | 
|---|
 | 454 |     // release semaphore to get next command | 
|---|
 | 455 |     sem_post( &semaphore ); | 
|---|
 | 456 |  | 
|---|
| [407] | 457 | }   // end cmd_kill() | 
|---|
| [230] | 458 |  | 
|---|
| [407] | 459 | ////////////////////////////////////////////// | 
|---|
 | 460 | static void cmd_load( int argc , char **argv ) | 
|---|
| [230] | 461 | { | 
|---|
| [436] | 462 |         int                  ret_fork;           // return value from fork  | 
|---|
 | 463 |         int                  ret_exec;           // return value from exec | 
|---|
 | 464 |     unsigned int         ksh_pid;            // KSH process PID | 
|---|
 | 465 |         char               * pathname;           // path to .elf file | 
|---|
 | 466 |     unsigned int         background;         // background execution if non zero | 
|---|
| [407] | 467 |  | 
|---|
| [427] | 468 |         if( (argc < 2) || (argc > 3) )   | 
|---|
| [407] | 469 |     { | 
|---|
| [469] | 470 |                 printf("  usage: %s pathname [&] / argc = %d\n", argv[0], argc );  // @@@ | 
|---|
| [407] | 471 |                 return; | 
|---|
 | 472 |         } | 
|---|
 | 473 |  | 
|---|
 | 474 |         pathname = argv[1]; | 
|---|
 | 475 |  | 
|---|
| [427] | 476 |     if( argc == 3 ) background = (argv[2][0] == '&'); | 
|---|
| [434] | 477 |     else            background = 0; | 
|---|
| [427] | 478 |  | 
|---|
| [434] | 479 |     // get KSH process PID | 
|---|
 | 480 |     ksh_pid = getpid(); | 
|---|
| [407] | 481 |  | 
|---|
| [469] | 482 | #if CMD_LOAD_DEBUG | 
|---|
 | 483 | long long unsigned cycle; | 
|---|
 | 484 | get_cycle( &cycle ); | 
|---|
 | 485 | printf("\n@@@ %s : KSH PID %x before fork / path %s / background %d / cycle %d\n", | 
|---|
 | 486 | __FUNCTION__, ksh_pid, argv[1], background, (int)cycle ); | 
|---|
| [457] | 487 | #endif | 
|---|
 | 488 |  | 
|---|
| [434] | 489 |     // KSH process fork CHILD process | 
|---|
| [436] | 490 |         ret_fork = fork(); | 
|---|
| [434] | 491 |  | 
|---|
| [457] | 492 |     if ( ret_fork < 0 )     // it is a failure reported to KSH | 
|---|
| [407] | 493 |     { | 
|---|
| [434] | 494 |         printf("  error: ksh process unable to fork\n"); | 
|---|
| [440] | 495 |         return; | 
|---|
| [434] | 496 |     } | 
|---|
| [457] | 497 |     else if (ret_fork == 0) // it is the CHILD process  | 
|---|
| [434] | 498 |     { | 
|---|
| [469] | 499 |  | 
|---|
 | 500 | #if CMD_LOAD_DEBUG | 
|---|
 | 501 | get_cycle( &cycle ); | 
|---|
 | 502 | printf("\n@@@ %s : CHILD_PID %x after fork, before exec / cycle %d\n", | 
|---|
 | 503 | __FUNCTION__ , getpid(), (int)cycle ); | 
|---|
 | 504 | #endif | 
|---|
 | 505 |  | 
|---|
| [434] | 506 |         // CHILD process exec NEW process | 
|---|
| [444] | 507 |         ret_exec = execve( pathname , NULL , NULL ); | 
|---|
| [434] | 508 |  | 
|---|
| [469] | 509 | #if CMD_LOAD_DEBUG | 
|---|
 | 510 | get_cycle( &cycle ); | 
|---|
 | 511 | printf("\n@@@ %s : CHILD_PID %x after exec / ret_exec %d / cycle %d\n", | 
|---|
 | 512 | __FUNCTION__ , getpid(), ret_exec, (int)cycle ); | 
|---|
 | 513 | #endif | 
|---|
 | 514 |  | 
|---|
| [441] | 515 |         // this is only executed in case of exec failure | 
|---|
| [436] | 516 |         if( ret_exec ) | 
|---|
| [409] | 517 |         { | 
|---|
| [441] | 518 |             printf("  error: child process unable to exec <%s>\n", pathname ); | 
|---|
 | 519 |             exit( 0 ); | 
|---|
| [436] | 520 |         }    | 
|---|
 | 521 |         }  | 
|---|
| [457] | 522 |     else                    // it is the KSH process : ret_fork is the new process PID | 
|---|
| [436] | 523 |     { | 
|---|
 | 524 |  | 
|---|
| [469] | 525 | #if CMD_LOAD_DEBUG | 
|---|
 | 526 | get_cycle( &cycle ); | 
|---|
 | 527 | printf("\n@@@ %s : KSH_PID %x after fork / ret_fork %x / cycle %d\n", | 
|---|
 | 528 | __FUNCTION__, getpid(), ret_fork, (int)cycle ); | 
|---|
| [457] | 529 | #endif | 
|---|
 | 530 |  | 
|---|
| [469] | 531 |         if( background )    // child in background =>  KSH must keep TXT ownership | 
|---|
| [457] | 532 |         { | 
|---|
 | 533 |             // execve() tranfered TXT ownership to child => give it back to KSH | 
|---|
 | 534 |             fg( ksh_pid ); | 
|---|
 | 535 |  | 
|---|
 | 536 |             // release semaphore to get next command | 
|---|
 | 537 |             sem_post( &semaphore ); | 
|---|
 | 538 |         } | 
|---|
| [436] | 539 |     } | 
|---|
| [407] | 540 | }   // end cmd_load | 
|---|
 | 541 |  | 
|---|
 | 542 | ///////////////////////////////////////////// | 
|---|
 | 543 | static void cmd_log( int argc , char **argv ) | 
|---|
 | 544 | { | 
|---|
 | 545 |         unsigned int i; | 
|---|
 | 546 |  | 
|---|
| [473] | 547 |         if (argc != 1) | 
|---|
 | 548 |     { | 
|---|
 | 549 |                 printf("  usage: %s\n", argv[0], argc );  | 
|---|
 | 550 |                 return; | 
|---|
 | 551 |         } | 
|---|
 | 552 |  | 
|---|
| [230] | 553 |         printf("--- registered commands ---\n"); | 
|---|
| [407] | 554 |         for (i = 0; i < LOG_DEPTH; i++)  | 
|---|
 | 555 |     { | 
|---|
| [436] | 556 |                 printf(" - %d\t: %s\n", i, &log_entries[i].buf); | 
|---|
| [230] | 557 |         } | 
|---|
 | 558 |  | 
|---|
| [457] | 559 |     // release semaphore to get next command | 
|---|
 | 560 |     sem_post( &semaphore ); | 
|---|
 | 561 |  | 
|---|
 | 562 | } // end cmd_log() | 
|---|
 | 563 |  | 
|---|
 | 564 |  | 
|---|
| [407] | 565 | //////////////////////////////////////////// | 
|---|
 | 566 | static void cmd_ls( int argc , char **argv ) | 
|---|
| [230] | 567 | { | 
|---|
| [407] | 568 |         char  * path; | 
|---|
| [230] | 569 |  | 
|---|
| [407] | 570 | //  struct dirent * file; | 
|---|
 | 571 | //  DIR *dir; | 
|---|
 | 572 |  | 
|---|
 | 573 |         if (argc == 1) | 
|---|
 | 574 |     { | 
|---|
| [230] | 575 |                 path = "."; | 
|---|
| [407] | 576 |         } | 
|---|
 | 577 |     else if (argc == 2)  | 
|---|
 | 578 |     { | 
|---|
| [230] | 579 |                 path = argv[1]; | 
|---|
| [407] | 580 |         }  | 
|---|
 | 581 |     else  | 
|---|
 | 582 |     { | 
|---|
| [409] | 583 |                 printf("  usage: ls [path]\n"); | 
|---|
| [230] | 584 |                 return; | 
|---|
 | 585 |         } | 
|---|
 | 586 |  | 
|---|
| [409] | 587 |     printf("  error: not implemented yet\n"); | 
|---|
| [407] | 588 | /* | 
|---|
 | 589 |         dir = opendir( path ); | 
|---|
| [230] | 590 |         while ((file = readdir(dir)) != NULL) | 
|---|
 | 591 |         { | 
|---|
 | 592 |                 printf(" %s\n", file->d_name); | 
|---|
 | 593 |         } | 
|---|
 | 594 |         closedir(dir); | 
|---|
| [407] | 595 | */ | 
|---|
| [230] | 596 |  | 
|---|
| [457] | 597 |     // release semaphore to get next command | 
|---|
 | 598 |     sem_post( &semaphore ); | 
|---|
 | 599 |  | 
|---|
 | 600 | } // end cmd_ls() | 
|---|
 | 601 |  | 
|---|
| [407] | 602 | /////////////////////////////////////////////// | 
|---|
 | 603 | static void cmd_mkdir( int argc , char **argv ) | 
|---|
| [230] | 604 | { | 
|---|
| [407] | 605 |         char * pathname; | 
|---|
| [230] | 606 |  | 
|---|
| [407] | 607 |         if (argc != 2) | 
|---|
 | 608 |     { | 
|---|
| [409] | 609 |                 printf("  usage: mkdir pathname\n"); | 
|---|
| [230] | 610 |                 return; | 
|---|
 | 611 |         } | 
|---|
 | 612 |  | 
|---|
| [407] | 613 |     pathname = argv[1]; | 
|---|
| [230] | 614 |  | 
|---|
| [409] | 615 |     printf("  error: not implemented yet\n"); | 
|---|
| [230] | 616 |  | 
|---|
| [457] | 617 |     // release semaphore to get next command | 
|---|
 | 618 |     sem_post( &semaphore ); | 
|---|
 | 619 |  | 
|---|
 | 620 | } // end cmd_mkdir() | 
|---|
 | 621 |  | 
|---|
| [407] | 622 | //////////////////////////////////////////// | 
|---|
 | 623 | static void cmd_mv( int argc , char **argv ) | 
|---|
| [230] | 624 | { | 
|---|
| [407] | 625 |  | 
|---|
| [230] | 626 |         if (argc < 3) | 
|---|
 | 627 |         { | 
|---|
 | 628 |                 printf("  usage : %s src_pathname dst_pathname\n", argv[0]); | 
|---|
 | 629 |                 return; | 
|---|
 | 630 |         } | 
|---|
 | 631 |  | 
|---|
| [409] | 632 |     printf("  error: not implemented yet\n"); | 
|---|
| [407] | 633 |      | 
|---|
| [457] | 634 |     // release semaphore to get next command | 
|---|
 | 635 |     sem_post( &semaphore ); | 
|---|
| [407] | 636 |  | 
|---|
| [457] | 637 | }  // end cmd_mv | 
|---|
| [230] | 638 |  | 
|---|
| [407] | 639 | ///////////////////////////////////////////// | 
|---|
 | 640 | static void cmd_pwd( int argc , char **argv ) | 
|---|
| [230] | 641 | { | 
|---|
| [407] | 642 |         char buf[1024]; | 
|---|
| [230] | 643 |  | 
|---|
| [407] | 644 |         if (argc != 1) | 
|---|
 | 645 |     { | 
|---|
| [473] | 646 |                 printf("  usage: %s\n", argv[0]); | 
|---|
| [407] | 647 |                 return; | 
|---|
 | 648 |         } | 
|---|
 | 649 |  | 
|---|
 | 650 |         if ( getcwd( buf , 1024 ) )  | 
|---|
 | 651 |     { | 
|---|
| [409] | 652 |                 printf("  error: unable to get current directory\n"); | 
|---|
| [407] | 653 |         } | 
|---|
 | 654 |     else  | 
|---|
 | 655 |     { | 
|---|
 | 656 |                 printf("%s\n", buf); | 
|---|
 | 657 |         } | 
|---|
 | 658 |  | 
|---|
| [457] | 659 |     // release semaphore to get next command | 
|---|
 | 660 |     sem_post( &semaphore ); | 
|---|
 | 661 |  | 
|---|
 | 662 | }  // end cmd_pwd() | 
|---|
 | 663 |  | 
|---|
| [407] | 664 | //////////////////////////////////////////// | 
|---|
 | 665 | static void cmd_rm( int argc , char **argv ) | 
|---|
 | 666 | { | 
|---|
 | 667 |         char * pathname; | 
|---|
 | 668 |  | 
|---|
 | 669 |         if (argc != 2) | 
|---|
 | 670 |     { | 
|---|
| [473] | 671 |                 printf("  usage: %s pathname\n", argv[0]); | 
|---|
| [230] | 672 |                 return; | 
|---|
 | 673 |         } | 
|---|
 | 674 |  | 
|---|
| [407] | 675 |         pathname = argv[1]; | 
|---|
| [230] | 676 |  | 
|---|
| [409] | 677 |     printf("  error: not implemented yet\n"); | 
|---|
| [407] | 678 |  | 
|---|
| [457] | 679 |     // release semaphore to get next command | 
|---|
 | 680 |     sem_post( &semaphore ); | 
|---|
| [230] | 681 |  | 
|---|
| [457] | 682 | }  // end_cmd_rm() | 
|---|
 | 683 |  | 
|---|
| [407] | 684 | /////////////////////////////////////////////// | 
|---|
 | 685 | static void cmd_rmdir( int argc , char **argv ) | 
|---|
| [230] | 686 | { | 
|---|
| [457] | 687 |     // same as cmd_rm() | 
|---|
| [230] | 688 |         cmd_rm(argc, argv); | 
|---|
 | 689 | } | 
|---|
 | 690 |  | 
|---|
| [442] | 691 | /////////////////////////////////////////////// | 
|---|
 | 692 | static void cmd_trace( int argc , char **argv ) | 
|---|
 | 693 | { | 
|---|
 | 694 |     unsigned int cxy; | 
|---|
 | 695 |     unsigned int lid; | 
|---|
 | 696 |  | 
|---|
 | 697 |         if (argc != 3) | 
|---|
 | 698 |     { | 
|---|
 | 699 |                 printf("  usage: trace cxy lid \n"); | 
|---|
 | 700 |                 return; | 
|---|
 | 701 |         } | 
|---|
 | 702 |  | 
|---|
 | 703 |     cxy = atoi(argv[1]); | 
|---|
 | 704 |     lid = atoi(argv[2]); | 
|---|
 | 705 |  | 
|---|
 | 706 |     if( trace( 1 , cxy , lid ) ) | 
|---|
 | 707 |     { | 
|---|
 | 708 |         printf("  error: core[%x,%d] not found\n", cxy, lid ); | 
|---|
 | 709 |     } | 
|---|
 | 710 |  | 
|---|
| [457] | 711 |     // release semaphore to get next command | 
|---|
 | 712 |     sem_post( &semaphore ); | 
|---|
 | 713 |  | 
|---|
 | 714 | }  // end cmd_trace | 
|---|
 | 715 |  | 
|---|
| [442] | 716 | /////////////////////////////////////////////// | 
|---|
 | 717 | static void cmd_untrace( int argc , char **argv ) | 
|---|
 | 718 | { | 
|---|
 | 719 |     unsigned int cxy; | 
|---|
 | 720 |     unsigned int lid; | 
|---|
 | 721 |  | 
|---|
 | 722 |         if (argc != 3) | 
|---|
 | 723 |     { | 
|---|
 | 724 |                 printf("  usage: untrace cxy lid \n"); | 
|---|
 | 725 |                 return; | 
|---|
 | 726 |         } | 
|---|
 | 727 |  | 
|---|
 | 728 |     cxy = atoi(argv[1]); | 
|---|
 | 729 |     lid = atoi(argv[2]); | 
|---|
 | 730 |  | 
|---|
 | 731 |     if( trace( 0 , cxy , lid ) ) | 
|---|
 | 732 |     { | 
|---|
 | 733 |         printf("  error: core[%x,%d] not found\n", cxy, lid ); | 
|---|
 | 734 |     } | 
|---|
 | 735 |  | 
|---|
| [457] | 736 |     // release semaphore to get next command | 
|---|
 | 737 |     sem_post( &semaphore ); | 
|---|
 | 738 |  | 
|---|
 | 739 | }  // end cmd_untrace() | 
|---|
 | 740 |  | 
|---|
 | 741 | /////////////////////////////////////////////////////////////////////////////////// | 
|---|
| [407] | 742 | // Array of commands | 
|---|
| [457] | 743 | /////////////////////////////////////////////////////////////////////////////////// | 
|---|
| [230] | 744 |  | 
|---|
| [407] | 745 | ksh_cmd_t cmd[] = | 
|---|
| [230] | 746 | { | 
|---|
| [435] | 747 |         { "cat",     "display file content",                            cmd_cat     }, | 
|---|
 | 748 |         { "cd",      "change current directory",                        cmd_cd      }, | 
|---|
 | 749 |         { "cp",      "replicate a file in file system",                 cmd_cp      }, | 
|---|
 | 750 |     { "fg",      "put a process in foreground",                     cmd_fg      }, | 
|---|
 | 751 |     { "display", "display vmm/sched/process/vfs/chdev/txt",         cmd_display }, | 
|---|
 | 752 |         { "load",    "load an user application",                        cmd_load    }, | 
|---|
 | 753 |         { "help",    "list available commands",                         cmd_help    }, | 
|---|
| [457] | 754 |         { "kill",    "kill a process (all threads)",                    cmd_kill    }, | 
|---|
| [435] | 755 |         { "log",     "list registered commands",                        cmd_log     }, | 
|---|
 | 756 |         { "ls",      "list directory entries",                          cmd_ls      }, | 
|---|
 | 757 |         { "mkdir",   "create a new directory",                          cmd_mkdir   }, | 
|---|
 | 758 |         { "mv",      "move a file in file system",                      cmd_mv      }, | 
|---|
 | 759 |         { "pwd",     "print current working directory",                 cmd_pwd     }, | 
|---|
 | 760 |         { "rm",      "remove a file from file system",                  cmd_rm      }, | 
|---|
 | 761 |         { "rmdir",   "remove a directory from file system",             cmd_rmdir   }, | 
|---|
| [442] | 762 |         { "trace",   "activate trace for a given core",                 cmd_trace   }, | 
|---|
 | 763 |         { "untrace", "desactivate trace for a given core",              cmd_untrace }, | 
|---|
| [435] | 764 |         { NULL,      NULL,                                                                              NULL        } | 
|---|
| [230] | 765 | }; | 
|---|
 | 766 |  | 
|---|
| [407] | 767 | //////////////////////////////////////////////////////////////////////////////////// | 
|---|
| [457] | 768 | // This function analyses one command (with arguments), executes it, and returns. | 
|---|
| [407] | 769 | //////////////////////////////////////////////////////////////////////////////////// | 
|---|
| [469] | 770 | static void __attribute__ ((noinline)) parse( char * buf ) | 
|---|
| [230] | 771 | { | 
|---|
 | 772 |         int argc = 0; | 
|---|
 | 773 |         char *argv[MAX_ARGS]; | 
|---|
 | 774 |         int i; | 
|---|
 | 775 |         int len = strlen(buf); | 
|---|
 | 776 |  | 
|---|
 | 777 |         // build argc/argv | 
|---|
| [407] | 778 |         for (i = 0; i < len; i++)  | 
|---|
 | 779 |     { | 
|---|
 | 780 |                 if (buf[i] == ' ')  | 
|---|
 | 781 |         { | 
|---|
| [230] | 782 |                         buf[i] = '\0'; | 
|---|
| [407] | 783 |                 } | 
|---|
 | 784 |         else if (i == 0 || buf[i - 1] == '\0')  | 
|---|
 | 785 |         { | 
|---|
 | 786 |                         if (argc < MAX_ARGS)  | 
|---|
 | 787 |             { | 
|---|
| [230] | 788 |                                 argv[argc] = &buf[i]; | 
|---|
 | 789 |                                 argc++; | 
|---|
 | 790 |                         } | 
|---|
 | 791 |                 } | 
|---|
 | 792 |         } | 
|---|
 | 793 |  | 
|---|
| [469] | 794 |     // analyse command type | 
|---|
| [407] | 795 |         if (argc > 0) | 
|---|
 | 796 |     { | 
|---|
| [230] | 797 |                 int found = 0; | 
|---|
 | 798 |  | 
|---|
 | 799 |                 argv[argc] = NULL; | 
|---|
 | 800 |  | 
|---|
| [407] | 801 |                 // try to match typed command  | 
|---|
| [469] | 802 |                 for (i = 0 ; cmd[i].name ; i++) | 
|---|
| [407] | 803 |         { | 
|---|
 | 804 |                         if (strcmp(argv[0], cmd[i].name) == 0) | 
|---|
 | 805 |             { | 
|---|
| [230] | 806 |                                 cmd[i].fn(argc, argv); | 
|---|
 | 807 |                                 found = 1; | 
|---|
 | 808 |                                 break; | 
|---|
 | 809 |                         } | 
|---|
 | 810 |                 } | 
|---|
 | 811 |  | 
|---|
| [457] | 812 |                 if (!found)  // undefined command | 
|---|
| [407] | 813 |         { | 
|---|
| [457] | 814 |                         printf("  error : undefined command <%s>\n", argv[0]); | 
|---|
 | 815 |  | 
|---|
 | 816 |             // release semaphore to get next command | 
|---|
 | 817 |             sem_post( &semaphore ); | 
|---|
| [230] | 818 |                 } | 
|---|
 | 819 |         } | 
|---|
| [446] | 820 | }  // end parse() | 
|---|
| [230] | 821 |  | 
|---|
| [574] | 822 | /////////////////////////////// | 
|---|
| [503] | 823 | static void interactive( void ) | 
|---|
| [230] | 824 | { | 
|---|
| [469] | 825 |         char           c;                                               // read character | 
|---|
 | 826 |         char           buf[CMD_MAX_SIZE];               // buffer for one command | 
|---|
 | 827 |     unsigned int   end_command;             // last character found in a command | 
|---|
 | 828 |         unsigned int   count;                   // pointer in command buffer | 
|---|
 | 829 |         unsigned int   i;                                               // index for loops | 
|---|
 | 830 |         unsigned int   state;                   // escape sequence state | 
|---|
| [230] | 831 |  | 
|---|
| [574] | 832 | /* This can be used to simplify debug, as it avoids interactive mode | 
|---|
| [457] | 833 |  | 
|---|
| [574] | 834 | for( i=1 ; 1 ; i++ ) | 
|---|
| [469] | 835 | { | 
|---|
 | 836 |     if( sem_wait( &semaphore ) ) | 
|---|
 | 837 |     { | 
|---|
 | 838 |         printf("\n[ksh error] cannot found semafore\n" ); | 
|---|
 | 839 |         exit( 1 ); | 
|---|
 | 840 |     } | 
|---|
 | 841 |     else | 
|---|
 | 842 |     { | 
|---|
| [574] | 843 |         printf("\n[ksh] %d for fft\n", i ); | 
|---|
| [469] | 844 |     } | 
|---|
 | 845 |     strcpy( buf , "load /bin/user/fft.elf" ); | 
|---|
 | 846 |     parse( buf ); | 
|---|
 | 847 | } | 
|---|
 | 848 |  | 
|---|
 | 849 | */ | 
|---|
 | 850 |  | 
|---|
| [407] | 851 |         enum fsm_states  | 
|---|
 | 852 |     { | 
|---|
| [457] | 853 |                 NORMAL = 0, | 
|---|
 | 854 |                 ESCAPE = 1, | 
|---|
 | 855 |                 BRAKET = 2, | 
|---|
| [230] | 856 |         }; | 
|---|
 | 857 |  | 
|---|
| [457] | 858 |         // This lexical analyser writes one command line in the command buffer. | 
|---|
 | 859 |         // It is implemented as a 3 states FSM to handle the following escape sequences: | 
|---|
| [230] | 860 |         // - ESC [ A : up arrow | 
|---|
 | 861 |         // - ESC [ B : down arrow | 
|---|
 | 862 |         // - ESC [ C : right arrow | 
|---|
 | 863 |         // - ESC [ D : left arrow | 
|---|
| [407] | 864 |         // The three states have the following semantic: | 
|---|
| [230] | 865 |         // - NORMAL : no (ESC) character has been found | 
|---|
 | 866 |         // - ESCAPE : the character (ESC) has been found | 
|---|
 | 867 |         // - BRAKET : the wo characters (ESC,[) have been found | 
|---|
| [436] | 868 |  | 
|---|
| [457] | 869 |     // external loop on the commands | 
|---|
 | 870 |     // the in teractive thread should not exit this loop | 
|---|
| [230] | 871 |         while (1) | 
|---|
 | 872 |         { | 
|---|
| [457] | 873 |             // initialize command buffer | 
|---|
 | 874 |             memset( buf, 0x20 , sizeof(buf) );   // TODO useful ? | 
|---|
 | 875 |             count = 0; | 
|---|
 | 876 |             state = NORMAL; | 
|---|
| [230] | 877 |  | 
|---|
| [469] | 878 |         // decrement semaphore, and block if the KSH process is not the TXT owner | 
|---|
 | 879 |         if ( sem_wait( &semaphore ) ) | 
|---|
 | 880 |         { | 
|---|
 | 881 |             printf("\n[ksh error] cannot found semafore\n" ); | 
|---|
 | 882 |             exit( 1 ); | 
|---|
 | 883 |         } | 
|---|
| [407] | 884 |  | 
|---|
| [457] | 885 |         // display prompt on a new line | 
|---|
 | 886 |         printf("\n[ksh] "); | 
|---|
 | 887 |   | 
|---|
 | 888 |         end_command = 0; | 
|---|
 | 889 |  | 
|---|
 | 890 |         // internal loop on characters in one command | 
|---|
 | 891 |         while( end_command == 0 ) | 
|---|
 | 892 |         { | 
|---|
 | 893 |             // get one character from TXT_RX | 
|---|
 | 894 |                 c = (char)getchar(); | 
|---|
 | 895 |  | 
|---|
 | 896 |             if( c == 0 ) continue; | 
|---|
 | 897 |  | 
|---|
 | 898 |                     if( state == NORMAL )  // we are not in an escape sequence | 
|---|
 | 899 |                     { | 
|---|
| [230] | 900 |                                 if ((c == '\b') || (c == 0x7F))  // backspace => remove one character | 
|---|
 | 901 |                                 { | 
|---|
| [457] | 902 |                                     if (count > 0) | 
|---|
 | 903 |                     { | 
|---|
 | 904 |                                         printf("\b \b"); | 
|---|
 | 905 |                                         count--; | 
|---|
 | 906 |                                     } | 
|---|
| [230] | 907 |                                 } | 
|---|
| [457] | 908 |                                 else if (c == '\n')                  // new line => end of command | 
|---|
| [230] | 909 |                                 { | 
|---|
| [457] | 910 |                                     if (count > 0)               // analyse & execute command | 
|---|
 | 911 |                                     { | 
|---|
 | 912 |                                             // complete command with NUL character | 
|---|
 | 913 |                                             buf[count] = 0; | 
|---|
 | 914 |                         count++; | 
|---|
| [230] | 915 |  | 
|---|
| [457] | 916 |                                         // register command in log arrays | 
|---|
 | 917 |                                             strcpy(log_entries[ptw].buf, buf); | 
|---|
 | 918 |                                             log_entries[ptw].count = count; | 
|---|
 | 919 |                                             ptw = (ptw + 1) % LOG_DEPTH; | 
|---|
 | 920 |                                             ptr = ptw; | 
|---|
| [230] | 921 |  | 
|---|
| [457] | 922 |                         // echo character | 
|---|
 | 923 |                         putchar( c ); | 
|---|
| [230] | 924 |  | 
|---|
| [457] | 925 |                                             // call parser to analyse and execute command | 
|---|
 | 926 |                                             parse( buf ); | 
|---|
 | 927 |                                     } | 
|---|
 | 928 |                     else                         // no command registered | 
|---|
| [441] | 929 |                     { | 
|---|
| [457] | 930 |                         // release semaphore to get next command | 
|---|
 | 931 |                         sem_post( &semaphore ); | 
|---|
| [441] | 932 |                     } | 
|---|
| [457] | 933 |  | 
|---|
 | 934 |                     // exit internal loop on characters | 
|---|
 | 935 |                     end_command = 1; | 
|---|
 | 936 |                 } | 
|---|
 | 937 |                             else if (c == '\t')             // tabulation => do nothing | 
|---|
 | 938 |                                 { | 
|---|
 | 939 |                             } | 
|---|
 | 940 |                             else if (c == (char)0x1B)       // ESC => start an escape sequence | 
|---|
 | 941 |                             { | 
|---|
 | 942 |                     state = ESCAPE; | 
|---|
 | 943 |                             } | 
|---|
 | 944 |                             else                                               // normal character | 
|---|
| [230] | 945 |                                 { | 
|---|
| [457] | 946 |                                     if (count < sizeof(buf) - 1) | 
|---|
 | 947 |                                     { | 
|---|
 | 948 |                         // register character in command buffer | 
|---|
 | 949 |                                             buf[count] = c; | 
|---|
 | 950 |                                             count++; | 
|---|
 | 951 |  | 
|---|
 | 952 |                         // echo character | 
|---|
 | 953 |                         putchar( c ); | 
|---|
| [230] | 954 |                                         } | 
|---|
 | 955 |                                 } | 
|---|
 | 956 |                         } | 
|---|
| [457] | 957 |                         else if( state == ESCAPE )   | 
|---|
| [230] | 958 |                         { | 
|---|
 | 959 |                                 if (c == '[')           //  valid sequence => continue | 
|---|
 | 960 |                                 { | 
|---|
 | 961 |                                         state = BRAKET; | 
|---|
 | 962 |                                 } | 
|---|
 | 963 |                                 else                               // invalid sequence => do nothing | 
|---|
 | 964 |                                 { | 
|---|
 | 965 |                                         state = NORMAL; | 
|---|
 | 966 |                                 } | 
|---|
 | 967 |                         } | 
|---|
| [457] | 968 |                         else if( state == BRAKET ) | 
|---|
| [230] | 969 |                         { | 
|---|
 | 970 |                                 if (c == 'D')   // valid  LEFT sequence => move buf pointer left | 
|---|
 | 971 |                                 { | 
|---|
 | 972 |                                         if (count > 0) | 
|---|
 | 973 |                                         { | 
|---|
 | 974 |                                                 printf("\b"); | 
|---|
 | 975 |                                                 count--; | 
|---|
 | 976 |                                         } | 
|---|
 | 977 |  | 
|---|
 | 978 |                                         // get next user char | 
|---|
 | 979 |                                         state = NORMAL; | 
|---|
 | 980 |                                 } | 
|---|
 | 981 |                                 else if (c == 'C')   // valid  RIGHT sequence => move buf pointer right | 
|---|
 | 982 |                                 { | 
|---|
 | 983 |                                         if (count < sizeof(buf) - 1) | 
|---|
 | 984 |                                         { | 
|---|
 | 985 |                                                 printf("%c", buf[count]); | 
|---|
 | 986 |                                                 count++; | 
|---|
 | 987 |                                         } | 
|---|
 | 988 |  | 
|---|
 | 989 |                                         // get next user char | 
|---|
 | 990 |                                         state = NORMAL; | 
|---|
 | 991 |                                 } | 
|---|
 | 992 |                                 else if (c == 'A')   // valid  UP sequence => move log pointer backward | 
|---|
 | 993 |                                 { | 
|---|
 | 994 |                                         // cancel current command | 
|---|
 | 995 |                                         for (i = 0; i < count; i++) printf("\b \b"); | 
|---|
 | 996 |                                         count = 0; | 
|---|
 | 997 |  | 
|---|
 | 998 |                                         // copy log command into buf | 
|---|
 | 999 |                                         ptr = (ptr - 1) % LOG_DEPTH; | 
|---|
 | 1000 |                                         strcpy(buf, log_entries[ptr].buf); | 
|---|
| [458] | 1001 |                                         count = log_entries[ptr].count - 1; | 
|---|
| [230] | 1002 |  | 
|---|
 | 1003 |                                         // display log command | 
|---|
 | 1004 |                                         printf("%s", buf); | 
|---|
 | 1005 |  | 
|---|
 | 1006 |                                         // get next user char | 
|---|
 | 1007 |                                         state = NORMAL; | 
|---|
 | 1008 |                                 } | 
|---|
 | 1009 |                                 else if (c == 'B')   // valid  DOWN sequence => move log pointer forward | 
|---|
 | 1010 |                                 { | 
|---|
 | 1011 |                                         // cancel current command | 
|---|
 | 1012 |                                         for (i = 0 ; i < count; i++) printf("\b \b"); | 
|---|
 | 1013 |                                         count = 0; | 
|---|
 | 1014 |  | 
|---|
 | 1015 |                                         // copy log command into buf | 
|---|
 | 1016 |                                         ptr = (ptr + 1) % LOG_DEPTH; | 
|---|
 | 1017 |                                         strcpy(buf, log_entries[ptr].buf); | 
|---|
 | 1018 |                                         count = log_entries[ptr].count; | 
|---|
 | 1019 |  | 
|---|
 | 1020 |                                         // display log command | 
|---|
 | 1021 |                                         printf("%s", buf); | 
|---|
 | 1022 |  | 
|---|
 | 1023 |                                         // get next user char | 
|---|
 | 1024 |                                         state = NORMAL; | 
|---|
 | 1025 |                                 } | 
|---|
 | 1026 |                                 else                               // other character => do nothing | 
|---|
 | 1027 |                                 { | 
|---|
 | 1028 |                                         // get next user char | 
|---|
 | 1029 |                                         state = NORMAL; | 
|---|
 | 1030 |                                 } | 
|---|
 | 1031 |                         } | 
|---|
| [457] | 1032 |                 }  // end internal while loop on characters | 
|---|
 | 1033 |         }  // end external while loop on commands | 
|---|
| [446] | 1034 | }  // end interactive() | 
|---|
 | 1035 |  | 
|---|
| [574] | 1036 | //////////////// | 
|---|
| [503] | 1037 | int main( void ) | 
|---|
| [446] | 1038 | { | 
|---|
 | 1039 |     unsigned int cxy;             // owner cluster identifier for this KSH process | 
|---|
 | 1040 |     unsigned int lid;             // core identifier for this KSH main thread | 
|---|
 | 1041 |     int          status;          // child process termination status | 
|---|
| [457] | 1042 |     int          child_pid;       // child process identifier | 
|---|
| [469] | 1043 |     int          parent_pid;      // parent process identifier (i.e. this process) | 
|---|
 | 1044 |     pthread_t    trdid;           // interactive thread identifier (unused) | 
|---|
| [457] | 1045 |     unsigned int is_owner;        // non-zero if KSH process is TXT owner | 
|---|
| [446] | 1046 |  | 
|---|
 | 1047 |     // initialize log buffer | 
|---|
 | 1048 |         memset( &log_entries , 0, sizeof(log_entries)); | 
|---|
 | 1049 |         ptw   = 0; | 
|---|
 | 1050 |         ptr   = 0; | 
|---|
 | 1051 |  | 
|---|
| [457] | 1052 |     // get KSH process pid and core | 
|---|
 | 1053 |     parent_pid = getpid(); | 
|---|
| [459] | 1054 |     get_core( &cxy , &lid ); | 
|---|
| [457] | 1055 |  | 
|---|
| [574] | 1056 | #if MAIN_DEBUG | 
|---|
 | 1057 | printf("\n[ksh] main started on core[%x,%d]\n", cxy , lid );  | 
|---|
 | 1058 | #endif | 
|---|
 | 1059 |      | 
|---|
 | 1060 |     // initializes the semaphore used to synchronize with interactive thread | 
|---|
| [469] | 1061 |     if ( sem_init( &semaphore , 0 , 1 ) ) | 
|---|
 | 1062 |     { | 
|---|
 | 1063 |         printf("\n[KSH ERROR] cannot initialize semaphore\n" ); | 
|---|
 | 1064 |         exit( 1 );  | 
|---|
 | 1065 |     } | 
|---|
| [457] | 1066 |  | 
|---|
| [574] | 1067 | #if MAIN_DEBUG | 
|---|
 | 1068 | printf("\n[ksh] main initialized semaphore\n" );  | 
|---|
 | 1069 | #endif | 
|---|
 | 1070 |      | 
|---|
| [446] | 1071 |     // initialize interactive thread attributes | 
|---|
 | 1072 |     attr.attributes = PT_ATTR_DETACH | PT_ATTR_CLUSTER_DEFINED; | 
|---|
 | 1073 |     attr.cxy        = cxy; | 
|---|
 | 1074 |  | 
|---|
 | 1075 |     // lauch the interactive thread  | 
|---|
 | 1076 |     pthread_create( &trdid, | 
|---|
 | 1077 |                     &attr, | 
|---|
 | 1078 |                     &interactive,   // entry function | 
|---|
 | 1079 |                     NULL );  | 
|---|
| [574] | 1080 | #if MAIN_DEBUG | 
|---|
 | 1081 | printf("\n[ksh] main launched interactive thread => wait children termination\n" );  | 
|---|
 | 1082 | #endif | 
|---|
| [446] | 1083 |      | 
|---|
 | 1084 |     // enter infinite loop monitoring children processes termination  | 
|---|
 | 1085 |     while( 1 ) | 
|---|
 | 1086 |     { | 
|---|
| [457] | 1087 |         // wait children termination | 
|---|
 | 1088 |         child_pid = wait( &status ); | 
|---|
| [446] | 1089 |  | 
|---|
| [574] | 1090 | #if MAIN_DEBUG | 
|---|
 | 1091 | if( WIFEXITED  (status) ) printf("\n[ksh] child process %x exit\n"   , child_pid ); | 
|---|
 | 1092 | if( WIFSIGNALED(status) ) printf("\n[ksh] child process %x killed\n" , child_pid ); | 
|---|
 | 1093 | if( WIFSTOPPED (status) ) printf("\n[ksh] child process %x stopped\n", child_pid ); | 
|---|
| [446] | 1094 | #endif | 
|---|
 | 1095 |  | 
|---|
| [457] | 1096 |         // release semaphore if KSH process is TXT owner, to unblock interactive thread | 
|---|
 | 1097 |         is_fg( parent_pid , &is_owner ); | 
|---|
 | 1098 |         if( is_owner ) sem_post( &semaphore ); | 
|---|
 | 1099 |  | 
|---|
| [446] | 1100 |     } | 
|---|
| [436] | 1101 | }  // end main() | 
|---|
| [230] | 1102 |  | 
|---|
| [446] | 1103 |  | 
|---|