2008년 11월 18일 화요일

pthread와 condition variable

일단 pthread관련한 전반적인 내용은 ...

https://computing.llnl.gov/tutorials/pthreads/#Thread


pthread가 제공하는 조건 변수 관련 함수들(pthread_cond_wait, pthread_cond_signal etc.)을 제공하는 이유는 무엇일까 ?

이를 이해하기 위해서 반대로 조건 변수를 사용하지 않을 경우 어떤 불편이 있는지 살펴보자.

while(1)
{
 pthread_mutex_lock(&mutex_test);
 if(cond_var>=condition)
 {
  do_something();
  cond_var--;
  pthread_mutex_unlock(&mutex_test);
  break;
 }
 pthread_mutex_unlock(&mutex_test);
};

위 코드는 조건 변수를 확인하기 위해서 계속적으로 CPU를 소모하며 polling을 해야 하므로 효율적이지 못하다. pthread_cond_xxx를 사용하면 아래와 같이 개선할 수 있다.

1: pthread_mutex_lock(&mutex_test);
2: while(cond_var < condition)
3:  pthread_cond_wait(...);
4: do_something();
5: cond_var--;
6: pthread_mutex_unlock((&mutex_test);

- Line 1에서 mutex lock.
- Line 3에서는 아래와 같은 일들이 벌어진다.
- mutex unlock
- pthread_condition_signal이나 pthread_condition_broadcast가 호출될 때까지 block
- mutex lock
- Line 4,5 실행
- Line 6에서 mutex unlock.

Line2에서 if대신 while을 사용한 것에 주목할 필요가 있다. 이는 pthread_conditon_wait가 여러 thread에서 호출하였을 경우 먼저 스케쥴된 thread에서 cond_var--이 실행되기 때문에 나중에 스케쥴된 thread를 다시 재우기 위함이다.

2008년 11월 5일 수요일

vim, ctags, cscope사용법 정리.

VI 설정.


Home directory아래 .vimrc 파일을 아래와 같이 설정


set number :
line number를 왼쪽에 보여줌.
set cindent :
c 스타일의 indent. 예를들어 여는괄호, 닫는 괄호 인덴트가 자동화됨
set smartindent :
정확히 어떤 똑똑한 인덴트 기능이 추가되는지 파악 못함
set ts=4 :
tab key눌렀을때 스페이스 4칸 만큼 떨어짐.
set sw=4 :
자동 인덴트시 스페이스 4칸 만큼 인덴트됨.
set ruler :
오른쪽 하단에 현재 커서 위치(좌표) 표시
syntax on:
syntax highlight(coloring)기능을 켬
set tags=tags :
태그 파일 설정. 오른쪽 tags는 vi를 실행시킨 디렉토리(current directory)의 tags란 파일을 의미함.
cs add cscope.out :
cscope파일 설정
source $HOME/cscope_maps.vim
cscope단축기 설정. cscope_map.vim은 "http://cscope.sourceforge.net/cscope_maps.vim"에서 다운 받을 수 있다.


vim에서 ctag및 cscope를 사용하기 위해서 해야 하는 일들.


find . -name *.[chsCHS] -print > cscope.files

cscope -b -i cscope.files

ctags -R .



> cscope의 -b 옵션을 주면 cscope.out파일만 생성되고 종료. -b 옵션이 없으면 cscope자체가 실행됨.
> cscope의 -i 옵션으로 입력파일 이름리스트가 있는 파일을 지정할 수 있음. -i옵션 없으면 default로 cscope.files를 사용하므로 위 예제에서는 -i 옵션이 굳이 필요 하지 않음.




vim에서 cs(cscope) 명령이 동작 하지 않는다면..

:ver 를 실행하여 +cscope인지 -cscope인지 확인할 것. -cscope면 +cscope로된 vim바이너리를 구하던지 vim을 직접 compile하여야 함. vim소스를 구했다면 일반적으로 --enable-cscope 옵션을 주고 컴파일하면 됨.


vim에서 cs 사용 법.
:cs find s symbol_name


cscope_maps.vim 설정을 사용하면 Cntl-'\' 단축기를 사용할 수 있다.



0 or s : (Cntl-'\' + s)
C 심볼중 검색
1 or g : (Cntl-'\' + g)
symbol_name의 정의를 점색
2 or d: (Cntl-'\' + d)
symbol_name에 해당하는 함수에 의해 호출되는 함수를 검색
3 or c: (Cntl-'\' + c)
symbol_name에 해당하는 함수를 호출하는 함수를 검색
4 or t: (Cntl-'\' + t)
symbol_name에 해당하는 text문자열을 검색
6 or e: (Cntl-'\' + e)
확장 정규식을 사용하여 symbol_name를 검색

7 or f: (Cntl-'\' + f)
파일이름중에서 symbol_name를 검색

8 or i: (Cntl-'\' + i)
symbol_name를 include하는 파일을 검색.









vim에서 아래와 같이 help를 불러올수 있다.


:help cscope




더 많은 내용이 필요할 경우에는...
http://wiki.kldp.org/wiki.php/VimCscopeTutorial

2008년 10월 9일 목요일

fopen 옵션 정리

fopen의 파일 열기 옵션은 좀처럼 제대로 외우기가 쉽지 않다. 또한 모든 옵션별 차이점을 제대로 파악하기도 쉽지 않고... 일단 파악된 만큼 정리해 놓고... 추후 더 발견된 사항이 있으면 지속적으로 update해 나가는게 좋을 듯..

"r" : 읽기 전용 모드. 파일이 없으면 NULL return.
"w" :쓰기 전용 모드. 파일이 없으면 생성되고 있으면 내용이 없어진다.
"a" : append모드. 파일이 없으면 생성. 이미 존재하는 파일 끝부분에 file pointer가 위치하게 되며 이 위치부터 뒷쪽으로만 write가능. 읽기는 불가능. fseek등으로 이 부분보다 앞으로 file pointer를 이동시키면 어떻게 될까 ? 아래 내용으로 봐서는 fseek등으로 file pointer를 이동하여도 이와 상관없이 파일 끝부분에 write가 되는 것으로 생각됨.

Opening a file in append mode (a in the mode) causes all subsequent writes to the file to be forced to the current end-of-file, regardless of previous calls to the fseek() function.

"r+" : 읽고 쓰기 모드, 파일이 없으면 NULL return.
"w+" : 읽고 쓰기 모드 단, 파일이 없으면 만들고 있으면 기존 내용을 지움. write를 먼저 한 후 동일 파일 포인터로 읽기 수행이 필요한 경우 사용. 보통은 읽기 전용, 혹은 쓰기 전용으로 fopen하므로 w+가 필요한 일은 별로 없을 듯.
"a+" : append모드, 읽고 쓰기 가능. 파일이 이미 존재할 경우 그 파일의 끝부분에서부터 추가된 내용을 쓴다. 읽기는 fseek로 지정한 file pointer위치에서 가능하나 쓰기는 파일 끝부분에서만 가능.

When a file is opened with update mode (+ in the mode), both input and output may be performed on the associated stream

2008년 10월 6일 월요일

C에서 C++ 함수 호출하는 방법

많이 발생하는 경우는 아니지만, C에서 C++ 함수의 호출이 필요한 경우가 있다. 이런 경우에는 아래와 같은 방법으로 C++ 함수를 호출하여 사용할 수 있다.

먼저 호출하고자하는 함수를 extern "C"로 감싼다. 하지만 호출하고자 하는 함수가 클래스의 메소드일 경우에는 해당 메소드를 C 스타일의 전역 함수로 감싸야(wrapping) 한다.

//In the cpp file.
extern "C" void func_in_cpp(void);
...
extern "C"
{

 void func_in_cpp(void)
 {
  class_type class_obj_name;
  class_obj_name.class_method1();
 }
}

/* In the C file */
int main(void)
{
 ...
 func_in_cpp();
 ...
 return 0;
}

위에서와 같이 extern "C"로 선언/정의된 함수에서도 class의 instance를 만들고 사용할 수 있다. 즉 위에서와 같이 glue I/F를 만들어 주고 이를 C 프로그램에서 호출함으로써 C++ 코드안의 함수를 호출할 수 있다. 단 여기서 실행파일 생성 시 주의할 점이 있다.

glue I/F (cpp파일)나, C++ 라이브러리는 compile시 당연히 C++컴파일러로 컴파일한다. (ex. g++사용, gcc를 사용해도 확장자를 인식해 g++로 컴파일 될 것임.)

g++ -c cppfile.cpp

C++ 함수를 호출하는 C 프로그램은 당연히 C 컴파일러로 컴파일 한다. (ex. gcc 사용)

gcc -c cfile.c

마지막으로 link시 C++ library가 link되도록 옵션을 설정하여야 한다.
gcc의 경우, gcc대신 g++을 사용하여 link하면 간단하게 해결된다.

g++ -o c_application cfile.o cppfile.o

하지만 빌드 tool chain에 따라서 이를 별도의 linker옵션으로 설정해야 하는 경우도 있다.
아래는 QNX tool chain에서 제공하는 링커의 옵션을 사용한 경우의 예이다.

qcc -lang-c++ -o c_application cfile.o cppfile.o

여게서 -lang-c++은 linker옵션으로 linker에게 c++ library를 사용해야 한다고 알려준다.
gcc대신 g++을 사용해서 c++ 링커 옵션을 대신할 수 있듯이 QNX 툴도 qcc대신 QCC를 사용하면 c++ 옵션을 대신할 수 있다. 하지만 대소문자 구분이 되지 않는 Windows환경을 host 컴퓨터로 사용하고 있다면 QCC를 제대로 인식하지 못할 것이다. 이런 경우 -lang-c++을 사용해야 한다.

C에서 C++함수를 호출할 때는 몇가지 주의 사항이 있다. 이에 대한 자세한 내용은 "BINARY HACKS 해커가 전수하는 테크닉 100선, 타카바야시 사토루외 4인, O'REILLY ****" 에서 찾을 수 있다.

2008년 3월 14일 금요일

awk 사용하기 - 1

awk는 개발자의 삶을 편안하게 해주는 툴이다. 사용자가 얼마나 창의적으로 사용하는가에 따라서 여러가지 목적으로 사용될 수 있기 때문에, 사용법보다 응용법이 더 중요하다. 우선 사용법이 잘 정리된 사이트를 소개한다.

http://www.4ellene.net/tt/1087


아래는 개인적으로 개발시 많이 사용하는 사용예이다.

make | awk '{for(i=1;i<=NF; i++) print $i }'


큰 규모의 프로그램을 컴파일할 때는 컴파일 및 링크 옵션이 매우 복잡하고 파일 경로가 길 경우 화면에 출력되는 로그의 양이 엄청나다. 따라서 자칫 makefile에 옵션을 잘못 넣어도 이를 찾아내기도 어렵고, 컴파일 에러가 발생해도 바로 문제 위치를 찾기 어렵다. 이럴 때 위와 같이 사용하면 출력되는 로그가 공백을 기준으로 줄바꿈되며 정렬된다.

아래는 위 옵션 이 없이 make했을때의 결과이다.
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
gcc -c -DSPIDER_AP -DVER1 -DCOBRA_AP -DAR
5315 -DFREEDOM_AP -ID:/io-pkt/core_networ
king/stage/usr/include -IC:/QNX632/target
/qnx6/usr/include -I../common/include -Ii
nclude -I../../../../src/dk/mdk/client/co
bra/soc_linux/include -c -V3.3.5,gcc_ntop
pcbe -O2 -I. -I../../../include -I../mdk
-I../devmld -DMAUI -I../../../../src/dk/m
dk/client/soc_linux_driver/include -D:/Av
inashWork/AP61_LinuxART_v53b59/releases/l
inuxsrc/src/802_11/madwifi/madwifi/ath -I
D:/AvinashWork/AP61_LinuxART_v53b59/relea
ses/linuxsrc/src/802_11/madwifi/madwifi -
ID:/io-pkt/core_networking/trunk/sys/dev_
nda/ath_hal -DSOC_LINUX -DLinux -DQNX -DM
DK_AP -DARCH_BIG_ENDIAN -DSOC_AP -DENDIAN
_SWAP -I../devlib -I../devlib/ar5210 -I..
/devlib/ar5211 -I../devlib/ar5212 -I../de
vlib/ar2413 -I../devlib/ar6000 -I../devli
b/ar5513 -I../devlib/inis ../../../../src
/dk/mdk/common/linux_hw.c -o ../../../../
src/dk/mdk/client/cobra/soc_linux/obj/lin
ux_hw.o
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~


awk를 사용하여 정리하면 다음 처럼 정렬되어 보인다.

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
gcc
-c
-DSPIDER_AP
-DVER1
-DCOBRA_AP
-DAR5315
-DFREEDOM_AP
-ID:/io-pkt/core_networking/stage/usr/inc

lude
-IC:/QNX632/target/qnx6/usr/include
-I../common/include-Iinclude
-I../../../../src/dk/mdk/client/cobra/soc

_linux/include

(중략)

-I../devlib/ar5513
-I../devlib/inis ../../../../src/dk/mdk/c

ommon/linux_hw.c
-o
../../../../src/dk/mdk/client/cobra/soc_l

inux/obj/linux_hw.o
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

2008년 3월 9일 일요일

종료상태 넘기기 실수담

며칠 전 디바이스의 레지스터값을 읽고 쓰는 작은 프로그램을 하나 포팅하였다. 타겟 환경은 QNX라는 유닉스 계열의 임베디드 OS였는데, 포팅이 끝난 후 프로그램의 동작 방식을 조금 수정해야 할 일이 생겼다. 원래 프로그램은 읽은 레지스터 값을 화면에 출력하고 종료하는 형태로 실행되는데, 다른 프로그램으로 읽은 레지스터 값을 넘겨주고 종료하도록 동작 방식을 바꾸어야 했다. 부모 프로그램에서 spawn( fork + exec를 합쳐놓은....)을 사용하여 레지스터 읽는 프로그램을 실행하고... 읽은 레지스터 값을 어떻게 받아올까를 잠시 고민했다. 4바이트 레지스터값을 넘기기 위해서 IPC를 사용하기가 귀찮아 간편한 방법을 고민하던 중 exit를 사용하여 프로세스 종료상태를 넘기는 대신 읽은 레지스터값을 넘기는 방법을 생각하기에 이르렀다. QNX에서 제공하는 spawn이라는 API는 P_WAIT옵션을 주면 실행된 자식프로세스가 끝날 때까지 block되어 있다가 호출한 프로세스에게 종료 상태값을 return하는 기능이 있었다. exit() API 문서에도 exit의 인자로 int형으로 명시되어 있어 spawn과 exit를 사용히면 4바이트 레지스터 값을 넘기는데 별 문제가 없어보였지만, 실제로는 잘 동작하지 않았다. 레지스터의 값이 255 이상일 경우에 읽은 레지스터 값이 종료 상태값(echo $?로 확인 가능)으로 넘어오지 않는 것이었다. exit가 int형 파라메터를 가지지만 실제로 unix계열의 OS에서 프로세스 종료 상태는 0~255사이의 값만 가진다는 것을 나중에야 알았다. (혹시 특정 계열 OS에서 255이상을 종료 상태값으로 가지는 환경이 있으면 알려주시기 바랍니다.)

2008년 3월 2일 일요일

개발자가 되기 위해 익혀야 하는 것들

개발자가 되기 위해서 노력하고 공부하는 사람들이 많지만 대부분의 사람들이 정확히 무엇을 공부해야 하는지 모른채 방황하는 경우가 많다. 여기 저기 개발 관련 사이트에 적극적으로 무엇을 공부해야 하는지 문의하는 사람도 있지만, 이에 정확한 대답을 해주기가 곤란한 경우가 많다. 묻는 사람이 정확히 어떠한 분야의 개발자가 되기를 원하는지를 정확히 하지 않으면 어떤 것을 공부해야 하는지를 구체적으로 정해주기가 어렵기 때문이다. 또한 현재 질문하는 사람의 개인적인 수준과 실력에 따라서 이에 맞는 다음 단계를 추천해야 하지만, 온라인상에서 질문하는 사람의 현 수준을 파악하는 것도 쉬운 일은 아니다.

임베디드 시스템 개발을 하는 나로써도 일반 IT분야 개발자들이 주로 어떤일을 수행하며, 어떤 공부가 필요하고, 어떤 툴을 사용하는지 잘 모르겠다. 개발 잡지를 들추어 보아도 임베디드 환경 개발자들 보다는 PC어플리케이션, 게임, 클라이언트/서버, 웹 개발등에 대한 내용이 훨신 더 많고 이제는 이런 분야에 대한 내용이 너무 낯설어 과연 이들과 내가 같은 IT분야 개발자라고 할 수 있는지 의문이 들때가 많다. 이러니 아직 자신이 무엇을 하게 될지 혹은 하려 하는지도 모르는 사람들에게 어떻게 무엇을 공부해야 하는지 알려줄 수 있겠는가 ? 하지만 이 분야에서 실력은 역시 기본기에서 나오는 것이기 때문에 결과적으로 개발자가 익혀야할 기본 항목들이 크게 차이가 나지는 않으리라 생각한다.

아래에는 내가 임베디드 개발자로써 (나의 업무를 기준으로) 꼭 필요한 것들 중 우선 언어와 개발툴 관련된 것을 정리하여 보았다.

1. C언어: 얼마전 자바에게 1위 자리(정확한 기준이 무엇인지 모르겠다. 사용자의 비율이 기준이려나?)를 내주었다는 소문이 있었지만, 역시 임베디드 환경에서는 C를 알아야 한다. C조차 제대로 못하고 입사하는 사람들이 왜이리 많은지... C는 기본중의 기본이므로 완전하게 마스터 해야 한다.
말이 기본이지 C를 제대로 이해하기 위해서는 상당한 내공이 필요하다. C의 spec.을 내부적으로 컴파일러가 어떻게 구현하는지에 대한 고민도 필요하고 단순히 C를 넘어서, 컴파일러 링커 어셈블러 등등에 대한 이해 및 사용법, make 유틸리티에 대한 이해까지... 한가지 언어 및 그에 필요한 추가적인 도구에 대한 사용법에 능숙해져 필요할 때 바로 사용이 가능해야 그 언어를 비로소 알 고 있다고 말할 수 있을 것이다. 자주 사용하지 않는 것들에 대한 방법(세부 옵션등)을 모두 외우고 있을 수는 없지만, 필요할 때 어떤 책이나 자료를 참조해서 필요한 정보를 얻을 수 있는지등은 알고 있어야 실전에서 바로 써먹을 수 있는 자신의 기술이 된다. C 언어를 안다면서 make 파일을 이해하지 못하여 다른 프로그래머가 제공한 프로젝트를 컴파일조차 못한다면 과연 C언어를 안다고 말할 수 있을까? 좀 더 나아가면, C++과 Java, C#등 C의 형제들도 어느정도 알아야 C를 제대로 이해하는데 도움이 될 것이다. C 전문가라고 말하려면 C만 알아서는 안된다.(사랑하지 않으면 떠나라 - 차드 파울러 - 문장을 조금 바꾸어 인용함) C만 아는것은 C 전문가가 아니라 단지 C만 아는 사람일 뿐이다.

2. Perl: 부끄럽고 창피하게도 나는 Perl을 C만큼 자유 자제로 다루지 못한다. 사실 Perl을 사용하여 실제로 유익한 프로그램을 작성하여 본 적도 없다. 하지만 이러한 스크립트 언어 중 한 개정도는 꼭 자유롭게 다룰 수 있도록 마스터해야 한다고 생각한다. 내가 대학 시절로 돌아갈 수 있다면 반드시 졸업전에 Perl을 꼭 마스터링 할 것이며, 지금도 당장의 필요에 의해서가 아니라 앞으로의 필요에 대비하여 틈틈히 공부하고 있다. 아무리 C를 잘해도 동일한 기능을 Perl로 구현하는 것보다 빠르게 구현하기는 쉽지 않다. 간단한 알고리즘 구현이나 선행 테스트, C로 구현한 프로그램의 Unit테스트 자동화, validation등을 위해서 꼭 배워야 하는 항목이라고 생각된다. 최근에는 파이션, 루비, 루나 등이 새롭게 각광받고 있지만 역시 아직도 가장 많이 사용되는것은 Perl이 아닐까?

3. sed/awk: 일반적 개발자의 필수 항목이라고 하기는 어렵지만, 알아두면 손발의 고생을 덜어주는 유틸리티라고 할 수있다. 사실 awk는 프로래밍 언어로 분류될 만큼 강력한 유틸리티로 주로 시스템 관리자가 시스템 관리를 목적으로 데이터를 정리할 때 사용되는 유틸리티이다. 모든 개발자에게 이런 유틸리티가 필요하다고 할 수는 없지만, 대용량 입출력 데이터(특히 텍스트로 된)를 다룬다면 꼭 배워둘 것을 권하고 싶다. 사실 하루정도만 배우고 연습해도 바로 사용이 가능할 정도로 배우기 쉽기 때문에 일단 익혀두면 죽기전에 본전은 찾을수 있을것이다. 특히 엑셀로 csv파일 데이터를 자주 정리한다면 같은 일을 sed/awk로 해보기를 권유한다.
grep이 라인단위로 원하는 패턴을 찾아서 출력해주는 유틸리티라면 sed는 grep에 편집 기능을 더했고, awk는 여기에 열단위 편집기능과 프로그래밍을 통한 편집 기능이 더해졌다고 할 수 있다.
나의 경우에 있어서, CAN통신 로그 파일과 같이 행과 열이 구분자(공백이나 , 혹은 : )로 분리된 데이터 파일에서 특별한 값을 가지는 데이터만 필터링하여 추출할 때 awk를 사용한다. 대부분의 경우 이러한 통신 로그 파일은 GUI로 구현된 전용 분석 툴이 있어 로그를 쉽게 분석할 수 있지만, 분석 파일이 크고 갯수가 많은 경우 또는 반복적으로 동일한 분석을 수행하여야 할 경우에 awk를 사용한다면 정말 큰 시간을 절약할 수 있다. 실제로 awk를 사용하기 전에 이틀간 수행했던 일을 awk로 한시간만에 끝낸적이 있다. (물론 동일한 작업을 perl등의 스크립트 파일을 사용하여 수행할 수도 있겠다.)

4. vim 에디터 : vi와 이맥스에 대한 해묵은 우열 논쟁이 있고 한편으로는 많을 개발자들이 윈도우즈 환경의 GUI 에디터를 사용하며 코웃음을 치고 있지만 임베디드 환경에서는 vi에디터는 기본으로 알고 있어야 한다. 이는 타겟 시트템이 이맥스나 윈도우용 에디터를 못돌리는 경우에도 vi 에디터는 사용할 수 있는 경우가 많고 무엇보다 공짜/상용 에디터중에 이만한 에디터를 찾기 힘들기 때문이다. 나도 손에 익은 윈도우용 에디터가 있가 있지만, 사용 목적에 따라 vi와 윈도우용 에디터를 번갈아 사용하며, 각기 장단점이 있어 vi를 결코 버릴 수는 없을 것 같다. 윈도우용 에디터는 노력하지 않아도 60%기능은 알고 시작하지만, vi는 노력하지 않으면 사용하기가 결코 만만하지 않다. vi가 별로라고 생각한다면 아직 vi 사용을 위해 별다른 노력을 하지 않았기 때문에다. 참고로 vi를 사랑하려면 ctag와 cscope를 사용하는 방법은 꼭 익혀놓자.

5. grep : 로그 분석을 위해서 sed나 awk를 추천했지만, 로그분석보다 더 자주 해야 하는게 소스 분석이다. 사실 소스 분석을 awk로 해도 grep보다 손색이 있는 것은 아니지만, 쥐잡는데 소잡는 칼 쓸 필요는 없을 것 같다. grep과 find를 함께 사용하여 원하는 내용을 쉽게 찾는 방법은 꼭 익혀 놓자.