[Linux]Signal2

공부기록·2023년 12월 7일
0
post-thumbnail

🔊 sigaction( )


  • 특정 시그널의 action을 뱌꿔주는 것이 가능하다.
    #include <signal.h>

    void sigaction(int signo, const struct sigaction *restrict act, struct sigaction *restrict oact);
	
    /* 성공시 0, 실패시 -1 반환*/
  • argument
    • signo : signal number
    • act : 바꿀 액션
    • oact : 원래 액션

act의 type은 sigaction 구조체이다.

struct sigaction{
	void (*sa_handler) (int);
    sigset_t sa_mask;
    int sa_flags;
    void (*sa_sigaction) (int signo, siginfo_t *info, void * context);
};
  • sigaction
    • sa_handler와 sa_sigaction은 둘 중 하나만 사용이 가능한데 이는 sa_flags로 설정이 가능핟.
    • sa_flags
      • SA_RESTART : slow interrupt 중 signal 처리로인하여 중단된 interrupt는 원래 종료되지만 해당 flag를 이용하면 해당 interrupt의 재시작이 가능하다.
      • SA_SIGINFO : sa_sigaction 이용시 설정하는 flag이다.

🔈 예제, SIGINT catch

 #include <signal.h>
 
 main() {
 	static struct sigaction act;
    void catchint (int);
    act.sa_handler = catchint;
    sigfillset(&(act.sa_mask));
    
    sigaction(SIGINT, &act, NULL);
    
    printf("Sleep call #1\n);
    sleep(1);
    printf("Sleep call #2\n);
    sleep(1);
    printf("Sleep call #3\n);
    sleep(1);
    
    printf("Exiting\n");
    exit(0);
    
    void catchint(int signo){
		printf("\nCatchint: signo=%d\n",signo);
        printf("CATCHINT: returning\n\n");
    }
}

-program 실행 중 SIGINT 발생
$ sigex
sleep call #1
<interrupt>

Catchint: signo=2
Catchint: returing
 
sleep call #2
sleep call #3
Exiting

🔊 Signals and System call


  • System call은 kernel에서 처리된다. 원래 도중에 들어온 signal은 무시되지만 slow system call에서는 interrupt가 가능하다.
  • System call 진행 중 signal이 발생하면 errno는 EINTR이 설정된다.
  • Slow system call
    • pipes, terminal devices, network devices의 I/O들 (Disk I/O는 제외)
    • pause(), wait(), ICP
again:
	if((n=read(fd, buf, BUFFFSIZE)) < 0) {
		if(errno == EINTR) goto again;
    }
}
  • system call중에 발생한 signal을 처리하고나면 error를 반환하고 아예 끝나는데 sa_flags에서 SA_RESTART를 설정하면 중단되었던 System call이 다시 실행하고 errno는 설정되지않는다.

void handler(int signo, siginfo_t info, void context);

🔊 siginfo의 구조

struct siginfo {
  int    si_signo;  //signal 번호
  int    si_errno;  
  int    si_code;   
  pid_t  si_pid;    // signal을 전송한 process ID
  uid_t  si_uid;    // signal을 전송한 real user ID
  void  *si_addr;   // signal을 전송한 Address
  int    si_status; 
  long   si_band;
};



🏷️ siginfo이용 예제

#include <signal.h>
void sig_handler(int sig, siginfo_t *siginfo, void* param2){
	printf("[parent:%d] : RECIEVE a signal from child %d!!\n".getpid(), siginfo->si_pid);
    
int main(){
	pid_t pid;
    struct sigaction act;
    int i = 0;
    memset($act, 0, sizeof(act)); // 메모리 초기화
    /* act.sa_handler 안씀 */
    act.sa_sigaction = sig_hander;
    act.sa_flags = SA_SIGINFO;
    sigfillset(&act.sa_mask);
    sigaction(SIGUSR1, &act, 0);
    
    i = 0;
    
    while(pid = fork()){
    	printf("[parent:%d] : CREATE child %d\n\n", getpid(), pid);
      if(++i==3) break; //자식을 3번 생성한다.
	}
    
    if(pid > 0){
    	getchar(); //아무키 누르면 부모 종료
    } esle {
		kill(getppid(), SIGUSR1); //부모에게 SIGURS1 signal 전송
    }
}



signal의 추가정보

  • signal-catching 함수 이후엔 signal mask는 reset된다.
  • sigaction.sa_mask를 이용하여 특정 signal을 block할 수 있다. block된 signal은 pending signal이라 한다.
  • 같은 signal이 들어와도 하나만 pending된다.

0개의 댓글

관련 채용 정보