DiskSim is a low-level storage simulation tool, which can generate timing-accurate simulation result. It is developed by Greg Ganger. Current version is 4.0 and it is out in June 2008.
SSD extension for DiskSim is an extensional module of DiskSim which implments SSD I/O Models. It is implemented by Microsoft Research.

Compiling DiskSim and SSD extension is very simple, but when I tried, there was some problem.
This article addresses those problems.
DiskSim does not compile in 64bit environment. Never try it. Even if you succeded compilation, it will not run -- just produces segmentation fault.


DiskSim requires bison and flex, which are parser generators for parameter file parsing codes.

먼저 위의 링크에서 disksim-4.0-with-dixtrac.tar 파일과 ssd-add-on.zip 파일을 받아야 한다.

sad-add-on.zip파일은 disksim-4.0-with-dixtrac.tar파일을 풀어 생긴 디렉토리(disksim-4.0)에 압축을 풀어야 한다.

그리고 patch는 disksim-4.0디렉토리에서 수행해야 한다.
Step 0. Install bison and flex, if you have not installed already.
$ sudo apt-get install bison flex

Step 1. Download and unzip.
Sources can be downloaded from the links above. I downloaded DiskSim 4.0 with dixtrac.
$ tar xfz disksim-4.0-with-dixtrac.tar.gz
$ cd disksim-4.0
$ unzip ../ssd-add-on.zip

Step 2. Apply SSD add on patch.
$ patch -p1 < ssdmodel/ssd-patch

Step 3. Append SSD model library path to dixtrac.


add these lines to dixtrac/.paths
# path to ssdmodel
export SSDMODEL_PREFIX=../ssdmodel
export SSDMODEL_INCL=$(SSDMODEL_PREFIX)/include
export SSDMODEL_CFLAGS=-I$(SSDMODEL_INCL)
export SSDMODEL_LDPATH=$(SSDMODEL_PREFIX)/lib
export SSDMODEL_LDFLAGS=-L$(SSDMODEL_LDPATH) -lssdmodel
modify dixtrac/Makefile like this :
$(LIBDISKSIM_LDFLAGS) \
$(MEMSMODEL_LDFLAGS) \
$(DISKMODEL_LDFLAGS) \
$(SSDMODEL_LDFLAGS) \
$(LIBPARAM_LDFLAGS) \
$(LIBDDBG_LDFLAGS) \
$(ST_LDFLAGS)

CFLAGS = -Wall -g -MD -I. $(DEFINES) -I$(STHREADS) $(DMINCLUDES) \
$(LIBDISKSIM_CFLAGS) \
$(DISKMODEL_CFLAGS) $(LIBPARAM_CFLAGS) $(LIBDDBG_CFLAGS) \
$(SSDMODEL_CFLAGS)

Step 4. Compile~~~!
$ make

Step 5. Check if it works well.
$ cd valid; ./runvalid
$ chmod a+x ../ssdmodel/valid/runvalid
$ cd ../ssdmodel/valid; ./runvalid

Ok. It is all.


출처 

http://scobyseo.blogspot.kr/2009/12/how-to-compile-disksim-40-ssdsimms-in.html


Posted by cyj4369
,

DiskSim is a low-level storage simulation tool, which can generate timing-accurate simulation result. It is developed by Greg Ganger. Current version is 4.0 and it is out in June 2008.
SSD extension for DiskSim is an extensional module of DiskSim which implments SSD I/O Models. It is implemented by Microsoft Research.

Compiling DiskSim and SSD extension is very simple, but when I tried, there was some problem.
This article addresses those problems.
DiskSim does not compile in 64bit environment. Never try it. Even if you succeded compilation, it will not run -- just produces segmentation fault.

DiskSim requires bison and flex, which are parser generators for parameter file parsing codes.

Step 0. Install bison and flex, if you have not installed already.
$ sudo apt-get install bison flex

Step 1. Download and unzip.
Sources can be downloaded from the links above. I downloaded DiskSim 4.0 with dixtrac.
$ tar xfz disksim-4.0-with-dixtrac.tar.gz
$ cd disksim-4.0
$ unzip ../ssd-add-on.zip

Step 2. Apply SSD add on patch.
$ patch -p1 < ssdmodel/ssd-patch

Step 3. Append SSD model library path to dixtrac.
add these lines to dixtrac/.paths
# path to ssdmodel
export SSDMODEL_PREFIX=../ssdmodel
export SSDMODEL_INCL=$(SSDMODEL_PREFIX)/include
export SSDMODEL_CFLAGS=-I$(SSDMODEL_INCL)
export SSDMODEL_LDPATH=$(SSDMODEL_PREFIX)/lib
export SSDMODEL_LDFLAGS=-L$(SSDMODEL_LDPATH) -lssdmodel
modify dixtrac/Makefile like this :
$(LIBDISKSIM_LDFLAGS) \
$(MEMSMODEL_LDFLAGS) \
$(DISKMODEL_LDFLAGS) \
$(SSDMODEL_LDFLAGS) \
$(LIBPARAM_LDFLAGS) \
$(LIBDDBG_LDFLAGS) \
$(ST_LDFLAGS)

CFLAGS = -Wall -g -MD -I. $(DEFINES) -I$(STHREADS) $(DMINCLUDES) \
$(LIBDISKSIM_CFLAGS) \
$(DISKMODEL_CFLAGS) $(LIBPARAM_CFLAGS) $(LIBDDBG_CFLAGS) \
$(SSDMODEL_CFLAGS)

Step 4. Compile~~~!
$ make

Step 5. Check if it works well.
$ cd valid; ./runvalid
$ chmod a+x ../ssdmodel/valid/runvalid
$ cd ../ssdmodel/valid; ./runvalid

Ok. It is all.


출처 

http://scobyseo.blogspot.kr/2009/12/how-to-compile-disksim-40-ssdsimms-in.html


Posted by cyj4369
,

+++++++++++++++++++++++++++++++++++++++++++++++++++++++ 

1. getconf 명령으로 확인 

- 32비트 커널

# getconf WORD_BIT

32

# getconf LONG_BIT

32

  

- 64비트 커널

# getconf WORD_BIT

32

# getconf LONG_BIT

64 

 

 

2. uname -a 명령으로 확인

- 32비트 커널

# uname -a

Linux localhost 2.6.32-71.el6.i686 #1 SMP Fri Nov 12 04:17:17 GMT 2010 i686 i686 i386 GNU/Linux          --> i386과 같이 32비트임이 표시

 

- 64비트 커널

# uname -a

Linux localhost 2.6.32-71.el6.i686 #1 SMP Fri Nov 12 04:17:17 GMT 2010 i686 i686 i686 GNU/Linux          --> 32비트 여부가 나오지 않음.

 

 

* 참고 : uname -a 의 필드

Linux localhost 2.6.32-71.el6.i686 #1 SMP Fri Nov 12 04:17:17 GMT 2010 i686 i686 i386 GNU/Linux

<Kernel Name> <nodename> <Kernel release> <Kernel version> <Machine Name> <Processor> <Hardware Platform> <Operating System>

