Android内核wake_up源码分析

免费教程   2024年05月10日 14:15  

今天小编给大家分享一下Android内核wake_up源码分析的相关知识点,内容详细,逻辑清晰,相信大部分人都还太了解这方面的知识,所以分享这篇文章给大家参考一下,希望大家阅读完这篇文章后有所收获,下面我们一起来了解一下吧。

内核中通常用法:

内核有个函数 _interruptible 通常来说看到这俩函数调用就是唤醒等待队列上的线程。

直到看了epoll的源码,发现并非如此。

boolwakeup_condition;wait_queue_head_twait_queue;init_waitqueue_head(&amp;wait_queue);wait_queue_entry_twq_entry//waitwait_event_interruptible(&amp;wait_queue,wakeup_condition||kthread_should_stop());//唤醒//设置等待条件为true,并唤醒wakeup_condition=true;wake_up(&amp;wait_queue);wake_up 的源码://common/include/linux/wait.h#defineTASK_NORMAL(TASK_INTERRUPTIBLE|TASK_UNINTERRUPTIBLE)#definewake_up(x)__wake_up(x,TASK_NORMAL,1,NULL)#definewake_up_interruptible(x)__wake_up(x,TASK_INTERRUPTIBLE,1,NULL)//common/kernel/sched/wait.c//wake_up是个宏,展开后调用的是__wake_up函数//__wake_up(x,TASK_INTERRUPTIBLE|TASK_UNINTERRUPTIBLE,1,NULL)int__wake_up(structwait_queue_head*wq_head,unsignedintmode,intnr_exclusive,void*key){return__wake_up_common_lock(wq_head,mode,nr_exclusive,0,key);}EXPORT_SYMBOL(__wake_up);//__wake_up_common_lock(wq_head,TASK_INTERRUPTIBLE|TASK_UNINTERRUPTIBLE,1,0,NULL)staticint__wake_up_common_lock(structwait_queue_head*wq_head,unsignedintmode,intnr_exclusive,intwake_flags,void*key){unsignedlongflags;wait_queue_entry_tbookmark;intremaining=nr_exclusive;bookmark.flags=0;bookmark.private=NULL;bookmark.func=NULL;INIT_LIST_HEAD(&bookmark.entry);//初始化链表:链表的next和prev指针都指向链表自身地址do{spin_lock_irqsave(&wq_head->lock,flags);//自旋锁上锁,对队列上锁remaining=__wake_up_common(wq_head,mode,remaining,wake_flags,key,&bookmark);spin_unlock_irqrestore(&wq_head->lock,flags);//自旋锁解锁}while(bookmark.flags&WQ_FLAG_BOOKMARK);returnnr_exclusive-remaining;//队列为空时,remaining=nr_exclusive,此时return0;}//__wake_up_common(wq_head,TASK_INTERRUPTIBLE|TASK_UNINTERRUPTIBLE,1,0,NULL,&bookmark);staticint__wake_up_common(structwait_queue_head*wq_head,unsignedintmode,intnr_exclusive,intwake_flags,void*key,wait_queue_entry_t*bookmark){wait_queue_entry_t*curr,*next;intcnt=0;lockdep_assert_held(&wq_head->lock);//bookmark.flags=0;WQ_FLAG_BOOKMARK=0x04;if(bookmark&&(bookmark->flags&WQ_FLAG_BOOKMARK)){//不会进入此分支curr=list_next_entry(bookmark,entry);list_del(&bookmark->entry);bookmark->flags=0;}elsecurr=list_first_entry(&wq_head->head,wait_queue_entry_t,entry);//获取wq_head队列的第一个元素if(&curr->entry==&wq_head->head)//队列为空时,直接返回传入的nr_exclusivereturnnr_exclusive;list_for_each_entry_safe_from(curr,next,&wq_head->head,entry){//遍历链表unsignedflags=curr->flags;intret;if(flags&WQ_FLAG_BOOKMARK)continue;/*调用wait_queue_entry_t中的回调函数func//这里依据func的类型会出现不同的结果。使用init_waitqueue_entry初始化的wait_queue_entry_t,func=default_wake_function,这个函数会唤醒curr->private上的线程。使用init_waitqueue_func_entry初始化的wait_queue_entry_t,仅仅是做普通的函数调用。*/ret=curr->func(curr,mode,wake_flags,key);if(ret<0)break;if(ret&&(flags&WQ_FLAG_EXCLUSIVE)&&!--nr_exclusive)break;if(bookmark&&(++cnt>WAITQUEUE_WALK_BREAK_CNT)&&(&next->entry!=&wq_head->head)){bookmark->flags=WQ_FLAG_BOOKMARK;list_add_tail(&bookmark->entry,&next->entry);break;}}returnnr_exclusive;}func 赋值过程wait_queue_head 和 wait_queue_entry 数据结构//内核4.14以后//common/include/linux/wait.hstructwait_queue_head{//wait队列spinlock_tlock;//自旋锁structlist_headhead;//添加到wait队列时,就是把wait_queue_entry.entry加入这个head链表};/**Asinglewait-queueentrystructure:*/structwait_queue_entry{//wait队列的一个项unsignedintflags;void*private;//私有数据,在init_waitqueue_entry中代表线程,在init_waitqueue_func_entry中为nullwait_queue_func_tfunc;//回调函数structlist_headentry;//添加到wait队列时,就是把这个entry加入到wait_queue_head.head的链表};typedefstructwait_queue_headwait_queue_head_t;//wait_queue_head_t同wait_queue_headtypedefstructwait_queue_entrywait_queue_entry_t;//wait_queue_entry_t同wait_queue_entry

