시그널 적용

EEEFFEE·2023년 11월 19일
0

kdt system-project note

목록 보기
2/15

23.11.19 최초 작성

1. 변경 내용

  • /ui/input.c : 콜 스택을 출력하는 segfault_handler함수를 추가해 segment fault가 발생할 경우 해당 함수를 작동시킴
  • /main.c : child process (system_server, gui, input, web_server)의 중단을 알리는 함수 sigcldHandler를 추가해 자식 프로세스의 종료를 확인함

2. 코드

  • /main.c : main()에 시그널을 등록하는 코드 signal(SIGCHLD, sigcldHandler)를 추가해 자식 프로세스의 종료를 확인함

#include <stdio.h>
#include <sys/wait.h>
#include <signal.h>

#include <system_server.h>
#include <gui.h>
#include <input.h>
#include <web_server.h>
#include <asm-generic/signal-defs.h>

/// sigcldHandler 
static void sigcldHandler(int sig){
    printf("Received signal from child : %d\n", sig);
}

int main()
{
    pid_t spid, gpid, ipid, wpid;
    int status, savedErrno;
	
    /// sigcldHandler assign
    signal(SIGCHLD, sigcldHandler);

    printf("메인 함수입니다.\n");
    printf("시스템 서버를 생성합니다.\n");
    spid = create_system_server();
    printf("웹 서버를 생성합니다.\n");
    wpid = create_web_server();
    printf("입력 프로세스를 생성합니다.\n");
    ipid = create_input();
    printf("GUI를 생성합니다.\n");
    gpid = create_gui();

    waitpid(spid, &status, 0);
    waitpid(gpid, &status, 0);
    waitpid(ipid, &status, 0);
    waitpid(wpid, &status, 0);

    return 0;
}

  • /ui/input.c : input()함수에 sigaction()코드를 작성해 SIGSEGV (segment fault)가 프로세스에 전달되면 콜 스택을 출력하는 함수 segfault_handler()가 작동하도록 함

#include <stdio.h>
#include <sys/prctl.h>
#include <execinfo.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ucontext.h>
#include <unistd.h>

#include <system_server.h>
#include <gui.h>
#include <input.h>
#include <web_server.h>
#include <bits/sigaction.h>


typedef struct _sig_ucontext {
    unsigned long uc_flags;
    struct ucontext *uc_link;
    stack_t uc_stack;
    struct sigcontext uc_mcontext;
    sigset_t uc_sigmask;
} sig_ucontext_t;

/// call stack print
void segfault_handler(int sig_num, siginfo_t * info, void * ucontext) {
  void * array[50];
  void * caller_address;
  char ** messages;
  int size, i;
  sig_ucontext_t * uc;

  uc = (sig_ucontext_t *) ucontext;

  /* Get the address at the time the signal was raised */
  caller_address = (void *) uc->uc_mcontext.rip;  // RIP: x86_64 specific     arm_pc: ARM

  fprintf(stderr, "\n");

  if (sig_num == SIGSEGV)
    printf("signal %d (%s), address is %p from %p\n", sig_num, strsignal(sig_num), info->si_addr,
           (void *) caller_address);
  else
    printf("signal %d (%s)\n", sig_num, strsignal(sig_num));

  size = backtrace(array, 50);
  /* overwrite sigaction with caller's address */
  array[1] = caller_address;
  messages = backtrace_symbols(array, size);

  /* skip first stack frame (points here) */
  for (i = 1; i < size && messages != NULL; ++i) {
    printf("[bt]: (%d) %s\n", i, messages[i]);
  }

  free(messages);

  exit(EXIT_FAILURE);
}


int input()
{
    printf("Enter input process\n");

	///segfault_handler 등록
    struct sigaction siga;

    siga.sa_sigaction = segfault_handler;

    sigaction(SIGSEGV, &siga, NULL);

    while (1) {
        sleep(1);
    }

    return 0;
}

int create_input()
{
    pid_t systemPid;
    const char *name = "input";

    printf("Creating input process\n");

    switch(systemPid = fork()){
        case -1:
            perror("input process create failed \n");
        
        case 0 :
            if (prctl(PR_SET_NAME, (unsigned long) name) < 0)
                perror("prctl()");
            input();
            break;

        default :
            break;
    }

    return 0;
}

0개의 댓글

관련 채용 정보