최근에 팀을 옮기면서 리눅스 관련 일을 하게 되었습니다. ^^;;; 리눅스는 사실 MINT64 OS를 만들 때 리눅스 커널 구조를 본 게 전부라... 제가 잘 할 수 있을 까 걱정이 많이 되었는데요, 아직까지는 별 탈 없이 잘 지내고 있습니다. ^^;;;

최근에 옮긴 팀에서는 주로 리눅스 커널 관련 일을 하고 있는데요, 그러다보니 간단한 커널 모듈을 만들 일이 많아 코드를 남겨둡니다. 아래 코드는 Loadable Kernel Module 형태로 insmod를 통해 로딩되면 /dev/hello 디바이스를 생성하고 통신하는 역할을 합니다. ^^

1. 커널 모듈 소스 코드 작성 및 Makefile 작성

터미널에서 vi hello.c를 입력한 뒤 아래 코드를 붙여넣고 저장합니다.

/**
 *  본 파일은 프레임워크 예제 파일임
 */
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/miscdevice.h>
#include <linux/fs.h>
#include <linux/syscalls.h>
#include <linux/fcntl.h>
#include <linux/cred.h>

int in_use = 0;

// 모듈 정보
MODULE_LICENSE("HIDDEN");
MODULE_AUTHOR("root");
MODULE_VERSION("1.0");
MODULE_DESCRIPTION("Hello World");

/**
 *  /dev 밑에 등록한 파일을 누가 열었을 때 호출되는 함수
 */
static int my_open(struct inode *inode, struct file *file)
{
    // 해당 파일을 동시에 여러개를 열지 못하도록 하는 코드
    if(in_use)
    {
        return -EBUSY;
    }

    in_use++;
    printk(KERN_INFO "Hello Open\n");

    return 0;
}

/**
 *  /dev 밑에 등록한 파일을 누가 닫았을 때 호출되는 함수
 */    
static int my_release(struct inode *inode, struct file *file)
{
    in_use--;
    printk(KERN_INFO "Hello Closed\n");
    return 0;
}

/**
 *  /dev 밑에 등록한 파일을 누가 닫았을 때 호출되는 함수
 */
static int my_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
{
    int retval = 0;
    printk(KERN_INFO "Hello Ioctl~!!\n");
    return retval;
}

/**
 *  /dev 밑에 등록한 파일을 누가 읽었을 때 호출되는 함수
 */
static ssize_t my_read(struct file *filp, char *buffer, size_t length, loff_t *offset)
{
    printk (KERN_INFO "Hello Read~!!.\n");
    //printk (KERN_INFO "%X\n", sys_call_table);
    return 0;

    // 실제로 Read 명령을 처리하는 코드, 일단 예제로 남겨둠
    /*
    // Number of bytes actually written to the buffer
    int bytes_read = 0;

    // If we're at the end of the message, return 0 signifying end of file
    if (*msg_Ptr == 0) return 0;

    // Actually put the data into the buffer
    while (length && *msg_Ptr)  
    {
        put_user(*(msg_Ptr++), buffer++);

        length--;
        bytes_read++;
    }

    // Most read functions return the number of bytes put into the buffer
    return bytes_read;
    */
}

/**
 *  /dev 밑에 등록한 파일에 누가 썼었을 때 호출되는 함수
 */
static ssize_t my_write(struct file *filp, const char *buff, size_t len, loff_t *off)
{
    printk (KERN_INFO "Hello Write~!!.\n");
    return -EINVAL;
}

/**
 *  /dev/hello 파일 등록시 필요한 file operation 구조체
 */
static const struct file_operations my_fops = \
{
    .owner = THIS_MODULE,
    .open = &my_open,
    .read = &my_read,
    .write = &my_write,
    .release = &my_release,
    .unlocked_ioctl = (void*) &my_ioctl,
    .compat_ioctl = (void*) &my_ioctl
};

