이미 보류 중인 경우 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_usa_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