Hardware Platform 으로 확인한다는 말씀. 

즉, uname -i 명령어로 확인하여도 된다.

 

 

 

3. /proc/cpuinfo   정보로 확인

# cat /proc/cpuinfo

processor       : 0
vendor_id       : GenuineIntel
cpu family      : 6
model           : 23
model name      : Intel(R) Core(TM)2 Quad CPU    Q8400  @ 2.66GHz
stepping        : 10
cpu MHz         : 2666.644
cache size      : 6144 KB
fdiv_bug        : no
hlt_bug         : no
f00f_bug        : no
coma_bug        : no
fpu             : yes
fpu_exception   : yes
cpuid level     : 5
wp              : yes

flags           : fpu vme de pse tsc msr pae mce cx8 apic sep mtrr pge mca cmov pat pse36 clflush dts acpi mmx fxsr sse sse2 ss ht tm pbe nx lm constant_tsc pni monitor ds_cpl vmx est tm2 ssse3 cx16 xtpr lahf_lm
bogomips        : 5333.28
clflush size    : 64
cache_alignment : 64
address sizes   : 36 bits physical, 48 bits virtual
power management:

 

--> flag 정보에서  lm 의 의미는 Long mode cpu - 64 bit CPU.

      32비트 시스템에서는 lm  플래그가 나오지 않는다.

 

 

* 32비트 시스템에서의 flag :

flags           : fpu vme de pse tsc msr pae mce cx8 apic mtrr pge mca cmov pat pse36 clflush mmx fxsr sse sse2 constant_tsc up pni monitor ssse3


'Embedded Lab > linux, x86' 카테고리의 다른 글

[DiskSim4.0 + SSDSim(MS)설치 방법]  (0) 2012.12.26
[DiskSim4.0 + SSDSim(MS)설치 방법]  (0) 2012.12.26
[커널 컴파일 및 설치방법]  (0) 2012.12.23
[커널 컴파일]  (0) 2012.12.20
[라즈베리 파이 포팅 문제기록]  (0) 2012.12.17
Posted by cyj4369
,
커널 컴파일을 위한 패키지 설치
Code:
sudo apt-get install build-essential bin86 kernel-package libqt3-headers libqt3-mt-dev wget libncurses5 libncurses5-dev

위에서 libqt3-headers libqt3-mt-dev 는 make xconfig 를 위한 건데... 현재 8.10 이면 qt4도 필요할수 있습니다. 전 우분투는 그놈인지라 qt용 xconfig 비추입니다.
따라서 menuconfig를 이용하실분은 그냥 

Code:
sudo apt-get install build-essential bin86 kernel-package wget libncurses5 libncurses5-dev
만 설치하셔도 됩니다.



Posted by cyj4369
,

커널 이미지를 만들어 커널 버전은 최신으로 유지하자.

커널 소스는 모듈 프로그래밍이나 드라이버 설치 다양한 작업에서 필요로 하기 때문에 설치하는것이 좋다.

기본적으로 작업은 root 계정에서 이루어 진다.



(1) 커널 소스 / 패키지 다운로드

: 커널 컴파일에 앞서 커널 소스와 필요한 패키지들을 설치한다.


커널 소스

: # apt-get install linux-source


 패키지

: # apt-get install build-essential

  # apt-get install bin86

  # apt-get install kernel-pakage

  # apt-get install libncurses5-dev (menuconfig를 위한 패키지)



(2) 커널 소스 설치

: /usr/src/linux-source-x.x.x 경로로 가면 다운받은 묶여있는 커널소스(linux-source-x.x.x.tar.bz2) 확인할 있다


  (ex) linux-source-3.0.0.tar.bz2


소스 설치

: /usr/src/ 경로에 linux-source-x.x.x.tar.bz2 링크 파일을 압축해제하면, /linux-source-x.x.x/ 폴더에 소스파일이 설치된다.

 # tar jxvf linux-source-x.x.x.tar.bz2

- 설치가 끝나면 linux-source-x.x.x 디렉토리에서 커널소스를 확인할 있다.



(3) 커널 환경설정

: 커널 컴파일 전에 커널 환경설정을 현재 사용하고 있는 커널의 환경설정과 동일하게 만들어줘야 한다.


환경 설정파일 복사

- /boot 경로의 파일들은 부트로더에서 사용한다.

- /boot 경로에서 configuration 파일을 확인할 있다. (ex) config-3.0.0-12-generic

- configuration 파일을 /usr/src/linux-source-x.x.x/linux-source-x.x.x/.config 복사한다.


  # cp /boot/config-3.0.0-12-generic /usr/src/linux-source-3.0.0/linux-source-3.0.0/.config


환경 설정파일 적용

- 이전에 컴파일했던 기록이 있으면 make mrproper 명령으로 의존성을 삭제한다. ( 컴파일이면 안해줘도 된다.)

- 커널소스 디렉토리에서 make menuconfig 명령 실행(root 권한)

- 설정 창의 밑에 Load하는 부분을 클릭하고 복사한 .config 파일을 선택하여 커널 컴파일시 적용 되도록 한다.

- 설정 창에서 저장하고 나온다.



(4) 커널 컴파일

: 컴파일을 위한 소스파일 설치 / 설정파일 적용 단계를 정상적으로 마쳤다면 커널 컴파일을 실행한다.


clean / compile (make-kpkg 컴파일할 경우)

  # make-kpkg clean (처음 컴파일시 생략가능)

  # make-kpkg --initrd --revision=love01 kernel_image modules_image kernel_headers


clean / compile (make 컴파일할 경우)

  # make distclean (처음 컴파일시 생략가능)

  # make -j8  ( -j 옵션을 사용해 cpu 사용률을 높여 빠른 시간에 컴파일을 진행할 있다.)


make -j 옵션 관련 포스팅 자료 (컴파일 속도 최적화)



make의 -j 옵션은 한번에 수행할수 있는 명령(Job)을 지정하는 패럴렐옵션입니다.
예를 들어, CPU코어가 4개이라면, 한번에 수행할수 있는 명령을 -j 4으로 지정하여 
프로세스가 4개가 생성되어 병령으로 수행합니다. 명령수는 프로세스수로 정의됩니다.

이렇게 하여 소스를 컴파일시 4개 CPU의 Utilization을 최대한 모두 소모하는 것을
top명령(실행후 숫자1번 키누르세요.)으로 확인할 수 있습니다. 고가CPU 본전 뽑아야겠습니다.

필자의 실험에서는 Intel Core2 Quad 9400(2.5Ghz) 컴퓨터에서 위의 명령을 시험하였습니다. 
2.6.31커널소스를 컴파일한 결과,
평균적으로 "make -j 4"가 "make" 명령보다 2배정도 속도가 빨랐습니다.

커널개발자는 소스를 컴파일할때  make를 애용합니다.
멀티코어에서는 컴파일 속도를 위해서 "-j"옵션을 이용하여 
해당 갯수만큼의 프로세스들을 생성하고, 
프로세스들은 다시 필요에 따라 N개의 쓰레드를 생성하여 컴파일을 병렬로 수행합니다.

