치춘짱베리굿나이스

[Rank 2] Minitalk - 사용가능 함수 정리 본문

42/42s Cursus

[Rank 2] Minitalk - 사용가능 함수 정리

치춘 2021. 9. 25. 16:10

signal

void (*)(int) signal(int sig, void (*handler)(int));
  • 시그널 처리 방법을 설정한다
  • 몇몇 시그널들은 이미 정의된 행동을 함으로써 처리되는데, 이처럼 기존에 정의된 행동을 그대로 할 지, 시그널을 그냥 무시할지, 아니면 사용자 정의 행동을 하도록 바꿔줄 지 선택할 수 있다
  • sig는 처리해줄 시그널 번호
  • *handler는 시그널을 처리해줄 핸들러SIG_IGN을 인자로 넘겨주면 해당 시그널을 무시한다
  • 함수포인터를 넘겨주면 시그널이 들어왔을 때 특정 함수를 호출한다
  • SIG_DFL을 인자로 넘겨주면 기존에 정의된 방법대로 수행한다

sigset_t 구조체

typedef struct {
        unsigned int __sigbits[4];
} sigset_t;

시그널은 비트로 이루어져 있으며, 시그널 집합은 이러한 시그널을 비트 마스크로 표현해준다

만약 특정 비트값이 1이면 해당 위치에 대한 시그널이 설정되어 있다는 의미이고, 0이면 설정되어 있지 않다는 뜻


sigemptyset

int sigemptyset(sigset_t *set);
  • 인자로 들어온 시그널 세트 (sigset) 를 초기화한다
  • *set은 초기화해 줄 시그널 세트
  • 반환값은 무조건 0이다

sigaddset

int sigaddset(sigset_t *set, int signo);
  • 인자로 들어온 시그널 (signo) 를 시그널 세트 (set) 에 추가한다
  • *set은 값을 넣을 시그널 세트
  • signo는 추가할 시그널 넘버
  • 반환값은 무조건 0이다

sigaction

int sigaction(int sig, const struct sigaction *restrict act, struct sigaction *restrict oact);
  • 인자로 들어온 시그널 (sig)가 호출되었을 때 실행할 행동을 정의한다
  • sig는 행동을 정의해 줄 시그널 종류
  • act는 행동이 정의된 sigaction 타입 구조체
  • oact는 기존의 행동이 정의된 sigaction 타입 구조체

sigaction (구조체)

struct sigaction {
    int sa_flags;
    union {
        void (*sa_handler)();
        void (*sa_sigaction)(int, siginfo_t *, void *);
    };
    sigset_t sa_mask;
}

// man 기준 sigaction 정의
struct sigaction {
    union __sigaction_u __sigaction_u;
    sigset_t sa_mask;
    int sa_flags;
}

union __sigaction_u {
    void (*__sa_handler)(int);
    void (*__sa_sigaction)(int, siginfo_t *, void *);
};

#define sa_handler __sigaction_u.__sa_handler
#define sa_sigaction __sigaction_u.__sa_sigaction
  • sa_flags는 다음과 같은 값이 들어오며, or 연산자를 이용하여 두 개 이상의 값을 한 번에 패러미터로 넘겨줄 수도 있다
    • SA_NOCLDWAIT : 시그널이 SIGCHLD이면 시스템은 자식 프로세스가 종료될 때 좀비 프로세스를 만들지 않는다
    • SA_NOCLDSTOP : 시그널이 SIGCHLD면 시스템은 자식 프로세스가 종료될 때 부모 프로세스에 SIGCHILD를 전달하지 않는다 (자식 프로세스가 SIGSTOP, SIGTSTP, SIGTTIN, SIGTTOU 등으로 인해 중단되어도 부모 프로세스가 이를 알 수 없다)
    • SA_ONESHOT : 시그널의 기본 처리 방법을 시스템 기본 설정인 SIG_DFL로 재설정 후, 시그널이 처리되는 동안 블록하지 않는다
    • SA_ONSTACK : 시그널 스택 (sigaltstack) 에 올라가 있는 프로세스로 시그널을 전달한다
    • SA_RESETHAND : 시그널의 기본 처리 방법을 시스템 기본 설정인 SIG_DFL로 재설정
    • SA_RESTART : 시그널을 받으면 시그널 처리 후 시그널 핸들러에 의해 중지된 기능을 재시작한다
    • SA_NOMASK : 시그널 핸들러가 실행되는 동안 (시그널을 처리하는 중)에는 전달된 시그널이 블록되지 않도록 한다
    • SA_NODEFER : 시그널 핸들러가 실행되는 동안 (시그널을 처리하는 중)에는 전달된 시그널이 블록되지 않도록 한다
    • SA_SIGINFO : sa_handler에 해당하는 함수가 동작하지 않고, sa_sigaction이 동작하며 더 다양한 인수를 받을 수 있다, sa_sigaction이 받는 인자값은 시그널 번호, 시그널이 만들어진 이유, 시그널을 받는 프로세스의 정보이다. SIG_DFLSIG_IGN이 사용될 땐 해당 비트를 사용하면 안 된다
  • sa_handlersigaction() 함수의 인자로 들어온 sig 시그널이 발생했을 때 실행할 함수이며, signal() 함수에서 인자값으로 넣어주는 핸들러 함수가 여기에 들어간다
  • sa_sigactionsa_flagsSA_SIGINFO가 설정되어 있을 때만 호출된다 (SA_SIGINFO가 설정되어 있지 않으면 sa_handler가 호출되고, SA_SIGINFO가 설정되어 있으면 sa_sigaction이 호출됨)
  • sa_mask는 시그널을 처리하는 동안 블록할 시그널 집합의 마스크이며, 시그널 핸들러 동작 중에, 다른 시그널들이 들어와도 블록할 수 있도록 막아준다. 이때 sa_flagsSA_NODEFER를 설정하지 않으면 시그널 핸들러를 호출하게 한 시그널도 블록됨

