1. 데이지 체인이란 연속적으로 연결되어 있는 하드웨어 장치들의 구성을 지칭한다. 예를 들어 SCSI 인터페이스는 최대 7개의 장치까지 데이지 체인형식을 지원한다.

  2. 데이지 체인은 예를 들어 어떤 장치 A가 B라는 장치에 연결되어 있고, 그 B라는 장치는 다시 C라는 장치에 연속하여 연결되어 있는 방식의 버스 결선방식을 말한다. 이때 가장 마지막에 있는 장치는 대개 저항장치 또는 단말장치에 접속된다. 모든 장치들은 동일한 신호를 수신할 수도 있지만, 단순한 버스와는 현저히 다르게 체인 내에 속한 각 장치가 하나 이상의 신호를 다른 장치에 전달하기 전에 내용을 수정하는 경우도 있다.

인터럽트를 처리하기 위해선 Linux에선 3가지 방법이 있습니다.

softirq, tasklet, work queue

가 그것이죠.

인터럽트란 HW적으로 CPU에 interrupt를 만들어 무엇인가 처리해야 할일을 처리하게끔(?) 만드는 역할을 합니다. 키보드를 누를때도 인터럽트가 발생하고, USB에 장치를 연결해도, 심지어 time tick을 처리하기 위해서도 1초에 300번정도(커널설정에 따라 변경 가능(i.e. 1000)) HW interrupt가 발생합니다. HW적으로 인터럽트핀이 CPU를 깨워서 인터럽트가 걸리면 맨앞 핸들러로 뛰어서 어떤인터럽트가 걸렸는지 확인하는 루틴이 실행됩니다. 이 루틴안에서 어떤 인터럽트인지 확인하고 다음처리를 담당하게 되죠. 그러나 주위해야하는점은 어떤 HW 인터럽트가 먼저 걸렸을때엔 다른 HW 인터럽트가 걸리지 않게 됩니다(인터럽트 pin을 SW적으로 내리기 전까진). 즉,응답성을 위해선 인터럽트 핸들러에선 정말 간단하게 어떤 인터럽트인지만 확인하고, 바로 인터럽트를 해제하지 않으면 그사이엔 어떠한 HW 인터럽트가 발생되지 않아 시스템의 응답성이 떨어지게 되겠죠.. 바로 HW인터럽트를 받아서 인터럽트핀을 해제하고 약간 지연되게 처리하는 방법이 위의 3가지라고 보시면 됩니다.

softirq

32가지 미리 정의된 인터럽트들을 정의하고, 인터럽트 핸들러가 종료되서 인터럽트 가능한 상태로 바뀌면 바로 softirq가 실행된다. 가장 높은 우선순위를 가지고 있으며, 고정된 인터럽트들을 처리하기 위해서 사용합니다. 현재 커널은 32가지중 6가지만 사용합니다. 종류는 HI_SOFTIRQ(높은 우선순위), TIMER_SOFTIRQ(타이머), NET_TX_SOFTIRQ(네트워크 패킷송신), NET_RX_SOFTIRQ(네트워크 패킷수신), SCSI_SOFTIRQ(SCSI), TASKLET_SOFTIRQ(태스크릿들)이고, HI_SOFTIRQ가 우선순위가 가장높게 처리됩니다.

tasklet
동적으로 할당된 softirq라고 생각하면 됩니다. 위 softirq의 SCSI_SOFTIRQ가 처리되고나서 TASKLET_SOFTIRQ가 처리되는데 이때엔 동적으로 할당을 받아서 처리하고 싶은 handler를 등록하고 처리하게 됩니다.

work queue
softirq나 tasklet들이 실행중에는 sw인터럽트중이라, hw 인터럽트는 가능하지만, 여전히 sw적으로 우선적으로 처리되는것들입니다. 즉 softirq중에는 user process들이나, context switch등은 처리되지 않고 있겠죠. 모든 sw irq를 softirq로만 처리한다면 user process나 context switch등은 처리안되어 유저입장에선 상당히 반응성이 안좋은 커널이라 생각할수 있습니다. 그래서 context switch등과 동일한 level에서 스케쥴링되는 work queue를 두어 sw interrupt들이지만 상당히 시간을 요하거나 계산해야될게 많은 작업들 혹은 휴면이 필요한 I/O작업이 필요한 일들은 context switch될때 같이 되게 만들어 주어 커널 응답성을 좋게 해줄수 있습니다.

출처 : http://kldp.org/node/112272

실리콘 래버러토리스
VoIP용 통신사업자급 듀얼ProSLIC 출시
실리콘 래버러토리스(www.silabs.com)가 듀얼채널 SLIC 및 코덱을 싱글칩에 통합한 Si3226을 출시, 자사의 듀얼 ProSLICSLIC (pro-grammable subscriber line interface) ProSLIC 제품군을 확대한다고 밝혔다.
Si3226 ProSLIC 제품군은 실리콘랩의 특허 디지털 SLIC 아키텍처가 적용되어 전세계에서 사용할 수 있는 통신사업자급 SLIC로, 광범위한 원격 진단 기능과 저전력 소모, 그리고 업계 동종 제품 중 가장 깨끗한 음성재생 기능을 제공한다. Si3226 제품군은 음성 기능의 케이블, DSL 모뎀, FTTP 광네트워킹 장비 및 PBX와 같이 엔터프라이즈 및 컨수머용 장비에 최적화 되어 있다.
아날로그 기반의 SLIC와는 달리, Si3226은 프로그래밍 수준이 높은 디지털 SLIC 아키텍처를 기반으로 설계되어 다양한 고객들의 요구사항을 만족시킬 수 있는 유연성을 제공한다. 또한 단일 하드웨어 설계 및 BOM(bill-of-materials)을 사용함으로써 전세계적으로 사용할 수 있다. Si3226은 멀티모드 링(ring) 제너레이터와 프로그래머블 배터리 트랙킹(tracking) DC/DC 컨트롤러를 결합해 모든 라인 상태에서 저전력 소모 동작을 유지한다.
 - 요약 -
어떤 전압의 직류전원에서 다른 전압의 직류전원으로 변환하는 전자회로 장치를 말하며, 넓은 뜻으로는 직류전동기와 직류발전기를 기계적으로 결합한 것도 포함된다. 텔레비전 수상기에서 주로 사용된다.

 - 본문 -

교류의 전압변환은 변압기로 할 수 있으나 직류에서는 그대로는 변압기를 사용할 수 없으므로, 직류전원에서 발진회로()에 의해 전력용량이 큰 교류를 발생시켜 변압기를 통해서 다른 전압의 교류로 변환하고, 다시 정류해서 직류를 얻는 것이 많다.

