1. [UP System] 프로세스 컨텍스트 간의 동기화


semaphore, preempt_disable

semaphore는 CS(Critical Section)를 공유하는 프로세스 컨텍스트들을 휴면 시켜서 동기화를 달성한다. preempt_disable은 CS를 공유하는 프로세스 컨텍스트들은 물론이고 다른 모든 프로세스 컨텍스트들 또한 선점을 금지시켜 동기화를 달성한다. CS 구간이 긴 경우 semaphore를 짧은 경우 preempt_disable을 사용한다.


local_irq_disable을 사용할 수도 있겠지만 인터럽트 컨텍스트가 없기 때문에 불필요하다. 프로세스 컨텍스트는 휴먼 가능 하므로 spin_lock은 사용 불가능하다.



2. [UP System] 프로세스 컨텍스트와 인터럽트 컨텍스트 간의 동기화


local_irq_disable

local_irq_disable은 모든 인터럽트를 금지 시키기 때문에(심지어 타이머 인터럽트에 기반한 스케줄러까지) CS를 공유하는 프로세스 컨텍스트와 인터럽트 컨텍스트 간 동기화를 달성한다.


인터럽트는 스케줄링 대상이 아니므로 semaphore, preempt_disable로는 프로세스 컨텍스트와 동기화를 달성할 수 없다. 또한 semaphore는 휴면 가능하므로 인터럽트 컨텍스트에서는 아예 사용이 불가능하다. 인터럽트 컨텍스트는 항상 프로세스 컨텍스트에 우선 하므로 spin_lock은 사용 불가능하다.



3. [UP System] 인터럽트 컨텍스트 간의 동기화


local_irq_diisable

인터럽트 컨텍스트는 스케줄링 대상이 아니므로 local_irq_disable로 동기화를 달성한다.


인터럽트는 우선순위에 따라 중첩이 가능하므로 spin_lock 사용 불가능하다.


semaphore, preempt_disable는 인터럽트 컨텍스트 간의 동기화에 아무런 역할을 하지 못하며 semaphore는 휴면 가능하므로 인터럽트에서는 아예 사용이 불가능하다.



4. [SMP System] 프로세스 컨텍스트 간의 동기화


spin_lock

프로세스 컨텍스트가 하나의 프로세서에서 유사 동시성을 가짐과 동시에 다수의 프로세서에서 진정한 동시성을 가지게 된다. CS가 다수의 프로세서에 의해 공유 되므로 spin_lock을 사용해야 다수의 프로세서 간에 동기화가 달성 된다.


preempt_disable

preempt_disable 은 특정 프로세서에서의 선점을 금지 한다. 예를 들어 A, B 두 개의 프로세서가 있다. 그리고 CS를  공유하는 1, 2, 3, 4 네 개의 태스크가 있다. 어떠한 원인인지는 몰라도(로드 밸런싱을 포함한 다수의 경우가 있을 수 있음) 태스크 1, 2는 A 프로세서에서 실행되고 있고, 태스크 3, 4는 B 프로세서에서 실행 된다고 가정한다. 프로세서 A의 태스크 1, 2 든 프로세서 B의 태스크 3, 4든 CS 진입 시에 preempt_disable을 호출하면 프로세서 A의 태스크 1, 2 간의 유사 동시성에 의한 동기화가 달성되고 프로세서 B의 태스크 3, 4 간의 유사 동시성에 의한 동기화도 달성 될 것이다. 하지만 이것만으로는 프로세서 간의 진정한 동시성에 의한 동기화는 달성할 수 없으므로 태스크(1, 2)와 (3, 4)간의 동기화는 spin_lock으로 달성 될 것이다.


preempt_disable은 유사 동시성에서의 동기화를 위해서만 사용되는 것이다.

SMP에서 프로세서 컨텍스트 간의 완벽한 동기화를 위해서는 다음과 같은 코드 모양이 될 것이다.


preempt_disable     --> 유사 동시성 동기화

spin_lock               --> 진정한 동시성 동기화

   .....

   CS

   .....

spin_unlock

preempt_enable


이렇게 코드가 작성 된다면 SMP에서 UP로 갈 경우 spin_lock만 걷어내면 될 것이다.



5. [SMP System] 프로세스 컨텍스트와 인터럽트 컨텍스트 간의 동기화


local_irq_disable + spin_lock

