kernel timer를 사용하려고 합니다. 맞는지 봐주실래요? ^^

sr97의 이미지

커널 모듈에서 네트워크 패킷을 캡쳐하여 정보 분석 큐에 기초 정보와 시간 정보를 기록하여 어플리 케이션 레벨로 덤핑하는 모듈을 만들고 있습니다.
패킷이 올때마다 시간 함수를 호출하여 기록하기에는 호출 횟수가 너무 많고 호출시 획득되는 데이터 간의 차이가 거의 없기 때문에(초단위 측정을 해서리) 커널에 타이머를 두고 1초 단위로 시간 변수를 접근하여 기록해두고
패킷이 올때마다 시간변수의 내용을 기록하는 방법을 사용하려고 합니다.
그런데 커널 타이머를 설정하는데 다음과 같은 방법을 썼습니다.

#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/time.h>
#include <linux/timer.h>
#include <linux/sched.h>
struct timer_list my_mod_timer; // 타이머 큐에 넣기 위한 타이머 변수
void func(unsigned long key); // 타이머의 초과 시간이 완료된 경우 실행할 타이머 핸들러
static int start()
{
init_timer(&my_mod_timer); // 타이머 노드 초기화
my_mod_timer.expires = (jiffies + 1 * HZ); // 1초단위 입니다.
my_mod_timer.data = 777; // 타이머 번호 설정
my_mod_timer.function = func; //핸들러 설정
add_timer(&my_mod_timer); // 타이머 큐에 추가
printk("module mod_prog is initialized\n");
return 0;
}

void void end()
{
del_timer(&my_mod_timer); // 타이머 큐에서 제거
printk("module mod_prog is cleanuped\n");
}
void func(unsigned long key)
{
if(key == 777)
{
printk("sucess\n");

init_timer(&my_mod_timer); // 노드 재 설정
my_mod_timer.expires = (jiffies + 1 * HZ);
my_mod_timer.data = 777;
my_mod_timer.function = func;

add_timer(&my_mod_timer); // 타이머 노드를 다시 집어 넣습니다.

}
}
EXPORT_NO_SYMBOLS;
module_init(start);
module_exit(end);

초기에는 초기화 함수에서 타이머 큐에 한번 넣으면 될 줄 알고 프로그래밍 했는데 초기화시 한번 동작하고 동작하지 않더군요.. 그래서 타이머 핸들러가 호출될때마다 큐에 다시 집어 넣는 방식을 사용했습니다.

이렇게 하니까 생각한대로 동작하더군요..
여기까지 짜면서 제가 알아낸 타이머 방식은 다음입니다.
1. expires에 현재 시간(jiffies)에 원하는 시간을 더하고 큐에 추가합니다.
2. 큐에서는 expires에 저장된 값과 현재 시간을 비교하여 같으면 노드에 연결된 콜백 함수를 호출합니다. 콜백 함수를 호출하면서 타이머 노드는 제거가 되고요.

이런 구조이기 때문에 타이머 노드를 타이머 큐에 계속 넣는 방법을 선택했는데. 이게 일반적인 방법인지 더나은 방법이 있는지 궁금합니다.
좋은 답변 바랍니다.

hb_kim의 이미지

먼저 시간함수가 어떻게 구현되어 있는지 확인해보셨습니까?

타이머 함수를 등록해서 자신의 커널모듈만을 위한 시각을 별도로 유지하는것이 나을 정도로 비효율적으로 구현되어 있던가요?

sr97의 이미지

타이머란 것은 현재 시간에서 정의한 시간이 흐르면 action을 취하는 것이 타이머인 걸로 알고 있습니다.
한번 설정에 한번의 action이죠.. 전자 시계에 붙어 있는 타이머를 비롯해 모든 타이머가 그런 식입니다. expires를 설정하면 expires가 지난 시점에 내부에 정의된 action을 취하죠..
구현하고자 하는 주기적인 타이머란 기존의 타이머를 이용하는 정책의 문제라고 생각합니다.
그렇다면 커널 내부에서 지원할 것은 기본적인 타이머이고 application layer에서 연속적인 타이머를 원한다면 필요한 추가 기능(저와 같이 주기적으로 타이머를 재설정 하는.. )이 구현된다고 생각합니다.
제 생각에는 효율이나 비효율보다 각 layer에서 구현해야할 것이 틀리다고 생각합니다. 매카니즘 위주인 커널과 정책 위주인 어플리케이션 처럼요..
효율 비효율을 평가하는게 적절한지 의문입니다. 더불어 제가 원하는 기능 즉 주기적인 타이머 프로그램(그것도 커널에서)을 혹 해보셨다면 제가 사용한 방법이 맞는지 아니면 다른 방법이 있는지를 답변해 주시면 고맙겠습니다.

