全部博文(45)
分类: LINUX
2017-08-02 20:08:45
最近看了linux内核中关于内核线程部分的代码,对kthread_stop和kthread_should_stop这两个API进行了学习,其中有了自己的一些见解,想把这部分的内容记录下来,以便日后查看。但是,kthread_stop这个API用到了completion,所以决定先将这部分内容记录一下,作为分析kthread_stop的准备工作吧。
一、completion的定义与常用API
1 、定义
在completion的定义中wait是一个等待队列队头,当有内核线程调用wait的时候,如果条件不满足,就会将该该线程添加该等待队列中。而completion的done成员,就是一个标记,用来标记这个条件的,当done为0的时候,条件不满足,非零的情况下,调用线程不需要等待。
2、completion的初始化
completion的初始化,分为静态初始化和动态初始化。静态初始化通过宏定义实现,源码如下:
动态初始化同样比较简单,实现如下:
2、wait_for_completion
对completion对象调用wait操作的函数很多,我先列示如下,由于其操作本质上都是一样的,只不过在条件不满足的时候采取的动作不同罢了,所以,只选择一个函数wait_for_completion进行分析。
wait_for_completion()这个函数实现的也是比较简单的,先列出其代码,然后在一一分析。
从上面内核源码可以很容看出,调用路径为wait_for_completion——>wait_for_common——>do_wait_for_common,这里wait_for_completion只是简单的讲了两个参数,一个timeout,其值为MAX_SCHEDULE_TIMEOUT,被定义为LONG_MAX,对理解wait_for_completion没什么影响。在do_wait_for_common函数中,可以看到,实际上是把当前进程加加入到了该complete变量x的等待队列中,这是在21行和22行中完成额。注意在21行设置了标记WQ_FLAG_EXCLUSIVE,这个标记实际上是避免“惊群现象”。默认情况下,当当等待时间满足时,会唤醒所有等待队列里面的任务,但只有其中一个任务会继续执行下去,其他的任务在被唤醒后又会再次等待。在设置了WQ_FLAG_EXCLUSIVE标记后,就不会发生这样的现象。具体怎么实现的可以查一查。在24行的signal_pending_state()函数中,实际上是为了检测进程是否可以休眠,如果有信号在pending状态,而且state状态还是UNINTERRUPTIBLE状态的话,是不能休眠等待的。果线程满足休眠的条件,就会到28行,更改线程的状态,调用schedule_timeout()函数,将当前线程休眠。在休眠之前释放自旋锁。
在32行,检测线程等待的条件是否满足。也就是done着这个标记是否被更改为非0值,或者是否等待时间到了,如果二者有一个条件满足,线程就不在等待,否则线程会再次等待。在34-35行,检测是否因为等待超时而被唤醒。如果执行37行,那么等待的条件以及满足了,当然这个条件是complete()设置了,这里实际行说已经与获得了自旋锁的状态了,所以37行才可以更改done。
4.complete() 和complete_all()
done这个标记的设置,实际上是在complete和complete_all这两个函数中设置,下面是这两个函数的源码。
点击(此处)折叠或打开
这两个函数逻辑很简单,只是修改done的值,然后唤醒等待线程。
B_C_10242019-11-25 13:33:52
kirito19960111:作者您好:wait_for_completion()的第30行这里传入的参数是 MAX_SCHEDULE_TIMEOUT,据我所知这个值是个负值,那么进入schedule_timeout()后,进入case MAX_SCHEDULE_TIMEOUT:分支,返回值应该是0(MAX_SCHEDULE_TIMEOUT为负值,所以return那里返回0),那么在wait_for_completion()的第32行判断时,timeout直接是0不就直接跳出循环了吗,我不知道中间哪一步分析出现了问题,您能解答一下吗?对于该部分函数的实现,您这是最详细的了。
几年没看linux内核的东西了,已经忘记了。好像schedule_timeout()执行的过程中,进程就会被调度走了,下次调度回来的的时候schedule_timeout()才会继续返回,往后执行吧。
回复 | 举报B_C_10242019-11-25 13:33:48
kirito19960111:作者您好:wait_for_completion()的第30行这里传入的参数是 MAX_SCHEDULE_TIMEOUT,据我所知这个值是个负值,那么进入schedule_timeout()后,进入case MAX_SCHEDULE_TIMEOUT:分支,返回值应该是0(MAX_SCHEDULE_TIMEOUT为负值,所以return那里返回0),那么在wait_for_completion()的第32行判断时,timeout直接是0不就直接跳出循环了吗,我不知道中间哪一步分析出现了问题,您能解答一下吗?对于该部分函数的实现,您这是最详细的了。
几年没看linux内核的东西了,已经忘记了。好像schedule_timeout()执行的过程中,进程就会被调度走了,下次调度回来的的时候schedule_timeout()才会继续返回,往后执行吧。
回复 | 举报kirito199601112019-10-17 16:30:30
作者您好:wait_for_completion()的第30行这里传入的参数是 MAX_SCHEDULE_TIMEOUT,据我所知这个值是个负值,那么进入schedule_timeout()后,进入case MAX_SCHEDULE_TIMEOUT:分支,返回值应该是0(MAX_SCHEDULE_TIMEOUT为负值,所以return那里返回0),那么在wait_for_completion()的第32行判断时,timeout直接是0不就直接跳出循环了吗,我不知道中间哪一步分析出现了问题,您能解答一下吗?对于该部分函数的实现,您这是最详细的了。