텔레비전 수상기에서는 브라운관용 고압 직류전원 등에 사용한다. 넓은 뜻으로는 직류전동기와 직류발전기를 기계적으로 결합한 것도 포함된다.


출처 : 네이버 백과사전
 SPI(Serial Peripheral Interface)는 Motorola사에 의하여 개발되었고 지금은 표준화 되어 전세계적으로 널리 사용하는 근거리용 직렬통신 규격으로서, 마스터(master)와 슬레이브(slave) 사이에서 MOSI, MOSO, SCK, SS 등 4개의 통신선을 사용하는 고속 동기식 직렬통신 방식이다.
 SPI 직렬통신은 반드시 1개의 마스터와 1개의 슬레이브 사이에서만 수행된다. 마스터는 송신 데이터와 함께 클럭 신호를 동시에 슬레이브에게 보낸다. 그러면 슬레이브는 이 클럭을 사용하여 데이터를 수신하면서 동시에 자신의 데이터를 마스터에게 보낸다.
 이와 같이 SPI 직렬통신에서는 마스터가 통신의 제어를 주도하며, 항상 송신 동작과 수신 동작이 동시에 수행되어 전이중 통신이 된다. 따라서, 만약 마스터가 슬레이브에게 데이터를 보내는 것이 목적이라면 마스터가 받은 수신 데이터는 무시하면 되며, 반대로 마스터가 슬레이브로부터 데이터를 가져오는 것이 목적이라면 슬레이브에게 더미 데이터를 송신하면서 수신된 데이터를 읽으면 된다.
 SPI 직렬통신 포트에서는 각각의 통신 채널마다 4개씩의 신호가 사용되는데, MOSI(Master-Out Slave-In) 신호는 마스터에서 서 출력되고 슬레이브로 입력되는 신호이고, MISO(Master-In Slave-Out) 신호는 마스터에서 출력되고 슬레이브로 입력되는 신호이며, SCK(Serial Clock) 신호는 마스터에 의하여 구동되는 직렬전송 클럭 신호이다. 또한 SS(Slave Select) 신호는 마스터가 여러개의 슬레이브 디바이스 중에서 마스터와 서로 데이터를 전송할 1개의 소자를 선택하는 칩선택 신호이다.

프로세스마다 인터럽트 처리 방식이 다르기 때문에 리눅스 커널에서는 동일하게 처리하기 위해 IRQ 인터럽트는 모두 do_IRQ() 함수를 호출하여 처리하도록 되어 있다. 이 do_IRQ() 함수는 오직 IRQ 처리만 담당하며, irq_desc라는 전역 변수에 등록된 인터럽트 서비스 함수를 호출하는 구조로 되어 있다.디바이스 드라이버나 커널에서 IRQ 인터럽트 처리가 필요한 경우에는 처리하고자 하는 IRQ 번호에 해당하는 인터럽트 서비스 함수를 이 irq_desc 전역 변수에 등록하면 된다.

IRQ 인터럽트 서비스를 처리하기 위해서는 request_irq() 함수를 이용하여 처리하고자 하는 IRQ 번호와 서비스 함수 주소를 등록한다. 인터럽트가 발생하면 커널은 아키텍처마다 고유의 IRQ 검출 루틴을 이용하여 발생된 인터럽트의 IRQ 번호를 획득하여 do_IRQ() 함수를 호출한다.

더이상의 인터럽트 처리가 필요없는 경우에는 하드웨어에서 인터럽트가 더이상 발생하지 않도록 처리한 후 free_irq() 함수를 이용하여 irq_desc 전역 변수에 등록된 인터럽트 서비스 함수를 제거한다.

 

. 커널 2.4

. #include <linux/sched.h>

. void int_handler(int irq, void* dev_id, struct pt_regs* regs)

{

}

. int request_irq(unsigned int irq, void (*handler)(int, void*, struct pt_regs*), unsigned long frags, const char* device, void* dev_id);

. void free_irq(unsigned int irq, void* dev_id);

 

. 커널 2.6

. #include <linux/interrupt.h>

. irqreturn_t int_hander(int irq, void* dev_id, struct pt_regs* regs)

{

    return IRQ_HANDLED;

}

. int request_irq(unsigned int irq, irqreturn_t(*handler)(int, void* struct pt_regs*), unsigned long frags const char* device, void* dev_id);

 

. frags

    . SA_INTERRUPT             다른 인터럽트를 허가하지 않느다

    . SA_SHIRQ                    동일한 인터럽트 번호를 공유한다

    . SA_SAMPLE_RANDOM  랜덤값 처리에 영향을 준다

. dev_id

    . 인터럽트 ID를 뜻하는 것으로 인터럽트 공유에 사용되거나 인터럽트 서비스 함수를 수행할 때 필요한 정보가 저장된 메모리의 선두 주소를 담고 있다.

    . 인터럽트 서비스 함수를 등록할 때 지정된 값이 그대로 전달된다.

. regs

    . 인터럽트가 발생한 당시의 레지시터 값들

 

* 인터럽트 서비스 함수 내의 메모리 할당

vmalloc() 함수나 vfree() 그리고 ioremap() 같은 함수를 인터럽트에서 사용하면 안 된다. kmalloc() 함수 역시 GFP_ATOMIC 인자를 사용한 방식만 사용해야 한다는 제약이 있다.

 

* 인터럽트 서비스 등록과 해제 시점

왜 open()함수와 close()함수에서 인터럽트 서비스 함수 등록과 해제 루틴을 넣을까?

모듈이 초기화될 때 서비스 함수가 등록되면 해당 디바이스를 사용하는 응용 프로그램이 없다 하더라도 인터럽트가 발생하면 인터럽트 서비스 함수가 항상 호출된다. 이런 호출 방식은 전체 시스템의 처리 속도를 약간 느리게 만드는 원인이 된다. 그래서 open() 함수나 close() 함수에서 인터럽트 서비스 함수의 등록과 해제가 이루어지도록 해야 한다.

PC 같은 범용 시스템에 사용되는 디바이스 드라이버를 만든다면 open() 함수와 close() 함수에서 처리해야 하고, 임베디드와 같은 특정 목적의 시스템에서는 모듈의 등록과 해제 시에 처리하는 것이 좋다.

 

* 인터럽트의 공유

인터럽트 서비스 함수를 등록할 때 같은 인터럽트 번호에 대해 다른 인터럽트 서비스 함수를 등록할 수 있도록 지원한다.

