typedef struct {  int counter;} atomic_t;

형식은 리소스 카운터 용도로 사용한다.ATOMIC_INIT() 매크로로 값을 초기화한다.
64비트형을 따로 쓰는 아키텍처에서는 ATOMIC64_INIT()을 쓴다.
일부 아키텍처에서는 atomic_t와 atomic64_t 두 가지 형식을 제공하지만, x86 형식에서는
atomic_t만 지원한다. 대신 atomic_32.h와 atomic_64.h 헤더 파일로 나누어 32비트와 64비트
커널에 따라 정의를 달리 쓰지만, 어느 쪽이든 32비트 부호형(32bit signed) 정수로 선언하므로
사실상 같다.(i386 아키텍처는 현재 2.6.20 이상의 커널에서 쓰이지 않으며 x86으로 변경되었다. i386은 현재 심볼 링크 형태로만 그 흔적이 남아있다)
atomic_read(), atomic_set(), atomic_inc(), atomic_dec() 등의 다양한 매크로로 값을 조작한다.
접미어 _t를 붙이는 형식은 데이터 추상화(ADT, Abstract Data Type)를 위해 C 언어에서 자주 쓰는 방법이다.

typedef int atomic_t;정도로 써도 될텐데, 그렇게 하지 않는다.
struct으로 감싼 것과 아닌 것의 차이가 뭘까? typedef int로 선언하면 ++ 연산을 이용할 수 있고,
이는 설계자가 의도하지 않은 코드 작성이 된다.
이를 막고 안전하게 atomic_inc() 등으로 접근하라는 의도가 코드에 포함된 설계다.
i++이나 atomic_int(i)나 차이가 뭐가 크다고? 생각할지도 모르겠다. i++은 i = i + 1의 형태이고
 이는 값 읽어오기, 연산, 저장의 과정으로 이뤄진다.
atomic_inc()의 구현은 각 아키텍처별 어셈블리어로 되어 있다. 어셈블리 명령 단 하나로
구현하였다. CPU를 어떻게 쪼개든 어셈블리 명령 하나(보통 incl 명령)는 반드시 실행된다.
이는 CPU에서 실행할 수 있는 최소 단위(atomic) 명령이기 때문이다.

커널 2.6.22 이전까지의 코드나 2.6.22 이후 일부 아키텍처(xtensa 등)에서는 atomic_t를
volatile int로 선언한다.
typedef struct {
      volatile int counter;
}atomic_t;
이전까지는 volatile로 선언했으나 2.6.23 이후 버전은 int로만 선언한다.<Professional Linux Kernel Architecter>(Wrox, 2008)에서도 volatile int로 소개하는데, 이는 틀린 내용이다.
(책은 커널 2.6.24를 기준으로 설명한다지만, 해당 부분의 원고는 아마도 2.6.22 이하 버전일 때
작성했다고 추측한다)
volatile int가 int로 바뀐 이유는 무엇일까?
atomic_read() 동작 방식 때문이다. 컴파일러 최적화를 이용하면 레지스터에 저장된 값을
재사용하게 되고, 이는 레지스터에서 어떤 값이든 읽을 수 있음을 뜻한다.
루프를 처리하는 데 atomic_t 형식의 값을 외부 코드에서 변경하게 되면 코드는 엉망이 되고
만다. barrier()를 써서 이런 버그를 피할 수 있지만, 이는 루프에서 사용하는 모든 레지스터 값을
 다시 읽어와야 한다(reload). 이는 성능 측면에서 바람직하지 않으며, 이런 동작이 모든 아키텍처
에서 꼭 필요한 것도 아니다. 루프 안에서 barrier()를 써야 한다는 불필요한 의존성도 제거하고,
atomic_t 루프 외부에서 값을 변경할 수 있다고 생각해 버리자는 의도.



출처 : http://stnzone.com/gboard/bbs/board.php?bo_table=rss&wr_id=12696

'Linux > Kernel Programming' 카테고리의 다른 글

__builtin_constant_p  (0) 2010.08.31
asmlinkage, __attribute__  (0) 2010.03.02

WRITTEN BY
RootFriend
개인적으로... 나쁜 기억력에 도움되라고 만들게되었습니다.

,