메뉴 바로가기 검색 및 카테고리 바로가기 본문 바로가기

한빛출판네트워크

한빛랩스 - 지식에 가능성을 머지하다 / 강의 콘텐츠 무료로 수강하시고 피드백을 남겨주세요. ▶︎

IT/모바일

저자에게 물어보세요: 알레산드로 루비니 & 조나단 코벳

한빛미디어

|

2001-07-19

|

by HANBIT

9,118

By 알레산드로 루비니 & 조나단 코벳, Linux Device Drivers, 2nd Edition의 공저자 이번에 출간된 Linux Device Drivers, 2nd Edition의 공동 저자인 알레산드로 루비니(Alessandro Rubini)와 조나단 코벳(Jonathan Corbet)이 도서 관련 독자의 질문 중 몇 개를 선택하여 답한 내용을 소개한다. Linux Device Drivers는 독자가 직접 컴파일하고 운영할 수 있는 예제를 들면서, 문자 디바이스, 블록 디바이스, 네트워크 인터페이스를 위한 드라이버를 작성하는 방법을 단계적으로 보여 준다. 2판에서는 커널 2.4를 다루며, 새로운 플랫폼을 비롯해 대칭형 다중처리(SMP), 범용 직렬 버스(USB) 등을 첨가했다. 질문: Linux Device Drivers와 곧 출간될 2판이 프로그래머가 디바이스 드라이버를 처음으로 코딩하는 데 가장 적합한 책임은 분명합니다. 그러나 프로그램을 잘 하려면 리눅스가 동작하는 원리를 전체적으로 이해해야 한다고 봅니다. 이 책을 쓰는 데 필요한 모든 정보와 지식을 어디에서 어떻게 습득했습니까? 리눅스의 내부 동작 원리나 구조를 깊이 알고 있지 못한 프로그래머에게 충고나 팁, 혹은 제안을 하신다면요? 어디에서부터 시작하는 게 좋을까요? - 클라우스 엑스트로엠(덴마크, 코펜하겐) 알레산드로: 사실 저는 소스 코드를 공부하면서 커널 프로그램을 배웠습니다. 현재는 프로그래밍에 대한 기본적인 문화와 C 언어, C 유지 능력(maintainability)에 관한 좋은 방책 같은 것을 잘 알고 있습니다. 그리고 한동안은 유닉스를 사용해서 프로그래밍하기도 했습니다.
Linux Device Driver, 2nd Edition
커널의 새로운 부분을 공부할 때 자주 사용한 툴은 이맥스(Emacs)와 연계된 grep과 etags였죠. 우선은 여러 명령행에 이 두 가지 툴을 사용했습니다. 물론 모든 코드가 잘 작성되지는 않았지만, 시스템의 핵심은 괜찮았습니다. 그래서 제 개인적으로는 소스 코드를 읽는 게 커널을 디자인하고 작동하는 원리를 익히는 가장 좋은 방법인 것 같습니다. 웹에 커널 소스 트리에 관해 많은 자료가 있긴 하지만, 전 웹 인터페이스에선 능숙하게 작업을 못 합니다. 이러한 내용(웹 인터페이스에 대한 포인터도 포함)은 Linux Device Drivers, 2nd Edition의 서문에 자세히 실었습니다. 조나단: 기본적인 지식은 대학에서 거의 다 배웠고(수년 전에), 개인적으로도 수많은 운영체제의 소스를 연구했습니다. 리눅스를 놓고 보자면, 가장 좋은 자원은 소스라는 알레산드로의 말에 찬성합니다. 소스 트리는 광범위한 문서를 담고 있거든요. 소스 트리의 조직은 뭔가가 빠진 듯 하지만, 이 디렉토리에는 유용한 정보가 아주 많습니다. 참, 오라일리의 Understanding the Linux Kernel에도 커널이 동작하는 원리에 대한 유용한 정보가 많습니다. 그리고 막 시작하려는 입문자에게는 Kernel Newbies Web site를 추천합니다. 질문: 수 천명에 달하는 해커가 Linux Device Drivers를 보고 많은 도움을 받았듯이, 2판이 출간되면 큰 인기를 끌 겁니다. 디바이스 드라이버를 개발할 때 어떤 디버깅 전략을 염두에 두고 하는지요? - 청 요 키(말레이시아, 콸라룸푸르) 알레산드로: 개인적으로는 코딩할 때 되도록 깔끔하게 하려고 노력하며(물론 다른 사람들도 그렇겠지만), 드라이버의 레벨에 상관없이, 개인 레지스터까지 사용자공간(user-space) 액세스를 제공하도록 합니다. 항상 드라이버를 상향식(bottom-up)으로 작성하는데, 추상화(abstraction)의 각 단계를 확실히 한 다음, 위 계층으로 이동합니다. 그 후에 문제가 발생하면, 모든 단계에서, 하드웨어 레지스터에서 추상적인 데이터 구조에 이르기까지 디바이스와 드라이버 상태를 검색할 수 있습니다. 사용자공간은 드라이버에서 /proc를 읽거나, 특정 목적의 디바이스 엔트리 포인트를 열거나, 혹은 ioctl()를 호출해서 볼 수 있습니다. 저의 경우에는 여러 명령행 툴을 가지고 있다가 다양한 ioctl() 명령을 호출합니다. 최근에는 두 가지 모듈을 작성하면 어떨까 하는 생각이 떠올랐습니다. 하나는 필요한 드라이버 특성이 있는 것이고, 다른 하나는 실제 드라이브 위에 스택해서 모든 디버깅 및 디깅 지원을 첨가하는 거죠. 조나단: 드라이버를 작성하거나 봉급 명부 시스템을 작성하건 간에, 코드를 중심으로 생각하는 게 최선의 디버깅 전략입니다. 그리고 저는 뭔가가 잘못되면, 코드가 저에게 말해 주는 걸 좋아합니다. 그러니까 자주 이상이 없는지 체크하도록 만든다는 겁니다. 체크를 잘 설정해 주면 소스와 인접한 캐치 문제를 해결할 수 있지만, 레지스터 덤프에서는 별로 유용하지 않습니다. "안정적인" 배포 후에는 유용성이 증가합니다. 어떤 것을 망가뜨리게 변경하기라도 하면, 코드가 바로 알려 주는 거죠. 책을 쓸 때, 샘플 드리이버로 작업해 보면서 디버깅 툴로는 사용자모드 리눅스(User-Mode Linux)가 맘에 들었습니다. 독립된 사용자 프로세스로 커널을 구동할 수 있으며, gdb를 사용할 수도 있습니다. 아직은 다소 전문적인 디바이스 드라이버 디버깅에 필요한 하드웨어 접근 지원이 부족하긴 하지만, 점점 좋아지고 있습니다. 질문: 여러 인터페이스에 연결되는 (말하자면, USB와 IR 둘 다) 하나의 디바이스를 작성할 때, 각각의 모드에 드라이버를 따로 작성해서 코드를 재사용하는 게 나을까요, 아니면 접속하거나 자기 검색(self-detecting)할 때 수동으로 설정해 줘야 하는 하나의 드라이버를 작성해서, 하나의 모듈에 있는 모든 공통 코드를 결합하는 게 더 현실적일까요? - 폴 헨드릭(텍사스, 칼리지 스테이션) 알레산드로: 제 생각에는 드라이버를 두 부분으로 분리하는 게 나을 것 같군요. 실제 디바이스를 컨트롤하는 백엔드(back-end)와 커널에 연결하는 프론트엔드(front-end) 부분으로 말입니다. 하지만 드라이버를 사용자에게 전달(deliver)하는 방법에 대해서는 정확히 뭐라고 말할 수가 없습니다. N+1 모듈을 전달하는 게 맞는 것 같지만(N이 프론트엔드의 수일 때) , 하나의 모듈을 전달하는 것도 역시 맞는 것 같네요. PCI-또는-ISA 디바이스에서는 하나의 모듈을 전달하는 게 낫지만 USB-또는-IrDA 디바이스에서는 다릅니다. USB의 사용자는 커널에 컴파일된 IrDA 지원이 없어서 insmod가 실패할 것이기 때문입니다. N 모듈이 모두 백엔드 코드를 포함할 때에는 N 모듈을 생성하는 것도 한 방법입니다. 이 때 링커(linker)를 잘 사용하면 정말 도움이 되죠. 프론트엔드와 백엔드 사이에 교차참조(cross-reference)를 허용하면 더욱 큰 이점을 얻을 수 있습니다. 만약 서로 별개의 모듈이라면, 하나의 모듈만이 다른 모듈에 의존하도록 해야 합니다. 방법은 여러 개가 있으니까 문제의 특정 인스턴스에 따라 가장 좋은 방법을 사용하면 됩니다. 조나단: 저 역시 일반적인 상황을 고려해서 대답하는 건 힘듭니다. 특정 경우에 한해서 살펴 봐야 할 겁니다. 이 문제를 놓고 보면, 우선 디바이스에 기본적인 접근을 제공하는 분리된 저급(low-level) 드라이버를 작성합니다. 그리고는 각각의 모듈에 공통 코드를 넣습니다. 사용자공간에서 이 모듈을 구동할 수도 있겠네요. 질문: 커널에서 부동소수점(floationg-point) 연산을 사용한다고 알고 있습니다. 그런데 저는 인터럽트 과정에서 부동소수점 연산이 필요합니다. 인터럽트 루틴이 적절한 fsave/frestor 명령을 사용한다고 가정하면, 이의 결과는 어떻게 나옵니까? - 사이먼 뮨튼(영국, 배스) 조나단: 인터럽트 서비스 루틴에서는 부동소수점 연산을 사용하지 않는 게 좋습니다. 부동소수점 단위를 다루는 게 레지스터를 저장 및 재저장하는 것보다 훨씬 복잡합니다. 커널은 정교하며 "안일한" 매커니즘을 가지고 있어, 꼭 필요한 경우가 아니라면 현재의 상태를 저장 및 재저장하지 않습니다. 그래서 부동소수점 연산을 사용하게 되면, 뜻밖의 프로세서 예외가 발생하게 되는 겁니다. 어쩔 수 없이 부동소수점을 사용해야 한다면, 코드를 잘 알아야 하고 이 코드가 어떻게 작동하는지 정확히 이해해야 합니다. 그래도 솔루션은 여전히 아키텍처에 의존적이며, 앞으로 나올 커널 버전에서는 불안정하게 될 겁니다. 질문: 커널에서는 사용할 수 있는 스택 공간이 제한되어 있습니다. 이의 이유는 무엇입니까? 사용 공간을 늘릴 수 있습니까? 커널 스레드에도 스택 공간이 제한됩니까? - 사이먼 뮨튼(영국, 배스) 알레산드로: 현재는 자동으로 스택 크기를 증가할 수 있는 지원이 없지만, 별로 필요하지도 않습니다. 이유는 단순합니다. 바로 페이지 폴트가 커널 코드용으로는 처리될 수 없어서 커널 스택이 자동으로 증가하지 않기 때문입니다. 그래서 커널 스택은 자동으로 각 프로세스에 배치해야 하므로, 크기를 작게 하는 게 낫습니다. 처리 과정에서 로컬 변수를 위해 더 많은 스택이 필요한 경우에는, 스택에 사용자의 배열/구조에 대한 포인터만을 유지하면서, 필요한 메모리를 배치한 다음에 릴리즈하는 게 현명합니다. 물론 커널 스레드도 하나의 프로세스이긴 하지만, 사용자공간 메모리 매핑은 없습니다. 가지고 있는 유일한 스택은 커널 스택으로, 어느 정도의 한계가 있습니다. 그러므로 실제 작업은 가능한 한 사용자 공간에서 해야 할 겁니다.
TAG :
댓글 입력
자료실

최근 본 상품0