2013-10-02 2 views
3

I는 신호 처리기과 같이은 sigaction을 사용하여 설정이 있습니다이상한은 sigaction()과의 getline() 상호 작용

struct sigaction act, oldact; 
memset(&act, 0, sizeof(struct sigaction)); 
act.sa_handler = sig_handler; 
sigemptyset(&act.sa_mask); 
sigaddset(&act.sa_mask, SIGALRM); 
sigaddset(&act.sa_mask, SIGINT); 
sigaddset(&act.sa_mask, SIGTERM); 
sigaddset(&act.sa_mask, SIGTSTP); 
sigaction(SIGALRM, &act, &oldact); 
sigaction(SIGINT, &act, &oldact); 
sigaction(SIGTERM, &act, &oldact); 
sigaction(SIGTSTP, &act, &oldact); 
act.sa_flags = 0; 

I 실행이 다음 입력을 수집하고 기본적으로처럼 행동 (다시 그것을 밖으로 인쇄하는 for 루프 고양이).

char *linebuf = NULL; 
size_t n = 0; 
int len; 
while(1){ 
    len = getline(&linebuf, &n, stdin); 
    if(len>0){ 
     printf("%s", linebuf); 
    } 
} 

그러나, 일단 내가 입력, 신호 처리에서 getline() 더 이상 블록을 반환하고 중단 된 시스템 호출 인 errno EINTR에 설정하는 동안 대신 지속적으로 -1를 반환합니다. 나는 분명히 getline()을 인터럽트하려고했지만 입력을 계속 읽을 수 있도록 어떻게 재설정합니까?

내 문제를 실제로 해결하지 못하는 몇 가지 유사한 질문이 있지만 문제를 더 잘 이해하는 데 도움이 될 수 있습니다. 2

또 다른 흥미로운 재미있는 이야기 1 내가 내 신호 처리를 위해 signal()를 사용 할 때 나는이 문제가되지 않았다이지만 POSIX 호환 때문에 sigaction()로 변경되었습니다.

+1

'printf (linebuf);는 아마도 유효한 C 구문이 아닙니다. – haccks

+1

@haccks 예,'printf ("% s", linebuf); ' – Shahbaz

+0

'printf ("% s", linebuf)로 변경했지만'printf (linebuf);'는 올바른 c 구문 (이 경고는'경고 : 문자열 리터럴 형식이 아니고 형식 인수가없는 형식 (-Wformat-security)')이지만 오류가 아니며 문제가되지 않습니다. – Connor

답변

4

링크 된 질문 중 하나가 실제로 답변을 제공합니다. 하지만 먼저, 몇 가지 참조. getline은 내부적으로 다른 기능 (아마도 read)을 사용하고 있습니다. read의 매뉴얼 페이지에서

: 그것은 모든 데이터를 판독하기 전에 판독()가 신호에 의해 중단되는 경우

그것을 반환한다 -1 [EINTR]로 설정 errno를.

...

는 ... 목적인 지정된 활동까지 정지한다 (데이터 읽기, 공간 등 작성하고)에 지정된 파일 검출 선택 부가 기능()가 설명자. select()를위한 시스템 용으로 작성된 응용 프로그램은 신호로 인한 I/O 중단이 필요한 상황 (예 : 키보드 입력)에서 read() 전에 사용하는 것이 일반적입니다. select의 사람 페이지에서

:

위해 pselect() 함수는 자신의 설명 중 일부는 읽기를 위해 준비가되었는지 확인하기 위해 파일 기술자 세트를 ... 조사해야한다는 서면에 대한 준비 예외적 인 보류 상태가 각각 있습니다.

select을 사용하면 언제 읽을 수 있는지 안전하게 알 수 있습니다. 그러나 그래도 read이 나중에 중단되는 것을 막지는 못합니다. (나는 당신의 정보를 위해 이것을 말했다).

실제로 스트림의 오류 플래그를 지우려면 연결된 질문 중 하나에 this answer이 표시되어야합니다 (C++에서도) clearerr 함수를 사용하여 스트림의 오류 플래그를 지울 필요가 있습니다. 맨 페이지 (C 표준뿐만 아니라)는 "인터럽트 된"플래그를 지우는 것을 구체적으로 말하지는 않지만, 이것은 C의 범위를 벗어나서 POSIX의 영역에 있기 때문입니다.보조 노트로


, 나는 구조체를 취소 memset를 사용하지 마십시오 말하고 싶습니다.

struct sigaction act = {0}; 

아니면 현학적 수 있도록하려면 struct sigaction의 첫 번째 요소는 다른 구조체 나 배열이 될 수 있기 때문에, 당신은 그것의 위임 필드 중 하나에 할당 할 수있는 :

C는 그것을하는 아주 좋은 방법이
struct sigaction act = { .sa_handler = NULL }; 
2

매우 늦은 대답이지만, 최근에 이것에 대해 배웠던 것을 나눌 것입니다. sigaction 구조체에서 sa_flags를 0으로 설정하면 신호를 받으면 읽기에 대한 기본 동작이 지워집니다. 이전 signal() 메서드를 사용하면이 기본 비헤이비어가 유지됩니다. 귀하의 경우에 이것을 되돌리려면 sa_flags = SA_RESTART를 설정해야합니다. 이 경우 비록 시그널 핸들러가 호출 될 것이고, getline은 그것이 읽는 중간에 있지 않다면 입력 대기를 재개 할 것이다. 읽기 도중에 신호가 발생하면 -1을 얻고, 다시 시작하기 전에 스트림을 clear()해야합니다. 그러나 데이터를 기다리는 동안 읽기가 차단되고 신호가 발생하면 SA_RESTART를 사용하여 신호 처리기가 성공적으로 실행 된 후 즉시 다시 읽습니다.

저는 개인적으로 getline()을 인터럽트 할 수 있기를 원했습니다. 따라서 파이프에서 대기중인 프로그램을 종료 할 수 있었고 이전 신호() 메서드를 사용하여 처리기를 설정했기 때문에 문제가있었습니다. 그래서 신호를 얻을 것이지만, getline은 데이터 읽기를 기다리는 것이 차단되어서 신호 처리기가 실행 된 후에 자동으로 읽기를 다시 시작하기 때문에 중단되지 않습니다. sigaction 구조체로 옮겨서 sa_flags = 0으로 설정했을 때 getline이 기본적으로 EINTR을 반환하도록 중단하고 프로세스에 신호를 보내 종료 할 수 있습니다.

나는이 포럼을 매우 좋아합니다. 나는 끈적 끈적한 문제를 해결하는데 얼마나 많은 시간을 할애했는지 셀 수 없다. 내가 돌려 주겠다고 생각 했어. 희망이 다음 프로그래머에게 도움이!