. frags : SA_SHIRQ가 포함되어야 하고

. dev_id : 동일한 인터럽트 서비스 함수를 구별하기 위해 0이 아닌 값을 사용해야 한다.

 

* 인터럽트의 금지와 해제

-. 인터럽트 서비스 함수가 동작중에 다른 인터럽트가 발생하지 못하게 막는 경우

. frags 매개변수에 SA_INTERRUPT를 포함시킨다. 인터럽트가 발생했을 때 SA_INTERRUPT 값이 포함된 인터럽트 서비스 함수는 커널이 프로세스의 인터럽트를 금지시킨 후 호출한다.

-. 일반적인 함수 수행중에 데이터 처리를 보호하기 위해 인터럽트를 강제로 막는 경우

. 특정 인터럽트 번호에 대한 금지와 해제

    . #include <asm/irq.h>

    . void disable_irq(int irq) : 인터럽트 금지

    . void enable_irq(int irq) : 인터럽트 허가

. 전체 인터럽트를 금지하고 해제

    . #include <asm/system.h>

    . 커널 2.4

        . cli(void) : 프로세서의 인터럽트 처리를 금지한다.

        . sti(void) : 프로세서의 인터럽트 처리를 허가한다.

        . save_flags(unsigned long frags) : 현재의 프로세스의 상태를 저장한다.

        . restore_flags(unsigned long frags) : 저장된 프로세스의 상태를 복구한다.

    . 커널 2.6

        . local_irq_disable(void) : 프로세서의 인터럽트 처리를 금지한다.

        . local_irq_enable(void) : 프로세서의 인터럽트 처리를 허가한다.

        . local_save_flags(unsigned long frags) : 현재의 프로세스의 상태를 저장한다.

        . local_restore_flags(unsigned long frags) : 저장된 프로세스의 상태를 복구한다.

 

        unsigned long frags;

        local_save_flags(frags);

        local_irq_disable();

        // 인터럽트 호출에서 보호하고자 하는 루틴

        local_restore_flags(frags);

        . local_irq_enable() 함수를 사용하지 않는데, 그 이유는 local_save_flags() 함수에 의해 저장된 frags 변수에는 이미 인터럽트 허가 상태가 포함되어 있기 때문이다. 그래서 굳이 local_irq_enable() 함수를 사용하지 않아도 local_restore_flags() 함수에 의해 local_irq_disable() 함수를 호출한 효과가 발생한다.

 

* 인터럽트 발생 횟수

인터럽트 발생 횟수는 커널이 알아서 계산한다. /proc/interrupts란 파일을 보면 현재 인터럽트의 발생 횟수를 볼 수 있다.

cat /proc/interrupts


출 처 http://blog.naver.com/jinynet9?Redirect=Log&logNo=40013761955

[출처] 인터럽트|작성자 jinynet9

윤 상배

dreamyun@yahoo.co.kr

교정 과정
교정 0.8 2003년 3월 1일 23시
최초 문서작성


1절. 소개

유닉스에서 사용되는 proc파일 시스템은 운영체제의 각종 정보를 커널모드가 아닌 유저모드에서 쉽게 접근할 수 있도록 만들어 줌으로 시스템 정보를 일반 프로그래머가 쉽게 접근 할 수 있도록 도와준다.

특히 리눅스에서는 프로세스 정보뿐만 아닌 다른 시스템 정보들까지 광범위 하게 제공해 준다. 이말은 proc파일시스템을 제대로 이해할 경우 리눅스 운영체제를 좀더 깊이 있게 다룰 수 있다는 말이 된다. 실제 ps와 같은 프로세스 상황감시에서 부터, CPU사용율, 인터럽트, 네트워크 패킷전송량, 적재된 모듈, IDE-SCSI와 같은 장치정보, CPU정보등의 데이터를 어렵지 않게 얻어 올 수 있다. 다른 대부분의 유닉스에서 이러한 정보를 얻어올려면 상당한 애로사항을 격게 될것이다.

이제 proc파일시스템에서 데이터를 읽어오는 것을 지나서 proc파일 시스템에 필요한 데이터를 쓰는 방법에 대해서 알아보도록 하겠다.


2절. 왜 proc파일시스템을 이용하는가

우리는 이미 일반 파일 시스템을 이용해서 필요한 데이터를 남기는 방법을 알고 있다. read(2), open(2), write(2) 이 3개의 함수만 사용할 줄 안다면, 필요한 모든 데이터를 읽고 쓰는데 별 부족함이 없다. 그렇다면 왜 굳이 proc파일시스템을 이용해야 하는지에 대해서 알아 보도록 하겠다.


2.1절. 파일 시스템 오버헤드를 줄일 수 있다.

일반적으로 사용되는 파일 시스템은 상당한 오버헤드를 가지고 있다. 각 파일의 inode와 superblocks와 같은 객체를 관리해야 하며 이러한 정보를 필요할때 마다 운영체제에 요청해야 한다. 이들 파일 시스템의 데이터들은 서로 어긋날수도 있으며, 단현화 현상등이 발생할 수도 있다. 운영체제는 이러한 모든 것을 관리해 주어야 하며, 당연히 상당한 오버헤드가 발생하게 된다.

proc파일 시스템은 이러한 일반 파일시스템의 문제점을 없애기 위해서 리눅스 커널에서 직접 파일시스템을 관리하는 방법을 채택하고 있다.

지금 여러분의 리눅스 시스템에서 mount명령을 내리면 다음과 같이 proc 파일 시스템이 자동으로 마운트 되어 있는 것을 확인할 수 있을 것이다.

# mount
/dev/hda7 on / type ext3 (rw)
none on /proc type proc (rw)
/dev/hda5 on /usr type ext3 (rw)
...
			
여러분이 최초에 리눅스 운영체제를 설치할 때 proc파일 시스템을 위해서 별도로 파티션작업을 한적이 없을 것이므로 mount정보에 표시되는게 이상할 수도 있을 것이다. 이유는 앞에서 말했듯이 proc파일 시스템은 리눅스 커널에서 직접 관리하는 것으로 운영체제가 부팅 되었을 때 생성되는 파일 시스템이기 때문이다. mount정보를 보면 알겠지만 어떤 장치에도 마운트되어 있지 않음을 확인할 수 있다. proc파일 시스템은 커널메모리에서 돌아가는 일종의 가상 파일 시스템이다.

메모리에서 그것도 커널이 직접관리를 하게 되니.. 당연히 빠를 수 밖에 없다.