make개발자에 의하면 총코어갯수에서 20%의 코어갯수를 추가하는 것이 가장 속도가 좋게
작업되었다고 합니다. 따라서,   -j <숫자> = 총CPU갯수 + round( 총CPU갯수*20%) 입니다.
풀이하면, CPU가 4개이면 20%가 코어 0.8개가 되므로,
반올림해서 4+1 => -j 5가 가장 이상적인 컴파일 속도 결과가 됩니다.

그래서, 일반적으로 커널소스 컴파일시에는
간단히 #> make -j `cat /proc/cpuinfo | grep cores | wc -l ` bzImage 하는 것이 올바릅니다.

최상의 속도를 위해서는 필자처럼 아래와 같이 스크립트를 작성할수 있습니다.
invain#> vi buildsource.sh
 #!/bin/bash
# created by invain for the best performance when compiling kernel source.
realnum=`cat /proc/cpuinfo | grep cores | wc -l `
let bestnum=$realnum+$(printf %.0f `echo "$realnum*0.2"|bc`)
make -j `echo $bestnum` bzImage


아래는 코어4개(쿼드 코어)에서 안드로이드 1.6 전체소스를 컴파일시의 소요 시간 결과입니다.
 -j4   : 19분 10초
 -j5   : 18분 52초 <--- 소스 컴파일 속도가 가장 좋음.
 -j8   : 19분 15초
 -j64 :  19분 54초

Posted by cyj4369
,

라즈베리 파이 포팅시 발생하는 문제 기록


1) win32diskimager로 SD카드에 img파일을 풀 때 아래와 같은 에러가 날 경우가 있다.

An error occurred when attempting to get a handle on the file. error 123


해결 : 이미지 파일 경로에 영어가 아닌 다른 언어가 있는 경우에 발생할 수 있는 에러이므로 한글이 있는지 점검해본다.

'Embedded Lab > linux, x86' 카테고리의 다른 글

[커널 컴파일 및 설치방법]  (0) 2012.12.23
[커널 컴파일]  (0) 2012.12.20
[부모프로세스와 자식 프로세스의 상속]  (0) 2012.12.14
[시그널(signal)이란?]  (0) 2012.12.13
[우분투 NAS 마운트 설정]  (0) 2012.12.11
Posted by cyj4369
,

fork는 이함수를 호출한 그로세스와 같은 프로세스를 만든다. 따라서 새로 만들어진 자식 프로세스는 부모 프로세스에게 다음 특징을 상속 받는다.

 

- 부모 프로세스의 실제 사용자 ID, 셀제 그룹 ID, 유효 사용자 ID 그리고 유효 그룹ID
- 부모 프로세스의 set-user-id, set-group-id 모드 비트
- 부모프로세스의 보조 그룹 ID 목록
- 부모 프로세스의 저장된 사용자 ID와 저장된 그룹 ID
- 부모 프로세스의 모든 환경변수와 부모 프로세스가 열고 있는 모든 파일 디스크립너 그리고 파일 오프셋
- 부모 프로세스가 파일 디스크립터에 설정안 close-on-exec 플래그
- 부모 프로세스의 파일 모드 생성 마스크(umask)
- 부모 프로세스가 설정한 신호 처리 방법(SIG_DFL, SIG_IGN, SIG_HOLD또는 신호 처리 함수 주소값)
- 부모 프로세스의 세션 ID와 프로세스 그룹 ID
- 부모 프로세서의 제어 터미널
- 부모 프로세스의 nice값
- 부모 프로세스의 현재 작업디렉토리
- 부모 프로세스의 자원 제한값


자식 프로세스와 부모 프로세스와의 다른점

- 자식 프로세스에는 자신만의 유일한 프로세스 ID가 있다.
- 자식 프로세스에는 자신만의 부모 프로세스 ID가 있다.
- 자식 프로세스에는 부모 프로세스가 열고 있는 파일 디스크립터에 대한 자신만의 복사본이 있다.
  따라서 복사본 파일 디스크립터를 닫는다 해도 부모 프로세스에게 아무런 영향을 미치지 않는다.
  그러나 부모와 자식 프로세스가 각 파일 디스크립터의 오프셋값을 공유하기 때문에 한 파일에 동시에

  쓰려고 한다면 결과가 섞일수도 있다.

  또한 한 파일에서 동시에 읽으려고 한다면 데이터를 일부만 읽게 될수도 있다.
- 자식 프로세스는 부모 프로세스가 만든 파일 잠금은 상속 받지 않는다.
- 자식 프로세스의 대기 시놓 집합은 빈 집합으로 초기화된다.

Posted by cyj4369
,

POSIX 시그널 원리
1. 시그널의 개념
시그널은 소프트웨어 인터럽트로써 프로세스간의 비동기적인 이벤트를
발생시키는 방법을 제공한다. 프로세스를 멈추게 하기 위해 사용자가
터미널에서 누르는 인터럽트 키도 시그널을 이용하는 예에 속한다.
시그널은 유닉스의 초기 버전부터 제공되었으나 몇 가지 문제점이 있었다.

시그널을 발생시켰으나 수신 프로세스에게 전달되지 않을 수도 있었으며
임계 코드(critical code)를 실행 중일 때 시그널을 선택적으로 차단시킬
수도 없었다. 그래서 4.3BSD와 SVR3는 기존의 시그널 방식에 변형을
가하였으나 서로 간의 호환성이 고려되지 않았다.
다행히 POSIX.1에서 제시한 표준안이 있으므로 이 표준을 기준으로
설명하기로 한다.

1.1 시그널 이름
모든 시그널은 이름이 있으며 'SIG'로 시작한다. 예를 들어 SIGINT는
Control-C를 누르면 발생되는 시그널이며 SIGABRT는 abort 함수를 호출할
때 발생하는 시그널이다. 이러한 이름들은 모두 <signal.h>에 양의 정수
값으로 정의되어 있다. 시그널 값으로써 0은 널(null)시그널이라 하며
kill 함수에서 특별한 의미로 쓰인다.
여러 가지 시그널들이 <표 1>에 나타나 있다.

1.2 시그널 발생(generation)과 전달(delivery)
시그널을 일으키는 이벤트가 처음으로 일어나면 시그널이 "발생"
하였다고 한다. 시그널을 일으키는 조건은 다양하다.

* 사용자가 특정 키를 누를 때 터미널에 의해 발생되는 시그널이 있다.
DELETE(또는 Control-C)를 누르면 인터럽트 시그널(SIGINT)이 발생된다.
이것은 폭주해 버린 프로그램을 종료시킬 수 있도록 해 준다.

* 하드웨어에 의해 시그널이 발생될 수 있다.
0으로 나누거나(divide by zero) 잘못된 메모리 참조 등을 한
프로세스는 커널에 의해 발생되는 시그널을 받게 된다. 예를 들어
허용되지 않는 메모리 참조를 하는 경우 SIGSEGV 시그널을 받게 된다.

* kill 함수.
kill 함수는 특정 프로세스 또는 특정 프로세스 그룹내의 모든
프로세스에게 원하는 시그널을 전달할 수 있도록 한다. 물론 이 때 대상
프로세스는 자신이 소유하고 있는 프로세스이거나 자신이
수퍼 유저이어야 한다.