local_irq_disable은 로컨 프로세서의 모든 인터럽트를 금지 하므로 유사 동시성에서의 프로세스 컨텍스트 간의 동기화를 달성함과 동시에 프로세스 컨텍스트와 인터럽트 컨텍스트 간의 동기화를 달성할 수 있다. 하지만 인터럽트는 다른 프로세서에 의해 핸들링 될 수 있으므로 반드시 spin_lock을 더해줘야 한다. 이 조합을 하나의 함수로 처리한 것이 spin_lock_irqsave(), spin_lock_irqstore()이다. UP에서와 마찬가지로 유사 동시성에서의 데드락을 방지하기 위해 반드시 인터럽트를 먼저 금지하고 락을 잡아야 한다.


물론 preempt_disalbe을 사용해 프로세스 컨텍스트 간의 동기화를 해결할 수 있겠지만, local_irq_disable이 이를 해결해주므로 사용할 필요가 없다. 또한 semaphore는 휴면 가능하므로 인터럽트 컨텍스트에서는 아예 사용이 불가능하다.


preempt_disable     --> 프로세스 컨텍스트 간의 동기화 (유사 동시성) => 불필요

locak_irq_disable   --> 프로세스 컨텍스트 간의 동기화 + 프로세스 컨텍스트와 인터럽트 컨텍스트 간 동기화(유사 동시성)

spin_lock              --> 진정한 동시성 동기화

   .....

   CS

   .....

spin_unlock

local_irq_enable

preempt_enable



6. [SMP System] 인터럽트 컨텍스트 간의 동기화


local_irq_disable + spinlock

locak_irq_disable은 유사 동시성에서의 동기화를 위해 사용하는 것이며 (단일 프로세서에서의 인터럽트 컨텍스트 간의 동기화), 진정한 동시성에서의 동기화는 spin_lock을 통해 달성 된다. 또한 유사 동시성에서의 데드락을 방지하기 위해 반드시 인터럽트를 먼저 금지하고 락을 잡아야 한다. semaphore, preempt_disable는 인터럽트 컨텍스트 간의 동기화에 아무런 영할을 하지 못하며, semaphore는 휴면 가능하므로 인터럽트 컨텍스트에서는 아예 사용할 수 없다.



spin_lock

spin_lock은 두 개 이상의 프로세서가 실제로 동일한 시간에 같은 CS 구간에 접근할 때만 사용을 한다. 하나의 프로세서만을 사용하는 시스템에서는 시분할에 의한 유사 동시성만을 가지므로 spin_lock이 필요 없다. SMP 시스템에서는 두 개  이상의 프로세서에 의한 진정한  동시성과 하나의 프로세서에 의한 유사 동시성을 가진다. 즉, SMP 시스템에서는 두가지 종류의 동시성을 모드 가지는 것이다. 이때 spin_lock이 의미가 있는 경우는 두 개 이상의 프로세서에 의한 진정한 동시성을 가질때 이다. 그러므로 spin_lock을 생각할 때 SMP냐 UP냐, 선점이냐 비선점이냐를 생각하며 고민할 필요가 없다.



출 처 : http://blog.naver.com/redcultuer?Redirect=Log&logNo=130109621698








리눅스상에서 콘솔을 통해 키를 입력받을때, Return키를 입력받지 않고 키 값에 반응해 실시간(?)으로 처리되는 작업이 필요할때가 있다. 헌데 리눅스에서는 윈도우처럼 getch함수가 존재하지 않기 때문에 이를 따로 구현해줘야 하는데, 아래는 리눅스 상에서 getch() 함수를 구현한 예이다.

  1. #include <stdio.h>  
  2. #include <term.h>  
  3. #include <termios.h>  
  4. #include <unistd.h>  
  5.   
  6. int getch(void)  
  7. {  
  8.   int ch;  
  9.   struct termios buf;  
  10.   struct termios save;  
  11.   
  12.    tcgetattr(0, &save);  
  13.    buf = save;  
  14.    buf.c_lflag &= ~(ICANON|ECHO);  
  15.    buf.c_cc[VMIN] = 1;  
  16.    buf.c_cc[VTIME] = 0;  
  17.    tcsetattr(0, TCSAFLUSH, &buf);  
  18.    ch = getchar();  
  19.    tcsetattr(0, TCSAFLUSH, &save);  
  20.    return ch;  
  21. }  
  22.   
  23. int main(void)  
  24. {  
  25.     int ch;  
  26.   
  27.     for(; !(ch=='\n');){  
  28.   
  29.         ch = getch();  
  30.         printf("%d \n", ch);  
  31.     }  
  32.   
  33.     return 0;  
  34. }  

터미널로부터 리턴키가 입력될때까지 자료를 입력받는 예제

