기본 콘텐츠로 건너뛰기

kernel Hello World

리눅스 커널 모듈 프로그래밍 가이드
참조:http://www.tldp.org/LDP/lkmpg/2.6/html/lkmpg.html

커널 모듈 가이드

아래 테스트는 우분투 14.04에서 테스트 되었습니다.

모듈 유틸리티

insmod:모듈을 커널에 적재한다.
rmmod:커널에서 모듈을 제거한다.
lsmod:커널에서 적재된 모듈 목록을 보여준다.
depmod: 모듈간 의존성 정보를 생성한다.
modprobe:모듈을 커널에 적재하거나 제거한다.
modinfo rdma_ucm


모듈 정보 보기:

#lsmod
#cat /etc/modprobe.conf
#modinfo ib_core

커널에서 제공하는 심볼 테이블
:커널 내부의 함수나 변수 중 외부에서 참조할 수 있는 함수의 심볼과 주소를 담은 테이블
#cat /proc/kallsyms

커널 모듈 제작해 보기


kernel ver 3.16

hello.c

/*
 *  hello.c - The simplest kernel module.
 */
#
#include <linux/module.h>
#include <linux/kernel.h>

int init_module(void)
{
    printk("<1>Hello World 1.\n");
    return 0;
}

void cleanup_module(void)
{
    printk(KERN_ALERT "Goodbye world 1.\n");
}
   


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


#make

make -C /lib/modules/3.16.0-30-generic/build M=/opt/kernel/base modules
make[1]: Entering directory `/usr/src/linux-headers-3.16.0-30-generic'
  CC [M]  /opt/kernel/base/hello.o
  Building modules, stage 2.
  MODPOST 1 modules
  CC      /opt/kernel/base/hello.mod.o
  LD [M]  /opt/kernel/base/hello.ko
make[1]: Leaving directory `/usr/src/linux-headers-3.16.0-30-generic'

#modinfo hello.ko
filename:       /opt/kernel/base/hello.ko
srcversion:     140276773A3090F6F33891F
depends:
vermagic:       3.16.0-30-generic SMP mod_unload modversions

#insmod hello.ko

아무내용이 나오지 않는다.

#dmesg
[27693.264826] Hello world 1.
맨 마지막에 볼수 있다.

insmod: ERROR: could not insert module rdma_krping.ko: Invalid parameters
현재 모듈이 다른 모듈의 함수를 사용했을 경우다. 
이때는 사용하려는 해당 모듈이 컴파일 되기전에 함수에 대한 심볼 테이블이 필요하다.
만약 foo.ko 가 bar.ko 의 함수를 사용한다면 우선 bar.ko 를 컴파일 한다. 
컴파일하면 해당 폴더에 Module.symvers 란 파일이 생성된다. 
이 파일을 foo.ko 가 컴파일될 폴더에 복사한후 foo.ko를 컴파일하면 에러 없이 컴파일되고 에러 없이 insmod 될 것이다.
혹은 makefile 에 KBUILD_EXTRA_SYMBOLS += {Module.symvers} 를 추가한다.


*. kthread

  대다수의 커널 쓰레드 들은 kthread 를 사용하여 구현되어 있습니다. (커널 소스 트리 검색)

  쓰레드 생성 api
    kthread_create();
    kthread_run();

  쓰레드 정지 api
    kthread_stop();
    kthread_should_stop();

  그외 api
    kthread_bind();
    kthread_data();
    kthreadadd();
    kthread_worker();
    init_kthread_worker();
    init_kthread_work();
    kthread_worker_fn();
    queue_kthread_work();
    flush_kthread_work();
    flush_kthread_worker();

  많은 API 가 있지만 주로 사용하는 API 는 아래와 같습니다. 
    kthread_create();        : 쓰레드 생성
    kthread_run();            : 쓰레드 생성 + 잘생성되었는지 검사
    kthread_stop();           : 쓰레드 종료하라고 명령 내림
    kthread_should_stop(); : 쓰레드 종료 명령이 내려졌는지 검사함. 

    kthread_bind()            : 쓰레드가 사용할 cpu 지정.



참조:http://www.programering.com/a/MDN4IjMwATk.html

간단한 kernel thread source

#include 
#include 
#ifndef SLEEP_MILLI_SEC
#define SLEEP_MILLI_SEC(nMilliSec)\
do { \
long timeout = (nMilliSec) * HZ / 1000; \
while(timeout > 0) \
{ \
timeout = schedule_timeout(timeout); \
} \
}while(0);
#endif

static struct task_struct * MyThread = NULL;

static int MyPrintk(void *data)
{
    char *mydata = kmalloc(strlen(data)+1,GFP_KERNEL);
    memset(mydata,'\0',strlen(data)+1);
    strncpy(mydata,data,strlen(data));
    while(!kthread_should_stop())
    {
        SLEEP_MILLI_SEC(1000);
        printk("%s\n",mydata);
    }
    kfree(mydata);
    return 0;
}

