[kernel] 스핀락

development 2012. 1. 4. 16:17
Table of content
  1. spin lock?
  2. example of spin_lock 












1. spin lock?
  프로세스 한개만 계속 수행되는 경우라면 critical section 에 대해서 신경쓸 필요가 없다.
  하지만, 현실은 여러 프로세스가 함께 동작하는 상황이므로 LOCK 에 대한 고민을 할 수 밖에 없다. 
 
  spin lock 은 커널에서 사용하는 LOCK 기법중의 하나이며 대표적인 기법이다.

  spin lock 의 API 들은 아래와 같다.

    spin_lock_init();
    spin_lock();
    spin_unlock();
    spin_locK_irqsave():
    spin_lock_irq();
    spin_lock_bh();
    spin_unlock_irqrestore();
    spin_unlock_irq();
    spin_unlock_bh();
    spin_trylock();
    spin_trylock_bh();

  spin lock() 이 커널의 LOCK 기법중 하나인 것을 감안하면 api 의 숫자가 많은 것에 놀랄수도 있다. 그만큼 LOCK 기법은 어렵고 신경써야 할 점이 많다는 것이라고 이해하면 된다. 


2. example of spin_lock
  spin lock 을 사용하려면
  
 
첫번째, spin lock 변수를 선언해야 하고
 
두번째, spin lock 변수를 초기화 해야 하며
    : static 과 dynamic 방식으로 구분된다. 
 
세번째, lock 을 얻어야 하며
    : spin_lock();
 
네번째, lock 을 풀어주어야 한다.
    : spin_unlock(); 

  아래는 spin lock 을 사용하는 가장 간단한 예제이다.

#include <asm/init.h>
#include <asm/kernel.h>
#include <asm/module.h>
#include <asm/version.h>
#include <asm/delay.h>
#include <asm/spinlock.h>
#include <asm/kthread.h>

spinlock_t g_this_lock;
struct task_struct *g_th_id1;
struct task_struct *g_th_id1;