/**
 *  /dev/hello 파일 등록시 필요한 device 구조체
 */
static struct miscdevice my_device = \
{
    MISC_DYNAMIC_MINOR,
    "hello",
    &my_fops
};

/**
 *  커널 드라이버 시작 함수
 *      - 커널 드라이버가 로딩될 때 호출됨
 */
static int __init hello_init(void)
{
    printk(KERN_INFO "Hello, world\n");    

    int retval = misc_register(&my_device);
    return 0;
}

/**
 *  커널 드라이버 종료 함수
 *      - 커널 드라이버가 언로딩될 때 호출됨
 */
static void __exit hello_exit(void)
{   
    printk(KERN_INFO "Goodbye, world\n");
    misc_deregister(&my_device);
}

// 시작 함수와 종료 함수 지정 매크로
module_init(hello_init);
module_exit(hello_exit);    

코드를 다 붙여넣었으면 이제 터미널에서 vi Makefile을 입력한 뒤 아래 코드를 붙여넣고 저장합니다.

obj-m += hello.o

all:
        make -C /lib/modules/$(shell uname -r)/build M=$(PWD) modules
clean:
        make -C /lib/modules/$(shell uname -r)/build M=$(PWD) clean

Makefile을 생성한 후에 make를 입력하면 자동으로 빌드가 시작되고 다음과 같이 hello.ko가 생성됩니다.

[root@BuildMachine module]# ll
합계 244
-rw-r--r-- 1 root root    154  2월 24 09:39 Makefile
-rw-r--r-- 1 root root      0  2월 24 09:39 Module.symvers
-rw-r--r-- 1 root root    351  2월 24 09:42 hello.c
-rw-r--r-- 1 root root 112027  2월 24 09:41 hello.ko
-rw-r--r-- 1 root root    454  2월 24 09:39 hello.mod.c
-rw-r--r-- 1 root root  63104  2월 24 09:39 hello.mod.o
-rw-r--r-- 1 root root  50384  2월 24 09:41 hello.o
-rw-r--r-- 1 root root     29  2월 24 09:41 modules.order

3. 커널 모듈 시험 및 결과 확인

커널 모듈은 insmod를 이용하여 커널에 동적으로 올릴 수 있구요, rmmod를 이용하여 커널에서 내릴 수 있습니다. 그리고 로딩된 모듈의 목록은 lsmod를 이용하여 확인할 수 있습니다.

커널 모듈은 슈퍼유저(root) 권한으로만 로딩할 수 있으므로, 커널 모듈 시험 전에 root 계정으로 로그인하거나 sudo와 함께 insmod를 실행합니다. 다음은 커널 모듈을 로딩하고 삭제한 뒤 그 결과를 dmesg를 통해 확인한 것입니다. printk() 출력은 dmesg나 cat /proc/kmsg 를 통해 확인할 수 있습니다.

$>insmod hello.ko
$>ls /dev/hello -l
crw------- 1 root root 10, 57  2월 26 13:59 /dev/hello

$>chmod 666 /dev/hello           <== /dev/hello를 유저 권한으로 읽고 쓸 수 있게 만듬

4. 커널 모듈 테스트 프로그램 구현 및 빌드

커널 모듈이 정상적으로 로딩되었으니 이제 테스트 프로그램을 만들 차례입니다. ^^ 프레임워크 커널 모듈은 /dev/hello에 접근하면 메시지를 출력하게 되어있습니다. 커널 모듈 테스트 프로그램의 소스 코드는 다음과 같고 터미널에서 vi test.c를 입력한 뒤 저장합니다.

/**
 * 본 파일은 프레임워크 테스트 파일임
 */
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <fcntl.h>

int main(int argc, char** argv)
{
    int fd;

    fd = open("/dev/hello", O_RDONLY);
    if (fd == -1)
    {   
        printf("Kernel Module Open Error\n");
    }   
    else
    {   
        printf("Kernel Module Open Success\n");
    }   
    close(fd);

    return 0;
}        

