UNIX System Programming Ki-Hyun, JUNG Email : kingjung@paran.com
구성 1 장 : 기본적인개념들과기초적인용어들 2 장 : 파일을다루는시스템호출 primitives 3 장 : 파일에대한문맥상의특성 4 장 : 유닉스디렉토리개념 5 장 : 유닉스프로세스의기본적인성질과제어 6 장 : 프로세스간통신 7 장 : 유용한유닉스프로세스간통신기법 8 장 : 시스템 V 에소개된프로세스간통신기법 9 장 : 시스템호출수준에서의단말기 10 장 : 유닉스네트워킹 11 장 : 주요한라이브러리패키지들 (St Standard di/olib Library) 12 장 : 기타시스템호출과라이브러리루틴들 2
시그널 (signal) 시스템에서발생하는임의의사건을프로세스에게전달하는기능을지원 비동기 (Asynchronous) 메시지를이용 3
시그널널발생 예외상황 Divide by 0 키보드입력 SIGINT(CTRL+C), SIGQUIT(CTRL+\), SIGSTP(CTRL+Z) kill() 시스템템콜 임의의프로세스가다른프로세스에게시그널전달을위해 SIGKILL, SIGTERM, SIGUSR1, SIGUSR2 자식프로세스종료 자신의부모프로세스에게 SIGCHLD 시그널전달 4
man signal (1/5) 5
Signal Sg Function cto 예제 (/5) (2/5) 6
man kill (3/5) 7
/usr/include/signal.h / ude/s (4/5) 8
Test (5/5) signal() 시스템콜은유닉스초기버전부터지원단점을보완하여 sigset() 시스템콜많이사용 9
사전 1 : 시그널널전달 프로세스에게시그널을전달하는방법 kill() 시스템콜 #include <sys/types.h> #include <signal.h> int main(void) { printf("before signal : SIGKILL \n"); sleep(5); kill(getpid(), SIGKILL); // exit() printf("after signal : SIGKILL \n"); printf("before signal : SIGUSR1 \n"); sleep(2); kill(getppid(), SIGUSR1); printf("after signal : SIGUSR1 \n"); 테스트방법 1. 그대로수행 2. sleep(5) 시간내에 CTRL+C 3. kill(getpid(), SIGKILL) comment 처리 10
사전 2 : 시그널널처리 기본처리 프로그래머가특별히시그널의처리에관한함수를재정의하지않으면시그널을받은프로세스는시그널별로미리정해진디폴트행동을수행 SIG_DFL 디폴트의의미는시그널마다다르게지정 시그널무시, 프로세스종료, 잠시정지 / 재시작 시그널무시 (SIG_IGN) IGN) 처리함수지정 지정된함수수행후, 프로세스원래작업계속수행 블록킹 (Blocking) 특정코드실행동안시그널인터럽트발생하지않도록 11
사전 3: 시그널널블록킹 관련시스템콜함수 sigemptyset() sigfillset() sigaddset() sigdelset() 시그널에대한블록킹 / 블록킹해제기능을수행하기위해서는 sigprocmask() int sigprocmask(int how, const sigset_t *set, sigset_t *oset); 12
#include <sys/types.h> #include <signal.h> int main(void) { sigset_t t set; sigemptyset(&set); sigaddset(&set, SIGINT); //kill(getpid(), () SIGINT); sigprocmask(sig_block, &set, (sigset_t *)0); printf("enter Critical Section \n"); // Doing Some Important Works //kill(getpid(), SIGINT); sleep(5); printf("leave Critical Section \n"); sleep(5); printf("before SIG_UNBLOCK \n"); sigprocmask(sig_unblock, &set, (sigset_t *)0); kill(getpid(), SIGINT); printf("bye \n"); 13
사전 4 : 시그널널핸들러지정 프로세스가시그널을받으면시그널처리함수인시그널핸들러를수행 디폴트로정의되어있는시그널핸들러 프로세스를종료시키는경우 수신받은시그널을무시하는경우 시그널핸들러변경시스템콜함수 signal() 유닉스초기버전부터지원 핸들러처리완료후, 자동으로 SIG_DFL 로변경 sigset() 해당시그널에대한핸들러의지정이취소되지않고계속유지 14
void (*signal (int sig, void (*disp) (int))) (int); void (*sigset (int sig, void (*disp) (int))) (int); 1. 함수 : 시그널핸들러로사용하고자하는사용자정의함수 2. SIG_IGN 3. SIG_DFL 15
#include <sys/types.h> #include <signal.h> void new_handler(int signo) { printf("signal Handler : %d \n", signo); main() { void (*old_handler) (int); old_handler = sigset(sigint, new_handler); if (old_handler == SIG_ERR) { perror("sigset"); exit(1); printf("before signal\n"); kill(getpid(), SIGINT); printf("after signal\n"); kill(getpid(), SIGINT); sleep(2); sigset(sigint, old_handler); printf("before SIGINT default \n"); kill(getpid(), SIGINT); printf("after SIGINT default \n"); 16
#include <sys/types.h> #include <signal.h> void new_handler(int signo) { printf("signal Handler : %d \n", signo); main() { int i; pid_t ret; void (*old_handler) (int); old_handler = sigset(sigint, new_handler); if (old_handler == SIG_ERR) { perror("sigset"); exit(1); ret = fork(); switch (ret) { case -1: perror("fork"); break; case 0: printf("child start\n"); default: //wait((int *)0); kill(ret, SIGINT); wait((int t *)0); kill(ret, SIGINT); printf("parent end \n"); for (i=0; i<500000; i++) getpid(); sleep(3); printf("child end\n"); exit(0); sleep(2); printf("parent t start\n"); t\ break; 17
사전 5: 핸들러내에서의블록킹 시그널핸들러를지정하면서핸들러수행중에블록킹되어야하는시그널을명시하기위해서는 sigaction() 시스템콜함수사용 18
#include <signal.h> #include <sys/types.h> void new_handler(int signo) { printf("handler : start \n"); //---- blocking sleep(10); printf("handler : end \n"); 테스트 : 여기에서 CTRL+\ main() { struct sigaction action; action.sa_flags = 0; sigemptyset(&action.sa_mask); sigaddset(&action.sa_mask, sa SIGQUIT); action.sa_handler = new_handler; sigaction(sigint, &action, (struct sigaction *)0); //sigaction(sigquit, &action, (struct sigaction *)0); printf("before SIGINT\n"); kill(getpid(), SIGINT); printf("after SIGINT\n"); printf("before SIGQUIT\n"); kill(getpid(), SIGQUIT); printf("after SIGQUIT\n"); 19
사전 6: 알람 (alarm) a 시그널 특정한시간이지난후에자동으로알람시그널이발생하도록하는기능 unsigned int alarm(unsigned int sec); 매개변수로입력되는초단위경과후 SIGALARM 시그널발생 타이머기능취소시 0 으로설정 20
#include <unistd.h> #include <signal.h> #include <sys/types.h> void handler(int signo) { printf("ding!! \n"); main() { sigset_t alarm_mask; sigset(sigalrm, handler); //sigemptyset(&alarm_mask); //sigaddset(&alarm_mask, SIGALRM); sigfillset(&alarm_mask); sigdelset(&alarm_mask, SIGALRM); SIGALRM 만차단 (Blocking) SIGALRM 만통과 alarm(5); printf("now Sleeping... \n"); sigsuspend(&alarm_mask); // wait SIGALRM printf("after signal \n"); 21
책본문내용 22
프로세스간간통신기법 시그널 파이프 FIFO 23
시그널널처리 1. 디폴트행동을취한다 2. 시그널을통째로무시하고수행을계속한다 3. 사용자가정의한지정된행동을취한다 24
시그널널검사및처리 인터럽트인터럽트로부터복귀 시스템호출 or 인터럽트 복귀 사용자수행중 Zombie exit sleep 수면중 ( 메모리내 ) 커널수행중 프로세스재스케줄 wakeup 중단, preempt 수행대기 ( 메모리내 ) 중단됨 preempted Swap out Swap out Swap in 생성 fork 수면 Swapped wakeup 수행대기 Swapped 메모리불충분 (swapping system 인경우 ) 25
시그널 System Call 초기화 : sigemptyset, sigfillset 조작 : sigaddset, sigdelset 시그널널행동지정 : sigaction 프로그램내위치지정 : sigsetjmp 저장된위치로리턴 : siglongjmp 시그널봉쇄 : sigprocmask 다른프로세스에게시그널보내기 : kill 자신에게시그널보내기 : raise, alarm, pause 26
SIGINT SGN 포착 #include <signal.h> main() { static struct sigaction act; void catchint(int); act.sa_handler = catchint; sigfillset(&(act.sa_mask)); sigaction(sigint, &act, NULL); printf("sleep call #1 \n"); printf("sleep call #2 \n"); printf("sleep call #3 \n"); printf("sleep call #4 \n"); printf("exiting... \n"); exit(0); void catchint(int signo) { printf("\ncatchint : signo = %d \n", signo); printf("catchint : returning \n\n"); 27
SIGINT SGN 무시 #include <signal.h> main() { static struct sigaction act; void catchint(int); //act.sa_handler = catchint; act.sa_handler = SIG_IGN; sigfillset(&(act.sa_mask)); sigaction(sigint, &act, NULL); printf("signal ignored from #1 to #4 \n"); printf("sleep call #1 \n"); printf("sleep call #2 \n"); printf("sleep call #3 \n"); printf("sleep call #4 \n"); act.sa_handler = SIG_DFL; sigaction(sigint, &act, NULL); printf("signal interrupt possible from #5 to #8 \n"); printf("sleep call #5 \n"); printf("sleep call #6 \n"); printf("sleep call #7 \n"); printf("sleep call #8 \n"); act.sa_handler = SIG_IGN; sigaction(sigint, &act, NULL); sigaction(sigquit, &act, NULL); printf("signal interrupt possible from #9 to #12 \n"); printf("sleep call #9 \n"); printf("sleep call #10 \n"); printf("sleep call #11 \n"); printf("sleep call #12 \n"); printf("exiting... \n"); exit(0); void catchint(int signo) { printf("\ncatchint : signo = %d \n", signo); printf("catchint : returning \n\n"); 28
이전행동복원 #include <signal.h> main() { static struct sigaction act, oact; void catchint(int); act.sa_handler = catchint; sigfillset(&(act.sa_mask)); sigaction(sigint, &act, NULL); printf("sleep call #1 \n"); printf("sleep call #2 \n"); printf("sleep call #3 \n"); printf("sleep call #4 \n"); sigaction(sigterm, NULL, &oact); printf("retrun to back \n"); act.sa_handler = SIG_IGN; sigaction(sigint, &act, NULL); sigaction(sigterm, &act, NULL); printf("sleep call #5 \n"); printf("sleep call #6 \n"); printf("sleep call #7 \n"); printf("sleep call #8 \n"); sigaction(sigterm, &oact, NULL); printf("exiting... \n"); exit(0); void catchint(int signo) { printf("\ncatchint : signo = %d \n", signo); printf("catchint : returning \n\n"); 29
Graceful Gaceu Exit #include <signal.h> #include <stdio.h> #include <stdlib.h> void g_exit(int s) { unlink("/tmp/tempfile"); fprintf(stderr, "Interrupted.. exiting \n"); exit(1); main() { static struct sigaction act; act.sa_handler = g_exit; sigaction(sigint, &act, NULL); printf("sleep call #1 \n"); printf("sleep call #2 \n"); printf("sleep call #3 \n"); printf("sleep call #4 \n"); printf("exiting iting... \n"); exit(0); 30
sigsetjmp sgsetj p&sgo siglongjmp gj 사용 #include <sys/types.h> #include <signal.h> #include <setjmp.h> #include <stdio.h> sigjmp_buf position; void domenu(void); main() { static struct sigaction act; void goback(int); if (sigsetjmp(position, 1) == 0) { act.sa_handler = goback; sigaction(sigint, &act, NULL); void goback(int s) { fprintf(stderr, "\n Interrupted \n"); siglongjmp(position, 1); void domenu(void) { printf(" In this function, insert action \n"); domenu(); printf("sleep call #1 \n"); printf("sleep p call #2 \n"); printf("sleep call #3 \n"); printf("exiting... \n"); exit(0); 31
sigprocmask sgp 사용 #include <signal.h> main() { sigset_t set1, set2; sigfillset(&set1); sigfillset(&set2); sigdelset(&set2, SIGINT); sigdelset(&set2, SIGQUIT); sigprocmask(sig_setmask, &set1, NULL); printf("this section -- very important \n"); sigprocmask(sig_unblock, &set2, NULL); printf("this section -- important \n"); sigprocmask(sig_unblock, &set1, NULL); 32
kill 사용 #include <unistd.h> #include <signal.h> int ntimes = 0; main() { pid_t pid=0, ppid=0; void p_action(int), c_action(int); static struct sigaction pact, cact; pact.sa_handler = p_action; sigaction(sigusr1, &pact, NULL); switch (pid==fork()) { case -1 : perror("synchro"); exit(1); case 0 : cact.sa_handler = c_action; sigaction(sigusr1, &cact, NULL); ppid = getppid(); for ( ; ; ) { kill(ppid, SIGUSR1); pause(); default : for ( ; ; ) { pause(); kill(pid, SIGUSR1); void p_action(int sig) { printf("parent caught signal #%d \n", ++ntimes); void c_ action(int sig) g){ printf("child caught signal #%d \n", ++ntimes); 33
alarm aa 사용 #include <stdio.h> #include <signal.h> #define TIMEOUT 5 #define MAXTRIES 5 #define LINESIZE 100 #define CTRL_G '\007' #define TRUE 1 #define FALSE 0 static int timed_out; static char answer[linesize]; char* quickreply(char *prompt) { void catch(int); int ntries; static struct sigaction act, oact; act.sa_handler = catch; sigaction(sigalrm, &act, &oact); for (ntries=0; ntries<maxtries; ntries++) { timed_out = FALSE; printf("\n %s > ", prompt); alarm(timeout); gets(answer); sigaction(sigalrm, &oact, NULL); return (ntries == MAXTRIES? ((char*) 0) : answer); void catch(int sig) { timed_out = TRUE; putchar(ctrl_g); main() { char* ret, prompt; ret = quickreply("you"); alarm(0); if (!timed_out) break; 34
pause 사용 #include <stdio.h> #include <stdlib.h> #include <sys/types.h> #include <signal.h> #include <unistd.h> #define TRUE 1 #define FALSE 0 #define BELLS "\007\007\007" int alarm_flag = FALSE; void setflag(int sig) { alarm_flag = TRUE; main(int argc, char** argv) { int nsecs, j; pid_t pid; static struct sigaction act; if (argc <= 2) : fprintf(stderr, "usage : command minutes message \n"); exit(1); if ((nsecs=atoi(argv[1] *60) <= 0)) { fprintf(stderr, "Invalid time \n"); exit(2); switch (pid=fork()) { case -1 : perror("test"); exit(1); case 0 : break; default : printf("process id %d \n", pid); exit(0); act.sa_handler = setflag; sigaction(sigalrm, &act, NULL); alarm(nsecs); pause(); if (alarm_flag == TRUE) { printf(bells); for (j=2; j<argc; j++) printf("%s", argv[j]); printf("\n"); exit(0); 35
분석하기 signal.h 36
문제 1 1에서 MAX까지의소수 (prime) 를계산하여파일에저장하는프로그램작성 ^C키를입력하면 SIGINT를포착하여지금까지계산된소수를출력한파일을닫은후, 종료 여러개의자식프로세스를생성하여수행시키고, 부모프로세스에서이들을종료시킬수있는프로그램작성 자식프로세스는 srand와 rand함수를발생시켜 sleep 수행 단말기로부터입력을받는도중인터럽트신호가포착되면메시지와함께신호번호를출력하는프로그램 자식프로세스를생성하여인수로받은명령어를실행시키고부모프로세스에서 alarm 을설정하여감시하고종료하지않으면 SIGKILL 신호를보내어강제종료시키는프로그램 명령어를실행시키고남은시간출력 37
문제 2 alarm 과 pause 시스템호출을이용하여 sleep 과같은기능을하는프로그램 signal, setjmp, longjmp 사용 무한루프를수행하면서인터럽트신호 (SIGINT) 가수신되면경고음 (bell) 을울리고, SIGQUIT신호가포착되면벨이울린회수를출력하고종료하는프로그램 여러개의파일을라운드로빈 (Round-Robin) 순서로읽는프로그램작성 한파일로부터한줄을읽고, 다음파일로부터한줄을읽음 TIME_OUT 으로주언진시간동안읽을수없으면다음파일을계속읽음 38