2.2절. 물리적인 파일시스템 장치를 필요로 하지않는다

/proc는 커널메모리에서 유지하는 파일 시스템이다. 때문에 별도의 장치(하드디스크 같은)을 필요로 하지 않는다. 이러한 특징은 임베디드시스템을 설계하고자 할때 중요한 요소가 된다.


2.3절. 최적화된 파일작업 수행

일반적인 파일 시스템 계층은 은 프로그래머를 위해서 POSIX 형식의 인터페이스를 제공한다. open, read, write, close등이 이것이다. 데이터 블럭들은 용이한 확장을 위해서 추상화 되어 있으며 상속가능한 형태로 구성된다.

이러한 일반 파일 시스템은 대용량의 데이터를 다루어야 하는 경우 매우 유용하지만, 고정적이고 처리해야할 데이터의 양이 적은 분야에는 오히려 비효율적이다. proc파일 시스템에서 다루어야 할 정보는 대부분 정해져 있으며, 데이터의 양도 그리 많지 않다. 고로 일반 파일시스템에서 제공하는 인터페이스를 사용하지 않고 필요한 작업에 최적화된 인터페이스를 사용할 수 있다.


3절. proc 파일시스템을 어디에 사용할 수 있을까

2절에서 proc 파일시스템을 사용했을 때 얻을 수 있는 잇점에 대해서 알아보았다. 그럼 어느 용도에 유용하게 사용할 수 있을지에 대해서 알아보자.


3.1절. 커널 모듈 프로그래밍

proc파일 시스템(이하 proc) 자체가 커널과 밀접하게 연관있는 이유로 일반 애플리케이션에서 proc를 사용하는 일은 드물다. 위에서 설명 했듯이 커널메모리에서 proc를 유지하게 되므로 많은 양의 데이터를 처리하는 애플리케이션의 용도와는 맞지 않다는 점도 있다.

그런점에서 proc는 커널모듈과 같이 커널과 밀접하게 관계있는 프로그램에서 유용하게 사용할 수 있다. 커널 모듈 프로그램은 주로 장치를 올리기 위한 용도로 사용되는데, 커널 레벨에서 작동하다 보니 모듈의 작동상황이나 성능등을 알아오기가 그리 쉽지 않다. 그렇다고 해서 일반 파일 시스템을 IPC를 사용하는 것 역시 그리 좋은 생각은 아니다. 이럴 때 proc를 이용하면 문제를 깔끔하게 해결 할 수 있다.


3.2절. 임베디드 프로그래밍

임베디드 시스템은 파일 시스템을 가지지 않는 경우가 많거나 가지고 있다고 하더라도 매우 제한적인 경우가 많다. 이럴 때 proc를 이용해서 관리자 환경이라든지 데이터 입출력 환경을 만들 수 있다.

물론 이경우는 리눅스커널을 기반의 임베디드 환경에 해당된다.


4절. proc 프로그래밍

이번장에서는 커널에서 제공하는 proc API들에 대해서 살펴볼 것이다. 다루어 지는 내용들은 커널 2.4.x를 기준으로 하고 있다.


4.1절. proc 구조체 및 API

4.1.1절. proc_dir_entry 구조체

proc에 있어서 가장 중요한 구조체로써 다음과 같이 정의되어 있다.

struct proc_dir_entry {
    unsigned short low_ino;
    unsigned short namelen;
    const char *name;
    mode_t mode;
    nlink_t nlink;
    uid_t uid;
    gid_t gid;
    unsigned long size;
    struct inode_operations * proc_iops;
    struct file_operations * proc_fops;
    get_info_t *get_info;
    struct module *owner;
    struct proc_dir_entry *next, *parent, *subdir;
    void *data;
    read_proc_t *read_proc;
    write_proc_t *write_proc;
    atomic_t count;     /* use count */
    int deleted;        /* delete flag */
    kdev_t  rdev;
};
				
name은 proc파일의 이름이다. mode는 proc파일의 권한으로 일반파일에 사용되는 권한과 동일하게 사용할 수 있다. mode에 대한 자세한 내용은 stat(2)의 man페이지를 참고하기 바란다.

struct proc_dir_entry *next ...는 proc파일이 위치하는 디렉토리로 일반 파일에서의 디렉토리 권한과 동일하게 사용되며, 링크드 리스트로 관리된다.

data proc에서 읽은 데이터를 리턴하기 위해서 사용된다.

read_proc, write_proc 유저영역의 프로세스는 직접 커널영역에 데이터를 읽거나 쓸수 없다. 때문에 모듈 프로그램등이 중간에서 커널과 유저영역 사이의 데이터전달을 해주어야 한다. 이러한 데이터 전달은 callback함수를 통해서 이루어진다. read_proc는 커널로 부터 읽은 데이터를 유저영역 프로세스로 되돌려주기 위해서 write_proc는 유저역역 프로세스에서 쓴데이터를 커널메모리 영역으로 복사하기 위해서 사용한다.


4.2절. proc API

proc는 사용하기 간단한 몇개의 API만을 제공하는데, 이들 API는 커널의 메이저 버젼에 따라서 차이가 있을 수 있다. 만약 여러분이 2.4.x외의 다른 커널 버젼을 사용하길 원한다면 해당 커널버젼의 커널 문서를 참고해야 할 것이다. 그렇다고 해서 이 문서가 전혀 필요 없지는 않을 것이다. 대부분의 경우 커널의 메이저 버젼이 업그레이드 된다고 하더라도 함수 API가 아주 크게 변하는 경우는 없기 때문이다. 이 문서를 익혀 놓는다면 다른 커널 버젼에도 쉽게 적응할 수 있을 것이다.


4.2.1절. create_proc_entry

struct proc_dir_entry *create_proc_entry
(
    const char *name,
    mode_t     mode,
    struct proc_dir_entry *parent);
);
				
이 함수는 첫번째 인자인 name을 이름으로 하는 proc파일을 생성한다. mode는 생성 될때의 파일 모드로 open(2)에 사용되는 것과 동일하게 사용된다. mode에 대한 자세한 내용은 man페이지를 참고하기 바란다.

마지막 인자인 parent는 name로 만들어진 proc파일이 위치할 디렉토리다. proc파일은 루트디렉토리가 "/"아닌 "/proc"에서 부터 시작하게 된다. 만약 NULL이라면 /proc 디렉토리 밑에 위치하게 된다.


4.2.2절. create_proc_read_entry