* kill 명령.
kill 명령은 쉘에서 자유롭게 시그널을 발생시키는 방법을 제공한다.
kill 명령은 kill 함수에 대한 인터페이스일 뿐이나 폭주해 버린
프로세스를 종료시키는 유용한 명령이다.

* 소프트웨어 컨디션.
alarm을 설정해 놓았을 때 발생하는 SIGALRM 또는 파이프를 이용한
통신에서 수신 프로세스가 종료했을 때 송신 프로세스가 파이프에
write하면 발생하는 SIGPIPE가 대표적인 예이다.

모든 프로세스는 각각의 시그널에 대해 취해져야 할 조치,다른 말로 액션
(action)을 가지게 되는데 시그널이 발생하여 액션이 실행되는 것을
시그널이 전달(deliver)되었다고 한다. 그리고 시그널의 발생과 전달 사이의
시간 동안은 시그널이 지연되고 있다(pending)고 한다. 보통 이러한 시간
간격은 응용 프로그램에 의해 감지될 수 없다. 그러나 시그널은 블럭될
수 있다. 그래서 만약 블럭된 시그널에 대한 액션이 시그널을 무시(ignore)
하는 것이 아니라면, 그 시그널이 발생하더라도 블럭이 해제되거나 액션이
무시하는 방법으로 변경될 때까지 계속 지연된 상태로 남아 있게 된다.

그리고 만약 블럭된 시그널에 대한 액션이 무시(ignore)하는 것이라면
시그널이 일어나자마자 사라져 버릴 수도 있고 지연된 상태로 남아 있을
수도 있다.이것은 시스템에 따라 다를 수 있다.모든 프로세스는 시그널
마스크(signal mask)를 가지는데 시그널 마스크는 현재 프로세스에게
전달되지 못하도록 블럭된 시그널들의 집합을 정한다.
이 후에 설명할 sigaction(), sigprocmask(), sigsuspend()는
시그널 마스크를 조작하는 기능을 제공한다.

1.3 signal 함수

┌─────────────────────────────────┐
│#include <signal.h> │
│ │
│void (*signal(int signo, void (*func)(int)))(int); │
│ │
│ return 값 : 시그널의 이전 액션(처리 방법) │
└─────────────────────────────────┘

인자 signo는 앞에서 기술한 시그널의 이름이다. func 값은 SIG_IGN,
SIG_DFL 또는 시그널이 발생했을 때 호출될 함수의 주소가 될 수 있다.

* SIG_IGN - 단순히 시그널을 무시한다.
* SIG_DFL - 디폴트 처리에 맡긴다.
* 사용자 정의 함수 - 시그널이 발생했을 때 호출될 함수의 주소를
지정할 수 있다.

이 경우 시그널을 catch 한다고 하며, 이함수는 시그널 핸들러
(signal handler) 또는 시그널 포착 함수(signal catching function)라고
부른다.

signal 함수의 프로토 타입을 보면 이 함수가 두 개의 인자를 필요로
하며 void 리턴 타입의 함수에 대한 포인터를 리턴함을 알 수 있다.
첫 번째 인자 signo는 정수형이며, 두 번째 인자는 하나의 정수형 인자를
갖고 리턴 값이 없는 함수에 대한 포인터이다. 그리고 signal 함수에 의해
그 주소가 리턴되는 함수는 하나의 정수형 인자를 갖는 함수이다.
signal 함수 호출에 의해 리턴되는 값은 그 시그널에 대한 이전 시그널
핸들러의 주소가 된다.

다음 예제 프로그램은 인터럽트 시그널(SIGINT)과 사용자 정의
시그널 1(SIGUSR1)을 포착(catch)하는 간단한 시그널 핸들러에 대한
예이다. 여기서 쓰인 pause 함수는 시그널이 도착할 때까지 프로세스를
수면 상태에 들도록 한다.

┌─────────────────────────────────┐
│리스트 1 PS_Number.c │
├─────────────────────────────────┤
│#include <unistd.h> │
│#include <stdio.h> │
│#include <signal.h> │
│ │
│static void │
│sig_handler(int signo) │
│{ if (signo == SIGINT) │
│ printf("INT signal received\n"); │
│ else if (signo == SIGUSR1) │
│ printf("SIGUSR1 signal received\n"); │
│ else │
│ printf("?? signal no = %d\n", signo); │
│ return; │
│} │
│ │
│int main(void) │
│{ if (signal(SIGINT, sig_handler) == SIG_ERR) │
│ fprintf(stderr, "can't catch SIGINT"); │
│ if (signal(SIGUSR1, sig_handler) == SIG_ERR) │
│ fprintf(stderr, "can't catch SIGUSR1"); │
│ │
│ for( ; ; ) │
│ pause(); │
│} │
└─────────────────────────────────┘

유닉스 명령 중 kill은 프로세스에게 시그널을 전달하는데 쓰인다. 예를
들어 kill -INT 131은 프로세스 ID가 131인 프로세스에게 인터럽트 시그널
(SIGINT)을 발생시킨다.

# a.out &
[1] 131
# PS
# kill -INT 131 a.out
# INT signal received

# kill -USR1 131
# SIGUSR1 signal received

# kill -9 131
[1]+ Killed a.out


------------------------------------------------------------------------------
[2] 제목 : [연재] <2> 유닉스 프로세스 구조-시그널
1.4 프로그램 기동(start-up)
프로그램이 exec되면 모든 시그널 상태는 디폴트 또는 ignore 상태로
설정된다. 특별히 exec을 호출하는 프로세스가 특정 시그널을 무시 하지
않는 이상 보통 모든 시그널은 디폴트 상태로 셋트된다. 만약 exec을 호출
하는 프로세스가 시그널 핸들러를 설정하고 있었다면 exec 호출에 의해
이 시그널의 상태는 디폴트로 복귀된다. (exec을 호출하면 이전 프로세스는
새로운 프로세스에 의해 완전히 대체되므로 이전 프로세스 내의 시그널
핸들러는 새로운 프로세스에 있어서 아무런 의미가 없다는 점을 생각하면
당연한 일이다.)

우리가 일상적으로 자주 마주치게 되는 예로써 쉘이 인터럽트 시그널이나
중단(quit) 시그널을 처리하는 방식에 대해 생각해 볼 수 있다. 작업 제어
기능이 없는 쉘의 경우, 만약 다음과 같이 프로세스를 후위로 수행시키면

cc signal.c &

쉘은 인터럽트/중단 시그널에 대한 처리를 무시하도록 자동적으로
설정한다. 이것은 사용자가 인터럽트 키를 누르더라도 후위 프로세스에게
영향을 미치지 않도록 하기 위한 것이다. 많은 상응식(interactive)
프로그램은 다음과 같이 이 두 시그널에 대해 처리한다.

int sig_int(), sig_quit();

if (signal(SIGINT, SIG_IGN) != SIG_IGN)
signal(SIGINT, sig_int);
if (signal(SIGQUIT, SIG_IGN) != SIG_IGN)
signal(SIGQUIT, sig_quit);