저장한 테스트 프로그램의 소스코드 코드는 다음과 같이 빌드할 수 있습니다.

$>gcc -o hello hello.c

5. 커널 모듈 기능 테스트

./hello를 실행하면 테스트 프로그램이 커널 모듈이 생성한 파일을 열어서 메시지를 표시합니다. 테스트 프로그램 실행 후 dmesg나 cat /dev/kmsg를 입력하여 커널 메시지를 확인하면 정상적으로 커널 모듈이 실행되었음을 알 수 있습니다. ^^

그럼 좋은 하루 되세요 ^^

파이썬(Python) 모듈을 python으로 직접 실행하는 경우만 실행되도록 하려면 아래와 같이 if __name__ == "__main__" 으로 묶어주면 됩니다. ^^

if __name__ == ""
    print "이 부분은 python a.py와 같이 직접 실행될 때만 호출됩니다"


파이썬 코드를 작성한 뒤에 실행했을 때 SyntaxError:Non-ASCII charactor… 가 발생하는 경우는 파일의 가장 위에 아래처럼 인코딩 정보를 표시해주면 됩니다.

# -*- coding: cp949 -*-      <== 윈도우에서 기본 설정으로 저장한 파일
# -*- coding: utf-8 -*-      <== UTF8 인코딩으로 저장한 파일


자꾸 까먹어서 이제는 코드 조각들을 웹에다가 올려야겠네요. ㅠㅠ 사용하는 주 언어가 아니다보니 매번 찾아보기도 귀찮고… ㅠㅠ

그럼 좋은 하루 되세요 ^^


ps) 파이썬 소켓에 대한 정보를 원하신다면 http://docs.python.org/2/library/socket.html 를 참고하세요 ^^

C++ 언어는 해가 갈수록 많은 기능들이 추가되어 점점 생산성이 향상되는 것 같네요. 저는 C++ 언어를 제대로 이해하지 못하고 있고, 잘 쓰지도 못하는 편이라 덩치가 커지고 있는 C++이 점점 무서워지고 있습니다. ㅠㅠ


C++ 표준이 다시 제정됨에 따라 마이크로소프트의 Visual Studio를 비롯해서 여러 컴파일러에 기능들이 추가되고 있는 모양이던데… 이런 새로운 기능들을 모아 구현해놓은 부스트 라이브러리를 이용하면 구식 C++ 컴파일러를 이용하더라도 최신 C++의 기능을 사용할 수 있다고 하네요. ^^;;;


부스트 라이브러리에 대한 내용은 신영진님의 블로그에서도 보실 수 있는데, 깔끔하게 잘 정리해 놓으신 것 같습니다. 특히 마지막에 있는 PPT 슬라이드는 필요한 기능만 찾아 쓰기에 그만이네요. ^^ ASIO는 시간 날 때 한 번 써봐야겠습니다. ㅎㅎ 비동기 IO를 이렇게 쉽게 처리할 수 있다니… 좀 충격이네요. ㅎㅎ


그럼 다들 좋은 밤 되시길~

MIPS를 사용하는 기기를 만질 일이 있어서 MIPS 어셈블리어랑 구조를 볼 기회가 생겼습니다. ^^;;; 그런데… 뭐랄까요… 이게 생소한게 한 두 가지가 아니더라구요. 일단 MIPS 어셈블리어의 형태가 x86과 달라서 이해하는데 시간이 엄청 들었고… 겨우 어셈블리어로 프로그래밍을 시작했을 때 이걸 실행해 볼 수가 없어서 엄청 고민했습니다. ㅠㅠ


