무한 루프 프로그램에게 시그널 보내기

  • 무한루프 프로그램 작성 - 무한루프 안에서 자신의 프로세스 아이디(pid) 출력
1
2
3
4
5
6
7
8
9
10
#include<stdio.h>
#include <sys/types.h>
#include <unistd.h>
int main(){
        while(1){
                printf("my pid is %ld \n",(long)getpid());
                sleep(1);
        }
        return 0;
}
cs
  • kill()을 이용하여 정지시키기 : kill -9 : SIGKILL -> 즉각적으로 죽음

 

  • 무한 루프중 Ctrl+C -> 프로세스를 아예 종료

 

  • 무한 루프중 Ctrl+Z -> stop

  • fg -> stop된 프로세스를 다시 재실행

 

  • kill -SIGSTOP

  • kill -SIGINT

 

  • sleep(seconds) -> 몇초 기다리다가 다시 실행
  • SIGQUIT = Ctrl+\ : 죽기전에 자신의 상태를 파일에 저장 후 죽음 -> 어떤 상황에서 죽었는지 확인 할 수 있음
    • 자체적으로 core저장을 막아놓기 때문에 명령어로 저장이 가능하게 해야 함
    • ulimit -c unlimited : core를 저장하지 못하도록 막은 것을 풀어줌 -> 너무 큰 파일이 저장 되지 않게 하기 위해서 default로 저장을 막아놓음

  • -g : debug정보를 추가한다는 의미

    • debug정보를 추가하여 용량이 늘어남

  • gdb ./debug : 디버그 실행

    • l : 소스코드 출력

      1. enter를 누를때마다 이후의 line이 출력

    • b main : break point를 main문에 지정

 

    • r : 실행시작 -> break point에서 걸림

 

    • s : 한줄씩 실행 main에서 fun1으로 들어감 -> fun2 -> fun3
      1. main -> fun1 -> fun2 -> fun3인 함수를 제작
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
#include<stdio.h>
#include <sys/types.h>
#include <unistd.h>
 
void fun3(){
        int i = 0;
        while(1){
                printf("my pid is %ld \n",(long)getpid());
                i++;
                sleep(1);
        }
 
}
void fun2(){
        fun3();
}
void fun1(){
        fun2();
}
int main(){
        fun1();
        return 0;
}
cs
 
  1. main문에서 fun1을 부르고 fun1에서 fun2를 .... fun3에서 끝나는 프로그램
  2. b main으로 break point를 정하고 s를 입력한 후 반복해보면

 

    • bt : 함수가 실행된 순서대로 출력

 

    • q : 나감

GDB를 이용하여 core 파일 분석

  • core파일을 통해 어디서 kill되었는지,끝난 이유 등 확인 가능
  • gcc -g whiledebug.c
  • gdb ./a.out core -> core 확인
  • bt : 어디서 중단되었는지 확인

 


sigaction(2)

  • 무한루프 프로그램 수정
  • sigaction(2)함수를 써서 SIGINT를 받으면 ouch!를 출력하도록 시그널 핸들러를 작성하여 등록
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
#include<stdio.h>
#include <sys/types.h>
#include <unistd.h>
#include <signal.h>
#include <stdlib.h>
 
void ouch(int sig){
        printf("OUCH: I got a signal %d\n",sig);
}
 
int main(){
        struct sigaction sa;
 
        sigemptyset(&sa.sa_mask);
        sa.sa_flags=0;
        sa.sa_handler = ouch;
 
        if(sigaction(SIGINT,&sa,NULL)==-1){
                perror("sigaction");
                exit(0);
        }
 
        while(1){
                printf("my pid is %ld \n",(long)getpid());
                sleep(1);
        }
        return 0;
}
cs
  1. sigaction을 사용하기 위한 struct선언
  2. sigemptyset으로 mask를 비워줌
  3. flag를 0으로 선언
  4. handler에 ouch라는 함수 지정
  5. sigaction사용 -> SIGINT에 ouch함수 지정 -> -1이면 에러
  6. 결과

  • 원래 while문이 진행되다가 Ctrl+C를 입력하면 ouch실행

추가로 SIGQUIT을 받으면 good bye를 출력하고 종료

  • 위의 파일에서 함수 하나만 더 추가하면 됨
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
#include<stdio.h>
#include <sys/types.h>
#include <unistd.h>
#include <signal.h>
#include <stdlib.h>
 
void ouch(int sig1){
        printf("OUCH: I got a signal %d\n",sig1);
}
 
void bye(int sig2){
        printf("Good bye %d\n",sig2);
        exit(0);
}
 
int main(){
        struct sigaction sa;
        struct sigaction sa_quit;
 
        sigemptyset(&sa.sa_mask);
        sa.sa_flags=0;
        sa.sa_handler = ouch;
 
        sigemptyset(&sa_quit.sa_mask);
        sa_quit.sa_flags=0;
        sa_quit.sa_handler = bye;
 
        if(sigaction(SIGINT,&sa,NULL)==-1){
                perror("sigaction");
                exit(0);
        }
 
        if(sigaction(SIGQUIT,&sa_quit,NULL)==-1){
                perror("sigaction");
                exit(0);
        }
 
        while(1){
                printf("my pid is %ld \n",(long)getpid());
                sleep(1);
        }
        return 0;
}
cs
  • 결과

 


