Signals

▪ A notification to a process that an event has occured.

⇒ S/W interrupts (process가 process에게 interrupt)

⇔ H/W interrupts: CPU가 interrupt를 처리하는 방법은 단순히 interrupt를 요구하는 외부장치의 요구를 처리해주는 program(interrupt handler)의 시작주소를 PC(program counter)에 넣어주면 된다.

ex) pushing enter key, arriving a message 등.

program 수행	interrupt    program 수행 재개

interrupt handler

▪ Signals can be sent from one process to another process

from the kernel   to a process.

▪ Every signal has a name in <signal.h>

p.44 fig.2-4: Unix kernel이 사용하는 signal의 종류.

⇒ process는 특정 signal을 받으면 그에 해당하는 작업을 수행.

- process table(PCB)에 process가 받은 signal이 기록됨.

⇒ 기록된 signal에 따라 action을 취함.

ex)	# kill -2 pid	/* send SIGINT to pid */

# kill -9 pid	/* send SIGKILL to pid */

▪ 한 machine내에서 process들간의 통신 방법.

- signal: 사건(event)이나 오류를 처리.

- pipe: process간에 많은 양의 data를 일방 통행으로 전달. producer process는 write()를 이용하여 data를 보내고, consumer process는 read()를 이용하여 data를 읽어들임.

- FIFO(named pipe): pipe의 결점(parent가 같은 process만 연결, 사용 후 사라짐)들을 보완. 소유자, 크기, 접근허가 등이 지정되어 영구적으로 존재.

- IPC(InterProcess Communication): process간에 양방향의 data 교환.

(chap. 3)

▪ Signal 처리 시나리오

1. keyboard interrupt의 경우

ex)	# cc verybig.c

cntl + c

#

/bin/csh

cc

from terminal

cntl + c

kernel

①keyboard 입력을 담당한 kernel 부분이 H/W interrupt를 감지.

→ kernel은 control terminal group에 모두 SIGINT를 보냄.

SIGINT(= 2)

SIGINT(= 2)

fork()

exec()

②cc process는 signal을 받으면 SIGINT와 관계되는 처리를 하고 종료(terminate)

③shell process는 계속해서 command를 처리해야 하기 때문에 signal을 무시(discarded)

/bin/csh

2. user process 오류처리의 경우

ex)	# badprog

segmentation violation -- core dumped

#	adb debugger에서 사용하는 image file

user proc.

kernel

①비정상적인 명령 수행

②감지

③ SIGKILL(= 9)

④해당 action

→ terminate

3. user process에서 user process로의 통신 경우.

ex)	# cc verybig.c &

2001

# kill -9 2001   /* OR kill 2001 - send SIGTERM(= 15) */

2001 terminated

#

cc

kill

①SIGKILL(= 9)

②해당 action

→ terminate

▪ Who can send a signal to whom? kill()

1. A process can send a signal to another process or to itself using

int kill (int pid, int sig);

to whom	signal 종류

① 특정 process에게 signal을 전달하는 경우: pid를 지정.

- process가 다른 process에 signal을 보내기 위해서는 두 process의 ‘real user ID’와 ‘eff. user ID’가 일치해야 함.

⇒ parent - child 관계

ex) kill(1234, SIGTERM);

- superuser의 process는 어떠한 process에게도 signal을 보낼 수 있음.

⇒ 만약 superuser에 속하지 않은 process가 다른 user에 속하는 procss에게 signal을 보내면 kill()은 실패하여 -1을 return.

② process group에 signal을 보내는 경우

- pid = 0: Signal to all processes in the sender's process group.

⇒ 자신과 같은 process group ID를 가진 모든 process들에게 signal.

- pid = -1 AND the sender ≠ the superuser: Signal to all processes whose the real user ID equals the eff. user ID of the sending process.

㉠ sender의 eff. user ID = real user ID 경우: 같은 user process에게 signal 전달.

㉡ sender의 eff. user ID ≠ real user ID 경우: 다른 user process에게 signal 전달.

Image

Pn

P1

Pm

111 rwxrwxrwx

eff. user ID

real user ID

.....

signal

- pid = -1 AND the sender = the superuser: signal to all processes except the ‘system processes’.

- pid < -1: signal to all processes whose process group ID equals |pid|.