static int __init init_kthread(void)
{
    MyThread = kthread_run(MyPrintk,"hello world","mythread");
    return 0;
}

static void __exit exit_kthread(void)
{
    if(MyThread)
    {
        printk("stop MyThread\n");
        kthread_stop(MyThread);
    }
}
module_init(init_kthread);
module_exit(exit_kthread);



===========================================

커널 스레드로 구현한 udp 서버 프로그램



#include
#include
#include
#include

#include
#include

#include
#include
#include

#include

#define DEFAULT_PORT 2325
#define CONNECT_PORT 23
#define MODULE_NAME "m_server"
#define INADDR_SEND INADDR_LOOPBACK

struct kthread_t
{
        struct task_struct *thread;
        struct socket *sock;
        struct sockaddr_in addr;
        int running;
};

struct kthread_t *kthread = NULL;

int ksocket_receive(struct socket *sock, struct sockaddr_in *addr, unsigned char *buf, int len);
int ksocket_send(struct socket *sock, struct sockaddr_in *addr, unsigned char *buf, int len);

static void ksocket_start(void)
{
        int size, err;
        int bufsize = 10;
        unsigned char buf[bufsize+1];

        /* kernel thread initialization */
        lock_kernel();
        current->flags |= PF_NOFREEZE;

        /* daemonize (take care with signals, after daemonize() they are disabled) */
        daemonize(MODULE_NAME);
        allow_signal(SIGKILL);
        unlock_kernel();
        kthread->running = 0;

        /* create a socket */
        if ( ( (err = sock_create(AF_INET, SOCK_DGRAM, IPPROTO_UDP, &kthread->sock)) < 0) )
        {
                printk(KERN_INFO MODULE_NAME": Could not create a datagram socket, error = %d\n", -ENXIO);
                goto out;
        }

        memset(&kthread->addr, 0, sizeof(struct sockaddr));
        kthread->addr.sin_family      = AF_INET;

        kthread->addr.sin_addr.s_addr      = htonl(INADDR_ANY);

        kthread->addr.sin_port      = htons(DEFAULT_PORT);

        if ( ( (err = kthread->sock->ops->bind(kthread->sock, (struct sockaddr *)&kthread->addr, sizeof(struct sockaddr) ) ) < 0))
        {
                printk(KERN_INFO MODULE_NAME": Could not bind or connect to socket, error = %d\n", -err);
                goto close_and_out;
        }

        printk(KERN_INFO MODULE_NAME": listening on port %d\n", DEFAULT_PORT);

        /* main loop */
        for (;;)
        {
                memset(&buf, 0, bufsize+1);
                size = ksocket_receive(kthread->sock, &kthread->addr, buf, bufsize);

                if (signal_pending(current))
                        break;

                if (size < 0)
                        printk(KERN_INFO MODULE_NAME": error getting datagram, sock_recvmsg error = %d\n", size);
                else
                {
                        printk(KERN_INFO MODULE_NAME": received %d bytes\n", size);
                        /* data processing */
                        printk("\n data: %s\n", buf);

                        /* sending */
                        memset(&buf, 0, bufsize+1);
                        strcat(buf, "testing...");
                        ksocket_send(kthread->sock, &kthread->addr, buf, strlen(buf));
                }
        }

close_and_out:
        sock_release(kthread->sock);
        kthread->sock = NULL;

out:
        kthread->thread = NULL;
        kthread->running = 0;
}

int ksocket_send(struct socket *sock, struct sockaddr_in *addr, unsigned char *buf, int len)
{
        struct msghdr msg;
        struct iovec iov;
        mm_segment_t oldfs;
        int size = 0;

        if (sock->sk==NULL)
           return 0;

        iov.iov_base = buf;
        iov.iov_len = len;

        msg.msg_flags = 0;
        msg.msg_name = addr;
        msg.msg_namelen  = sizeof(struct sockaddr_in);
        msg.msg_control = NULL;
        msg.msg_controllen = 0;
        msg.msg_iov = &iov;
        msg.msg_iovlen = 1;
        msg.msg_control = NULL;

        oldfs = get_fs();
        set_fs(KERNEL_DS);
        size = sock_sendmsg(sock,&msg,len);
        set_fs(oldfs);
        return size;
}

int ksocket_receive(struct socket* sock, struct sockaddr_in* addr, unsigned char* buf, int len)
{
        struct msghdr msg;
        struct iovec iov;
        mm_segment_t oldfs;
        int size = 0;

        if (sock->sk==NULL) return 0;

        iov.iov_base = buf;
        iov.iov_len = len;

        msg.msg_flags = 0;
        msg.msg_name = addr;
        msg.msg_namelen  = sizeof(struct sockaddr_in);
        msg.msg_control = NULL;
        msg.msg_controllen = 0;
        msg.msg_iov = &iov;
        msg.msg_iovlen = 1;
        msg.msg_control = NULL;

        oldfs = get_fs();
        set_fs(KERNEL_DS);
        size = sock_recvmsg(sock,&msg,len,msg.msg_flags);
        set_fs(oldfs);

        return size;
}