kill

int kill(pid_t pid, int sig);
  • 무시무시한 이름과는 다르게.. 죽이는 짓은 안하고 시그널만 전달해주는 얌전한 함수
  • pid에 시그널을 받을 프로세스의 id가 들어간다
    • pid가 0보다 클 경우: 해당 pid에 시그널이 보내짐
    • pid가 0일 경우: 시그널을 보낸 프로세스와 같은 그룹에 속한 (그룹아이디가 같은) 모든 프로세스에 시그널이 보내짐
    • pid가 -1일 경우:
      • 유저가 관리자 권한을 가지고 있다면 (Superuser privilege) 시스템 프로세스와 현재 시그널을 전송하려는 프로세스를 제외한 모든 프로세스에 시그널을 전송
      • 유저가 관리자 권한을 가지고 있지 않다면, 해당 유저와 같은 uid를 가진 프로세스에만 현재 시그널을 전송
  • sig에 해당 프로세스에 보낼 시그널이 들어간다sig에 0을 넣을 경우 에러 체킹을 시도하며, pid의 유효성을 검사할 수 있다
  • 이때 인자값으로 들어갈 signal은 sigaction()에 이미 정의되어 있어야 함
  • 정상적으로 kill 함수가 수행되면 0을 리턴, 에러 발생 시에는 -1 리턴 및 errno 세팅됨

exit

void exit(int status);
  • 프로세스를 종료한다 (커널 종료 작업)
  • 커널 종료 작업 시에는 프로세스가 사용하던 메모리 (malloc 되었거나.. 뭐 지역변수나.. static...) 를 모두 해제하고, 파일 디스크립터를 모두 닫는다

malloc

void *malloc(size_t size);
  • 힙 메모리에 size만큼의 메모리를 동적으로 할당하고, 해당 주소값을 반환한다

free

void free(void *ptr);
  • malloc, calloc 등으로 할당한 메모리를 해제한다

sleep

unsigned int sleep(unsigned int seconds);
  • seconds 초만큼 스레드를 일시정지한다 (대기 상태). 만약 sleep 중간에 시그널이 발생하면 바로 복귀 후 남은 시간이 반환된다
  • 만약 15초를 쉬는 중에 (seconds = 15) 5초만에 시그널이 발생하여 복귀하였을 경우, 리턴값은 10

usleep

int usleep(useconds_t microseconds);
  • microseconds 마이크로초만큼 스레드를 일시정지한다 (대기 상태)
  • 나머지는 sleep과 동일

write

ssize_t write(int fd, const void *buf, size_t count);
  • 우리의 오랜 친구.. 출력을 도와주는 write
  • fd는 파일 디스크립터 (문자열을 적을 위치, 0은 표준입력 1은 표준출력)count는 출력할 문자열의 길이
  • *buf는 출력할 문자열의 주소

getpid

pid_t getpid(void);
  • 현재 프로세스의 아이디를 리턴한다현재 프로세스의 부모 프로세스 아이디를 리턴하는 getppid()도 있으나 뭐 여기선 안쓰니까...
  • 아이디는 모든 프로세스가 다 고유한 값을 가지기 때문에 임시 파일명을 지을 때 좋다고 man이 말한다
  • getpidgetppid는 무조건 성공하기 때문에 (프로그램을 구동한다는 건 반드시 개별적인 프로세스가 동작하는 것과 같으니까 애초에 해당 함수를 불러오는 시점에서 프로세스 아이디는 무조건 존재) 실패했을 경우에 반환하는 값은 없다

pause

int pause(void);
  • kill() 함수나 내부 타이머 (setitimer() 참고) 에 의해 시그널을 받기 전까지 현재 스레드를 일시정지시킨다
  • pause()를 통해 스레드가 일시정지된 상태에서 시그널 처리기 (signal handler) 가 멈출 경우 pause()는 리턴값을 뱉는다고 한다
  • 어떤 경우에서든 무조건 -1을 리턴한다

'42 > 42s Cursus' 카테고리의 다른 글

[Rank 2] Minitalk 구현 (Bonus)  (4) 2021.09.25
[Rank 2] Minitalk 구현 (Mandatory)  (0) 2021.09.25
[Rank 2] Minitalk  (0) 2021.09.25
[Rank 3] Philosophers 반성회  (4) 2021.09.13
[Rank 3] Philosophers - 사용가능 함수 정리 [Mandatory]  (0) 2021.09.04
Comments