그런데, 이런 고민을 저만 한 게 아닌가 보더군요. ^^;;; 일반 PC 환경에서 MIPS 기기를 에뮬레이션 해주는 SPIM이라는 프로그램이 있었습니다. 다운로드는 여기에서 받을 수 있습니다. 사실 MIPS 어셈블리어 코드를 실행해보려면 컴파일러/링커와 MIPS 머신이 필요한데요, 이런 부분을 하나로 합쳐서 어셈블리어 소스 코드를 넣으면 직접 실행해줍니다. ^^


게다가 오픈 소스에 윈도우/리눅스/맥까지 지원하고 있어서 더 멋지다는~!! MIPS가 명령어도 x86 계열에 비해 단순하고, 명령어 바이트도 4바이트로 고정되어 있어서 에뮬레이터를 만들기가 좀 수월할 것 같기도 합니다. 나중에 시간이 나면 소스 코드도 한 번 훝어봐야겠네요.


ps) MIPS 어셈블리어가 궁금하다면 여기를 참고하세요 ^^

아우~ 오늘 대충 만든 테스트에 속아서 테스트 케이스만 실컷 수정하다가, 심각한 버그를 발견했습니다. ㅡ_ㅡa… 제가 지금하고 있는 일은 기존 코드에 새로운 기능을 추가하는 것인데… 기존 코드가 잘 돈다는 보장이 없어서 상당히 난감할 때가 있습니다. 사람의 심리가 그렇듯이 자기보다는 남을 더 의심하는 법이지요. 재미있는 것은 기존 사원들 역시 자신들이 만든 코드는 의심하지 않고 제 소스를 먼저 의심한다는 겁니다.

오늘도 이것 때문에 문제가 살짝 있었습니다. 저희가 수정한 프로젝트로 테스트를 진행하던 기존 사원이 프로그램이 잘 안 돈다고 뭐라고 한 것이지요. 뭐라고 한 것에 대해서는 저도 경험이 많으니(??) 이해합니다만, 자신의 코드에 일말의 의심도 안하는 것에 충격을 먹었습니다.  ^^;;;

사실 수정한 코드에 문제가 발생했을 때, 코드의 어디가 문제인가를 가장 쉽게 알아보는 방법은 동일한 케이스로 기존 코드를 테스트하는 것입니다. 만약 기존의 코드가 잘 돈다면 제가 수정한 부분에 문제가 있는 것이고, 그렇지 않다면 기존 코드 자체에 있던 버그가 밖으로 나왔다고 볼 수 있습니다. 이러한 간단한 테스트로 디버깅해야 하는 범위와 시간을 줄일 수 있는 것이지요. 하. 지. 만 그냥 테스트 프로그램이 안 돈다고 말하면서, 기존 코드를 테스트 해보자는 제 말을 살며시 일축하더군요. ^^;;;;

테스트 케이스를 처음 봤을 때, 인덱스가 잘 못 들어가는 오류가 있어서 그 부분만 수정했습니다. 하지만 이게 시작이었습니다. @ㅠ@ 인덱스를 수정했는데, 이번에는 다른 포인트에서 계속 죽는 겁니다. ㅠㅠ 혹시나 하는 마음에 원래 프로그램을 돌려봤는데, 역시나 동일한 문제가 있었습니다. ㅡ_ㅡa… 결국 기존 사원이 와서 수정하는 걸로 마무리…!!!

쩝쩝… 허접하게 작성된 테스트 케이스 덕에 심각한 버그를 찾아낼 수 있었네요. 어휴… 이 버그를 모르고 그냥 릴리즈했다가 들어 먹었을 욕을 생각하면 등골이 오싹합니다. 릴리즈하고 난 뒤는 모두 제가 덮어쓰는 거라… 더 오싹하더군요. 앞으로는 기존 소스 및 수정한 소스 모두 테스트 해봐야겠습니다.