이런 식으로 구성함으로써 현재 무시되고 있지 않은 시그널만을
핸들한다.

1.5 프로세스 생성
프로세스가 fork를 호출하면 자식 프로세스는 부모 프로세스의 시그널
처리를 그대로 상속받게 된다. exec과 달리 fork는 부모 프로세스의 메모리
이미지를 복사해 주기 때문에 부모 프로세스 내의 시그널 핸들러는 자식
프로세스에게 있어서도 여전히 의미가 있다.

2. 시그널의 처리 : 액션(actions)
시그널은 비동기적인 이벤트이므로 언제 발생할지 예상할 수 없다.
따라서 시그널을 처리하고자 하는 프로세스는 시그널이 발생했을 때
수행해야 할 부분을 마련하여 커널에 알려야 한다.시그널 처리
(disposition 또는 action)에 있어서 다음 세 가지 방법이 가능하다.

2.1 시그널을 무시한다.(SIG_IGN)
SIGKILL과 SIGSTOP을 제외한 모든 시그널은 단순히 무시하도록 설정할
수 있다. 그러나 SIGKILL과 SIGSTOP은 무시할 수 없는데 이것은
수퍼 유저가 프로세스를 종료시킬 수 있는 확실한 방법이 된다.

아직 프로세스에게 전달되지 않은 지연된 시그널에 대한 액션을
SIG_IGN로 셋트하는 경우 그 시그널에 대한 디폴트 액션이 무시하는
것이면(예를 들어 SIGCHLD), 시그널이 블럭된 상태인지에 상관없이
시그널이 제거된다.

2.2 시그널을 받아들인다(catch).
그러기 위해서는 시그널이 일어나면 실행될 함수를 작성하여 커널에
등록해야 한다. 예를 들어 자식 프로세스가 종료하면 SIGCHLD 시그널이
발생하는데 부모 프로세스는 SIGCHLD 시그널이 전달되었을 때 수행해야
할 일(waitpid 함수를 이용하여 종료된 자식 프로세스의 종료 상태를
검사하는 일)을 함수로 만들어 커널에 등록함으로써 시그널을
처리할 수 있다.
특히, 이 때 시그널을 처리하는 함수를 시그널 핸들러(handler)라고
한다.SIGKILL과 SIGSTOP 시그널에 대해서는 시그널 핸들러를 둘 수 없다.

2.3 디폴트 처리에 맡길 수 있다.(SIG_DFL)
시그널에 대해 특별한 처리(위의 1, 2번)를 하지 않으면 미리 정해진
디폴트 루틴이 실행된다. 모든 시그널에는 디폴트 처리방법이 정해져
있다. (<표 1>을 참조) 대부분의 시그널에 대해 디폴트 처리는
프로세스를 종료시키는 것임에 유의하여야 한다.

만약 디폴트 액션이 프로세스를 정지시키는 것이라면, 프로세스의 수행은
일시적으로 보류된다. 프로세스가 정지하면, 그 부모 프로세스에게
SIGCHLD 시그널이 발생된다. (부모 프로세스가 SA_NOCLDSTOP 플래그를
셋트하고 있지 않다면) 프로세스가 정지하고 있는 동안은 SIGKILL 시그널을
제외한 모든 시그널이 전달되지 않는다. 프로세스가 고아 프로세스
그룹에 속하는 경우 SIGTTIN, SIGTTOU, SIGTSTP 시그널에 대한 액션으로
중단되지는 않는다.


이 름 설 명 ANSI C POSIX.1 SVR4 4.3+BSD 디폴트 처리
SIGABRT 비정상적 종료(abort)
SIGALRM 시간 초과(alarm)
SIGBUS 하드웨어 결함
SIGCHLD 자식 프로세스 상태의 변화
SIGCONT 중단된 프로세스의 수행 재개
SIGEMT 하드웨어 결함
SIGFPE arithmetic exception
SIGHUP hangup
SIGILL 불법적 하드웨어 명령
SIGINFO 키보드로부터의 상태 요청
SIGINT 터미널 인터럽트 문자
SIGIO 비동기적 입출력
SIGIOT 하드웨어 결함
SIGKILL 종료
SIGPIPE 수신자 없는 파이트에 쓰기 시도
SIGPOLL 폴(poll)할 수 있는 이벤트
SIGPROF profiling 타임 알람(setitimer)
SIGPWR 정전/재시작
SIGQUIT 터미널 중단 문자
SIGSEGV 잘못된 메모리 참조
SIGSTOP 정지
SIGSYS 잘못된 시스템 호출
SIGTERM 종료
SIGTRAP 하드웨어 결함
SIGTSTP 터미널 정지 문자
SIGTTIN 제어 터미널에 대한 후위에서의 읽기
SIGTTOU 제어 터미널에 대한 후위에서의 쓰기
SIGURG 급박한 상태
SIGUSR1 사용자 정의 시그널
SIGUSR2 사용자 정의 시그널
SIGVTALRM 가상 타임 알람(setitimer)
SIGWINCH 터미널 윈도우 크기의 변경
SIGXCPU CPU 한계의 초과(setrlimit)
SIGXFSZ 파일 크기 한계의 초과(setrlimit)


job
job


job



job
job
job

terminate w/core
terminate
terminate w/core
ignore
continue/ignore
terminate w/core
terminate w/core
terminate
terminate w/core
iignore
terminate
terminate w/ignore
terminate w/core
terminate
terminate
terminate
terminate
ignore
terminate w/core
terminate w/core
stop process
terminate
terminate
terminate w/core
stop process
stop process
stop process
ignore
terminate
terminate
terminate
ignore
terminate w/core
terminate w/core

<표 1> 유닉스 시그널


------------------------------------------------------------------------------
[3] 제목 : [연재] <3> 유닉스 프로세스 구조-시그널
3. 시그널의 종류
유닉스에는 여러 가지 시그널들이 존재한다. <표 1>에는 여러 가지
시그널의 이름과 각 시그널을 지원하는 표준과 시스템들이 정리되어 있다.
또한 각 시그널에 대한 간략한 설명과 디폴트 액션도 첨가하였다.
"job" 이라고 쓰여진 것은 작업 제어 기능이 지원되는 시스템에만
해당된다는 뜻이다. "terminate w/core"는 프로세스를 종료시키고 현재
작업 디렉토리에 core 파일을 생성한다는 뜻이다. core는 프로세스
종료 시의 프로세스의 메모리 이미지를 담고 있는데, 이 파일은 유닉스
디버거를 이용하여 종료될 당시의 프로세스 상태를 검사할 수 있도록
한다. core 파일이 생성되지 않을 수도 있는데, 그 경우는 다음과 같다.

* 프로세스가 set-user-ID 프로그램이었으며 현재의 사용자가
프로그램 파일의 소유자가 아닌 경우
* 프로세스가 set-group-ID 프로그램이었으며 현재의 사용자가
프로그램의 그룹 소유자가 아닌 경우
* 현재 작업 디렉토리에 대한 쓰기 권한이 없는 경우
core 파일이 너무 큰 경우 ( RLIMIT_CORE는 core 파일 크기의 상한을
정의한다.)

