2014-02-11 2 views
0

그것은 c의 리눅스 쉘의 구현입니다. 백그라운드 프로세스 지원을 추가했기 때문에 이해가 안되는 출력이 있습니다. 여기에 코드입니다 : 내가 "LS &"같은 BG 명령을 실행하면내 프로세스가 이와 같이 작동합니까?

#include <stdlib.h> 
#include <errno.h> 
#include <stdio.h> 
#include <stdlib.h> 
#include <string.h> 
#include <unistd.h> 
#include <sys/types.h> 
#include <sys/time.h> 
#include <sys/resource.h> 
#include <signal.h> 
#include <wait.h> 

#define DEFAULT_PROMPT "\nLog710H2014%>" 
#define EXIT_CMD "exit" 
#define CD_CMD "cd" 
#define HOME_ENV_VAR "HOME" 
#define NEW_LINE "\n**************************************************\n" 
#define BCG_CMD_FLAG "&" 

void cd_handler(int argc, char *argv[]); 
int lire(char *chaine, int longueur); 
char** init_command(int* size,char *str); 
int execProg(int *argc, char **argv); 
int execProgBg(int *argc, char **argv); 
void sigchldHandler(int sig_num); 

struct beanProcess { 
    pid_t pid; 
    int job_num; 
    char *command; 
}; 

struct beanProcess *beans; 

int jobCount = 1; 

int main() { 

    printf(NEW_LINE); 
    printf("Bienvenue sur le shell de l'equipe 1"); 
    printf(NEW_LINE); 

    while(1){ 
     char str[200]; 
     printf(DEFAULT_PROMPT); 

     lire(str, 200); 
     int commArgsC = 0, bg = 0; 
     char** comms = init_command(&commArgsC, str); 

     if(commArgsC == 0){ 
      printf("Saisie vide, veuillez entrez une commande."); 
      continue; 
     } 

     if(strcmp(comms[commArgsC-1], BCG_CMD_FLAG) == 0){ 
      bg = 1; 
      comms[commArgsC-1] = 0; 
     } 
     if(strcmp(comms[0], CD_CMD) == 0){ 
      cd_handler(commArgsC, comms); 
      commArgsC = commArgsC -1; 
     } 
     else if (strcmp(comms[0], EXIT_CMD) == 0){ 
      exit(0); 
     } 
     else { 
      if(bg){ 
       execProgBg(&commArgsC, comms); 
      } 
      else{ 
       execProg(&commArgsC, comms); 
      } 
     } 
    } 
    exit; 
} 
void cd_handler(int argc, char *argv[]){ 
    char buff[512]; 
    char * directory; 

    if(argc < 2){ 
     directory = getenv(HOME_ENV_VAR); 
    }else if (argc == 2){ 
     directory = argv[1]; 
    }else{ 
     exit(1); 
    } 

    if (chdir(directory) == -1) { 
     printf ("Erreur de changement de repertoire actif", strerror (errno)); 
    }else{ 
     if (getcwd(buff, sizeof(buff)) == NULL) 
      perror("Impossible d'afficher le repertoire courant"); 
     else 
      printf("le repertoire courant est: %s\n", buff); 
    } 
} 
//Cette fonction est adaptée a partir du code de refp sur http://stackoverflow.com/questions/11198604/c-split-string-into-an-array-of-strings 
char** init_command(int* size, char* str){ 
    char ** res = NULL; 
    char * p = strtok (str, " "); 
    int n_spaces = 0; 

    while (p) { 
     res = realloc (res, sizeof (char*) * ++n_spaces); 

     if (res == NULL){ 
      exit (-1); 
     } 
     res[n_spaces-1] = p; 
     p = strtok (NULL, " "); 
    } 
    res = realloc (res, sizeof (char*) * (n_spaces+1)); 
    res[n_spaces] = 0; 
    *size = n_spaces; 
    return res; 
} 
//cette fonction est tirée d'un exemple de http://fr.openclassrooms.com/informatique/cours/apprenez-a-programmer-en-c/recuperer-une-chaine-de-caracteres 
int lire(char *chaine, int longueur) 
{ 
    char *positionEntree = NULL; 

    if (fgets(chaine, longueur, stdin) != NULL) 
    { 
     positionEntree = strchr(chaine, '\n'); 
     if (positionEntree != NULL) 
     { 
      *positionEntree = '\0'; 
     } 
     return 1; 
    } 
    else 
    { 
     return 0; 
    } 
} 
int execProg(int *argc, char **argv){ 
    char path[] = "/bin/"; 
    strcat(path,argv[0]); 
    printf("\nThis is the %d process executing the code in non bg mode\n", getpid()); 
    printf("Voici le resultat de l'execution de votre commande\n"); 
    pid_t pid; 
    pid = fork(); 

    if (pid < 0) { 
     perror("Creation de processus avec fork echouee"); 
     exit(-1); 
    } 
    else if (pid == 0) { 
     if(execvp(argv[0], argv) == -1){ 
      printf("\nthis is the child process %d executing the command in non bg mode\n", getpid()); 
      perror("execv"); 
      return EXIT_FAILURE; 
     } 
    } 
    else { 
     printf("\nthis is the parent process %d showing the stats in non bg mode\n", getpid()); 
     struct rusage rusg; 
     long temp, tempCpu; 
     wait (NULL); 
     getrusage(RUSAGE_CHILDREN, &rusg); 
     printf("\nStatistique de la commande %s:\n", argv[0]); 

     temp = (rusg.ru_utime.tv_sec * 1000) + (rusg.ru_utime.tv_usec/1000); 
     tempCpu = (rusg.ru_stime.tv_sec * 1000) + (rusg.ru_stime.tv_usec/1000); 

     printf("\nLe temps wall-clock (ms): %ld", temp); 
     printf("\nLe temps CPU (ms) %ld", tempCpu); 
     printf("\nNB interruptions volontaires: %ld", rusg.ru_nvcsw); 
     printf("\nNB interruptions involontaires: %ld", rusg.ru_nivcsw); 
     printf("\nNB defaults de pages: %ld", rusg.ru_majflt); 
     printf("\nNB defaults de pages satifaits du noyau : %ld", rusg.ru_minflt); 
    } 
    return EXIT_SUCCESS; 
} 
int execProgBg(int *argc, char **argv){ 

    signal(SIGCHLD, sigchldHandler); 
    printf("\nThis is the %d process executing the code in bg mode\n", getpid()); 

    pid_t pid; 
    pid = fork(); 

    if (pid < 0) { 
     perror("Creation de processus avec fork echouee"); 
     return EXIT_FAILURE; 
    } 
    else if (pid == 0) { 
     //printf("This is the pid %d", getpid()); 
     printf("\nthis is the child process %d executing the command in bg mode\n", getpid()); 

     if(execvp(argv[0], argv) == -1){ 
      perror("execvp"); 
      return EXIT_FAILURE; 
     } 
    } 
    else { 
     printf("\nthis is the parent process %d showing the queue in bg mode\n", getpid()); 

     printf("[%d] %d", jobCount, pid); 
     jobCount++; 
     //cleanJobList(childPid); 

     //ajoutProcess(); 
    } 
    return EXIT_SUCCESS; 
} 
void sigchldHandler(int sig_num) 
{ 
    int status; 
    int childPid; 
    childPid = waitpid(-1, &status, 1); 
    printf("Hello the process %d has died\n", childPid); 
    //cleanJobList(childPid); 
} 