static inline
struct proc_dir_entry *create_proc_read_entry
(
    const char *name,
    mode_t mode,
    struct proc_dir_entry *base,
    read_proc_t * read_proc, 
    void *data
);
				
이 함수는 create_proc_entry의 포장(wrapper)함수다.
static inline
struct proc_dir_entry *create_proc_read_entry
(
    const char     *name,
    mode_t         mode,
    struct proc_dir_entry *base,
    read_proc_t  *read_proc, 
    void         *data
)
{
    struct proc_dir_entry *res = create_proc_entry(name, mode, base);
    if (res)
    {
        res->read_proc = read_proc;
        res->data=data;
    }
   return res;
}
				
create_proc_read_entry는 쉽게 읽기용 proc파일을 만들 수 있도록 도와준다.


4.2.3절. create_proc_info_entry

static inline 
proc_dir_entry *create_proc_info_entry
(
    const char *name,
    mode_t     mode,
    get_info_t *get_info
);
				
마찬가지로 create_proc_entry의 포장함수이다.
ststic inline
struct proc_dir_entry *create_proc_info_entry
(
    const char            *name,
    mode_t                mode,
    struct proc_dir_entry *base,
    get_info_t            *get_info
)
{
    struct proc_dir_entry *res = create_proc_entry (name, mode, base);
    if (res) res->get_info = get_info;
    return res;
}
				


4.2.4절. proc_mkdir

proc파일 시스템에 디렉토리를 생성한다. 만들어 지는 디렉토리는 proc파일 시스템의 최상위 디렉토리(/proc)를 기준으로 한다.

extern struct proc_dir_entry *proc_mkdir
(
    const char *dir_name,
    struct proc_dir_entry *parent
) 
				


4.2.5절. proc_symlink

심볼릭 링크를 만들기 위해서 사용된다. 단지 실제 사용자(real user)만이 사용가능하다.

extern struct proc_dir_entry *proc_symlink
(
    const char    *file_name,
    struct proc_dir_entry *parent,
    const char    *symlink_name  
);
				


4.2.6절. remove_proc_entry

커널 모듈 프로그램밍시 celanup_module()함수에서 proc 파일을 지워주지 않을 경우 시스템에 좋지 않은 영향을 미칠 수 있다. 일단 proc를 생성했다면 프로그램 종료시 반드시 이 함수를 호출해서 proc파일을 지워주도록 하자.

extern void *remove_proc_entry
(
    const char            *name,
    struct proc_dir_entry parent
);
				


4.3절. 기타 포장 함수들

모듈 프로그래밍시 proc파일 시스템은 매우 자주 이용된다. 그러므로 이왕이면 쓰기편한 함수들이 준비되면 좋을 것이다. 여기에서 설명하는 함수들은 기존의 proc함수들을 사용하기 편하도록 포장한 함수들이다.


4.3.1절. proc_net_create

이 함수는 create_proc_info_entry의 /proc/net정보에 대한 포장함수이다. 네트워크 서브시스템에 대해서 쉽게 접근하도록 도와준다.

static inline
struct proc_dir_entry *proc_net_create
(
    const char *name,
    mode_t     mode,
    get_info_t *get_info
)
{
    return create_proc_info_entry(name, mode, proc_net, get_info);
}
				


4.3.2절. proc_net_remove

네트워크 서브 시스템에 대한 remove_proc_entry의 포장함수이다.

static inline void proc_net_remove(const char *name)
{
    remove_proc_entry(name, proc_net)
}
				


4.4절. 일반 유저와의 데이터 교환

일반 파일에서 유저와의 데이터 교환은 매우 단순하며, 별로 신경쓸 필요도 없다. 프로그램이 파일에 쓴 내용 그대로를 유저가 보며, 유저가 파일에 쓴 내용그대로를 다시 프로그램이 읽어들인다.

그러나 proc파일 시스템에서의 데이터는 실제 파일에 저장되는 것과는 달리 커널메모리에 저장된다. 알다 시피 커널메모리는 유저레벨 에서 직접 접근할 수 없다. 유저가 cat(혹은 read함수)등을 통해서 파일의 내용을 읽을려고 하면 커널에서 데이터를 유저에게 일정한 포맷으로 뿌려주게 된다. 마찬가지로 유저가 어떤 내용을 proc파일에 쓰게되면 데이터를 받아들인후 가공해서 커널메모리에 적재하게 된다.

이를 위해서 커널과 일반유저 사이에 데이터를 서로에게 전달해 주는 어떤 함수가 필요하고 이 함수가 다룰 수 있는 표준적인 자료구조가 있어야 한다. 유저가 데이터를 읽고 쓰기 위해서는 읽기와 쓰기를 위한 callback함수를 등록시켜서 사용 해야한다.

struct proc_dir_entry *entry;

entry->read_proc = read_proc_foo;
entry->write_proc = write_proc_foo;
			
위에서 처럼 pric_dir_entry에 읽기/쓰기를 위한 콜백함수를 등록하면 된다.


4.4.1절. 데이터 읽기

콜백함수로 등록되는 읽기함수는 유저영역 프로세스의 요청을 받으면 커널로 부터 데이터를 읽어들여서 알맞은 포맷으로 변경한다음 유저영역 프로세스로 되돌려준다. 읽기함수는 다음과 같은 모습을 가진다.

int read_func(char* page, char** start, off_t off, int count, int* eof, void* data);
				
읽기함수는 일어들인 정보를 page에 쓰게 된다.


4.4.2절. 데이터 쓰기

쓰기 콜백함수는 유저영역 프로세스로 부터 데이터를 받은다음 커널이 읽기에 적당한 형식으로 변경후 커널에 넘겨준다. 쓰기함수는 다음과 같은 모습을 가진다.

int write_func(struct file* file, const char *buffer, unsigned long count,
			void *data);
				
쓰기함수는 buffer로 부터 유저가 쓴 데이터를 읽어들인다. buffer는 유저 데이터 이므로 copy_from_user을 이용해서 커널메모리영역으로 데이터를 복사한다.


4.5절. Proc파일 시스템을 이용한 예제

그럼 간단한 예제를 만들어 보도록 하겠다. 예제는 일반 애플리케이션이 아닌 커널 모듈 프로그램이다. 커널 모듈프로그래밍에 대한 내용은커널 모듈 프로그래밍을 참고하기 바란다.

