头文件
#include
定义并初始化
- wait_queue_head_t r_wait;
- init_waitqueue_head(&cm_dev->r_wait);
wait_queue_head_t 表示等待队列头,等待队列wait时,会导致进程或线程被休眠,一个等待队列头中可以有很多的等待队列元素。每个元素绑定一个进程或者线程。这里绑定进程或者线程的目的,是为了在执行wakeup时,知道应该唤醒谁。
定义并初始化等待队列元素
wait_queue_t wait = __WAITQUEUE_INITIALIZER(wait, current);
- /*
- * Macros for declaration and initialisaton of the datatypes
- */
-
- #define __WAITQUEUE_INITIALIZER(name, tsk) { \
- .private = tsk, \
- .func = default_wake_function, \
- .task_list = { NULL, NULL } }
Core.c (kernel\sched)
- int default_wake_function(wait_queue_t *curr, unsigned mode, int wake_flags,
- void *key)
- {
- return try_to_wake_up(curr->private, mode, wake_flags);
- }
- EXPORT_SYMBOL(default_wake_function);
宏current
这是一个struct task_struct * 类型的变量。放在线程里,用于获取当前线程的指针。下面这两个函数虽然没有给它传递struct task_struct *参数,但是它却知道当前线程的指针,就是因为他们内部实现都调用了current。
- bool kthread_should_stop(void);
- bool kthread_should_park(void);
- /**
- * kthread_should_stop - should this kthread return now?
- *
- * When someone calls kthread_stop() on your kthread, it will be woken
- * and this will return true. You should then return, and your return
- * value will be passed through to kthread_stop().
- */
- bool kthread_should_stop(void)
- {
- return test_bit(KTHREAD_SHOULD_STOP, &to_kthread(current)->flags);
- }
- /**
- * kthread_should_park - should this kthread park now?
- *
- * When someone calls kthread_park() on your kthread, it will be woken
- * and this will return true. You should then do the necessary
- * cleanup and call kthread_parkme()
- *
- * Similar to kthread_should_stop(), but this keeps the thread alive
- * and in a park position. kthread_unpark() "restarts" the thread and
- * calls the thread function again.
- */
- bool kthread_should_park(void)
- {
- return test_bit(KTHREAD_SHOULD_PARK, &to_kthread(current)->flags);
- }
将等待队列元素加入等待队列头,这个和list_add做相同理解也可以。
- void add_wait_queue(wait_queue_head_t *q, wait_queue_t *wait)
- {
- unsigned long flags;
-
- wait->flags &= ~WQ_FLAG_EXCLUSIVE;
- spin_lock_irqsave(&q->lock, flags);
- __add_wait_queue(q, wait);
- spin_unlock_irqrestore(&q->lock, flags);
- }
将wait从等待队列中删除。
- void remove_wait_queue(wait_queue_head_t *q, wait_queue_t *wait)
- {
- unsigned long flags;
-
- spin_lock_irqsave(&q->lock, flags);
- __remove_wait_queue(q, wait);
- spin_unlock_irqrestore(&q->lock, flags);
- }
设置当前进程或者线程的状态
set_current_state是有内存屏障的功能。__set_current_state不具备内存屏障功能。
state_value可取值:
#define TASK_RUNNING 0
#define TASK_INTERRUPTIBLE 1
#define TASK_UNINTERRUPTIBLE 2
- /*
- * set_current_state() includes a barrier so that the write of current->state
- * is correctly serialised wrt the caller's subsequent test of whether to
- * actually sleep:
- *
- * set_current_state(TASK_UNINTERRUPTIBLE);
- * if (do_i_need_to_sleep())
- * schedule();
- *
- * If the caller does not need such serialisation then use __set_current_state()
- */
- #define __set_current_state(state_value) \
- do { current->state = (state_value); } while (0)
- #define set_current_state(state_value) \
- set_mb(current->state, (state_value))
函数schedule
asmlinkage void schedule(void);
这个函数声明前面有个asmlinkage ,这个参数网上说是用于规定传参是通过寄存器传输还是堆栈传输的。我在Linkage.h (include\linux) 中也看到了如下的宏定义,这些对于本次的实验都没有影响。
- #ifdef __cplusplus
- #define CPP_ASMLINKAGE extern "C"
- #else
- #define CPP_ASMLINKAGE
- #endif
-
- #ifndef asmlinkage
- #define asmlinkage CPP_ASMLINKAGE
- #endif
signal_pending函数,给他传递current参数。
- static inline int signal_pending(struct task_struct *p)
- {
- return unlikely(test_tsk_thread_flag(p,TIF_SIGPENDING));
- }
该段代码是一个大模块中的一小段测试代码,该线程中从ready_list中取出内存节点,然后给他赋值,然后放入ok_list链表,直到ready_list链表变成空链表为止。因为暂时没有调用wakeup给他唤醒。所以当ready_list为空时,它一定会处于阻塞的状态。
这里需要注意的一点是,运行schedule函数后,如果执行kthread_stop停止该线程,signal_pending返回值也是0,在此后要调用kthread_should_stop来判断线程是否可以停止运行。
在判断ret值非0后,是否continue,还是执行其他操作,这个也要具体情况具体分析,避免锁死在这里。
- static int
- cm_thread_1(void *arg)
- {
- int ret = 0;
- int send_count = 0;
- struct buf_node *pnode;
- struct cm_dev_ *cm_dev = (struct cm_dev_ *)arg;
- wait_queue_t wait = __WAITQUEUE_INITIALIZER(wait, current);
- add_wait_queue(&cm_dev->w_wait,&wait);
- while(1){
- if(kthread_should_stop()){
- DEBUG_CM("exit thread");
- break;
- }
- while(cm_list_size(&cm_dev->ready_list) == 0){
- set_current_state(TASK_INTERRUPTIBLE);
- DEBUG_CM("start schedule");
- schedule();
- DEBUG_CM("end schedule");
- ret = signal_pending(current);
- if(ret){
- DEBUG_CM("ret = %d",ret);
- continue;
- }
- //执行kthread_stop函数后,也会调度该线程,此时signal_pending也是0
- if(kthread_should_stop()){
- DEBUG_CM("exit thread");
- goto end_thread_1;
- }
- }
- ++send_count;
- DEBUG_CM("send a string:%d",send_count);
- pnode = pop_list(&cm_dev->ready_list);
- sprintf(pnode->buf,"send_count:%d",send_count);
- list_add_tail(&pnode->node,&cm_dev->ok_list);
- wake_up_interruptible(&cm_dev->r_wait);
- }
- end_thread_1:
- remove_wait_queue(&cm_dev->w_wait,&wait);
- return 0;
- }
从输出结果可知,调用完schedule()函数后,线程就开始睡觉了。而不是调用set_current_state以后才开始睡觉的。从set_current_state的函数实现可知,set_current_state只是设置了flags的标志位。
- root@hehe:~# insmod csi_buf.ko
- [ 27.546429] /big/csi_driver/csi_buf/csi_buf.c:cm_init:192: ready_list size = 5
- [ 27.553906] /big/csi_driver/csi_buf/csi_buf.c:cm_init:193: ok_list size = 0
- [ 27.561109] /big/csi_driver/csi_buf/csi_buf.c:cm_thread_1:145: send a string:1
- [ 27.569831] /big/csi_driver/csi_buf/csi_buf.c:cm_thread_1:145: send a string:2
- [ 27.578217] /big/csi_driver/csi_buf/csi_buf.c:cm_thread_1:145: send a string:3
- [ 27.585521] /big/csi_driver/csi_buf/csi_buf.c:cm_thread_1:145: send a string:4
- [ 27.592757] /big/csi_driver/csi_buf/csi_buf.c:cm_thread_1:145: send a string:5
- [ 27.600136] /big/csi_driver/csi_buf/csi_buf.c:cm_thread_1:135: start schedule
- /*睡眠在这里*/
此时执行 ps aux,看到我们的内核线程在睡觉,如下
- root@hehe:~# ps aux | grep cm_thread_1
- root 569 0.0 0.0 0 0 ? S 01:44 0:00 [cm_thread_1]
- root 575 0.0 0.3 3596 1648 ttymxc0 S+ 01:46 0:00 grep cm_thread_1
- root@hehe:~#
-
执行rmmod xxx.ko卸载该模块
- root@hehe:~# rmmod csi_buf.ko
- [ 38.326944] /big/csi_driver/csi_buf/csi_buf.c:cm_thread_1:137: end schedule
- [ 38.334002] /big/csi_driver/csi_buf/csi_buf.c:cm_thread_1:145: exit thread
- [ 38.340905] /big/csi_driver/csi_buf/csi_buf.c:cm_exit:240: tsks_1 stop
- [ 38.347628] /big/csi_driver/csi_buf/csi_buf.c:cm_exit:247: cm_exit ok
- root@hehe:~#
卸载函数中的代码如下:从上面的执行结果可知,执行kthread_stop后schedule函数返回0,然后判断kthread_should_stop,可以停止,然后结束线程。
- kthread_stop(cm_dev->tsks_1);
- DEBUG_CM("tsks_1 stop");
wake_up系列宏
- #define wake_up(x) __wake_up(x, TASK_NORMAL, 1, NULL)
- #define wake_up_nr(x, nr) __wake_up(x, TASK_NORMAL, nr, NULL)
- #define wake_up_all(x) __wake_up(x, TASK_NORMAL, 0, NULL)
- #define wake_up_locked(x) __wake_up_locked((x), TASK_NORMAL, 1)
- #define wake_up_all_locked(x) __wake_up_locked((x), TASK_NORMAL, 0)
-
- #define wake_up_interruptible(x) __wake_up(x, TASK_INTERRUPTIBLE, 1, NULL)
- #define wake_up_interruptible_nr(x, nr) __wake_up(x, TASK_INTERRUPTIBLE, nr, NULL)
- #define wake_up_interruptible_all(x) __wake_up(x, TASK_INTERRUPTIBLE, 0, NULL)
- #define wake_up_interruptible_sync(x) __wake_up_sync((x), TASK_INTERRUPTIBLE, 1)
本次实验,我们使用wake_up_interruptible。
线程1,从ready_list中取出节点,然后写数据,然后放入ok_list。
线程2,从ok_list中取出数据,输出,然后将节点放ready_list
- static int
- cm_thread_1(void *arg)
- {
- int ret = 0;
- int send_count = 0;
- struct buf_node *pnode;
- struct cm_dev_ *cm_dev = (struct cm_dev_ *)arg;
- wait_queue_t wait = __WAITQUEUE_INITIALIZER(wait, current);
- DEBUG_CM("");
- add_wait_queue(&cm_dev->w_wait,&wait);
- while(1){
- DEBUG_CM("");
- if(kthread_should_stop()){
- DEBUG_CM("exit thread");
- break;
- }
- DEBUG_CM("");
- while(cm_list_size(&cm_dev->ready_list) == 0){
- set_current_state(TASK_INTERRUPTIBLE);
- schedule();
- ret = signal_pending(current);
- if(ret){
- DEBUG_CM("ret = %d",ret);
- continue;
- }
- //执行kthread_stop函数后,也会调度该线程,此时signal_pending也是0
- if(kthread_should_stop()){
- DEBUG_CM("exit thread");
- goto end_thread_1;
- }
- }
- ++send_count;
- DEBUG_CM("send a string:%d",send_count);
- if(cm_list_size(&cm_dev->ready_list) > 0){
- pnode = pop_list(&cm_dev->ready_list);
- sprintf(pnode->buf,"send_count:%d",send_count);
- list_add_tail(&pnode->node,&cm_dev->ok_list);
- wake_up_interruptible(&cm_dev->r_wait);
- }else{
- DEBUG_CM("ready_list size == 0");
- }
-
- }
- end_thread_1:
- remove_wait_queue(&cm_dev->w_wait,&wait);
- return 0;
- }
-
- static int
- cm_thread_2(void *arg)
- {
- int ret = 0;
- int send_count = 0;
- struct buf_node *pnode;
- struct cm_dev_ *cm_dev = (struct cm_dev_ *)arg;
- wait_queue_t wait = __WAITQUEUE_INITIALIZER(wait, current);
- add_wait_queue(&cm_dev->r_wait,&wait);
- while(1){
- if(kthread_should_stop()){
- DEBUG_CM("exit thread");
- break;
- }
- while(cm_list_size(&cm_dev->ok_list) == 0){
- set_current_state(TASK_INTERRUPTIBLE);
- schedule();
- ret = signal_pending(current);
- if(ret){
- DEBUG_CM("ret = %d",ret);
- continue;
- }
- //执行kthread_stop函数后,也会调度该线程,此时signal_pending也是0
- if(kthread_should_stop()){
- DEBUG_CM("exit thread");
- goto end_thread_2;
- }
- }
- ++send_count;
- if(cm_list_size(&cm_dev->ok_list) > 0){
- DEBUG_CM("send a string:%d",send_count);
- pnode = pop_list(&cm_dev->ok_list);
- DEBUG_CM("pnode->buf = %s",pnode->buf);
- list_add_tail(&pnode->node,&cm_dev->ready_list);
- wake_up_interruptible(&cm_dev->w_wait);
- }else{
- DEBUG_CM("ready_list size == 0");
- }
- }
- end_thread_2:
- remove_wait_queue(&cm_dev->r_wait,&wait);
- return 0;
- }
截取一段运行结果:
- [ 432.577454] /big/csi_driver/csi_buf/csi_buf.c:cm_thread_2:200: pnode->buf = send_count:5258
- [ 432.585847] /big/csi_driver/csi_buf/csi_buf.c:cm_thread_1:152: send a string:5259
- [ 432.593387] /big/csi_driver/csi_buf/csi_buf.c:cm_thread_2:198: send a string:5259
- [ 432.600879] /big/csi_driver/csi_buf/csi_buf.c:cm_thread_2:200: pnode->buf = send_count:5259
- [ 432.609265] /big/csi_driver/csi_buf/csi_buf.c:cm_thread_1:131:
- [ 432.615217] /big/csi_driver/csi_buf/csi_buf.c:cm_thread_1:136:
- [ 432.621145] /big/csi_driver/csi_buf/csi_buf.c:cm_thread_1:152: send a string:5260
- [ 432.628686] /big/csi_driver/csi_buf/csi_buf.c:cm_thread_2:198: send a string:5260
- [ 432.636204] /big/csi_driver/csi_buf/csi_buf.c:cm_thread_1:131:
- [ 432.642132] /big/csi_driver/csi_buf/csi_buf.c:cm_thread_1:136:
- [ 432.648086] /big/csi_driver/csi_buf/csi_buf.c:cm_thread_2:200: pnode->buf = send_count:5260
- [ 432.656472] /big/csi_driver/csi_buf/csi_buf.c:cm_thread_1:152: send a string:5261
- [ 432.664001] /big/csi_driver/csi_buf/csi_buf.c:cm_thread_2:198: send a string:5261
- [ 432.671492] /big/csi_driver/csi_buf/csi_buf.c:cm_thread_2:200: pnode->buf = send_count:5261
- [ 432.679875] /big/csi_driver/csi_buf/csi_buf.c:cm_thread_1:131:
- [ 432.685825] /big/csi_driver/csi_buf/csi_buf.c:cm_thread_1:136:
- [ 432.691755] /big/csi_driver/csi_buf/csi_buf.c:cm_thread_1:152: send a string:5262
- [ 432.699340] /big/csi_driver/csi_buf/csi_buf.c:cmcsi_buf/csi_buf.c:cm_thread_1:152: send a string:5284
- [ 433.476323] /big/csi_driver/csi_buf/csi_buf.c:cm_thread_2:198: send a string:5284
- [ 433.483846] /big/csi_driver/csi_buf/csi_buf.c:cm_thread_1:131:
- [ 433.489777] /big/csi_driver/csi_buf/csi_buf.c:cm_thread_1:136:
- [ 433.495737] /big/csi_driver/csi_buf/csi_buf.c:cm_thread_2:200: pnode->buf = send_count:5284