역시 테스트는 좋은 것입니다~!!!  테스트 만세~!!!!

 옛날에 AMD 듀얼코어를 사면서 인텔 패치도 본적이 있었는데, 오늘 갑자기 생각나서 급히 정리해 놓습니다. 앞으로 XP를 얼마나 쓰게 될지는 모르겠지만, 그래도 백업을 해둬야 할 것 같아서... 듀얼 코어 패치를 하면 성능이 조금 개선된다고 하던데, 글쎄요... ^^;;; 잘 모르겠습니다.
 설치 방법은 아주 간단하고 아래와 같습니다. ^^)/~

1. 아래의 파일을 모두 받습니다.
2. WindowsXP-KB896256-v4-x86-KOR.exe 파일을 실행해서 설치합니다. 그리고 재부팅하지 않음을 선택해서 3번 단계로 넘어갑니다.
3. windowsxp_kb896256_enable-enflenfl1014.reg 파일을 더블 클릭해서 레지스트리에 병합해 줍니다.
4. 마지막으로 [시작]->[실행]->"C:\boot.ini"를 실행하셔서 맨 마지막에 /usepmtimer 를 추가해 줍니다.
[boot loader]
timeout=30
default=multi(0)disk(0)rdisk(0)partition(1)\WINDOWS
[operating systems]
multi(0)disk(0)rdisk(0)partition(1)\WINDOWS="Microsoft Windows XP Professional" /noexecute=optin /fastdetect /usepmtimer


 다들 알고계신 내용일텐데... 역시나 뒷북성 포스트를... ^^;;;

 지금까지 한 RSS 리더를 쓰고 있었습니다. 좌측에 RSS 목록이 표시되고 우측에 세부내용이 표시되는 형식이지요. 상당히 편리한 구조라고 생각합니다. ^^

 그런데 오늘 재미있는 글을 읽었습니다. RSS의 내용을 책처럼 표시해주면 어떨까하는 글이었는데, 원문은 http://naggingmachine.tistory.com/253 에서 보실 수 있습니다. 이 글을 보자마자 너무 아무생각없이 살고 있던게 아닌가 하는 생각이 들었습니다.

 물론 웹브라우저를 통해 RSS의 내용을 보니 웹브라우저의 인터페이스를 그대로 따르는 것이 자연스럽다고 생각되지만(스크롤하고 링크를 누르는...), 책처럼 표시되게 만드는 것도 그리 어렵지는 않을 것 같습니다. 최악의 방법은 화면을 한 화면 크기로 캡쳐해서 표시하는 방법도... ㅡ_ㅡa... (최악의 상황입니다. 최악.. ㅎㅎ)

 아니면 CSS를 어떻게 잘 편집해서 화면을 좌우로 분할한 다음 책처럼 표시해주는 방법도 있겠지요. ^^ 요즘 와이드 LCD를 많이 쓰니 분할하면 예쁘게 나올듯도 합니다.

 시간나면 한번 만들어봐야겠습니다. 뭔가 색다를듯 하군요. ^^)/~

 
 블로그를 순회하다보면 가끔 포스트 하단에 각종 RSS의 구독 버튼이 달려있는 것을 쉽게 볼 수 있습니다. 어떻게 하는 것인지 궁금했는데, 오늘에서야 그 비밀을 알게 됬습니다. ^^)/~
사용자 삽입 이미지

RSS 리더 구독 권유 버튼


  "리플바" 라고하는 자바스크립트더군요. ^^ http://skin.repl.net/bookbar/index.html 에 가면 각 블로그 별로 추가할 수 있는 템플릿 코드를 생성해 줍니다. 제 블로그(kkamagui.tistory.com)을 넣어서 생성하니 아래와 같은 코드가 나오더군요.
사용자 삽입 이미지

리플바 사이트


 생성된 코드는 아래와 같습니다.

 위의 코드를 티스토리 스킨 편집에서 붙여넣으면 끝입니다. ^^ 방금 추가했는데, 아주 멋지군요. >ㅁ<)/~!!! 신나는 하루입니다. ^^;;;;

+ Recent posts