对于 wait_queue_entry 有两种常用的初始化方法 init_waitqueue_entry 和 init_waitqueue_func_entry

两种等待任务 wait_queue_entry:线程 和 函数//common/include/linux/wait.hstaticinlinevoidinit_waitqueue_entry(structwait_queue_entry*wq_entry,structtask_struct*p){wq_entry-&gt;flags=0;wq_entry-&gt;private=p;//把需要唤醒的线程存储到private数据中//func赋值为default_wake_function函数//这个函数的作用是唤醒等待队列上的线程wq_entry-&gt;func=default_wake_function;//这函数作用是:唤醒线程p}staticinlinevoidinit_waitqueue_func_entry(structwait_queue_entry*wq_entry,wait_queue_func_tfunc){wq_entry-&gt;flags=0;wq_entry-&gt;private=NULL;wq_entry-&gt;func=func;//直接把传入的回调函数赋值给wq_entry-&gt;func}default_wake_function 函数

这个函数的作用基本等效于 wake_up_process 函数。

intdefault_wake_function(wait_queue_entry_t*curr,unsignedmode,intwake_flags,void*key){WARN_ON_ONCE(IS_ENABLED(CONFIG_SCHED_DEBUG)&amp;&amp;wake_flags&amp;~WF_SYNC);//try_to_wake_up函数通过把进程状态设置为TASK_RUNNING,并把该进程插入本地CPU运行队列rq来达到唤醒睡眠和停止的进程的目的.//curr-&gt;private存储了需要唤醒的线程returntry_to_wake_up(curr-&gt;private,mode,wake_flags);}EXPORT_SYMBOL(default_wake_function);综上:

wake_up ,可能是唤醒队列上的线程,也可能仅仅是触发一个回调而已

wake_up的两种用法:

boolwakeup_condition;wait_queue_head_twait_queue;init_waitqueue_head(&wait_queue);wait_queue_entry_twq_entry//wait第一种用法:线程等待wait_event_interruptible(&wait_queue,wakeup_condition||kthread_should_stop());第二种用法:添加一个回调到等待队列上init_waitqueue_func_entry(&wq_entry,callback);add_wait_queue(&wait_queue,&wq_entry);//唤醒设置等待条件为true,并唤醒wakeup_condition=true;//内部遍历队列,调用每个wait_queue_entry的func函数,根据func不同为产生不同效果wake_up(&wait_queue);

以上就是“Android内核wake_up源码分析”这篇文章的所有内容,感谢各位的阅读!相信大家阅读完这篇文章都有很大的收获,小编每天都会为大家更新不同的知识,如果还想学习更多的知识,请关注行业资讯频道。

域名注册
购买VPS主机

您或许对下面这些文章有兴趣:                    本月吐槽辛苦排行榜

看贴要回贴有N种理由!看帖不回贴的后果你懂得的!


评论内容 (*必填):
(Ctrl + Enter提交)   

部落快速搜索栏

各类专题梳理

网站导航栏

X
返回顶部