프로그램의 이름은 my_proc.c로 하겠다. 이 모듈은 proc파일 시스템에 myproc라는 디렉토리를 만들고 이 모듈 아래에 foo와 jiffies라는 파일을 만든다. 만약 유저가 cat등을 통해서 이들 파일을 열면 모듈은 모듈 정보를 적당한 포맷으로 만들어서 사용자에게 보여주게 된다. foo파일의 경우에는 파일에 내용을 쓸수도 있도록 되어 있어서 사용자가 내용을 바꾸면 이 내용은 모듈에서 읽어 들이게 된다.

여러분이 커널 모듈 프로그래밍에 대한 이해가 있다는 가정하에 설명은 주석으로 대신하도록 하겠다. 모듈에서 main()함수에 해당하는module_init()함수에서 차근차근 분석해나가면 좀더 쉽게 이해할 수 있을 것이다.

예제 : myproc.c

#include <linux/module.h>
#include <linux/tty.h>
#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/proc_fs.h>
#include <linux/sched.h>
#include <asm/uaccess.h>

#define MODULE_VERSION	"1.0"

// 모듈의 이름이다. 
// 이 모듈이름으로 /proc밑에 디렉토리가 생성된다. 
#define MODULE_NAME		"myproc"

// 생성된 /proc/MODULE_NAME 밑에 아래 2개의 파일이 
// 생성된다. 
#define FOO_FILE		"foo"
#define JIFFIE_FILE		"jiffies" 

#define FOOBAR_LEN 8

// foo 파일에 저장될 데이터 구조체
struct fb_data_t
{
	char name[FOOBAR_LEN + 1];
	char value[FOOBAR_LEN + 1];
};
struct fb_data_t foo_data;


static struct proc_dir_entry *example_dir, *foo_file, *jiffies_file;

// 사용자가 cat등을 통해서 /proc/[MODULE_NAME]/jiffies파일을 열면 
// 커널은 이 함수를 호출해서 해당 정보를 넘겨준다. 
static int proc_read_jiffies(char *page, char **start, off_t off,
			   int count, int *eof, void *data)
{
	int len;

	MOD_INC_USE_COUNT;
	// 사용자가 이해하기 쉬운 포맷으로 만든다. 
	// cat, vi등을 사용해서 이 파일을 열경우 
	// jiffies = 1234 와 같은 형식으로 보인다. 
	len = sprintf(page, "jiffies = %ld\n", jiffies);
	// 해당 내용을 printk를 통해서 로그로 남긴다.  
	// 이 데이터는 /var/log/message로 출력된다.
	printk("<1> read jiffies = %ld\n", jiffies);
	MOD_DEC_USE_COUNT;

	return len;
}

// 사용자가 /proc/[MODULE_NAME]/foo 파일을 열었을 때 
// 출력해주는 정보 
static int proc_read_foobar(char *page, char **start, off_t off, 
							int count, int *eof, void *data)
{
	int len;
	struct fb_data_t *fb_data = (struct fb_data_t *)data;

	MOD_INC_USE_COUNT;
	// fb_data구조체의 내용을 보시쉽게 만들어서 출력해준다. 
	len = sprintf(page, "%s = %s",
					fb_data->name, fb_data->value);
	MOD_DEC_USE_COUNT;
	return len;
}

// 사용자는 /proc/[MODULE_NAME]/foo에 내용을 쓰기를 원할때도 있을 것이다.
// 이 때 이함수가 호출된다.
static int proc_write_foobar(struct file *foke, const char *buffer,
							unsigned long count, void *data)
{
	int len;
	struct fb_data_t *fb_data = (struct fb_data_t *)data;

	MOD_INC_USE_COUNT;
	if (count > FOOBAR_LEN)
		len = FOOBAR_LEN;
	else
		len = count;

	printk("<1> DATA COPY %d\n", len);
	// echo "xxxxx" > /proc/[MODULE_NAME]/foo 등으로 입력받은 값을
	// fb_data->value에 저장한다. 
	if (copy_from_user(fb_data->value, buffer, len))
	{
		MOD_DEC_USE_COUNT;
		return -EFAULT;
	}

	fb_data->value[len] = 0x00;
	MOD_DEC_USE_COUNT;

	return len;

}

// 커널 모듈 초기화 함수
static int init_myproc(void)
{
	int rv = 0;

	printk("<1> Module Start\n");
	example_dir = proc_mkdir(MODULE_NAME, NULL);
	if (example_dir == NULL)
	{
		rv = -ENOMEM;
		printk("<1> mkdir failure\n");
		goto out;
	}

	// JIFFILE파일의 경우 단지 읽기만 허용한다.
	example_dir->owner = THIS_MODULE;
	jiffies_file = create_proc_read_entry(JIFFIE_FILE, 0444, example_dir,
									proc_read_jiffies, NULL);
	if (jiffies_file == NULL)
	{
		rv = -ENOMEM;
		printk("<1> read entry failure\n");
		goto no_jiffies;
	}
	printk("<1> OK MAKE MODULE\n");
	jiffies_file->owner = THIS_MODULE; 

	// FOO_FILE의 경우 읽기와 쓰기 모두 가능해도록 해야 하며 
	// 각각의 경우에 호출될 함수를 지정해 줘야 한다. 
	foo_file = create_proc_entry(FOO_FILE, 0644, example_dir);
	if (foo_file == NULL)
	{
		rv = -ENOMEM;
		goto no_foo;
	}

	strcpy(foo_data.name, "foo");
	strcpy(foo_data.value, "dream");

	// 커널 자료구조에 저장될 데이터 
	foo_file->data = &foo_data;
	// 읽기를 요청했을 때 호출될 함수
	foo_file->read_proc = proc_read_foobar;
	// 쓰기가 요청되었을 때 호출될 함수
	foo_file->write_proc = proc_write_foobar;
	foo_file->owner = THIS_MODULE;

	printk("<1> %s %s initialised\n", "myproc", "1.0");

	// 제대로 초기화가 이루어졌다면 0을 리턴해야 한다. 
	return 0;
	no_foo:
		remove_proc_entry(FOO_FILE, example_dir);
	no_jiffies:
		remove_proc_entry(MODULE_NAME, NULL);
	out:
		return rv;
}

// cleanup 함수
static void cleanup_myproc(void) 
{
	printk("<1> END\n"); 
	remove_proc_entry(FOO_FILE, example_dir);
	remove_proc_entry(JIFFIE_FILE, example_dir);
}

module_init(init_myproc);
module_exit(cleanup_myproc);

MODULE_AUTHOR("yundream");
MODULE_DESCRIPTION("Sanmpe proc");
			

다음은 위 프로그램을 컴파일 하기 위한 make파일이다.

Makefile