4. 시그널 발생 함수 : kill과 raise

┌─────────────────────────────────┐
│#include <sys/types.h> │
│#include <signal.h> │
│ │
│int kill(pid_t pid, int sig); │
│int raise(int signo); │
│ │
│ return 값 : 성공하면 0, 에러가 발생하면 -1 │
└─────────────────────────────────┘

kill 함수는 pid로 지정된 하나의 프로세스 또는 프로세스 그룹에
시그널을 보낸다. 보내어질 시그널은 sig에 의해 지정되는데 이것은 앞에서
설명한 시그널 이름에 대한 상수 값 또는 0이 될 수 있다.
POSIX.1에는 raise 함수에 대한 언급이 없는데 raise는 자기 자신에게
시그널을 보내는 함수로써 ANSI C에 정의되어 있다.

POSIX.1은 시그널 값 0을 null signal로 정의하고 있다. 이것은 실제의
시그널을 보내는 것이 아니라 일반적인 오류 검사를 수행하는 기능을
가진다. 임의의 프로세스의 존재 여부를 파악할 때 사용하면 편리하다.
프로세스가 존재하지 않을 경우 kill은 -1을 리턴하고 errno를
ESRCH로 셋트시킨다.

물론 한 프로세스가 다른 프로세스에게 시그널을 전송하기 위해서는
그에 따르는 권한이 필요하다. 일반적으로, 수퍼 유저는 아무
프로세스에게나 시그널을 보낼 수 있다. 그 외의 경우 시그널을 보내는
프로세스의 실제 사용자 ID 또는 유효 사용자 ID가 시그널을 수신할
프로세스의 실제 사용자 ID 또는 유효 사용자 ID와 동일하면 시그널 전송의
권한을 가진다.

한 가지 특별한 경우가 있다. 전송될 시그널이 SIGCONT이면 프로세스는
같은 세션에 있는 임의의 프로세스에게 시그널 전송이 가능하다.
만약 _POSIX_SAVED_IDS가 정의되어 있다면 수신 프로세스의 유효 사용자
ID 대신 저장 사용자 ID(saved set-user-ID)가 검사될 것이다.
kill의 인수 pid는 다음의 네 가지 중 하나이다.

pid > 0 프로세스 ID가 pid인 프로세스에게 시그널이 전송된다.
pid == 0 시그널을 보낸 프로세스와 동일한 그룹에 있는 모든
프로세스에게 시그널이 전송된다. 스와퍼,
init, pagedaemon등의 시스템 프로세스는 제외된다.
pid < 0 그룹의 ID가 pid의 절대 값과 같은 모든 프로세스에게
시그널이 전달된다.
pid == -1 사용이 유보되어 있다.

물론 위의 각각의 경우에 있어서 시그널을 송신하는 프로세스는
수신 프로세스에 대해 시그널을 보낼 권한이 있어야 한다.
만약 자기 자신에게 시그널을 보내는 경우라면 (즉, pid가 자신의 프로세스
ID인 경우), sig에 의해 지정된 시그널이나 블럭된 상태가 아닌 지연된
시그널들 중 적어도 한 시그널이 도착된 후에야 kill 함수의 리턴이
일어날 것이다. kill이 실패하면 시그널은 전송되지 않는다.
Unix에서 프로세스 ID는 순환되므로 사용에 주의를 요한다. 에러 발생의
경우는 아래와 같다.

EINVAL signo의 값이 유효하지 않을 때
EPERM 발신 프로세스가 적합한 권한을 갖지 않을 때
ESRCH pid에 대한 적절한 프로세스가 존재하지 않을 때

5. 인터럽트된 시스템 호출(Interrupted System Calls)
초기 유닉스 시스템의 특징은 프로세스가 "느린" 시스템 호출로 블럭된
상태에 있을 때 시그널이 도착하면 시스템 호출이 인터럽트 된다는
점이었다. 이 때 시스템 호출은 리턴되었고 errno는 EINTR로 셋트되었다.
이러한 특징을 지원하기 위해 모든 시스템 호출은 두 가지 범주로 나뉘었다.
"느린" 시스템 호출과 나머지 시스템 호출로 구분하는 것이 바로 그것이다.
느린 시스템 호출이란 이를 호출한 프로세스를 영원히 블럭시킬 수 있는
호출을 말하며 다음과 같은 범주의 호출은 이에 해당한다.

* 원하는 데이터가 존재하지 않으면 호출 프로세스를 영원히 블럭시킬
수 있는 파일(파이프, 터미널 장치, 네트워크 장치)로부터의 읽기를
시도한다.
* 데이터가 즉시 받아들여질 수 없는 경우 호출 프로세스를 영원히
블럭시킬 수 있는 파일에 대해 쓰기를 시도한다.
* 특정 조건이 발생할 때까지 블럭시키는 파일을 오픈한다. (예를 들어,
부착된 모뎀이 전화에 대해 응답할 때까지 기다려야 하는 터미널 장치)
* pause와 wait
* 몇몇 ioctl 동작.
* 몇몇 프로세스간 통신 함수들

이러한 느린 시스템 호출에 대한 주목할 만한 예외는 디스크 입출력에
관련된 호출이다. 비록 디스크 파일에 대한 읽기/쓰기 작업은 호출자를
일시적으로 블럭시킬 수 있으나 하드웨어 에러가 발생하지 않는 이상,
항상 리턴하며 호출자에 대한 블럭을 곧 해제시킨다.
(디스크 드라이버는 요청에대한 대기열을 관리하며 요청에 대한
응답 시간을 최적화 시킨다).

이러한 인터럽트된 시스템 호출과 관련하여 이제는 에러 리턴 값을
검사해야 한다는 문제가 발생한다. 전형적인 코딩은 다음과 같을 것이다.

again:
if ((n = read(fd, buf, BUFSIZE)) < 0) {
if (errno == EINTR)
goto again: /* interrupted system call */
...
}

4.2BSD에서는 응용 프로그램이 인터럽트된 시스템 호출에 대한 처리를
할 필요가 없도록 몇 가지 시스템 호출에 대해서는 인터럽트 되었을 때
자동적으로 다시 시작하도록 하는 개념을 도입하게 되었다.
이러한 호출에는 ioctl, read, readv, write, writev, wait, waitpid가
포함되는데, 앞에서 말한 바와 같이 이 중 앞의 5개는 느린 장치에 대해
동작할 때만 인터럽트될 수 있으며, wait과 waitpid는 시그널이 발생하면
항상 인터럽트되는 특성이 있다.

BSD4.2에서 자동적 재시작 기능을 도입한 이유는 입력 혹은 출력 장치가
느린 장치인지를 모를 때가 종종 있기 때문이다. 만약 어떤 프로그램이
상응식(interactive)으로 사용될 수 있다면 터미널이 이러한 느린 장치
범주에 속하므로 모든 읽기/쓰기 동작에 대해 시그널에 의해
리턴 되었는지의 여부를 항상 확인해야 하며, 만약 그렇다면 읽기/쓰기를
다시 시도해야 한다.
<표 2>는 여러 시그널 함수와 이를 지원하는 시스템에서의 의미를
요약적으로 보여 준다.

