[ZLG-ARM] 内核源码kfifo分析

[复制链接]
2124|1
 楼主| reeper 发表于 2009-4-9 14:51 | 显示全部楼层 |阅读模式
/**<br />*&nbsp;kfifo_init&nbsp;-&nbsp;allocates&nbsp;a&nbsp;new&nbsp;FIFO&nbsp;using&nbsp;a&nbsp;preallocated&nbsp;buffer<br />*&nbsp;@buffer:&nbsp;the&nbsp;preallocated&nbsp;buffer&nbsp;to&nbsp;be&nbsp;used.<br />*&nbsp;@size:&nbsp;the&nbsp;size&nbsp;of&nbsp;the&nbsp;internal&nbsp;buffer,&nbsp;this&nbsp;have&nbsp;to&nbsp;be&nbsp;a&nbsp;power&nbsp;of&nbsp;2.<br />*&nbsp;@gfp_mask:&nbsp;get_free_pages&nbsp;mask,&nbsp;passed&nbsp;to&nbsp;kmalloc()<br />*&nbsp;@lock:&nbsp;the&nbsp;lock&nbsp;to&nbsp;be&nbsp;used&nbsp;to&nbsp;protect&nbsp;the&nbsp;fifo&nbsp;buffer<br />*<br />*&nbsp;Do&nbsp;NOT&nbsp;pass&nbsp;the&nbsp;kfifo&nbsp;to&nbsp;kfifo_free()&nbsp;after&nbsp;use!&nbsp;Simply&nbsp;free&nbsp;the<br />*&nbsp;&struct&nbsp;kfifo&nbsp;with&nbsp;kfree().<br />*/<br />struct&nbsp;kfifo&nbsp;*kfifo_init(unsigned&nbsp;char&nbsp;*buffer,&nbsp;unsigned&nbsp;int&nbsp;size,<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;gfp_t&nbsp;gfp_mask,&nbsp;spinlock_t&nbsp;*lock)<br />{<br />&nbsp;&nbsp;&nbsp;&nbsp;struct&nbsp;kfifo&nbsp;*fifo;<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;/*&nbsp;size&nbsp;must&nbsp;be&nbsp;a&nbsp;power&nbsp;of&nbsp;2&nbsp;*/<br />&nbsp;&nbsp;&nbsp;&nbsp;BUG_ON(size&nbsp;&&nbsp;(size&nbsp;-&nbsp;1));&nbsp;//大小必须为2的k次方(k&gt0)的目的在于put/get中从虚拟索引计算真实索引,size&nbsp;&&nbsp;(size&nbsp;-&nbsp;1)是常用判断技巧<br /><br /><br />&nbsp;&nbsp;&nbsp;&nbsp;fifo&nbsp;=&nbsp;kmalloc(sizeof(struct&nbsp;kfifo),&nbsp;gfp_mask);&nbsp;//分配kfifo数据结构<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;if&nbsp;(!fifo)<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;ERR_PTR(-ENOMEM);<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;fifo-&gtbuffer&nbsp;=&nbsp;buffer;<br />&nbsp;&nbsp;&nbsp;&nbsp;fifo-&gtsize&nbsp;=&nbsp;size;<br />&nbsp;&nbsp;&nbsp;&nbsp;fifo-&gtin&nbsp;=&nbsp;fifo-&gtout&nbsp;=&nbsp;0;&nbsp;//当fifo-&gtin&nbsp;==&nbsp;fifo-&gtout&nbsp;时,表示空队列<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;fifo-&gtlock&nbsp;=&nbsp;lock;<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;fifo;<br />}<br /><br /><br />/**<br />*&nbsp;kfifo_alloc&nbsp;-&nbsp;allocates&nbsp;a&nbsp;new&nbsp;FIFO&nbsp;and&nbsp;its&nbsp;internal&nbsp;buffer<br />*&nbsp;@size:&nbsp;the&nbsp;size&nbsp;of&nbsp;the&nbsp;internal&nbsp;buffer&nbsp;to&nbsp;be&nbsp;allocated.<br />*&nbsp;@gfp_mask:&nbsp;get_free_pages&nbsp;mask,&nbsp;passed&nbsp;to&nbsp;kmalloc()<br />*&nbsp;@lock:&nbsp;the&nbsp;lock&nbsp;to&nbsp;be&nbsp;used&nbsp;to&nbsp;protect&nbsp;the&nbsp;fifo&nbsp;buffer<br />*<br />*&nbsp;The&nbsp;size&nbsp;will&nbsp;be&nbsp;rounded-up&nbsp;to&nbsp;a&nbsp;power&nbsp;of&nbsp;2.<br />*/<br />//通过调用kfifo_alloc分配队列空间,该函数会调用kfifo_init初始化kfifo结构体,并调整size的大小以适应运算<br /><br />struct&nbsp;kfifo&nbsp;*kfifo_alloc(unsigned&nbsp;int&nbsp;size,&nbsp;gfp_t&nbsp;gfp_mask,&nbsp;spinlock_t&nbsp;*lock)<br />{<br />&nbsp;&nbsp;&nbsp;&nbsp;unsigned&nbsp;char&nbsp;*buffer;<br />&nbsp;&nbsp;&nbsp;&nbsp;struct&nbsp;kfifo&nbsp;*ret;<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;/*<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;round&nbsp;up&nbsp;to&nbsp;the&nbsp;next&nbsp;power&nbsp;of&nbsp;2,&nbsp;since&nbsp;our&nbsp;'let&nbsp;the&nbsp;indices<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;wrap'&nbsp;tachnique&nbsp;works&nbsp;only&nbsp;in&nbsp;this&nbsp;case.<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*/<br />&nbsp;&nbsp;&nbsp;&nbsp;if&nbsp;(size&nbsp;&&nbsp;(size&nbsp;-&nbsp;1))&nbsp;{&nbsp;//如果size不是2的k次方,代码将size调整最近的2^k次方附近<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;BUG_ON(size&nbsp;&gt&nbsp;0x80000000);<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;size&nbsp;=&nbsp;roundup_pow_of_two(size);<br />&nbsp;&nbsp;&nbsp;&nbsp;}<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;buffer&nbsp;=&nbsp;kmalloc(size,&nbsp;gfp_mask);<br />&nbsp;&nbsp;&nbsp;&nbsp;if&nbsp;(!buffer)<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;ERR_PTR(-ENOMEM);<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;ret&nbsp;=&nbsp;kfifo_init(buffer,&nbsp;size,&nbsp;gfp_mask,&nbsp;lock);<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;if&nbsp;(IS_ERR(ret))<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;kfree(buffer);<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;ret;<br />}<br /><br />/**<br />*&nbsp;__kfifo_put&nbsp;-&nbsp;puts&nbsp;some&nbsp;data&nbsp;into&nbsp;the&nbsp;FIFO,&nbsp;no&nbsp;locking&nbsp;version<br />*&nbsp;@fifo:&nbsp;the&nbsp;fifo&nbsp;to&nbsp;be&nbsp;used.<br />*&nbsp;@buffer:&nbsp;the&nbsp;data&nbsp;to&nbsp;be&nbsp;added.<br />*&nbsp;@len:&nbsp;the&nbsp;length&nbsp;of&nbsp;the&nbsp;data&nbsp;to&nbsp;be&nbsp;added.<br />*<br />*&nbsp;This&nbsp;function&nbsp;copies&nbsp;at&nbsp;most&nbsp;@len&nbsp;bytes&nbsp;from&nbsp;the&nbsp;@buffer&nbsp;into<br />*&nbsp;the&nbsp;FIFO&nbsp;depending&nbsp;on&nbsp;the&nbsp;free&nbsp;space,&nbsp;and&nbsp;returns&nbsp;the&nbsp;number&nbsp;of<br />*&nbsp;bytes&nbsp;copied.<br />*<br />*&nbsp;Note&nbsp;that&nbsp;with&nbsp;only&nbsp;one&nbsp;concurrent&nbsp;reader&nbsp;and&nbsp;one&nbsp;concurrent<br />*&nbsp;writer,&nbsp;you&nbsp;don't&nbsp;need&nbsp;extra&nbsp;locking&nbsp;to&nbsp;use&nbsp;these&nbsp;functions.<br />*/<br />unsigned&nbsp;int&nbsp;__kfifo_put(struct&nbsp;kfifo&nbsp;*fifo,<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;unsigned&nbsp;char&nbsp;*buffer,&nbsp;unsigned&nbsp;int&nbsp;len)<br />{<br />&nbsp;&nbsp;&nbsp;&nbsp;unsigned&nbsp;int&nbsp;l;<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;//fifo-&gtsize&nbsp;-&nbsp;fifo-&gtin&nbsp;+&nbsp;fifo-&gtout,这段代码计算空闲的空间<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;//in是写索引,out是读索引,而且put与get操作都是分别增加in与out的值来重新计算虚拟索引<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;//注意,out&nbsp;始终不会大于&nbsp;in,(in&nbsp;-&nbsp;out)是有效数据空间大小,size是总空间的大小<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;//那么空闲的空间大小就是&nbsp;size&nbsp;-&nbsp;(int&nbsp;-&nbsp;out)<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;//如果请求的len大于空闲空间,就使len&nbsp;=&nbsp;size&nbsp;-&nbsp;(int&nbsp;-&nbsp;out)<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;len&nbsp;=&nbsp;min(len,&nbsp;fifo-&gtsize&nbsp;-&nbsp;fifo-&gtin&nbsp;+&nbsp;fifo-&gtout);&nbsp;<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;/*<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;Ensure&nbsp;that&nbsp;we&nbsp;sample&nbsp;the&nbsp;fifo-&gtout&nbsp;index&nbsp;-before-&nbsp;we<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;start&nbsp;putting&nbsp;bytes&nbsp;into&nbsp;the&nbsp;kfifo.<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*/<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;smp_mb();<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;/*&nbsp;first&nbsp;put&nbsp;the&nbsp;data&nbsp;starting&nbsp;from&nbsp;fifo-&gtin&nbsp;to&nbsp;buffer&nbsp;end&nbsp;*/<br />&nbsp;&nbsp;&nbsp;&nbsp;//(fifo-&gtin&nbsp;&&nbsp;(fifo-&gtsize&nbsp;-&nbsp;1))这段代码计算真实的写索引偏移,笔者假设为real_in<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;//这是因为in在每次调用put之后都会增加一个len的长度<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;//由于fifo-&gtsize必定是2的k次方,而(fifo-&gtsize&nbsp;-&nbsp;1)就是类似0x00FFFFF的值<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;//(fifo-&gtin&nbsp;&&nbsp;(fifo-&gtsize&nbsp;-&nbsp;1))的操作从数学角度将就是对长度fifo-&gtsize的取模运算<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;//这里能用AND运算代替取模运算得益于前面申请的空间大小为2^k次方<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;//l&nbsp;=&nbsp;min(空闲空间大小,从real_in开始到缓冲区结尾的空间)<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;l&nbsp;=&nbsp;min(len,&nbsp;fifo-&gtsize&nbsp;-&nbsp;(fifo-&gtin&nbsp;&&nbsp;(fifo-&gtsize&nbsp;-&nbsp;1)));<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;//先从buffer中拷贝l字节到缓冲区剩余空间,l&lt=len,也&lt=从real_in开始到缓冲区结尾的空间<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;//所以这个copy可能没拷贝完,但是不会造成缓冲区越界<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;memcpy(fifo-&gtbuffer&nbsp;+&nbsp;(fifo-&gtin&nbsp;&&nbsp;(fifo-&gtsize&nbsp;-&nbsp;1)),&nbsp;buffer,&nbsp;l);<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;/*&nbsp;then&nbsp;put&nbsp;the&nbsp;rest&nbsp;(if&nbsp;any)&nbsp;at&nbsp;the&nbsp;beginning&nbsp;of&nbsp;the&nbsp;buffer&nbsp;*/<br />&nbsp;&nbsp;&nbsp;&nbsp;//当len&nbsp;&gt&nbsp;l时,拷贝buffer中剩余的内容,其实地址当然为buffer&nbsp;+&nbsp;l,而剩余的大小为len&nbsp;-&nbsp;l<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;//当len&nbsp;==&nbsp;l时,下面的memcpy啥都不干,绝对精妙的算法<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;memcpy(fifo-&gtbuffer,&nbsp;buffer&nbsp;+&nbsp;l,&nbsp;len&nbsp;-&nbsp;l);<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;/*<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;Ensure&nbsp;that&nbsp;we&nbsp;add&nbsp;the&nbsp;bytes&nbsp;to&nbsp;the&nbsp;kfifo&nbsp;-before-<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;we&nbsp;update&nbsp;the&nbsp;fifo-&gtin&nbsp;index.<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*/<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;smp_wmb();<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;//更新in(写者)的逻辑索引<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;fifo-&gtin&nbsp;+=&nbsp;len;<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;len;<br />}<br /><br />/**<br />*&nbsp;__kfifo_get&nbsp;-&nbsp;gets&nbsp;some&nbsp;data&nbsp;from&nbsp;the&nbsp;FIFO,&nbsp;no&nbsp;locking&nbsp;version<br />*&nbsp;@fifo:&nbsp;the&nbsp;fifo&nbsp;to&nbsp;be&nbsp;used.<br />*&nbsp;@buffer:&nbsp;where&nbsp;the&nbsp;data&nbsp;must&nbsp;be&nbsp;copied.<br />*&nbsp;@len:&nbsp;the&nbsp;size&nbsp;of&nbsp;the&nbsp;destination&nbsp;buffer.<br />*<br />*&nbsp;This&nbsp;function&nbsp;copies&nbsp;at&nbsp;most&nbsp;@len&nbsp;bytes&nbsp;from&nbsp;the&nbsp;FIFO&nbsp;into&nbsp;the<br />*&nbsp;@buffer&nbsp;and&nbsp;returns&nbsp;the&nbsp;number&nbsp;of&nbsp;copied&nbsp;bytes.<br />*<br />*&nbsp;Note&nbsp;that&nbsp;with&nbsp;only&nbsp;one&nbsp;concurrent&nbsp;reader&nbsp;and&nbsp;one&nbsp;concurrent<br />*&nbsp;writer,&nbsp;you&nbsp;don't&nbsp;need&nbsp;extra&nbsp;locking&nbsp;to&nbsp;use&nbsp;these&nbsp;functions.<br />*/<br />unsigned&nbsp;int&nbsp;__kfifo_get(struct&nbsp;kfifo&nbsp;*fifo,<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;unsigned&nbsp;char&nbsp;*buffer,&nbsp;unsigned&nbsp;int&nbsp;len)<br />{<br />&nbsp;&nbsp;&nbsp;&nbsp;unsigned&nbsp;int&nbsp;l;<br />&nbsp;&nbsp;&nbsp;&nbsp;//读取的大小不能超过有效空间长度<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;//经过min运算后len&nbsp;&lt=&nbsp;请求的空间len,&nbsp;len&nbsp;&lt=&nbsp;size<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;len&nbsp;=&nbsp;min(len,&nbsp;fifo-&gtin&nbsp;-&nbsp;fifo-&gtout);<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;/*<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;Ensure&nbsp;that&nbsp;we&nbsp;sample&nbsp;the&nbsp;fifo-&gtin&nbsp;index&nbsp;-before-&nbsp;we<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;start&nbsp;removing&nbsp;bytes&nbsp;from&nbsp;the&nbsp;kfifo.<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*/<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;smp_rmb();<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;/*&nbsp;first&nbsp;get&nbsp;the&nbsp;data&nbsp;from&nbsp;fifo-&gtout&nbsp;until&nbsp;the&nbsp;end&nbsp;of&nbsp;the&nbsp;buffer&nbsp;*/<br />&nbsp;&nbsp;&nbsp;&nbsp;//同理,fifo-&gtout&nbsp;&&nbsp;(fifo-&gtsize&nbsp;-&nbsp;1)等于out(读者)的虚拟索引计算出来真实索引real_out<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;//fifo-&gtsize&nbsp;-&nbsp;real_out就等于该索引到缓冲区尾部的空间大小<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;//经过min运算后,l&lt=len,l&lt=real_out至缓冲区尾部的空间大小<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;l&nbsp;=&nbsp;min(len,&nbsp;fifo-&gtsize&nbsp;-&nbsp;(fifo-&gtout&nbsp;&&nbsp;(fifo-&gtsize&nbsp;-&nbsp;1)));<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;//从real_out开始拷贝l字节内容到buffer中<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;memcpy(buffer,&nbsp;fifo-&gtbuffer&nbsp;+&nbsp;(fifo-&gtout&nbsp;&&nbsp;(fifo-&gtsize&nbsp;-&nbsp;1)),&nbsp;l);<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;/*&nbsp;then&nbsp;get&nbsp;the&nbsp;rest&nbsp;(if&nbsp;any)&nbsp;from&nbsp;the&nbsp;beginning&nbsp;of&nbsp;the&nbsp;buffer&nbsp;*/<br />&nbsp;&nbsp;&nbsp;&nbsp;//如果l&ltlen,那么从fifo-&gtbuffer的首部开始继续拷贝剩下的内容<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;//如果l&nbsp;==&nbsp;len,memcpy啥都不干<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;memcpy(buffer&nbsp;+&nbsp;l,&nbsp;fifo-&gtbuffer,&nbsp;len&nbsp;-&nbsp;l);<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;/*<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;Ensure&nbsp;that&nbsp;we&nbsp;remove&nbsp;the&nbsp;bytes&nbsp;from&nbsp;the&nbsp;kfifo&nbsp;-before-<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;we&nbsp;update&nbsp;the&nbsp;fifo-&gtout&nbsp;index.<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*/<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;smp_mb();<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;//更新out(读者)的虚拟索引<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;fifo-&gtout&nbsp;+=&nbsp;len;<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;return&nbsp;len;<br />}<br />&nbsp;<br /><br /><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;从上面几个重要的函数可以看出一些特性,就是put函数能放入的数据长度永远不会大于缓冲区的长度,而fifo-&gtin&nbsp;-&nbsp;fifo-&gtout永远小于等于size。<br />get函数得到的数据永远小于等于size(这个是必然的)。<br />
zcying 发表于 2009-4-9 14:58 | 显示全部楼层

kfifo是干什么的?有什么功能?

  
您需要登录后才可以回帖 登录 | 注册

本版积分规则

139

主题

185

帖子

0

粉丝
快速回复 在线客服 返回列表 返回顶部