2016-12-12 1 views
2

나는 내 자신의 껍질을 만들고있어. 명령을 실행하고 &으로 종료하면 백그라운드에서 프로세스가 실행되므로 백그라운드 프로세스를 포그 라운드에 넣을 수있는 fg 명령을 만들고 싶습니다.포 그라운드 신호 tcsetpgrp c

fg 기능을 만드는 데 문제가 있습니다. 올바르게 이해한다면, 자식 프로세스에 signal()을 넣으면 자식 프로세스가 신호를받을 수있게됩니다. 신호는 signum과 핸들러 함수라는 두 개의 인수를받습니다. tcsetpgrp()를 사용하여 주어진 백그라운드 프로세스를 포 그라운드로 설정합니다. 그래서 lsh_fg에서 나는 tcsetpgrp (STDIN_FILENO, pid)를 호출한다.

그래서 signum은 tcsetpgrp()에서 신호를받을 수 있도록 sigttou 여야합니다.

내가 (tcsetpgrp를하기 때문에, 핸들러 내부에 넣어되어야 하는지를 모른다는) 매뉴얼 페이지를 설명으로 할 예정이다 : 는 " 함수 tcsetpgrp를()는 프로세스 그룹 ID 을 pgrp와 프로세스 그룹을 만드는 fd 에 연결된 터미널의 전경 프로세스 그룹 " 내가 이해하는 것처럼 tcsetpgrp()는 신호 (sigttou, handler)가있는 프로세스로 신호를 보내고, 신호를 받으면 포 그라운드로 보냅니다. 그러나 그것이 작동하지 않기 때문에 나는 이것을 분명히 오해하고 있습니다.

내 질문 : tcsetpgrp()와 signal (sigttou, handler)가 함께 작동하는 방식을 어떻게 이해해야합니까? 그리고 내 처리기에는 무엇이 포함되어야합니까? 정말 답장 해 주셔서 감사합니다. :-) 아래 코드를 참조하십시오. Ps : 저는 C와 시스템 프로그래밍을 처음 접했고 이것은 내 첫 번째 게시물이기 때문에 코드에 관한 건설적인 비판을 환영합니다. 고마워 : D

#include <sys/wait.h> 
#include <unistd.h> 
#include <stdlib.h> 
#include <stdio.h> 
#include <string.h> 
#include <signal.h> 

pid_t pid; 

int toke_c; 
//function declaration for the function pointers 
int lsh_cd(char **args); 
int lsh_pwd(char **args); 
int lsh_exit(char **args); 
int lsh_fg(char **args); 

//An array of functions: 
int (*builtin_func[]) (char **) = { 
    &lsh_cd, 
    &lsh_pwd, 
    &lsh_exit, 
    &lsh_fg 
}; 

//An array of the given strings: 
char *builtin_str[] = { 
    "cd", 
    "pwd", 
    "exit", 
    "fg" 
}; 

///built in functions cd and pwd 

int lsh_fg(char **args){ 
tcsetpgrp(STDIN_FILENO, pid); 
    return 1; 
} 

void fg_handler() 
{ 
//What to put here??? 
} 

///built in functions cd and pwd 
int lsh_cd(char **args) 
{ 
    if (args[1] == NULL) { 
    fprintf(stderr, "lsh: cd: no arguments given\n"); 
    } else { 
    if (chdir(args[1]) != 0) { 
     perror("lsh"); 
    } 
    } 
    return 1; 
} 

int lsh_pwd(char **args) 
{ 
char * cwd; 
    cwd=getcwd (NULL,0); 
    printf ("%s\n ", cwd); 
    return 1; 
} 

int lsh_exit(char **args) 
{ 
    return 0; 
} 

/* Handlers Here*/ 
void killer() 
{ 
    if (pid == 0) 
    exit(0); 
} 

void handler() 
{ 
    //I DON'T KNOW WHAT TO PUT HERE 
} 

int lsh_launch(char **args) 
{ 

    int status=0; 
    pid = fork(); 
    if (pid == 0) { 
    // child process 
    signal(SIGINT, killer); 
    if (execvp(args[0], args) == -1) { 
     fprintf(stderr,"Command not found in $PATH\n"); 
    } 
    return 1; 
    } else if (pid < 0) { 
    //error 
    perror("lsh"); 
    } else { 
    // parent 
    signal(SIGINT, killer); 
    waitpid(pid, &status, WUNTRACED); 
    } 
    return 1; 
} 

int lsh_background(char **args) 
{ 

    pid_t pid; 
    int status=0; 
    pid = fork(); 
    if (pid == 0) { 
    // child process 
    setpgid(0, 0); 
    signal(SIGINT, killer); 
    signal(SIGTTOU, fg_handler); 
    if (execvp(args[0], args) == -1) { 
     fprintf(stderr,"Command not found in $PATH\n"); 
    } 
    return 1; 
    } else if (pid < 0) { 
    //error 
    perror("lsh"); 
    } else { 
    // parent 
    signal(SIGTTOU, fg_handler); 
    signal(SIGINT, killer); 
    } 
    return 1; 
} 

