두 개의 커널 스레드를 생성하고 각각 하나의 전역 변수를 증가시키는 샘플 Linux 장치 드라이버 코드를 작성했습니다. 나는 변수를 증가시키는 작업을 수행하기 위해 대기열을 사용했으며 타이머가 만료되고 각 스레드가 무작위로 깨어날 때까지 각 스레드는 대기열에서 대기합니다.대기 행렬 대기 시스템이있는 Linux 드라이버 코드
하지만이 모듈을 삽입하면 전체 시스템이 멈추고 컴퓨터를 다시 시작해야합니다. 이것은 모듈을 삽입 할 때마다 발생합니다. 실수로 dead-lock 상황에 들어가는 지 확인하기 위해 kthread 코드를 디버깅하려고 시도했지만 코드에 문제가 있는지 확인할 수 없습니다.
아무도 내가 전화 끊기 상황을 코드에서 잘못하고 있다고 말할 수 있습니까?
#include <linux/module.h>
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/errno.h>
#include <linux/semaphore.h>
#include <linux/wait.h>
#include <linux/timer.h>
#include <linux/sched.h>
#include <linux/kthread.h>
spinlock_t my_si_lock;
pid_t kthread_pid1;
pid_t kthread_pid2 ;
static DECLARE_WAIT_QUEUE_HEAD(wqueue);
static struct timer_list my_timer;
int kthread_num;
/* the timer callback */
void my_timer_callback(unsigned long data){
printk(KERN_INFO "my_timer_callback called (%ld).\n", jiffies);
if (waitqueue_active(&wqueue)) {
wake_up_interruptible(&wqueue);
}
}
/*Routine for the first thread */
static int kthread_routine_1(void *kthread_num)
{
//int num=(int)(*(int*)kthread_num);
int *num=(int *)kthread_num;
char kthread_name[15];
unsigned long flags;
DECLARE_WAITQUEUE(wait, current);
printk(KERN_INFO "Inside daemon_routine() %ld\n",current->pid);
allow_signal(SIGKILL);
allow_signal(SIGTERM);
do{
set_current_state(TASK_INTERRUPTIBLE);
add_wait_queue(&wqueue, &wait);
spin_lock_irqsave(&my_si_lock, flags);
printk(KERN_INFO "kernel_daemon [%d] incrementing the shared data=%d\n",current->pid,(*num)++);
spin_unlock_irqrestore(&my_si_lock, flags);
remove_wait_queue(&wqueue, &wait);
if (kthread_should_stop()) {
break;
}
}while(!signal_pending(current));
set_current_state(TASK_RUNNING);
return 0;
}
/*Routine for the second thread */
static int kthread_routine_2(void *kthread_num)
{
//int num=(int)(*(int*)kthread_num);
int *num=(int *)kthread_num;
char kthread_name[15];
unsigned long flags;
DECLARE_WAITQUEUE(wait, current);
printk(KERN_INFO "Inside daemon_routine() %ld\n",current->pid);
allow_signal(SIGKILL);
allow_signal(SIGTERM);
do{
set_current_state(TASK_INTERRUPTIBLE);
add_wait_queue(&wqueue, &wait);
spin_lock_irqsave(&my_si_lock, flags);
printk(KERN_INFO "kernel_daemon [%d] incrementing the shared data=%d\n",current->pid,(*num)++);
spin_unlock_irqrestore(&my_si_lock, flags);
remove_wait_queue(&wqueue, &wait);
if (kthread_should_stop()) {
break;
}
}while(!signal_pending(current));
set_current_state(TASK_RUNNING);
return 0;
}
static int __init signalexample_module_init(void)
{
int ret;
spin_lock_init(&my_si_lock);
init_waitqueue_head(&wqueue);
kthread_num=1;
printk(KERN_INFO "starting the first kernel thread with id ");
kthread_pid1 = kthread_run(kthread_routine_1,&kthread_num,"first_kthread");
printk(KERN_INFO "%ld \n",(long)kthread_pid1);
if(kthread_pid1< 0){
printk(KERN_ALERT "Kernel thread [1] creation failed\n");
return -1;
}
printk(KERN_INFO "starting the second kernel thread with id");
kthread_pid2 = kthread_run(kthread_routine_2,&kthread_num,"second_kthread");
printk(KERN_INFO "%ld \n",(long)kthread_pid2);
if(kthread_pid2 < 0){
printk(KERN_ALERT "Kernel thread [2] creation failed\n");
return -1;
}
setup_timer(&my_timer, my_timer_callback, 0);
ret = mod_timer(&my_timer, jiffies + msecs_to_jiffies(2000));
if (ret) {
printk("Error in mod_timer\n");
return -EINVAL;
}
return 0;
}
static void __exit signalexample_module_exit(void)
{
del_timer(&my_timer);
}
module_init(signalexample_module_init);
module_exit(signalexample_module_exit);
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("Demonstrates use of kthread");
사람들이 커널 코드를 연구하도록하려면 최소한 커널 코딩 스타일을 사용하여 가독성을 높이십시오. – sawdust
두 번째 터미널 창을 열고 모듈을로드하는 동안 해당 창에서 "tail -f"을 사용해보십시오. 시스템은 계속 잠기지 만, printk 호출이 시스템 로그에 추가되기 전에 볼 수 있습니다.또한,이게 당신의 문제는 아니지만, 귀하의 kthread_pid 변수를'struct task_struct *'데이터 유형으로 변경하십시오. kthread_run을 호출하는 것은 userspace의 fork()와 같지 않으며 [다른 데이터 유형을 반환합니다] (http://lxr.free-electrons.com/source/include/linux/kthread.h#L22). –
skrrgwasme