alarm(2)

 

  • 무한루프 프로그램 수정
  • alarm(2) 함수를 통해 매 1초마다 SIGALRM을 발생
  • sigaction(2) 함수를 써서 SIGALRM를 받으면 Alarm arrived!를 출력하도록 시그널 핸들러를 작성하여 등록
  • alarm은 한번만 SIGALRM을 발생시킨다 주기적으로 SIGALRM을 발생시키기 위해서는 SIGALRM시그널 핸들러에서도 alarm(2)을 설정해 주어야 한다 -> 완전히 끝내 줘야 다시 호출할 수 있음
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
#include<stdio.h>
#include <sys/types.h>
#include <unistd.h>
#include <signal.h>
#include <stdlib.h>
 
void al(int sig){
        printf("Alarm arrived!\n");
        alarm(2);
}
 
int main(){
        struct sigaction sa;
 
        sigemptyset(&sa.sa_mask);
        sa.sa_flags=0;
        sa.sa_handler = al;
 
        if(sigaction(SIGALRM,&sa,NULL)==-1){
                perror("sigaction");
                exit(0);
        }
        alarm(2);
        while(1){
                printf("my pid is %ld \n",(long)getpid());
                sleep(1);
        }
        return 0;
}
cs
  1. 위와 마찬가지로 struct sigaction을 정의 sa
  2. flag = 0
  3. handler = al함수로 지정
  4. SIGALRM에 sa를 지정하면 알람이 올때마다 handler로 지정된 al함수 실행
  5. alarm(2)를 al함수에 넣어주는 이유는 한번 실행하고 while문이 반복되기 때문에 다시 alarm을 실행하지 못하기때문
  • 결과

  • sleep(1)이므로 1초마다 while문이 실행
  • 2번의 실행 후 alarm이 실행됨

sigprocmask(2)

  • 주어진 코드
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
#include<stdio.h>
#include <sys/types.h>
#include <unistd.h>
#include <signal.h>
#include <stdlib.h>
 
struct two_double{
        double a;
        double b;
}data;
 
void signal_handler(int sig){
        printf("%f, %f\n",data.a,data.b);
        alarm(1);
}
 
int main(void){
        struct sigaction sa;
        static struct two_double zeros={0.0,0.0}, ones={1.0,1.0};
 
        sigemptyset(&sa.sa_mask);
        sa.sa_flags=0;
        sa.sa_handler = signal_handler;
 
        if(sigaction(SIGALRM,&sa,NULL)==-1){
                perror("sigaction");
                exit(0);
        }
 
        data = zeros;
        alarm(1);
 
        while(1){
                data = zeros;
                data = ones;
        }
        return 0;
}
cs
  • 의도한 결과 : 0.0 0.0 혹은 1.0 1.0이 번갈아가면서 출력되는 함수
  • 결과

 

  • 0 0/ 1 1 뿐만 아니라 0 1/ 1 0도 함께 출력되는 것을 볼 수 있음
  • 원인? : alarm(1)에 의하여 handler는 1초에 한 번씩 출력을 하는데 while문이 빠르게 동작하면서 값이 바뀌는 중간에 swiching 되기 때문
  • sigprocmask(2)를 이용하여 의도한 코드를 완성시켜 보자
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
#include<stdio.h>
#include <sys/types.h>
#include <unistd.h>
#include <signal.h>
#include <stdlib.h>
 
struct two_double{
        double a;
        double b;
}data;
 
void signal_handler(int sig){
        printf("%f, %f\n",data.a,data.b);
        alarm(1);
}
 
int main(void){
        struct sigaction sa;
        static struct two_double zeros={0.0,0.0}, ones={1.0,1.0};
        sigset_t block_set, prev_set;
        sigemptyset(&block_set);
        sigaddset(&block_set,SIGALRM);
 
        sigemptyset(&sa.sa_mask);
        sa.sa_flags=0;
        sa.sa_handler = signal_handler;
 
        if(sigaction(SIGALRM,&sa,NULL)==-1){
                perror("sigaction");
                exit(0);
        }
 
        sigprocmask(SIG_BLOCK,&block_set,&prev_set);
        data = zeros;
        alarm(1);
 
        while(1){
                sigprocmask(SIG_SETMASK,&prev_set,NULL);
                sigprocmask(SIG_BLOCK,&block_set,&prev_set);
                data = ones;
                sigprocmask(SIG_SETMASK,&prev_set,NULL);
                sigprocmask(SIG_BLOCK,&block_set,&prev_set);
                data = zeros;
        }
        return 0;
}
cs
  1. procmask에 SIGALRM을 추가하여 alarm의 signal을 막아줌
  2. data를 바꾸기전에 alarm을 block해준 후 모두 바뀌고 이전 값을 set해줌
  3. 이렇게 하면 데이터가 바뀌는 중간에 alarm이 걸리지 않아서 결과가 0 0혹은 1 1이 나오게 됨
  4. 결과

 

+ Recent posts