───────────────────────────────────
함 수 시스템 시그널 핸들러가 시그널을 인터럽트된
계속 인스톨 되어 블럭 시킬 수 시스템 호출의
있는가? 있는가? 자동적 재시작


V7, SVR2
signal never
SVR3,SVR4

sigset, sighold,
sigrelse
sigignore,
sigpause

SVR3, SVR4
never
signal, sigvec,
sigblock
sigsetmask,
sigpause
4.2BSD
always
4.3BSD,
4.3+BSD
default
sigaction,
sigprocmask
sigpending,
sigsuspend
POSIX.1
unspecified
SVR4
optional
4.3+BSD
optional

<표 2> 여러 시그널 구현 방법에 따라 제공되는 특성들

위의 구분 방법이 전적으로 옳지만은 않다는 점에 유의하기 바란다.
예를 들어 SunOS 4.1.2에서는 sigaction의 경우 자동적재시작 기능을
지원하는데 이것은 SVR4나 4.3+BSD 어느 쪽과도 같지 않다.

?
------------------------------------------------------------------------------
[4] 제목 : [연재] <4> 유닉스 프로세스 구조-시그널
6. 재진입 가능 함수(reentrant functions)
시그널에 대한 핸들러를 마련하고 있는 프로세스에서의 제어 흐름을
생각해보자. 일단 시그널이 발생하면 프로세스가 수행하고 있던 일련의
명령들은 일시적으로 인터럽트되며 이제 제어는 시그널 핸들러로 넘어가
핸들러 함수의 처음부터 명령이 실행되기 시작한다.
그리고 시그널 핸들러가 리턴하면 그제서야 시그널이 발생하기 전에
실행하던 명령문을 계속할 수 있게 된다. 그러나 시그널 핸들러에서는
시그널이 일어났을 당시 프로세스가 어느 부분을 수행하고 있었는지를
알 수 없다.

만약 프로세스가 malloc을 이용하여 히프에서 추가의 메모리를 할당받고
있는 중이었는데 시그널 핸들러 안에서 또 다시 malloc을 호출한다면?
또는 수행 결과를 정적 영역에 저장하는 getpwnam 함수를 실행 중이었는데
시그널 핸들러에서도 getpwnam을 다시 호출한다면?
특히 malloc 예의 경우는 큰 피해를 가져올 수 있다. 왜냐하면 malloc은
이미 할당된 영역의 연결 리스트를 유지하므로 시그널이 발생할 당시에
이 리스트를 변경하고 있었을 수도 있다.
또 getpwnam의 경우는 시그널 핸들러에서의 getpwnam 호출로 리턴된
정보로 인해 먼저 호출된 getpwnam의 결과가 지워질 수도 있다.

POSIX.1은 재진입 할 수 있는 함수들에 관한 규정을 명시하고 있다.
<표 3>은 이러한 재진입 가능 함수들의 예를 보이고 있다. 이 표에서 *로
표시된 함수는 POSIX.1에서는 재진입 가능으로 규정하고 있지 않으나
SVR4 SVID에서 규정하고 있는 함수를 뜻한다.

┌───────┬────────┬───────┬────────┐
│_exit │ fork │ pipe │ stat │
│abort* │ fstat │ read │ sysconf │
│access │ getegid │ rename │ tcdrain │
│alarm │ geteuid │ rmdir │ tcflow │
│cfgetispeed │ getgid │ setgid │ tcflush │
│cfgetospeed │ getgroups │ setpgid │ tcgetattr │
│cfsetispeed │ getpgrp │ setsid │ tcgetpgrp │
│cfsetospeed │ getpid │ setuid │ tcsendbreak │
│chdir │ getppid │ sigaction │ tcsetattr │
│chmod │ getuid │ sigaddset │ tcsetpgrp │
│chown │ kill │ sigdelset │ time │
│close │ link │ sigemptyset │ times │
│creat │ longjmp* │ sigfillset │ umask │
│dup │ lseek │ sigismember │ uname │
│dup2 │ mkdir │ signal* │ unlink │
│execle │ mkfifo │ sigpending │ utime │
│execve │ open │ sigprocmask │ wait │
│exit* │ pathconf │ sigsuspend │ waitpid │
│fcntl │ pause │ sleep │ write │
└───────┴────────┴───────┴────────┘
<표 3> 시그널 핸들러에서 호출될 수 있는 재진입 가능 함수들

<표 3>에 빠져 있는 대부분의 함수들은 a) 정적 데이터 구조를
사용하거나 b) malloc 또는 free 함수를 호출하거나 c)표준 입출력
라이브러리의 일부분이기 때문이다. 표준 입출력 라이브러리의 대부분은
전역 데이터 구조를 사용하여 재진입할 수 없는 방식으로 구현되어 있다.

errno 변수는 오직 하나만 존재한다. 따라서 비록 <표 3> 에 나열되어
있는 함수라도 시그널 핸들러 내에서 호출하면 errno 값이 변할 수 있다.
예를 들어 main에서 errno 값이 특정 값으로 셋트된 후에 시그널
핸들러가 호출되었을 때 만약 read와 같은 함수를 호출한다면, 이 호출로
인해 errno 값이 새로운 값으로 변할 수 있다. 따라서 일반적으로
시그널 핸들러에서 <표 3>에 나열된 함수를 호출할 때는 errno 값을
일단 저장한 후 나중에 다시 복원시켜야 한다.

이 표는 longjmp나 siglongjmp 함수를 포함하고 있지 않다. 그 이유는
프로세스가 재진입 불가능한 방식으로 데이터 구조를 갱신하고 있을 때에도
시그널이 일어날 가능성이 있기 때문이다. 만약 시그널 핸들러에서
리턴하지 않고 siglongjmp를 호출한다면 갱신 중의 데이터 구조를 불완전한
상태로 남겨두게 될 위험이 있다. 따라서 전역 데이터 구조를 이런 재진입
불가능한 방식으로 갱신하려고 하는 응용 프로그램이 만약 시그널 핸들러에
sigsetjmp를 호출하는 코드를 담고 있을 때는 이러한 데이터 구조를
갱신하고 있는 동안 시그널을 블럭시켜야 한다.

7. 시그널 셋트(set)의 개념과 조작
시그널 셋트란 여러 시그널을 표현할 수 있는 데이터 타입으로써 뒤에
설명될 sigprocmask와 같은 함수에서 쓰인다. 4.3+BSD 계열 시스템에서는
31개의 시그널이 존재하며 한 시그널 당 한 비트씩 할당하여
integer 형으로 시그널 셋트를 표현하고 있다. 그러나 문제점은 시그널의
가지 수가 integer의 비트(보통 32비트)수를 초과할 수 있다는 것이다.
따라서 일반적으로 시그널 셋트는 정수형 변수로 표현할 수 없다.
POSIX.1에서는 sigset_t라는 데이터 타입을 마련하여 이러한 시그널 셋트
연산에 사용될 것을 지정하고 있다.