static int
 thr_spin_lock_1(void *arg)
{
  int i = 0;
 
  printk(KERN_ALERT "@ %s() : called\n", __FUNCTION__);

  spin_lock(&g_this_lock);

  
printk(KERN_ALERT "@ %s() : get locked\n", __FUNCTION__);

  for(i=0;i<30;i++){
    
printk(KERN_ALERT "@ %s() : loop\n", __FUNCTION__);
    ssleep(1); 

  } 
 

  spin_unlock(&g_this_lock); 

  printk(KERN_ALERT "@ %s() : unlocked\n", __FUNCTION__);
 
 
return 0; 



static int
 thr_spin_lock_2(void *arg)

  printk(KERN_ALERT "@ %s() : called\n", __FUNCTION__);

  spin_lock(&g_this_lock);

  
printk(KERN_ALERT "@ %s() : get locked\n", __FUNCTION__);

  ssleep(10);

  spin_unlock(&g_this_lock); 


  
printk(KERN_ALERT "@ %s() : unlocked\n", __FUNCTION__);
  
  
return 0; 


static void __init only_spin_lock_init(void)
{
  spin_lock_init(&_ghis_lock);

  g_th_id1 = kthread_run(thr_spin_lock_1, NULL, "LOCK1");
  g_th_id2 = kthread_run(thr_spin_lock_2, NULL, "LOCK2");

  return 0; 



 위 예제는 문제를 내포하고 있는 코드입니다. spin_lock 이 걸려 있는 상태에서 rmmod 로 모듈을 제거하게 되면 "device is busy" 가 발생하게 됩니다. 
 

'development' 카테고리의 다른 글

[program] 2차원 배열 동적 할당  (0) 2012.02.10
[kernel] Top Half? Bottom Half? context?  (5) 2012.01.13
[program] Makefile  (0) 2012.01.04
[kernel] 커널 쓰레드  (0) 2012.01.04
[kernel] 시간지연  (1) 2012.01.02
블로그 이미지

김유석0

,

[program] Makefile

development 2012. 1. 4. 13:15

Table of Content
  1. Example of Makefile
  2. 텍스트 함수









1. Example of Makefile
  하위 디렉토리를 관리하는 가장 기본적인 예제

 .SILENT:

SUB_DIRS=$(shell ls -d */ |cut -f1 -d/)

all:
    @for list in $(SUB_DIRS); do make -C $$list ; done

clean:
    @for list in $(SUB_DIRS); do make -C $$list clean ; done

distclean:
    @make clean
  위 예제는 하위 디렉토리를 자동 검색하게 하여 make list 에 넣는 형태로 되어 있다.
  배포용으로는 아주 좋은 형태이지만, 실제 개발 프로젝트 진행시에는 모든 하위 디렉토리를 컴파일하게 만들면 불편한 상황이 발생하게 된다.  
  그래서 아래와 같이 make list 를 명시적으로 지정하게 하는 것이 개발할 때 더 편하다.
 
  개발 프로젝트 진행시 가장 편리한 예제
 .SILENT:

SUB_DIRS=project1\
               project2\
               project3

all:
    @for list in $(SUB_DIRS); do make -C $$list ; done

clean:
    @for list in $(SUB_DIRS); do make -C $$list clean ; done

distclean:
    @make clean
 


2. 텍스트 함수

makefile 은 텍스트를 다루는 다양한 기능(함수) 를 제공한다.

subst

문법

  $(subst TARGET,DEST,SRC_TEXT)

설명

  SRC_TEXT 에서 TARGET 을 DEST 로 변환한다.

예제

  SRC_STRING="I am a boy"

  RESULT=$(subst boy,man,$(SRC_STRING))

  => I am a man 으로 변환됨.

notdir :

wildcard

'development' 카테고리의 다른 글

[kernel] Top Half? Bottom Half? context?  (5) 2012.01.13
[kernel] 스핀락  (1) 2012.01.04
[kernel] 커널 쓰레드  (0) 2012.01.04
[kernel] 시간지연  (1) 2012.01.02
[kernel] 커널 메모리 모델  (0) 2011.12.29
블로그 이미지

김유석0

,

Table of Content
  1. kernel_thread VS kthread
  
2. kernel_thread 
     A. 소개
     B. daemonize()
     
  3
. kthread 
  
4. kthread 예제 

1. kernel_thread VS kthread
  linux kernel 에서 쓰레드를 구현하는 기법엔 크게 두가지가 있습니다.
  첫번째는 kernel_thread() 를 사용하는 것이고
  두번째는 kthread_xxxx() 를 사용하는 것입니다.

  kernel_thread() 는 가장 기본적인 쓰레드 구현 방법인데 실제 커널 코드상에서는 사용 빈도가 극히 드뭅니다. 
  kernel_thread() 를 직접 사용하면 이것저것 해 줘야 할 것들이 많아지는데  
kthread_xxxx() 계열을 사용하면 코드가 상당히 간단해 집니다.  

kthread_create()
kthread_run()
kthread_bind()
kthread_sop()
kthread_should_stop()
kthread_data() 

 자세한 내용은 커널 소스 트리와 linux/kthread.h 를 참조해 주십시요. 

2. kernel_thread
A. 소개 

  kernel_thread 는 잘 사용안하는 방법으로 생각됩니다. 커널 코드를 살펴보아도 5~6 군데에서만 사용하고 있습니다. 
  쓰레드 종료와 SMP 에 대해서는 크게 신경쓰고 있지 않는 것으로 보입니다.
  샘플 코드는 아래와 같습니다. 
  
#include <linux/init.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/completion.h>
#include <linux/delay.h>
#include <linux/kthread.h>

int flag=0;
struct task_struct *th_id;

static int kernel_thread_thr_wait(void *arg)
{
  int i = 0;
  char *text = (char *)arg;
  while(flag)
  {
    printk(KERN_ALERT "KERNEL_THREAD. %d [ %s ]\n", i, text);
    ++i;
    udelay(1000);
  }
  printk(KERN_ALERT "KERNEL_THREAD. Stoped\n");
 
return 0;


static void DONE(void)
{
  flag = 0;
}  


static int __init kernel_thread_init(void)
{
  flag = 1;
  th_id = (struct task_struct *)kernel_thread(kernel_thread_thr_wait, "TEST", CLONE_KERNEL);
  if(IS_ERR(th_id)){
    printk(KERN_ALERT "Fail to create the thread\n");
    return -1;
  }
  udelay(5000);
  DONE();
  로 udelay(5000);
 
return 0;


static void kernel_thread_release(void)
{
  printk(KERN_ALERT "Exit %s()\n", __FUNCTION__);


module_init(kernel_thread_init);
module_exit(kernel_thread_release);
MODULE_LICENSE("Dual BSD/GPL"); 

B. daemonize()
  kernel_thread() 로 생성된 쓰레드는 부모 쓰레드가 자식 쓰레드보다 먼저 죽게되면 자식 쓰레드는 좀비 쓰레드가 됩니다. 
  이런 일을 방지하기 위해서 daemonize() 를 호출하여 부모 쓰레드를 kthreadd 라는 커널 쓰레드로 바꿔주어서 자식 쓰레드가 죽을 때까지 기다릴 수 있게 만들어 줍니다. 

  사용방법은 커널 소스트리를 살펴봐 주세요. 

3. 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 지정.

4. kthread 예제
  kthread 에 대한 간단한 예제는 아래와 같습니다. 

#include <linux/init.h>
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/completion.h>
#include <linux/delay.h>
#include <linux/kthread.h>

struct task_struct
 *g_th_id=NULL;

static int kthread_example_thr_fun(void *arg)
{
  printk(KERN_ALERT "@ %s() : called\n", __FUNCTION__);
  while(!kthread_should_stop())
  {
    printk(KERN_ALERT "@ %s() : loop\n", __FUNCTION__);
    ssleep(1); 

  }
  printk(KERN_ALERT "@ %s() : kthread_should_stop() called. Bye.\n", __FUNCTION__);
  return 0;


static int __init kthread_example_init(void)
{
  printk(KERN_ALERT "@ %s() : called\n", __FUNCTION__);
 
  if(g_th_id == NULL){ 

     g_th_id = (struct task_struct *)kthread_run(kthread_example_thr_fun, NULL, "kthread_example");
  }
 
return 0;


static void __exit kthread_example_release(void)
{
  if(g_th_id){
     kthread_stop(g_th_id);
     g_th_id = NULL;
  }
  printk(KERN_ALERT "@ %s() : Bye.\n", __FUNCTION__);

 

module_init(kthread_example_init);
module_exit(kthread_example_release);
MODULE_LICENSE("Dual BSD/GPL"); 

  위 코드를 살펴보면 g_th_id 을 자동관리해 주지 않는다는 것을 알 수 있습니다.
  항상 g_th_id 에 대한 관리를 확실히 해 주는 것이 중요할 것으로 예상됩니다.
 


 


  


'development' 카테고리의 다른 글

[kernel] 스핀락  (1) 2012.01.04
[program] Makefile  (0) 2012.01.04
[kernel] 시간지연  (1) 2012.01.02
[kernel] 커널 메모리 모델  (0) 2011.12.29
[etc] 빌드 시스템  (0) 2011.12.23
블로그 이미지

김유석0

,
Table of Content
  1. Intro
  2. 쉬운 API
  3. 어려운  API
  4. 어려운 API 와 쉬운 API?
  5. CPU 소모성 API
  6. CPU 소모가 없는 API
  7. msleep()
  8. msleep_interruptible()
  9. ssleep()
  10. schedule_timeout_interrupt()
  11. schedule_timeout_uninterrupt() 
  12. schedule_timeout() 
  13. ndelay(), udelay(), mdelay()  


1. Intro
 커널에서 시간 지연 함수는 여러가지가 있습니다. 
 굳이 분류를 하자면 쉬운 API, 어려운 API, CPU 소모성 API, CPU 소모가 없는 API 정도로 나눌 수 있습니다. 

2. 쉬운 API
 쉬운 API는 크게 보면 아래와 같습니다. 
  #include <linux/delay.h>
  #include <linux/timer.h>

  msleep()
  ssleep()

 이 API들은 함수명대로 micro  second, milli second, 1 second 을 뜻합니다. 
 그냥 사용하시면 됩니다. 

3. 어려운 API
 어려운 API 는 크게 보면 아래와 같습니다. 

 
  #include <linux/delay.h>
   #include <linux/timer.h>
   
   msleep_interruptible()
   schedule_timeout_interruptible();
   schedule_timerout_uninterruptible();
   schedule_timeout();

 이것도 그냥 사용하면 됩니다.

4. 어려운 API 와 쉬운 API ?
  어려운 API 와 쉬운 API 의 차이점은 무엇일까요? 

  가장 기본이 되는 지연 함수는 schedule_timeout() 입니다. 
  관계를 살펴보면

      ssleep()
    -----------------------------------------
      msleep()

    -----------------------------------------
      schedule_timeout_interruptible(), schedule_timeout_uninterruptible
 
    -----------------------------------------
      schedule_timeout()

 입니다. 위에 그림만으로는 잘 설명이 안될 수도 있는데, 커널 소스를 살펴보면 관계를 확실히 확인 할 수 있습니다. 

  ssleep() 는 msleep() 를 호출합니다. 
  msleep() 는 schedule_timeout_uninterrupt() 를 호출합니다. 
  schedule_timeout_uninterrupt() 는 schedule_timeout() 을 호출합니다. 

 결국 최종으로 호출되는 것은 schedule_timeout() 인데 시간 지연이라는게 인터럽트를 허용할 수도, 아닐수도 있고 또한 사용상의 편의상 ssleep() 나 msleep() 같은 front-end 를 만들어 쓴다고 생각하면 됩니다. 

8. CPU 소모성 API
 지정한 지연시간까지 loop 를 돌면서 cpu 시간을 소모하는 형태의 API 입니다. 
 
 ndelay();
 udelay();
 mdelay();

 위와 같이 delay 라는 이름이 붙은 API 들이 CPU 소모성 API 이며 아래와 같이 구현할 경우에도 CPU 소모성 API 입니다. 
 
 while(time_before(jiffies, j1))
 {
   cpu_relax();
 }

9. CPU 소모가 없는 API
 CPU 점유가 없이 시간 지연을 구현하려면 현재 자기자신한테 할당된 프로세스 시간을 반납하고 대기하는 방식을 사용하면 됩니다. 

 schedule_timeout_interruptible()
 schedule_timeout_uninterruptible()

 등이 그런 계통입니다. 

7. msleep()
  header :
asm/delay.h
  void msleep(unsigned int msecs);
  unsigned long msleep_interruptible(unsigned int msecs);

 => 밀리세컨드 동안 지연해 줍니다. 지연시간동안에는 인터럽트를 받을 수 없습니다. 

example
 #include <asm/delay.h>

static void example_msleep(void)
{
  msleep(1000);


 
8. msleep_interruptible()
  header : 
asm/delay.h
  unsigned long msleep_interruptible(unsigned int msecs);

 => 밀리세컨드 동안 지연해 줍니다. 지연시간동안에는 인터럽트를 받을 수 있습니다. 

example)
 #include <asm/delay.h>

static void example_msleep(void)
{
  msleep_interruptible(1000);


 
9. ssleep()
  
  header : asm/delay.h
    void ssleep(unsigned int seconds);

 => 초단위로 지연해 줍니다. 지연시간동안에는 인터럽트를 받을 수 없습니다. 

example)
 #include <linux/sched.h>

static void example_ssleep(void)
{
  ssleep(2);



10. schedule_timeout_interruptible()

  
  header : linux/sched.h
    void schedule_timeout_interruptible(unsigned long timeout);

 => timeout 시간만큼 지연해 줍니다.  

example)
 #include <linux/sched.h>

static void example_ssleep(void)
{
  schedule_timeout_interruptible(1 * HZ); /* 1 초간 지연 */


11. schedule_timeout_uninterruptible()

  
  header : linux/sched.h
    void schedule_timeout_uninterruptible(unsigned long timeout);

 => timeout 시간만큼 지연해 줍니다. 지연시간도중에는 인터럽트를 받을 수 없습니다. 
  
  
example)
 #include <linux/sched.h>

static void example_ssleep(void)
{
  schedule_timeout_uninterruptible(1 * HZ); /* 1 초간 지연 */


 
12. schedule_timeout()

  
  header : linux/sched.h
    void schedule_timeout(unsigned long timeout);

 => timeout 시간만큼 지연해 줍니다. 가장 기본이 되는 함수입니다. 그렇기 때문에 직접 호출하여 사용하지는 않습니다. 

example)
 #include <linux/sched.h>

static void __sched schedule_timeout_interruptible(void long timeout)
{
  __set_current_state(TASK_INTERRUPTIBLE);
 
return schedule_timeout(timeout); 


13. ndelay, udelay, mdelay
   header : linux/delay.h
   #define ndelay(n);
   #define udelay(n); 
   #define mdelay(n);

  busy wait 방식이어서 cpu 로드가 많은 편입니다. 하지만 간단하게 쓸 수 있는 장점이 있습니다.

example)
#include <linux/delay.h>

void delay_test(void long timeout)
{
  ndelay(1000);
  udelay(1000);
  mdelay(1000); 
 


 

 
   

 

'development' 카테고리의 다른 글

[program] Makefile  (0) 2012.01.04
[kernel] 커널 쓰레드  (0) 2012.01.04
[kernel] 커널 메모리 모델  (0) 2011.12.29
[etc] 빌드 시스템  (0) 2011.12.23
[kernel] Thread 와 Kill  (0) 2011.11.26
블로그 이미지

김유석0

,
 리눅스 커널도 하나의 프로세스이므로 총 4GByte 의 Virtual memory 를 사용하게 됩니다.

 4GByte 의 메모리는 아래와 같이 크게 두 개로 나뉘게 되며 하위 3GByte 는 user space(application) 용이며 상위 1GByte 는 kernel space 로 구분합니다. 



 위와 같이 커널 영역은 Virtual memory 4GByte 영역중에서 하위 1GByte 영역에 위치하게 됩니다.(0xc0000000 ~ 0xffffffff)

 커널 영역의 상위 8Byte 는 아래와 같이 물리 메모리와 1:1 매핑되게 됩니다.


 커널 영역의 하위 128MByte 는 아래와 같이 특수 목적을 위해 커널에서 Reserved 하여 사용하게 됩니다.(물리 메모리와는 상관 없습니다.)


 그러므로 Virtual memory 중에서 커널 영역에서 사용할 수 있는 공간은 1GByte - 128MByte = 896MByte 입니다.  


 위에 설명한 모든 내용은 PAE(Physical Address Extension) 를 사용하지 않는 32Bit CPU 일 경우에 관한 내용입니다.
 64Bit CPU 를 사용하거나 PAE 를 사용하는 경우에는 메모리 매핑하는 방법이 약간 달라집니다.

리눅스메모리모델.pptx




'development' 카테고리의 다른 글

[kernel] 커널 쓰레드  (0) 2012.01.04
[kernel] 시간지연  (1) 2012.01.02
[etc] 빌드 시스템  (0) 2011.12.23
[kernel] Thread 와 Kill  (0) 2011.11.26
[GCC] -S 옵션?  (0) 2011.11.18
블로그 이미지

김유석0

,

[etc] 빌드 시스템

development 2011. 12. 23. 11:02

build_system.tar.bz2


제가 사용중인 빌드시스템입니다.

'development' 카테고리의 다른 글

[kernel] 시간지연  (1) 2012.01.02
[kernel] 커널 메모리 모델  (0) 2011.12.29
[kernel] Thread 와 Kill  (0) 2011.11.26
[GCC] -S 옵션?  (0) 2011.11.18
[kernel] module_init(), module_exit()  (0) 2011.11.17
블로그 이미지

김유석0

,

 아래와 같이 쓰레드를 여러개 생성하는 application 이 있습니다.

 1334 root      20   0     0    0    0 S    0  0.0   0:00.00 nfsd                                                                   
 1335 root      20   0     0    0    0 S    0  0.0   0:00.00 nfsd                                                                   
 1336 root      20   0     0    0    0 S    0  0.0   0:00.00 nfsd 


 nfsd 를 kill 하려고 하면 아래와 같이 입력하면 됩니다. 

 poplinux@poplinux: ~$ kill -9 1334 


아마 잘 동작할겁니다.

그런데 이상하지 않나요?

내가 죽이라고 한 것은  PID 1334 번 Process 인데 PID 1335, 1336 번까지 함께 죽어버리니까요.

 kill 명령은 지정한 PID 에 해당되는 프로세스가 죽이는 기능입니다. 





 이유를 살펴보니 이런 역사가 있었습니다. 


 예전에는 "Multi Thread" 라는 개념이 없었습니다.

 그래서 PID == Process 처럼 1:1 매칭이 되었었지요. 그래서 앞에서 언급한 것 같은 논리적인 오류가 없었는데

 이런 세상에, 컴퓨터 공학의 천재들이 그만 "Thread" 라는 녀석을 만들어 버렸네요.

 Thread 라는 녀석이 생겨나면서 PID == Process 라는 가정에 균열이 생기기 시작합니다.

 분명히 쓰레드는 각각 별도의 PID 를 가지고는 있지만 kill 신호로 부모 process 를 죽였는데 자식 쓰레드만 살아서 돌아다닌다면 큰 문제일 겁니다.

 그래서 나온 아이디어가 "부모 프로세스와 자식 쓰레드들을 하나의 그룹으로 묶자" 입니다.

 그게 바로 아래 구조입니다. 

 struct task_struct{
   pid_t pid;
   pid_t tgid;
 }

1개의 쓰레드로 동작하는 프로세스는 pid == tgid 입니다.
N개의 쓰레드로 동작하는 프로세스는 pid != tgid 입니다.

예를 들어 아래와 같은 프로세스가 있을때,

  Process     : pid = 100, 
tgid = 100
  - Thread_1 : pid = 101, tgid = 100
  - Thread_2 : pid = 102,tgid = 100

와 같이 구성되어 있고 getpid()  를 호출하면 pid 를 리턴하는게 아니라 tgid 를 리턴하게 됩니다.

이제 이해가 됩니다.

'development' 카테고리의 다른 글

[kernel] 커널 메모리 모델  (0) 2011.12.29
[etc] 빌드 시스템  (0) 2011.12.23
[GCC] -S 옵션?  (0) 2011.11.18
[kernel] module_init(), module_exit()  (0) 2011.11.17
[kernel] obj-y ? obj-m ? obj-$(CONFIG_TEST) ?  (1) 2011.11.08
블로그 이미지

김유석0

,

[GCC] -S 옵션?

development 2011. 11. 18. 11:58
아래와 같은 코드를 작성하였습니다.

test.c

#include <stdio.h>
int test(int i)
{
  printf("%d\n", i); return 0;
}

int main(int argc, char *argv[])
{
  int i;
  for(i=0;i<10;i++){
    test(i);
  }
  return 0;
}    
 
이 코드를 어셈블리 코드로 보고 싶다면?

gcc -S test.c    
 
-S 옵션을 붙여 주면 됩니다.
 
gcc -S test.c    
 
그럼 아래와 같이 어셈블리 코드로 볼 수 있습니다. 
 
    .file "test.c"
    .section .rodata
.LC0:
    .string "%d\n"
    .text
    .globl test
    .type test, @function
test:
.LFB0:
    .cfi_startproc
    pushl %ebp
    .cfi_def_cfa_offset 8
    .cfi_offset 5, -8
    movl %esp, %ebp
    .cfi_def_cfa_register 5
    subl $24, %esp
    movl $.LC0, %eax
    movl 8(%ebp), %edx
    movl %edx, 4(%esp)
    movl %eax, (%esp)
    call printf
    movl $0, %eax
    leave
    .cfi_restore 5
    .cfi_def_cfa 4, 4
    ret
    .cfi_endproc
.LFE0:
    .size test, .-test
    .globl main
    .type main, @function
main:
.LFB1:
    .cfi_startproc
    pushl %ebp
    .cfi_def_cfa_offset 8
    .cfi_offset 5, -8
    movl %esp, %ebp
    .cfi_def_cfa_register 5
    andl $-16, %esp
    subl $32, %esp
    movl $0, 28(%esp)
    jmp .L3
.L4:
    movl 28(%esp), %eax
    movl %eax, (%esp)
    call test
    addl $1, 28(%esp)
.L3:
    cmpl $9, 28(%esp)
    jle .L4
    movl $0, %eax
    leave
    .cfi_restore 5
    .cfi_def_cfa 4, 4
    ret
    .cfi_endproc
.LFE1:
    .size main, .-main
    .ident "GCC: (Ubuntu/Linaro 4.6.1-9ubuntu3) 4.6.1"
    .section .note.GNU-stack,"",@progbits
 
참고로 전 어셈코드를 못 봅니다. 능력이 안됩니다.
 
블로그 이미지

김유석0

,

아래와 같이 구현하면 어떻게 될까요?

Makefile

MODULE=multi_init

obj-m := $(MODULE).o
$(MODULE)-objs += check_money.o
$(MODULE)-objs += get_money.o
$(MODULE)-objs += put_money.o

KERNEL_DIR := /lib/modules/$(shell uname -r)/build
PWD := $(shell pwd)

all: 

     $(MAKE) -C $(KERNEL_DIR) M=$(PWD) modules

clean: 

     rm -rf *.o *.ko *mod.c .*cmd .*versions Module.symvers modules.order  

 
check_money.c
#include <linux/init.h>
#include <linux/module.h>

int check_money_init(void)
{
  printk(KERN_ALERT "%s() : called\n", __FUNCTION__);
  return 0;
}

void check_money_exit(void)
{
  printk(KERN_ALERT "%s() : bye\n", __FUNCTION__);
}

module_init(check_money_init);
module_exit(check_money_exit);
MODULE_LICENSE("Dual BSD/GPL");
 
get_money.c
#include <linux/init.h>
#include <linux/module.h>

int get_money_init(void)
{
  printk(KERN_ALERT "%s() : called\n", __FUNCTION__);
  return 0;


void get_money_exit(void)
{
  printk(KERN_ALERT "%s() : bye\n", __FUNCTION__);
}

module_init(get_money_init);
module_exit(get_money_exit);
MODULE_LICENSE("Dual BSD/GPL"); 
  
put_money.c
#include <linux/init.h>
#include <linux/module.h>

int put_money_init(void)
{
  printk(KERN_ALERT "%s() : called\n", __FUNCTION__);
  return 0;


void put_money_exit(void)
{
  printk(KERN_ALERT "%s() : bye\n", __FUNCTION__);
}

module_init(put_money_init);
module_exit(put_money_exit);
MODULE_LICENSE("Dual BSD/GPL"); 
   


컴파일 하면 에러 납니다. 


module_init(), module_exit() 는 한 모듈당 하나씩만 사용 가능합니다.

가끔씩 이거 물어 보시는 분들이 있어서 정리해 놓았습니다.


 


블로그 이미지

김유석0

,
 Makefile 을 살펴보면

  obj-y := audio_device.o

 혹은

  obj-m := audio_device.o

 혹은

  obj-$(CONFIG_TEST) := audio_device.o

 와 같은 형태를 볼 수 있다.

 무슨 차이가 있을까? 

 커널소스 트리에 있는 각종 드라이버들은 모듈로 컴파일 될 수도 있고 커널 이미지에 바로 들어갈 수 도 있다.

 
  obj-$(CONFIG_TEST) := audio_device.o

 
위와 같이 정의하면 make menuconfig 결과에 따라 모듈이나 빌트인으로 알아서 컴파일 된다.

 그럼 빌트인으로 컴파일하라는 명령은?

  obj-y := audio_device.o

 이고

 모듈로 컴파일 하라는 명령은?

  obj-m := audio_device.o 

 이다.  

  간혹 보면 아래와 같이 구성되는 경우도 있다. 


  obj-y := target.o
  target-objs += audio_driver.o
  target-objs += i2s.o
 
이런 무슨 뜻일까? 색을 칠해 보았다. 

  obj-y := target.o
  target-objs += audio_driver.o
  target-objs += i2s.o
 
 풀어서 설명하면,
 
  audio_driver.c 와 i2s.c 를 컴파일한 후 하나로 묶어서
  target.o 를 만들것이고
  target.o 는 빌트인으로 커널 이미지로 들어가게 된다는 뜻이다. 


그럼 이것은?

  obj-m := target.o
  target-objs += audio_driver.o
  target-objs += i2s.o

다 똑같은데 모듈로 만들겠다는 것만 다르다. 

그럼 이것은?
 

  obj-$(CONFIG_TEST) := target.o
  $(CONFIG_TEST)-objs += audio_driver.o
  $(CONFIG_TEST)-objs += i2s.o
 
menuconfig 결과에 따라 모듈로 컴파일 될 수도, 빌트인으로 컴파일 될 수도 있다는 뜻이다.

끝.

 
블로그 이미지

김유석0

,