위의 예제를 보다 발전(?)시키기 위해서 좀더 많은 자료가 필요하다면, 아래의 링크를 참조하기 바란다. 터미널을 제어하는 방법에 대한 내용이 자세하게 정리되어 있는 페이지이다.
링크 : http://www.joinc.co.kr/modules/moniwiki/wiki.php/article/termios


◆ 추가로 터미널 입력시 특수문자를 요약한 Table

Figure 18.9. Summary of special terminal input characters

Character

Description

c_ccsubscript

Enabled by

Typical value

POSIX.1

FreeBSD 5.2.1

Linux 2.4.22

Mac OS X 10.3

Solaris 9

   

field

flag

      

CR

carriage return

(can't change)

c_lflag

ICANON

\r

DISCARD

discard output

VDISCARD

c_lflag

IEXTEN

^O

 

DSUSP

delayed suspend (SIGTSTP)

VDSUSP

c_lflag

ISIG

^Y

 

 

EOF

end of file

VEOF

c_lflag

ICANON

^D

EOL

end of line

VEOL

c_lflag

ICANON

 

EOL2

alternate end of line

VEOL2

c_lflag

ICANON

   

ERASE

backspace one character

VERASE

c_lflag

ICANON

^H, ^?

ERASE2

alternate backspace character

VERASE2

c_lflag

ICANON

^H, ^?

 

     

INTR

interrupt signal (SIGINT)

VINTR

c_lflag

ISIG

^?, ^C

KILL

erase line

VKILL

c_lflag

ICANON

^U

LNEXT

literal next

VLNEXT

c_lflag

IEXTEN

^V

 

NL

line feed (newline)

(can't change)

c_lflag

ICANON

\n

QUIT

quit signal (SIGQUIT)

VQUIT

c_lflag

ISIG

^\

REPRINT

reprint all input

VREPRINT

c_lflag

ICANON

^R

 

START

resume output

VSTART

c_iflag

IXON/IXOFF

^Q

STATUS

status request

VSTATUS

c_lflag

ICANON

^T

 

 

 

STOP

stop output

VSTOP

c_iflag

IXON/IXOFF

^S

SUSP

suspend signal (SIGTSTP)

VSUSP

c_lflag

ISIG

^Z

WERASE

backspace one word

VWERASE

c_lflag

ICANON

^W

 

출처 : http://codeidol.com/%5B~MODULE~%5D/advanced-programming-in-unix/Terminal-I-O/-18.3.-Special-Input-Characters/

출처 : kldp

http://kldp.org/node/1725

 

 

참조 : http://www.joinc.co.kr/modules.php?name=News&file=article&sid=24

 

 

다음 과 같은 함수는 대몬화 하는 함수입니다.
int daemon_init(void)
{
pid_t pid;

if ( (pid = fork()) < 0)
return (-1);
else if (pid != 0)
exit(0); /* parent goes bye-bye */

/* child continues */
setsid(); /* become session leader */
chdir("."); /* change working directory */
umask(0); /* clear our file mode creation mask */

return (0);
}

함수가 이해가 안되는것이 아니고 왜 이렇게 하는지를 모르겠내요.
자세한 설명 부탁드릴게요.

 

 

 

 

답변 : xfmulder  님

 

일단 fork()해서 자신은 죽고 CHILD 를 남기는 이유는 init 의 자식이 되기 위해서이지요.
setsid() 함으로써 자신이 기존의 세션과 분리되면 제어 터미널을 잃습니다.
이때 getpgid() 하면 이전의 프로세스 그룹 으로부터도 독립되어 있게 됩니다.
참고로 프로세스와 관련된 id 는 네가지 입니다. pid, ppid, pgid(프로세스그룹), sid(세션ID) (getpid(), getppid() , getpgid() , getsid() 를 찾아보세요 )

세션id를 독립하면 자동으로 프로세스그룹ID(pgid) 도 sid 값으로 바뀝니다.
기존의 프로세스가 kill(0,SIGTERM); 하면 자신의 프로세스 그룹에 15번 시그널을 날리는데 이 데몬은 이미 프로세스그룹에서 독립했으므로 이 시그널 안받습니다. 물론 기존의 제어터미널에서도 독립했습니다.

chdir("/"); 하는건 현재디렉토리를 변경하는것. (자신이 로그를 기록할 적당한 디렉토리로 가도 됩니다. 상대PATH로 파일명 줄수 있음)

umask(0); umask 를 0 으로 했으므로 파일생성 모드 대로 생성됨.
(예를 들면 umask (022) 이면 파일을 rwxrwxrwx 로 생성해도 umask때문에
rwxr-xr-x 로 만들어 지게 됩니다)

[출처] daemon화 하는 펑션|작성자 김정은

+ Recent posts