┌─────────────────────────────────┐
│#include <signal.h> │
│ │
│ int sigemptyset(sigset_t *set); │
│ int sigfillset(sigset_t *set); │
│ int sigaddset(sigset_t *set, int signo); │
│ int sigdelset(sigset_t *set, int signo); │
│ int sigismember(const sigset_t *set, int signo); │
└─────────────────────────────────┘

* sigemptyset : set의 모든 시그널을 0으로 셋트한다. 즉, 모든
시그널이 제외된다.
* sigfillset : set의 모든 시그널을 1로 셋트한다. 즉, 모든 시그널이
포함된다.
* sigaddset : set의 멤버로써 signo로 지정된 시그널을 추가 한다.
* sigdelset : set에서 signo로 지정된 시그널을 제거한다.
* sigismember : signo 시그널이 set의 멤버인지를 검사한다.

시그널 셋트에서 특정 시그널에 대한 비트가 0으로 셋트되었다는 것은
이 시그널 셋트를 인자로 하여 수행되는 함수에서 해당 시그널이
제외된다는 뜻이며, 1로 셋트되면 수행되는 함수의 영향을 받는다는
뜻임에 유의하기 바란다. sigismember 함수를 제외한 모든 함수는
성공적으로 수행되면 0을 실패하면 -1을 리턴하며, sigismember는 옳으면
1을 틀리면 0을 리턴한다.

[출처] 유닉스 시그널|작성자 럭키Dragon


Posted by cyj4369
,

먼저, smbfs가 설치되어 있어야 한다.


마운트 될 경로를 만들어 두고, 권한을 읽고 쓰기 좋게 설정해 둔다. 나는 /mnt/NAS350D/elex에 마운트 할 예정이다.


/etc/fstab 파일을 관리자 권한으로 편집해야 한다.

sudo gedit /etc/fstab


/etc/fstab의 아래에 다음의 내용을 추가한다. 맨 앞의 IP는 NAS의 주소이다.

//192.168.10.100/경로 /mnt/NAS350D/elex smbfs defults,username=아이디,password=비번,uid=리눅스사용자아이디,gid=users,dir_mode=0755,file_mode=0644 0 0


파일 저장 후 sudo mount -a 를 실행하면 변경내용이 적용된다.

Posted by cyj4369
,

2.3.3 Process Identification Numbers
 Unix process들은 항상 유일하게 확인 가능한 숫자하나를 할당받는다. 이 숫자는 Process identification number 또는 줄여서 PID 라고 부른다. 각 fork 나 clone system call로 생성된 process는 kernel 에 의해 system에 유일한 새로운 PID 를 할당받게 된다. 

Process Identifiers
 각 process는 PID 뿐만 아니라 다른 식별자로 특성이 구분될 수 있다. 몇 가지 형태를 살펴보도록 한다. 

□ 하나의 Thread Group 내에 있는 모든 process는(즉, CLONE_THREAD flag와 함께 호출 된 clone system call 로 생성된 process 내의 서로 다른 실행 문맥-thread) 같은 thread group id(TGID)를 가진다. 만약 하나의 process가 thread를 사용하지 않는다면,  PID  와 TGID 값은 같다. 
ex)
  parent process에서 아래와 같은 시스템 콜을 사용하였을 때, 결과 예측값,
1. fork(), vfork(), clone(CLONE_CHILD_CLEARID | CLONE_CHILD_SETID)
    parent : TGID(1234), PID(1234)
    child : TGID(1235), PID(1235)
2. pthread_XXX(), clone(CLONE_THREAD)
    parent : TGID(1234), PID(1234)
    child : TGID(1234), PID(1235)

    thread group 에 있는 main process는 group leader 라고 부른다. task_struct 의 group_leader 변수(struct task_struct * group_leader)는 thread group 내에서 생성된 thread 들이 main process를 가리키기 위해 사용된다. 

□ 또다른 한가지는, 독립적으로 수행되는 process들을 하나의 process group로 결합시킬수 있다.(setpgrp system call 사용) task_struct 의 pgrp 요소(실제로 task_struct 내부에 명시적인 pgrp 변수는 없다)는 하나의 group 내애서 process group leader의 pid 값으로 모두 같다.


//pgrp 의 값구하는 code 참조.

Process group는 그 group내에 있는 모든 process에게 signal을 일괄적으로 보내는데 용이 하게 사용된다.(다양한 system programming을 하는데 도움이 된다는데...) 
process group 는 pipe 를 이용하여 연결 된 것을 포함한다. 
ex) 

더보기

위와 같이 사용된 ps process와 grep process는 하나의 process group 가 되는 것이다. 

□ 여러 process group 는 하나의 session으로 결합될 수 있다. 하나의 session 내부의 process들은 task 구조체의 session 요소에 모두 같은 session id 값을 가지고 있다. SID 값은 setsid system call 로 변경이 가능하다. 

 Namespace는 PID 들을 관리하기 위해 추가적인 복잡함이 더해진다. PID namespace들이 계측적으로 구성된다는 것을 다시 상기해보자. 새로운 namespace가 생성되면, 모든 pid들은 parent namespace에게 보여지게 되지만 child namespace에서는 parent namespace의 PID를 볼수 없다. 위의 상황을 유추해보면, 어떤 task들은 하나 혹은 그 이상(namespace 당 하나의 PID)의 PID 값을 가질 수 있다는 것을 알 수 있다. data structure 에도 이런 사항이 반영되어 Global ID 와 Local ID 로 나누어 관리한다. 

 □ Global ID는 kernel 그 자체내부나 최초 부팅을 포함하여 init task가 실행했던 namespace(최초 namespace) 내부에서 확인 가능한 숫자이다. 이는 시스템 전체에서 유일한 값을 가지게됨을 보장한다. 
□ Local ID는 특정 namespace에 속한 ID이며, 시스템 전체에서 유효하게 사용하지 못한다. 그 process가 속한 namespace에서만 통용되며, 다른 namespace에서 같은 ID 값을 가지고 사용될 수 있다. 

위의 Global PID 와 TGID 는 task_struct 에서 직접 관리 한다. 

이들의 type 는 모두 pid_t 이며, 이것은 __kernel_pid_t 을 typedef 한 것이다.( include/linux/types.h). 즉 이것은 각각의 architecture 마다 새로 정의 가능 하다. 
대게는 int 로 사용되어 2^32 의 서로 다른 ID가 시스템에서 사용 가능하다는 것이다. 

 session ID와 process group ID는 task struct 내부에서 직접관리 되지 않는다. 위에서 살펴본 group_leader field 에서 가져 올 수 있다. 

<task_struct>->group_leader->pids[PIDTYPE_SID].pid //get session id
<task_struct>->group_leader->pids[PIDTYPE_PGRP].pid //get pgrp id

system call, setpgrp() 또는 setsid() 를 이용해 각각의 값을 설정 할 수 있다. 
(현재 2.6.35 의 내용을 하고 있으므로 책의 내용과는 상이 할 수 있다. interface 및 자료 구조 내부의 내용이 변경되었슴.)

Posted by cyj4369
,