WARN    := -W -Wall -Wstrict-prototypes -Wmissing-prototypes    
INCLUDE := -isystem /lib/modules/`uname -r`/build/include    
CFLAGS  := -O2 -DMODULE -D__KERNEL__ ${WARN} ${INCLUDE}    
CC      := gcc                                 
TARGET  := my_proc 
     
my_proc.o: my_proc.c
	${CC} ${CFLAGS} -c my_proc.c 
                                     
.PHONY: clean                                                      
                                          
clean:                                    
	rm -rf ${TARGET}.o    
			

insmod를 이용해서 모듈을 올린후 cat, echo 등을 통해서 직접 테스트가 가능하다.

# echo "okok" > /proc/myproc/foo
# cat /proc/myproc/foo
foo = okok 
			
작성된 모듈프로그램의 작동상황은 /var/log/message의 내용을 확인하면 된다. 만약 syslog와 klogd가 떠있다면 tail등의 도구를 이용해서 모듈작동상황을 확인할 수 있을 것이다.


4. 모듈 파라미터 처리

모듈은 command line에서 인자들을 받을  있다인자를 모듈로 넘기기 위해서는 module_param() 매크로를 사용하여 변          .     “ insmod

hello_world_parm.ko myarg1=1같이 int형의 하나의 인자를 넘기기 위해서는 커널의 모듈 코드에 다음과 같이 선언해야 한다.

 

int myarg1 = 0

module_param(myarg1, int, 0);

 

module_parm 매크로는 변수의 이름타입, sysfs 관련된 파일의 permission 이렇게 3개의 인자를 갖는다. 인자로 배열을 넘기는 방법은 약간 다르다먼저 매크로는

module_param_array 사용하며 4개의 인자를 갖는다. 3번째 인자로 배열의 갯수를 받을  있는 변수를 추가되었다.

 

int myarg2 [4];

int count;

module_parm_array(myarg2, int, &count , 0);

 

인자의 갯수를 특별히 받고 싶지 않다면 단순히 NULL 사용하면 된다.

다음모듈의 파라미터를 설명하기 위한 MODULE_PARM_DESC() 매크로가 있다이것은 모듈을 사용하는 사람을 위해서 인자를 설명하기 위한 방법이다이것은 변수의 이름과  변수를 설명하는 문자열을 받게 된다.

 

MODULE_PARM_DESC(myarg2, "This is int array forI/O port data");

위의 모든 것을  포함해서 hello_world2 만들어 보자.

 

#include <linux/module.h>

#include <linux/moduleparam.h>

#include <linux/kernel.h>

#include <linux/init.h>

#include <linux/stat.h>

 

MODULE_LICENSE("GPL");

MODULE_AUTHOR("you");

 

static int argint = 1;

static char *argstring = "This is a string";

static int argarray[2] = { 0, };

static int size_argarray= 0;

 

 

module_param(argint, int, S_IRUSR | S_IWUSR |

S_IRGRP | S_IWGRP);

MODULE_PARM_DESC(argint, "A short integer");

module_param(argstring, charp, 0000);

MODULE_PARM_DESC(argstring, "A character string");

module_param_array(argarray, int, &size_argarray,

0000);

