이미 보류 중인 경우 Linux 시스템은 신호를 대기열에 넣지 않는다.
이 유형의 신호! 보너스 타임?
실행 파일의 이름은 client
와 server
로 지정해야 한다.
오류를 민감하게 처리해야 한다. 프로그램이 예기치 않게 종료되면 안된다. (세그먼테이션 오류, 버스 오류, 이중 자유 등)
프로그램에 메모리 누수가 있으면 안된다.
하나의 전역 변수를 사용할 수 있지만 이유가 합리적이어야 한다.
Manadatory part에서 다음 함수 및 기능들을 사용할 수 있다.
#include <unistd.h>
ssize_t write(int fildes, const void *buf, size_t nbyte);
파일에 데이터를 출력하는 함수
반환값
ft_printf 과제에서 만든 ft_printf 함수 또는 그와 동일한 기능을 하는 자체 함수
#include <signal.h>
void (*signal(int sig, void (*func)(int)))(int);
시그널(signal)을 받아 해당 함수를 실행시키는 함수
void handler(int signo);
반환값
에러
SIG_ERR
리턴Singal
시그널은 <signal.h> 헤더 파일에 정의되어있고, 시그널에 따른 기본 처리는 프로세스를 종료하거나, 코어 덤프를 생성한다.
No | Name | Default Action | Description |
---|---|---|---|
1 | SIGHUP | terminate process | terminal line hangup |
2 | SIGINT | terminate process | interrupt program |
3 | SIGQUIT | create core image | quit program |
4 | SIGILL | create core image | illegal instruction |
5 | SIGTRAP | create core image | trace trap |
6 | SIGABRT | create core image | abort program (formerly SIGIOT) |
7 | SIGEMT | create core image | emulate instruction executed |
8 | SIGFPE | create core image | floating-point exception |
9 | SIGKILL | terminate process | kill program |
10 | SIGBUS | create core image | bus error |
11 | SIGSEGV | create core image | segmentation violation |
12 | SIGSYS | create core image | non-existent system call invoked |
13 | SIGPIPE | terminate process | write on a pipe with no reader |
14 | SIGALRM | terminate process | real-time timer expired |
15 | SIGTERM | terminate process | software termination signal |
16 | SIGURG | discard signal | urgent condition present on socket |
17 | SIGSTOP | stop process | stop (cannot be caught or ignored) |
18 | SIGTSTP | stop process | stop signal generated from keyboard |
19 | SIGCONT | discard signal | continue after stop |
20 | SIGCHLD | discard signal | child status has changed |
21 | SIGTTIN | stop process | background read attempted from control terminal |
22 | SIGTTOU | stop process | background write attempted to control terminal |
23 | SIGIO | discard signal | I/O is possible on a descriptor (see fcntl(2)) |
24 | SIGXCPU | terminate process | cpu time limit exceeded (see setrlimit(2)) |
25 | SIGXFSZ | terminate process | file size limit exceeded (see setrlimit(2)) |
26 | SIGVTALRM | terminate process | virtual time alarm (see setitimer(2)) |
27 | SIGPROF | terminate process | profiling timer alarm (see setitimer(2)) |
28 | SIGWINCH | discard signal | Window size change |
29 | SIGINFO | discard signal | status request from keyboard |
30 | SIGUSR1 | terminate process | User defined signal 1 |
31 | SIGUSR2 | terminate process | User defined signal 2 |
#include <signal.h>
int sigempty(sigset_t *set);
int sigaddset(sigset_t *set, int signo);
sigempty()
set
: 비우려는 시그널 집합의 주소반환값
sigaddset()
set
: 시그널을 추가하려는 시그널 집합의 주소signo
: 시그널 집합에 추가로 설정하려는 시그널반환값
시그널 집합은 시그널을 비트 마스크로 표현한다. 즉, 시그널 하나가 각 비트 하나를 가리킨다.
각 비트는 특정 시그널과 1:1로 연결되어 있다.
유닉스에서는 시그널 집합의 처리를 위해 sigset_t
라는 구조체를 제공한다
#include <sys/signal.h>
typedef struct {
unsigned int _sigbits[4];
} sigset_t;
#include <signal.h>
// 성공: 0, 실패: -1
int sigaction(int sig, const struct sigaction *restrict act, struct sigaction *restrict oact);
signal()
함수 보다 향상된 기능을 제공하는 시그널 처리를 결정하는 함수
sig
: 시그널 번호act
: 설정한 행동. 즉, 새롭게 지정할 처리 행동oact
: 이전 행동. 즉, 이 함수를 호출하기 전에 지정된 행동 정보반환값
에러
EINVAL
: 부적절한 시그널이 지정되거나, 무시할 수 없는 SIGKILL SIGSTOP
에 대한 액션을 변경하고자 할 경우EFAULT
: act
, oact
, set
, oset
이 타당하지 않은 메모리 영역을 가리킬 경우EINTR
: 시스템 호출이 인터럽트(interrupt) 되었다.signal()
에서는 처리할 행동 정보로 시그널이 발생하면 호출이 될 함수 포인터를 넘겨주었다.
그러나 sigaction()
에서는 sigaction 구조체 값을 사용해 좀 더 다양한 지정이 가능하다.
#include <signal.h>
struct sigaction {
/* signal handler */
union __sigaction_u __sigaction_u;
/* signal mask to apply */
sigset_t sa_mask;
/* see signal options below */
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
__sigaction_u
sa_handler
로 사용되며, sig
에 대한 동작을 나타내는 함수의 포인터로서 사용된다. 설정되지 않으면 기본동작을 의미하는 SIG_DFL
이다.sa_flags
로 SA_SIGINFO
를 사용하면 sa_handler
대신에 sa_sigaction
으로 설정할 수 있다. 신호 처리부(신호를 처리하는 함수)에 두가지 정보를 더 담아 보낸다. siginfo_t
와 프로세스 문맥의 식별자가 그것이다.void sig_handler(int sig, siginfo_t *sip, void *ucp);
sa_mask
: 차단할 신호의 집합이다. sigprocmask
를 통해 특정 신호를 BLOCK 시킬지, 말지를 정한다.sa_flags
: 시그널 처리 프로세스의 행위를 수정하는 일련의 플래그들을 명시한다. 다음 중 하나 이상의 것들에 의해 만들어진다.SA_NOCLDSTOP
: 만약 sig
가 SIGCHLD
라면, 자식 프로세스가 SIGSTOP
, SIGTSTP
, SIGTTIN
, SIGTTOU
등을 받아서 중단되었을 때 이를 통지 받을 수 없게 된다.SA_NOCLDWAIT
: sig
가 SIGCHLD
일 때, 자식 프로세스가 종료되었을 때 시스템이 좀비 프로세스를 만들지 않게 한다.SA_ONSTACK
: sigaltstack
으로 대체 스택을 선언해두었다면 신호가 대안 스택의 프로세스에 전달된다.SA_NODEFER
: 신호가 잡혀서 신호 처리 함수가 실행되는 도중에 다시 같은 신호가 발생됐을때, 시스템이 자동으로 차단하지 않는다.SA_RESETHAND
: 신호 처리 함수에 진입할 때 이 신호의 처리 방식을 SIG_DFL
로 재설정하고 SA_SIGINFO
플래그를 지운다.SA_RESTART
: 시그널 핸들러에 의해 중지된 시스템 호출을 자동적으로 재시작한다.SA_SIGINFO
: 시그널이 발생한 원인을 알 수 있다. SA_SIGINFO
를 지정하면 sigaction
구조체에서 시그널 핸들러를 지정할 때 sa_handler
대신 sa_sigaction
을 사용한다. SA_SIGINFO
플래그를 설정하면 시그널 핸들러는 다음과 같은 인자 세 개를 받는 형태로 정의된다.void handler(int sig, siginfo_t *sip, ucontext_t *ucp);
siginfo_t {
int si_signo; /* 시그널 넘버 */
int si_errno; /* errno 값 */
int si_code; /* 시그널 코드 */
pid_t si_pid; /* 프로세스 ID 보내기 */
uid_t si_uid; /* 프로세스를 전송하는 실제 사용자 ID */
int si_status; /* Exit 값 또는 시그널 */
clock_t si_utime; /* 소모된 사용자 시간 */
clock_t si_stime; /* 소모된 시스템 시간 */
sigval_t si_value; /* 시그널 값 */
int si_int; /* POSIX.1b 시그널 */
void * si_ptr; /* POSIX.1b 시그널 */
void * si_addr; /* 실패를 초래한 메모리 위치 */
int si_band; /* 밴드 이벤트 */
int si_fd; /* 파일 기술자 */
}
#include <signal.h>
int kill(pid_t pid, int sig);
kill
대상 프로세스 ID반환값
에러
EINVAL
: 잘못된 시그널 번호를 지정했을 경우ENOTSOCK
: s가 소켓가 아닌 파일일 경우ENOTCONN
: 소켓이 연결되어 있지 않을 경우ENOBUFS
: 시스템에 연산을 위해 이용할 수 있는 자원 부족kill()
함수는 쉘에서 프로세스를 죽이는 kill 명령과는 달리 프로세스에 시그널을 전송한다. 물론, 프로세스에 SIGKILL
을 보내면 쉘 명령의 kill
과 같은 역할을 할 수도 있다.
특정 프로세스 뿐만 아니라 같은 그룹 ID가 같은 모든 프로세스에게 동시에 시그널을 전송할 수 있으며, 권한 안에 있는 모든 프로세스에게도 시그널을 전송할 수 있다.
pid 값에 따라 다음과 같이 처리된다.
pid | 의미 |
---|---|
양수 | 지정한 프로세스 ID에만 시그널을 전송 |
0 | 함수를 호출하는 프로세스와 같은 그룹에 있는 모든 프로세스에 시그널을 전송 |
-1 | 함수를 호출하는 프로세스가 전송할 수 있는 권한을 가진 모든 프로세스에 시그널을 전송 |
-1 이외의 음수 | 첫 번째 인수 pid 의 절대값 프로세스 그룹에 속하는 모든 프로세스에 시그널을 전송 |
#include <unistd.h>
pid_t getpid(void);
실행중인 프로세스 ID를 구해 반환하는 함수
42seoul 클러스터 맥에서 쉘 스크립트를 이용해 확인한 결과 숫자가 증가하며 pid가 배정된다.
최소 100 에서 최대 99998 사이에서 숫자가 배정되는 것을 확인하였다.
#include <stdlib.h>
void * malloc(size_t size);
void free(void *ptr);
malloc()
반환값
free()
반환값
#include <unistd.h>
int pause(void);
반환값
에러
EINTR
: 시스템 호출이 인터럽트(interrupt) 되었다.#include <unistd.h>
unsigned int sleep(unsigned int seconds);
int usleep(useconds_t microseconds);
sleep()
반환값
usleep()
반환값
#include <stdlib.h>
void exit(int status);
status
는 운영체제에 전달하며 main함수의 return값과 같은 역할이다.status
값은 에러 코드와 같으므로 정상 종료시 0을, 에러로 인한 종료시 0이 아닌 숫자, 대체로 1을 반환한다.참고 자료
https://blockdmask.tistory.com/23
https://m.blog.naver.com/skssim/121268634
https://reakwon.tistory.com/215
https://www.joinc.co.kr/w/man/2/
https://badayak.com/category/%EC%BB%B4%ED%93%A8%ED%84%B0/%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%98%EB%B0%8D
https://blog.naver.com/PostView.nhn?isHttpsRedirect=true&blogId=mokdonjr&logNo=220813555163
https://m.blog.naver.com/PostView.naver?isHttpsRedirect=true&blogId=skssim&logNo=121271980