int __init ksocket_init(void)
{
        kthread = kmalloc(sizeof(struct kthread_t), GFP_KERNEL);
        memset(kthread, 0, sizeof(struct kthread_t));

        kthread->thread = kthread_run((void *)ksocket_start, NULL, MODULE_NAME);
        if (IS_ERR(kthread->thread))
        {
                printk(KERN_INFO MODULE_NAME": unable to start kernel thread\n");
                kfree(kthread);
                kthread = NULL;
                return -ENOMEM;
        }

        return 0;
}

void __exit ksocket_exit(void)
{

#if 0
        if (kthread->thread==NULL)
                printk(KERN_INFO MODULE_NAME": no kernel thread to kill\n");
        else 
        {
                lock_kernel();
                err = kill_proc(kthread->thread->pid, SIGKILL, 1);
                unlock_kernel();

                if (err < 0)
                        printk(KERN_INFO MODULE_NAME": unknown error %d while trying to terminate kernel thread\n",-err);
                else 
                {
                        while (kthread->running == 1)
                                msleep(10);
                        printk(KERN_INFO MODULE_NAME": succesfully killed kernel thread!\n");
                }
        }
#endif

        if (kthread->running)
                kthread_stop(kthread->thread);
        if (kthread->sock != NULL)
        {
                sock_release(kthread->sock);
                kthread->sock = NULL;
        }

        kfree(kthread);
        kthread = NULL;

        printk(KERN_INFO MODULE_NAME": module unloaded\n");
}

module_init(ksocket_init);
module_exit(ksocket_exit);

MODULE_DESCRIPTION("UDP socket example");
MODULE_AUTHOR("Toni Garcia-Navarro ");

MODULE_LICENSE("GPL");


Proc 프로그래밍 (kernel <-> user) 통신

댓글

이 블로그의 인기 게시물

톰캣 세션 타임 아웃 설정

web.xml 파일이 있습니다. 이 파일을 열어서 session이라고 검색해 보십시오. <session-config>   <session-timeout>360</session-timeout> </session-config> 위 단락을 찾을 수 있습니다. session-timeout 시간 360이 바로 자동로그아웃 세션 시간입니다.  단위는 분이고요. 30분으로 하고 싶으시면 30으로 바꿔서 저장해주시면 되는 것이죠~ Tomcat 내에서 Session Timeout 를 설정하는 우선 순위가 존재 한다. session.setMaxInactiveInterval() 프로그램내에서 time out 를 설정했을 경우 Web application 내의 WEB-INF/web.xml Tomcat 내의 conf/web.xml 실제로 Tomcat(conf/web.xml)내에 Default 로 설정되어 있는 것은 다음과 같다. < HttpSession 메서드 > getCreationTime() - 세션 생성 시간 getLastAccessedTime() - 마지막 요청 시간 setMaxInactiveInterval() - 최대허용시간 설정 (초) getMaxInactiveInterval() - 최대허용시간 invalidate() - 세션 제거 < 타임아웃 설정하기 > - 일정 시간 동안 요청이 없으면 세션을 제거한다  1. DD에서 전체 세션 타임아웃 설정       web.xml 1. DD에서 전체 세션 타임아웃 설정       web.xml <web-app ... >     <servlet>        ...

java 특정 디렉토리에 있는 파일 목록을 읽어내기, 정렬해서 가져오기

폴더 리스트 가져오기 String path="C:\"; File dirFile=new File(path); File []fileList=dirFile.listFiles(); for(File tempFile : fileList) {   if(tempFile.isFile()) {     String tempPath=tempFile.getParent();     String tempFileName=tempFile.getName();     System.out.println("Path="+tempPath);     System.out.println("FileName="+tempFileName);     /*** Do something withd tempPath and temp FileName ^^; ***/   } } 정렬해서 가져오기 import java.io.FileFilter; import java.io.IOException; import java.util.Arrays; import java.util.Date; import org.apache.commons.io.comparator.LastModifiedFileComparator; import org.apache.commons.io.filefilter.FileFileFilter; public class LastModifiedFileComparatorTest { public static void main(String[] args) throws IOException { File directory = new File("."); // get just files, not directories File[] files = directory.listFiles((FileFilter) FileFileFilter.FILE); System.out.println("Defaul...

dmesg 메시지 실시간으로 보기

참조사이트 http://imitator.kr/Linux/556 # tail -f /var/log/messages # tail -f |dmesg //기본 2초 단위로 갱신 된다. # watch "dmesg | tail -f" //1초 단위로 갱신하면서 보여준다. # watch -n 1 "dmesg | tail -f" // 보여주는 줄을 20으로 늘린다. (기본 10줄) # watch -n 1 "dmesg | tail -f -n 20"