⇒ 같은 user ID를 가진 다른 process group에 signal을 전달.

ex) setpgrp()

- sig = 0: Error checking is done, but no signal is sent.

⇒ Check the validity of the pid.

즉, pid를 가진 process가 존재하는지를 check.

2. The kill command can send signals.

ex) # kill -9 1002	/* SIGKILL to the 1002 process */

3. Certain terminal characters generate signals.

ex)	The interrupt char. (Ctrl+C or Delete)

→ Terminates a running process by generating SIGINT signal.

The quit char. (Ctrl+\)

→ Terminates a running process by generating SIGQUIT signal & generate a core image of the process. (can be used by 'adb' debugger)

The teminal suspend char. (Ctrl+Z)

→ Suspends the terminal immediately by generating SIGTSTP.

etc.

⇒ Teminal generated signals are sent to the running process and all processes in the control group of the terminal.

4. Certain H/W conditions generate signals.

- floating point arithmatic errors generate a SIGFPE.

ex) 3.0/0.0

- referencing an addr. outside a process' addr. generates SIGSEGV.

ex) segmentation violation

→ address 변수값이 영역 밖에 있을 때.

5. Certain S/W conditions generate signals.

ex) socket error generates SIGURG.

→ message의 크기가 너무 클 때.

→ discard.

▪ How a receiving process act with a signal? signal()

1. Ignore a signal.

All signals can be ignored except SIGKILL. (p.83)

ex) signal(SIGUSR1, SIG_IGN);	/* ignore the SIGUSR1 signal */

2. Allow the default to happen. (p.44 fig.2-4)

- default = ignore: SIGURG, SIGCONT, SIGIO, SIGWINCH

- default = stop the process: SIGSTOP, SIGTSTP, SIGTTIN, SIGTTOU

- default = terminated with a core image: 나머지 signal.

ex) signal(SIGUSR1, SIG_DFL);	/* allow the default to happen */

3. Call a specific signal handling function based on the type of signal.

A process can choose its action using

# include <signal.h>

int (*signal (int sig,   void (*func) (int))) (int);

returns the pointer	the addr. of a signal handling func.

to a func. that	that does not return anything (void)

returns an integer.

ex)	변수/함수 pointer

구분	변수 pointer	함수 pointer
변수/함수	int x=3;	int twice(int x){ return 2*x; }
Declare ptr	int *p;	int (*pf) (int); /* int.를 받아 int.를 return 하는 함수의 ptr. */
Define	p=&x;	pf=twice;
Use	*p=3;	pf(3);

x

p

3

twice

pf

ex) synch.c - example for kill()

Parent

signal()

fork()	Child

signal()	# synch

SIGUSR1

pause()	kill()	parent caught signal #1

print signal#1	child caught signal #1

SIGUSR1

kill()	pause()	parent caught signal #2

print signal#1	child caught signal #2

SIGUSR1

pause()	kill()	……

print signal#2	cntl+c

SIGUSR1

kill()	pause()	#

print signal#2

……	……

#include <stdio.h>

#include <unistd.h>

#include <signal.h>

#define NIL    0

void parent(), child();	// signal 처리 functions

int cnt=0;

main(argc,argv)

int argc;

char *argv[];

{

int pid, ppid;

/* set SIGUSR1 action for parent */

signal(SIGUSR1, parent);

switch(pid=fork()){	/* return twice, 0 for child and childpid for parent */

case -1:                  /* if pid=-1, error */

fprintf(stderr,"synch error.....");

exit(1);

case 0:                   /* if pid=0, set action for child */

signal(SIGUSR1, child);

ppid=getppid();

for(;;){

sleep(1);

kill(ppid,SIGUSR1);

pause();

}

default:	/* if pid=childpid, set action for parent */

for(;;){

pause();

sleep(1);

kill(pid,SIGUSR1);

}

}

}

void parent()

{

printf("parent caught signal #%d\n",++cnt);

signal(SIGUSR1,parent);

}

void child()

{

printf("child caught signal #%d\n",++cnt);

signal(SIGUSR1,child);

}

▪ Reliable signals

- The signal facility were "unreliable" in "earlier" Unix. - 초기 Unix의 경우.