, 여기에 출력입니다 :

************************************************** 
Bienvenue sur le shell de l'equipe 1 
************************************************** 

Log710H2014%>ls & 

This is the 23464 process executing the code in bg mode 

this is the parent process 23464 showing the queue in bg mode 
[1] 23472 
Log710H2014%> 
this is the child process 23472 executing the command in bg mode 
Debug PARTIE3.c 
Hello the process 23472 has died 

This is the 23464 process executing the code in non bg mode 
Voici le resultat de l'execution de votre commande 

this is the parent process 23464 showing the stats in non bg mode 
Debug PARTIE3.c 

Statistique de la commande ls: 

Le temps wall-clock (ms): 0 
Le temps CPU (ms) 2 
NB interruptions volontaires: 2 
NB interruptions involontaires: 9 
NB defaults de pages: 0 
NB defaults de pages satifaits du noyau : 644 
Log710H2014%> 

왜 부모 프로세스가 리라() ​​함수를 중첩되어 있고 직접 이동 첫 번째 실행 후 execProg 함수에?

+0

'디버그 PARTIE3.c '는 어디에서 왔습니까? – Nabla

+0

명령 ls & – user2966439

답변

1

너는 while 루프에있다. execProgBg 함수가 반환 할 때 아무리 반환해도 루프는 계속 진행됩니다. 당신이 멈추고 싶다면 break이 필요하거나 exitexecProgBg으로 불러야합니다.

왜 그

나는 당신이 당신의 프로그램을 실행하는 방법을 알고하지 않습니다하지만이처럼 보이는 첫 번째 실행 후 execProg 기능에 직접가는 리라() ​​함수와 중복 부모 프로세스 두 번째 시간은 fgets입니다. lire 함수의 반환 코드를 확인하지 않으므로 알지 못합니다. 그래서 당신은 계속해서 이전 호출에서 버퍼를 재사용합니다. EOF을 프로그램에 전달한 것 같습니다. 아마도 ctrl-d를 누르면됩니다.


나는 코드를 실행하기로 결정하고, 영업 이익은 처음 ls & 후 CTRL-D를 눌렀을 때처럼 같은 결과를 얻었다.


그것은 점 외에하지만 몇 가지 설명을 보증 :

exit; 

이 함수 포인터로 변환하는 기능 출구를 평가하고 그 결과를 버린다. 함수를 호출하지 않습니다. 더 중요한 것은 main의 마지막 문장으로 exit를 호출하는 것이 main이 종료되기 때문에 무의미하다는 것입니다. 실패가 성공했음을 나타내려면 단지 return some_code이어야합니다.

+0

종료 문제를 해결했지만 루프의 두 번째 반복에서 내 prog이 (stdin의 fgets를 포함하는) lire 함수에서 블로킹하지 않는 이유는 무엇입니까? – user2966439

+0

@Nabla 질문은 그 사이에 편집되었으며 처음으로 나는 두 번째 부분을 보지 못했습니다. 찾고. – cnicutar

+0

@Nabla'fgets'가 실패했습니다. 그것은 EOF처럼 보이지만 뭔가 더 미묘 할 수 있습니다. – cnicutar