jaeik의 이미지

typedef struct timer_priv {
    uint                timer_no;
    struct timer_list   tp_timer;
    spinlock_t          tp_lock;
    struct timer_priv    *tp_next;
} timer_priv_t;

timer_poll (unsigned long arg)
{
    ulong       flags;
    timer_priv_t *tp = (timer_priv_t *)arg;

    spin_lock_irqsave(&tp->tp_lock, flags);
    // do your timer job
    spin_unlock_irqrestore(&tp->tp_lock, flags);
    mod_timer(&tp->tp_timer, jiffies + HZ);
}

timer_start () {
    timer_priv_t     *tp;
...
    if (first) {
        init_timer(&tp->tp_timer);
        tp->tp_timer.expires = jiffies + HZ;
        tp->tp_timer.function = timer_poll;
        tp->tp_timer.data = (ulong)tp;
        add_timer(&tp->tp_timer);
    }
}


도움이 되기를...
hb_kim의 이미지

일단 타이머로 깨어나서 액션을 취한 다음에 그때 시간을 보고 다시 타이머를 설정하는 방법을 쓰면 jitter가 축적됩니다. Jitter는 커널의 각종 모듈들이 locking 을 하거나 하면서 인터럽트를 끔으로써 자신의 태스크가 깨어나야 할 시간에 못깨어나고 나중에 깨어나기 때문에 생깁니다. 결국 조금 지나면 자기 자신의 시간에 오차가 점차 커진다는것이고 이 오차의 증가가 시스템의 사양에 따라 혹은 동작 상태에 따라 매번 변한다는 것입니다. 따라서 자신의 시계를 정확하게 유지하려면 8253 이나 RTC 의 주기적 하드웨어 인터럽트를 사용하는 수밖에 없습니다. 결국 현재 커널의 시각유지 코드와 거의 비슷한 코드를 만들어야 겠죠.

그런데 이 모든 문제를 생각하기 전에 먼저 봐야 될게 "과연 내가 wheel 을 reinvent 해야 하느냐?" 하는 문제입니다.

혹 이런 방법을 생각해내시기전에 do_gettimeofday() 가 어떻게 구현되어 있는지 확인해 보셨습니까? 이 루틴이 정말로 너무나도 느리거나, 꼭 필요한 기능을 빼어놓았다면 자신의 코드를 다시 만들어야겠죠. 그런데 제가 얼핏 추측하기엔 그렇지 않은것 같습니다.

결국, 제가 보기엔 do_gettimeofday() 가 최소한의 locking과 최소한의 연산으로 정확한 시각을 커널 모듈에 제공하는 함수라고 보여지며, 이를 그냥 쓰시는 것이 제일 쉽고, 빠르고, 정확하게 원하는 기능을 얻을수 있는 방법으로 생각됩니다.

salbang2의 이미지

만약 sk_buff 를 이용하여 패킷을 받으시는거라면, 이미 sk_buff 구조체에 패킷이 들어온 시간이 있습니다.. 물론 훨씬 윗단이라서 sk_buff 를 받아 보실 수 없다면 소용없는 얘기이구요..

sk_buff 의 stamp 변수가 그것입니다..

댓글 달기

Filtered HTML

  • 텍스트에 BBCode 태그를 사용할 수 있습니다. URL은 자동으로 링크 됩니다.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>
  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.

BBCode

  • 텍스트에 BBCode 태그를 사용할 수 있습니다. URL은 자동으로 링크 됩니다.
  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param>
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.

Textile

  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • You can use Textile markup to format text.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>

Markdown

  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • Quick Tips:
    • Two or more spaces at a line's end = Line break
    • Double returns = Paragraph
    • *Single asterisks* or _single underscores_ = Emphasis
    • **Double** or __double__ = Strong
    • This is [a link](http://the.link.example.com "The optional title text")
    For complete details on the Markdown syntax, see the Markdown documentation and Markdown Extra documentation for tables, footnotes, and more.
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>

Plain text

  • HTML 태그를 사용할 수 없습니다.
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.
  • 줄과 단락은 자동으로 분리됩니다.
댓글 첨부 파일
이 댓글에 이미지나 파일을 업로드 합니다.
파일 크기는 8 MB보다 작아야 합니다.
허용할 파일 형식: txt pdf doc xls gif jpg jpeg mp3 png rar zip.
CAPTCHA
이것은 자동으로 스팸을 올리는 것을 막기 위해서 제공됩니다.