⇒ Any occurrence of the "same" signal would be "lost", before the user's signal handler could call signal() again.

⇒ Unix signal은 “누적”되지 않는다. 하나의 process에 대하여 한 순간에는 같은 종류의 signal이 오직 하나만 존재한다. 반면에 여러 종류의 signal은 동시에 존재할 수 있다.

- Blocking a signal: If a signal is generated a second time, while the process is handling its first occurrence, the signal handler is not called again, the second is "remembered".

⇒ If the signal handler returns normally, only then it is called "again" to handle the "remembered" signal.

ex) synch.c의 parent() & child()에서 signal()을 다시 call하지 않아도 됨.

/* signal(SIGUSR1, parent);  */

/* signal(SIGUSR1, child);  */

Process Groups

▪ Process group ID

- process ID, parent process ID, process group ID.

- Every process is a member of a process group.

⇒ signal을 같이 받는 process들의 모임.

- process ID = process group ID   ; A process group leader

PID =1000

pgID=1000

PID=1001

pgID=1000

PID=1002

pgID=1000

PID=1003

pgID=1000

fork()

fork()

fork()

만약 process group leader에게 signal이 가면 그 그룹에 속한 모든 process에게 전달됨.

ex) kill(1000, SIGKILL)

ex) Process group leader가 terminate되면 같은 group의 process들은 모두 terminate됨.

- int getpgrp(int pid);	/* returns the process group ID */

□ return pgID  □ if 0, current process

if not, that process

- int setpgrp(int pid, int pgid);  /* changes its process group ID */

↑          ↑        □ 원하는 group ID.

0 if ok        if 0 : current process

-1 otherwise.   if not : 현 process와 eff. user ID가 같은 process 혹은

현 process = super user process

⇒ setprgp()를 사용하는 이유: signal을 받지 않으려고.

ex) p.83

setpgrp(0, getpid());

⇒ daemon process 생성시 자신이 process group leader가 되어야 함.

⇒ 그렇지 않으면 parent process의 signal을 받게됨.

▪ Terminal group ID and control terminal

- Each process can be a member of a terminal group.

⇒ 같은 terminal을 공유하는 process들의 모임.

ex)

# ps ↲

:

:

□ + □

#

/bin/csh

/bin/csh

ps

fork()

exec()

wait()

SIGINT

SIGINT

ignore

terminate

⇒ 같은 신호를 받더라도 프로세스에

따라 달리 처리함.

control

terminal

process group leader &

control process for a terminal

- Terminal group ID: the process ID of the process group leader that opened the terminal.

⇒ the login shell,  /bin/csh

▪ Socket group ID

- A process group for a open socket.

- socket group ID: A process group for the delivery of SIGIO, SIGURG signals from a socket.

⇔ Terminal group ID: A process group for the delivery of SIGINT, SIGQUIT, SIGHUP, SIGIO, SIGTSTP, SIGCONT, SIGWINCH signals from a terminal.

ex) p.76 fig.2-13

▪ Time_of_day

- Measure the amount of time.

- returns the # of sec.s since 00:00:00 GMT, Jan. 1. 1970.

#include <sys/time.h>

struct timeval {

long tv_sec;	/* sec.s */

long tv_usec;	/* microsec.s */  }

int gettimeofday(struct timeval *tvalptr, struct timezone tzoneptr);

return 0 if ok.	fill in timeval	time zone info.

ex)	# time find / -name csh.1 -print

/usr/share/man/man1/csh.1

real 1:23:31.5	/* the elapsed (real) time - 1/100 sec. 까지 */

user    1:33.2	/* the user CPU time	*/

sys    11:28.2	/* the system call CPU time	*/

ex)	#include <stdio.h>

#include <sys/time.h>

#define LOOP 100

main(argc, argv)

int argc;

int argv;

{

struct timeval tvalptr;

struct timezone tzoneptr;

int i;

gettimeofday(&tvaptr, &tzoneptr);

printf("start_time=%ld %ld\n",tvalptr.tv_sec, tvalptr.tv_usec);

for(i=0; i=LOOP; i++) printf("i=%d\n",i);

gettimeofday(&tvaptr, &tzoneptr);

printf("end_time=%ld %ld\n",tvalptr.tv_sec, tvalptr.tv_usec);

exit(0)

}