MODULE_PARM_DESC(argarray, "An array of

integers");

 

 

static int __init hello_init(void)

{

int i;

printk(KERN_EMERG "argint : %d ", argint);

printk(KERN_EMERG "argstring : %s ", argstring);

for (i = 0; i < (sizeof (argarray) / sizeof (int)); i++)

{

printk(KERN_INFO "argarray [%d] : %d ", i,

argarray [i]);

}

printk(KERN_INFO "argarrary size : %d ",size_argarray);

return 0;

}

static void __exit hello_exit(void)

{

printk(KERN_EMERG "Goodbye, world ");

}

module_init(hello_init);

module_exit(hello_exit);

 

 

위의 코드를 컴파일   실행하기 전에 modinfo 통해 모듈의 정보를 확인해보자.

 

root@barrios-desktop:~/example/module2# modinfo

hello_world.ko

filename: hello_world.ko

license: GPL

author: you

vermagic: 2.6.18 SMP mod_unload 586 REGPARM gcc-4.1

depends:

srcversion: 300231DCA83E809D0F54644

parm: argarray:An array of integers (array of int)

parm: argstring:A character string (charp)

parm: argint:A short integer (int)

 

 

위와 같이 이전에 비하여 많은 정보들이 출력되는 것을  수 있다 중에는 여러분들이 파라미터를 설명하는문자열도 출력된다이번에는 모듈을 로드해보자무엇이 출력되는가?

 

root@barrios-desktop:~/example/module2# insmod

hello_world.ko argint=100 argstring="hey"

argarray=100,200

여러분들의 예상이 맞는가?


출처 : http://www.linux.co.kr/home2/board/bbs/board.php?bo_table=lecture&wr_id=1640&sca=1&sca2=32

spinlock_t - SpinLock을 위한 자료구조

 

spin_lock(slp) - SpinLock을 획득

 

spin_unlock(slp) - SpinLock을 해제

 

spin_lock_init(slp) - SpinLock을 해제된 상태로 초기화 

 

spin_trylock(slp) - SpinLock을 획득하기위해 시도를 하고, 성공하면 1, 실패하면 0을 돌려줌 

 

spin_unlock_wait(slp) - SpinLock이 풀릴 때까지 기다린다. 

 

spin_lock_irq(slp) - 인터럽트를 금지시키고, SpinLock을 획득

 

spin_unlock_irq(slp) - SpinLock을 해제하고, 인터럽트금지를 해제 

 

spin_lock_irqsave(slp, flags) - 인터럽트플래그를 저장하고, 인터럽트를 금지하고, SpinLock을 획득 

 

spin_unlock_irqrestore(slp, flags) - SpinLock을 해제하고, 인터럽트플래그를 복구하며, 인터럽트금지를 해제 

 

 

어디서 가져온 자료인지 기억이 안나요...ㅜ..ㅜ

죄송합니다..;;

출처 : http://blog.naver.com/wjdguddnr00?Redirect=Log&logNo=20018016177

SpinLock이란?

Spin Lock 은 이름이 뜻하는대로, 만약 다른 스레드가 lock을 소유하고 있다면 그 lock이 반환될 때까지 계속 확인하며 기다리는 것이다.

Spinlock은 다음과 같은 특성을 갖는다.

  1. Lock을 얻을 수 없다면, 계속해서 Lock을 확인하며 얻을 때까지 기다린다. 이른바 바쁘게 기다리는 busy wating이다.
  2. 바쁘게 기다린다는 것은 무한 루프를 돌면서 최대한 다른 스레드에게 CPU를 양보하지 않는 것이다.
  3. Lock이 곧 사용가능해질 경우 컨택스트 스위치를 줄여 CPU의 부담을 덜어준다. 하지만, 만약 어떤 스레드가 Lock을 오랫동안 유지한다면 오히려 CPU 시간을 많이 소모할 가능성이 있다.
  4. 하나의 CPU나 하나의 코어만 있는 경우에는 유용하지 않다. 그 이유는 만약 다른 스레드가 Lock을 가지고 있고 그 스레드가 Lock을 풀어 주려면 싱글 CPU 시스템에서는 어차피 컨택스트 스위치가 일어나야하기 때문이다

 출처 : http://devnote.net/wiki/index.php/Spinlock

즉, 멀티코어CPU 환경에서 Lock을 소유하고 있는 시간이 매우 순간일 경우에 Critical Section이나 Mutex대신에 사용하면 더욱 좋은 성능을 기대 할 수 있다.


SpinLcok 구현

01.class SpinLock
02.{
03.private:
04.static size_t const ms_NonSleepLoopCount = 1000000;//Sleep을 사용하지 않고 Lock을 체크하는 갯수 설정
05.LONG volatile    m_lOwnThreadID;//현재 Lock을 소유한 thread id
06. 
07.public:
08.SpinLock():m_lOwnThreadID(0){}
09.~SpinLock(){}
10. 
11.void Lock()
12.{
13.LONG lThreadID = static_cast<LONG>(::GetCurrentThreadId());
14. 
15.size_t loop = 0;
16.LONG lCompareID = 0;
17.while ( lCompareID != ::InterlockedCompareExchange(&m_lOwnThreadID, lThreadID, lCompareID) )
18.{// Lock을 소유할 수 없는 경우에 Loop를 돌면서 계속해서 체크
19.if ( loop > ms_NonSleepLoopCount )
20.{
21.::Sleep(0);// Sleep
22.}
23.else
24.{
25.++loop;
26.}
27.}
28.}
29. 
30.void UnLock()
31.{
32.LONG lThreadID = static_cast<LONG>(::GetCurrentThreadId());
33.LONG Exchange = 0;
34.LONG lRet = ::InterlockedCompareExchange(&m_lOwnThreadID, Exchange, lThreadID);
35.assert( lThreadID == lRet );
36.}
37.};

Lock을 걸때는 ::InterlockedCompareExchange를 이용하여 현재 소유한 threadid가 없을경우 내threadid로 설정을 시도한다.
내 threadid로 설정을 하지 못하면 계속해서 loop를 돌면서 시도를 한다.
이 때, loop를 너무 오랜시간 동안 돌면 오히려 성능이 나빠질 수 있으니, 적절히 Sleep를 사용할 수 있도록 한다.
(loop 를 돌때마다 Sleep을 사용한다면 컨택스트 스위칭이 일어나 SpinLock이 무용지물이 될 가능성이 많다)

UnLock 에서는 소유한 threadid를 해제시켜주기만 하면 된다.

위의 소스에서는 Recursive Call을 할경우에 DeadLock이 걸린다.
Recursive Call을 지원하기 위해 아래와 같이 수정하였다.

01.class SpinLock
02.{
03.private:
04.static size_t const ms_NonSleepLoopCount = 1000000;//Sleep을 사용하지 않고 Lock을 체크하는 갯수 설정
05.LONG volatile    m_lOwnThreadID;//현재 Lock을 소유한 thread id
06.int m_iRecursiveLockCount;//Recursive Call을 한 횟수 기록
07. 
08.public:
09.SpinLock():m_lOwnThreadID(0), m_iRecursiveLockCount(0){}
10.~SpinLock(){}
11. 
12.void Lock()
13.{
14.LONG lThreadID = static_cast<LONG>(::GetCurrentThreadId());
15. 
16.// 현재 소유 threadID가 호출 threadID와 같으면 Recursive Call Count 만 증가
17.if ( m_lOwnThreadID == lThreadID )
18.{
19.++m_iRecursiveLockCount;
20.assert( m_iRecursiveLockCount > 0 );
21.return;
22.}
23. 
24.size_t loop = 0;
25.LONG lCompareID = 0;
26.while ( lCompareID != ::InterlockedCompareExchange(&m_lOwnThreadID, lThreadID, lCompareID) )
27.{// Lock을 소유할 수 없는 경우에 Loop를 돌면서 계속해서 체크
28.if ( loop > ms_NonSleepLoopCount )
29.{
30.::Sleep(0);// Sleep
31.}
32.else
33.{
34.++loop;
35.}
36.}
37.}
38. 
39.void UnLock()
40.{
41.LONG lThreadID = static_cast<LONG>(::GetCurrentThreadId());
42. 
43.// Recursive Call Count가 있으면 감소만 함
44.if ( m_iRecursiveLockCount )
45.{
46.assert(m_lOwnThreadID == lThreadID);
47.--m_iRecursiveLockCount;
48.return;
49.}
50. 
51.LONG Exchange = 0;
52.LONG lRet = ::InterlockedCompareExchange(&m_lOwnThreadID, Exchange, lThreadID);
53.assert( lThreadID == lRet );
54.}
55.};

성능 테스트

그럼 이제 실제로 Critical Section과 SpinLock의 성능 차이를 테스트 하였다.
(테스트 방법에 따라 결과가 달라질 수 있음)

  - 테스트 환경 : 듀얼코어 CPU
  - 방법 
    1) std::map<int,int>을 하나 생성해서 1~1000000까지 키를 입력
    2) 각 쓰레드는 1~1000000까지 루프를 돌면서 map에서 find실행 이때, find한번당 Lock, UnLock을 호출하며, 루프가 종료되는데 걸린 시간을 측정
          for ( int iFind=0; iFind<1000000; ++iFind)
         {
          // Lock
              std::map<int, int>::const_iterator itr = g_map.find(iFind);
          // UnLock
          }
    3) 쓰레드 3개를 만들어서 결과 측정


측정결과는 예상대로 Critical Section을 사용하는 것 보다 SpinLock을 사용하는 것이 성능향상이 있었으며,
성 능향상율은 평균 20%정도나 되었다.

criticalsection.png
< Critical Section을 사용했을 때>

spinlock.png
< SpinLock을 사용 했을 때 >


출처 : http://yonmy.com/xe/blog/646


+ Recent posts