//if a command was entered that we've been using 
int lsh_exec(int argc, char **args) 
{ 
    int i; 
    if (args[0] == NULL) {return 1;} 
    int tresh=4; 

    char **args1=malloc(toke_c*sizeof(char *)); 
    int j; 
    for(j=0;j<toke_c-1;j++){ 
     args1[j]=args[j]; 
    } 

    if(strcmp(args[toke_c-1],"&")==0){ 
     return lsh_background(args1); 
     } 

     for (i = 0; i < tresh; i++) { 
     if (strcmp(args[0], builtin_str[i]) == 0) { 
     return (*builtin_func[i])(args); 
     } 
    } 

    return lsh_launch(args); 
} 

#define MAX_STR 256 

//reading the line 
char *lsh_lread(void) 
{ 
    char *str = malloc (MAX_STR); 
    fgets (str, MAX_STR, stdin); 
} 

//tokenizer 
char **lsh_tokenizer(char *line) 
{ 
    int bufsize = 64; 
    int pos_t = 0; 
    char **tokens = malloc(bufsize * sizeof(char*)); 
    char *token; 
    token = strtok(line, " \t\r\n\a"); 

    while (token != NULL) { 
    tokens[pos_t] = token; 
    pos_t++; 

    token = strtok(NULL, " \t\r\n\a"); 
    } 
    tokens[pos_t] = NULL; 
    toke_c=pos_t; 

    return tokens; 
} 


void lsh_loop(void) 
{ 
    int argc; 
    char *line; 
    char **args; 
    int status; 

    do { 
    printf(">> "); 
    line = lsh_lread(); 
    args = lsh_tokenizer(line); 
    status = lsh_exec(argc,args); 
    free(line); 
    free(args); 
    } while (status); 
} 


int main(int argc, char **argv) 
{ 
    lsh_loop(); 

    return 0; 
} 

답변

1

어떻게하는 방식 tcsetpgrp를() 및 신호 (SIGTTOU, 핸들러) 함께 일을 이해 하는가?

목적에 따라 다르다. 프로세스 그룹을 전경 그룹으로 만들기 위해 프로세스에 신호를 보낼 필요는 없습니다 (아래 참조). 사실 나는 당신이 포 그라운드에 넣으려고하는 프로세스 그룹에 의도적으로 SIGTTOU을 보내는 이유를 알지 못합니다. 프로세스가 제어 터미널을 가지고 있다면

, tcsetpgrp()pgid_id에 단말기와 연관된 전경 프로세스 그룹 ID를 설정한다

여기 (강조 효과) POSIX's documentation for tcsetpgrp()의 중앙 부분이다. 응용 프로그램은 fildes과 관련된 파일이 호출 프로세스의 제어 터미널이고 제어 터미널이 현재 호출 프로세스의 세션과 연관되어 있는지 확인해야합니다. 응용 프로그램은 pgid_id 값이 호출 프로세스와 동일한 세션에있는 프로세스의 프로세스 그룹 ID와 일치하는지 확인해야합니다.

시도 처리 그룹 SIGTTOU 신호가 전송 될 터미널을 제어한다 연관된 fildes에서 백그라운드 프로세스 그룹의 구성원 인 프로세스에서 tcsetpgrp()을 사용한다. [...]

fg 명령을 구현하는 것에 대해 이야기하고 있습니다. 그러한 명령의 주된 유용성은 대화 형 실행이며, 프로세스 (예 : 셸)가 해당 명령을 대화식으로 수신하는 경우에는 포어 그라운드 프로세스 그룹에 있어야합니다. 단말기. 그러한 프로세스가 함수를 호출하고 인수가 개별 요구 사항을 만족한다고 가정하면 "tcsetpgrp()은 터미널과 관련된 전경 프로세스 그룹 ID를 pgid_id으로 설정해야합니다." 물론 실패합니다. 시그널링이 문서화되어 있지 않다.

SIGTTOUtcsetpgrp()배경 프로세스 그룹에 프로세스에 의해 호출되는 경우에만이 그림에 온다. 쉘을 구현했다면 백그라운드에서 실행중인 쉘에 대한 작업 제어를 비활성화 할 수 있습니다 (명령은 오류와 함께 실패합니다). 이 신호의 기본 핸들러는 프로세스를 중지합니다 ( 종료와 동일하지 않습니다). 이는 세션의 제어 터미널에 쓰기를 시도하는 백그라운드 프로세스에 적합합니다. 마찬가지로, SIGTTIN은 기본적으로 프로세스를 중지하고 세션을 제어하는 ​​터미널에서 읽으려고 시도하는 백그라운드 프로세스에 전달됩니다. fg 명령에 대한

, 예상 또는 SIGTTOU 또는 SIGTTIN, 을 처리하고 싶지만 그건 당신이 신호 할 필요가 없습니다 의미하지는 않습니다하지 않습니다. 오히려 tcsetpgrp()을 호출하는 (초기 포어 그라운드) 프로세스는 이후에 해당 프로세스의 일부 또는 전부가 중지 된 경우 나중에 SIGCONT을 새로운 forground pgroup으로 보내야합니다. 이 신호의 기본 핸들러는 프로세스가 중지 된 경우 다시 시작합니다. 원하는 프로세스입니다.

간단히 말해,이 목적을 위해 사용자 정의 신호 처리기를 작성할 필요가 없을 것입니다.

관련 문제