반환 값과 에러 상황에 대한 자세한 내용은 man 확인을 권장합니다.
기존 함수
•
ft_printf
•
malloc
•
free
•
write
•
exit
신규 함수
•
getpid
•
sleep
•
usleep
•
pause
•
kill
•
sigemtpyset
•
sigaddset
•
signal
•
sigaction
<unistd.h>
PID 출력
•
getpid 함수는 항상 성공하므로 에러 처리가 불필요하다.
pid_t getpid(void); // 호출 프로세스의 PID 반환
C
복사
스레드 정지
unsigned int sleep(unsigned int seconds); // 설정된 만큼 대기 (초 단위)
int usleep(useconds_t microseconds); // 설정된 만큼 대기 (마이크로초 단위)
int pause(void); // 시그널이 올 때 까지 대기
C
복사
함수 | RETURNS |
sleep(3) | 내부적으로 nanosleep(2)을 입력된 초 만큼 호출하여 대기한다.
0 : 성공
> 0 : 시그널 캐치 후 남은 대기 시간 |
usleep(3) | 내부적으로 nanosleep(2)을 입력된 마이크로 초 만큼 호출하여 대기한다.
0 : 성공
-1 : EINTR(시그널 캐치) |
pause(2) | 시그널이 캐치될 때까지 대기한다.
-1 : EINTR(시그널 캐치) |
<signal.h>
시그널 전송
int kill(pid_t pid, int sig); // 지정된 프로세스로 지정된 시그널 전송
C
복사
•
pid
◦
pid > 0 지정 프로세스로 시그널 전송
◦
pid == 0 호출 프로세스 그룹의 모든 프로세스로 시그널 전송
◦
pid == -1 호출 프로세스 그룹의 모든 프로세스로 시그널 전송 (본인 제외)
◦
pid < -1 지정 프로세스 그룹의 모든 프로세스로 시그널 전송
•
반환값
◦
0 : 성공
◦
-1 : EINVAL (유효하지 않은 시그널)
◦
-1 : EPERM (호출 프로세스에서 목표 프로세스에 시그널을 보낼 권한 없음)
◦
-1 : ESRCH (목표 프로세스 또는 그룹이 존재하지 않음)
시그널 집합 설정
•
반환값
◦
1 : sigismember 함수의 set 멤버가 시그널인 경우
◦
0 : 성공
int sigemptyset(sigset_t *set); // 시그널 집합에서 모든 시그널 제거
int sigaddset(sigset_t *set, int signo); // 시그널 집합에서 특정 시그널 추가
C
복사
시그널 등록
•
signal : 시그널 처리를 결정하는 간단한 함수 (운영체제에 따라 다른 동작)
•
sigaction : 시그널 처리를 결정하는 상세한 함수 (운영체제 차이가 없어 안정적)
#include <signal.h>
typedef void (*sig_t) (int);
void (*signal(int sig, void (*func)(int)))(int);
sig_t signal(int sig, sig_t func);
int sigaction(int sig, \
const struct siaction *restrict act, \ // 새로운 시그널 정보 등록
struct sigaction *restric oact); // 기존의 시그널 정보 백업
C
복사
•
반환값
◦
0 : 성공
◦
-1 : EINVAL
(유효하지 않은 시그널)
◦
-1 : EFAULT (유효하지 않은 메모리 act, oact)
시그널 예시
서버가 잘 동작하는지 kill 과 bc를 활용하여 테스트할 수 있다.
$ kill -l # 시그널 목록 확인
$ kill -USR1 <pid> # SIGUSR1 (10)전달
$ kill -USR2 <pid> # SIGUSR2 (12)전달
Shell
복사
$ man ascii
$ bc <<< "obase=2; 65" # 'A'
1000001
$ bc <<< "obase=10; ibase=2; 1000001"
65
# 문자 'A' 출력
$ kill -USR2 <pid> # 0
$ kill -USR1 <pid> # 1
$ kill -USR2 <pid> # 0
$ kill -USR2 <pid> # 0
$ kill -USR2 <pid> # 0
$ kill -USR2 <pid> # 0
$ kill -USR2 <pid> # 0
$ kill -USR1 <pid> # 1
Shell
복사
signal
#include <stdio.h>
#include <signal.h>
static volatile sig_atomic_t g_signal;
void ft_handler(int sig)
{
g_signal = sig;
}
int main(void) {
// 시그널 호출되었을 때 수행될 시그널 핸들러 등록 (커널에 등록됨)
signal(SIGUSR1, ft_handler);
signal(SIGUSR2, ft_handler);
// 시그널 호출까지 대기
while (1)
{
if (g_signal == 0)
continue ;
printf("pid[%d] signal[%d]\n", NULL, g_signal);
g_signal = 0;
}
return (0);
}
C
복사
sigaction
#include <stdio.h>
#include <signal.h>
static volatile sig_atomic_t g_pid;
static volatile sig_atomic_t g_signal;
void ft_handler(int sig, siginfo_t *info, ucontext_t *uap)
g_pid = info->si_pid;
g_signal = sig;
}
int main(void) {
struct sigaction act;
// 시그널이 호출되었을 때 블록될 시그널 설정
sigemptyset(&act.sa_mask);
sigaddset(&act.sa_mask, SIGUSR1); //block SIGUSR1
sigaddset(&act.sa_mask, SIGUSR2); //block SIGUSR2
// 시그널 처리를 위한 핸들러 설정
act.sa_flags = SA_SIGINFO | SA_RESTART;
act.sa_sigaction = ft_handler; // SA_SIGINFO가 지정된 경우에 사용되는 핸들러
act.sa_handler = NULL; // SA_SIGINFO가 지정되지 않은 경우 사용되는 기본 핸들러
// 시그널 호출되었을 때 수행될 시그널 정보 등록 (커널에 등록됨)
sigaction(SIGUSR1, &act, NULL);
sigaction(SIGUSR2, &act, NULL);
// 시그널 호출까지 대기
while (1)
{
if (g_signal == 0)
continue ;
printf("pid[%d] signal[%d]\n", g_pid, g_signal);
g_signal = 0;
}
return 0;
}
C
복사