리눅스 커널에서 spin lock 관련 질문.
우선 소스입니다. 헤더는 HTML이 먹는 관계로 brace가 아닌 quote로 처리합니다.
#include "linux/module.h"
#include "linux/kernel.h"
#include "linux/init.h"
#include "linux/kthread.h"
#include "linux/delay.h"
#include "linux/spinlock.h"
#include "linux/sched.h"
spinlock_t mylock;
struct task_struct *th[4];
unsigned cnt = 0;
unsigned myexit = 1;
unsigned mydone = 0;
static int my_thread(void *arg)
{
struct task_struct *temp = current;
mydone++;
while(myexit){
printk("kthread %u : %u\n", temp->pid, cnt);
ssleep(1);
spin_lock(&mylock);
cnt++;
spin_unlock(&mylock);
}
mydone--;
return 0;
}
static int __init start_module(void){
int i = 0;
spin_lock_init(&mylock);
for( i = 0 ; i < 4 ; i++)
th[i] = (struct task_struct*)kthread_run(my_thread, NULL, "mythread");
return 0;
}
static void __exit exit_module(void){
myexit = 0;
while(mydone)
printk("mydone : %d\n", mydone);
}
module_init(start_module);
module_exit(exit_module);
MODULE_LICENSE("GPL");
어려운 소스는 아닙니다.
4개의 스레드를 만들고 각 스레드는 스핀락으로 보호되는 카운트 변수를 증가시키고 printk로 출력을 합니다.
각 스레드는 스레드 함수 진입시 mydone변수를 증가 시키고 함수에서 나갈 때 감소 시킵니다.
모듈이 내려가면서 모든 스레드가 종료되었는지 확인하기 위해 mydone변수가 0인지 확인합니다.
문제가 되는 소스 부분은 모듈이 내려갈 때 호출되는 아래 부분입니다.
while(mydone)
printk("mydone : %d\n", mydone);
현재는 mydone 변수를 출력하면서 mydone의 값을 확인하는데, while문의 뒤에 세미콜론을 넣어 보았습니다.
while(mydone);
printk("mydone : %d\n", mydone);
특별히 두개의 차이는 없어보이는데, 위의 경우는 문제가 없고 아래의 경우에는 커널이 죽습니다.
너무 빠르게 while을 돌아 cpu 사용률이 너무 많아서 컨텍스트 스위칭이 되지 않아서 죽는 걸까요?
그렇다고 하기에는 이해가 가지 않아서 여러분들의 조언을 구합니다.
* 환경은 우분투 14.04, 커널은 3.17.2 입니다.
죽을거에요.
어셈블리 code를 생성해보세요.
while(mydone);
mydone이 volatile이 아니라서, 이 부분이 optimizing되었을 수도 있지 않나 싶습니다.
그리고,
저렇게 loop를 돌리면, 도대체 어느 시점에 다른 thread들이 실행될지 모르겠네요.
설마 저 thread들이 진심 동시에 실행된다고 생각하시는건 아니겠죠?
그리고, 저 while() loop가 금방 끝날것처럼 보여도
kernel 입장에서는 상당시간 block이 될거고
죽을겁니다.
어쨋거나, while()을 써서 대기하는 것은 아주 안좋은 방법 같습니다.
답변 감사합니다.
일에 쫓겨서 답변이 늦었습니다.
실제로 저렇게 사용하는건 아니고, 빠르게 테스트용으로 짜던 코드인데, 이유가 궁금해서 여쭤봤습니다.
최적화를 막고나니 문제가 없는 것 같네요. 어셈코드로 한번 봐야겠습니다.
답변 감사합니다 ^^
--------------------------------------------------------------
세상엔 알아야 할 것도 알지 말았어야 할 것도 너무 많았습니다.
혹시 모르지만 cnt, myexit, mydone
혹시 모르지만 cnt, myexit, mydone 전역변수 선언시 volatile을 넣어보세요.
volatile unsigned int cnt = 0;
이렇게요.
댓글 달기