注册 登录  
 加关注
   显示下一条  |  关闭
温馨提示!由于新浪微博认证机制调整,您的新浪微博帐号绑定已过期,请重新绑定!立即重新绑定新浪微博》  |  关闭

小白的博客

嵌入式爱好者

 
 
 

日志

 
 

linux中request_region()函数的分析  

2012-09-26 17:23:01|  分类: 韦东山视频第二轮 |  标签: |举报 |字号 订阅

  下载LOFTER 我的照片书  |
闲话少说,上代码:

struct resource ioport_resource = {
.name = "PCI IO",
.start = 0,
.end = IO_SPACE_LIMIT, //IO_SPACE_LIMIT = 0xffffffff
.flags = IORESOURCE_IO,
};

request_region(iobase, 2, dev->name)
      __request_region(&ioport_resource, (start), (n), (name), 0)
              struct resource *res = kzalloc(sizeof(*res), GFP_KERNEL);
              res->name = name;
              res->start = start;
              res->end = start + n - 1;
              res->flags = IORESOURCE_BUSY;
              res->flags |= flags;                //以上是将资源的信息记录在res中
              write_lock(&resource_lock);//关于这个锁详见注释1
              conflict = __request_resource(parent, res);//请求资源,返回值为0表示请求成功,详见注释2
如果申请成功的话,就保留res空间,因为这是已经形成了注释2里面的链表了。如果申请失败的话,回进行如下处理:
判断返回值是否是parent,是parent则表示是资源本身就有问题。如果没有问题的话,判断与本次申请相冲突的资源是否真的处于繁忙状态,如果不是真的繁忙,就会重新申请,否则向下执行。
如果资源真的繁忙的话,会判断该资源是否是多路复用的,如果是的话,就会将当前进程挂起,调度其他进程来执行!当本进程重新被调度时,又会循环去判断是否可以获得资源。所以如果资源可以多路复用,得不到该资源就不会返回。如果该资源不可多路复用,则立即会释放空间,返回NULL!

注释1:
read_lock()和write_lock()
锁变量的初值为RW_LOCK_UNLOCKED(0x01000000),锁变量为正时为未锁状态反之为上锁状态。 
read_lock()对锁变量减1,如果结果为负,则说明已被某个write_lock()上锁。然后read_lock()对锁变量加1,释 放read_lock状态,接着等待锁变量的值变为1;一旦锁变量变为1,read_lock()再次对锁变量减1 ,如果非负则成功,否则重复上述过程。 
write_lock()对锁变量减0x01000000,如果结果非零,则说明已被write_lock()或read_lock()上锁。然 后write_lock()对锁变量加0x01000000,释放write_lock()状态,接着等待锁变量的值变为0x01000000;一旦锁变 量变为0x01000000,write_lock()再次对锁变量减0x01000000,如果为零则成功,否则重复上述过程。 
由此可以实现多个同时读,但是读----写和写-----写是互斥的!

那么针对上面的程序,就是说,当一个进程没有释放写锁之前,另一个进程无法对write_lock(&resource_lock);和write_unlock(&resource_lock);之间的代码进行操作!

注释2:
static struct resource * __request_resource(struct resource *root, struct resource *new)
{
resource_size_t start = new->start;
resource_size_t end = new->end;
struct resource *tmp, **p;

        //以下三个判断是出错处理,不必关心
if (end < start)
return root;
if (start < root->start)
return root;
if (end > root->end)
return root;
p = &root->child; 
for (;;) {
tmp = *p;
if (!tmp || tmp->start > end) {
new->sibling = tmp;  
*p = new;                   
new->parent = root;
return NULL;    
}
p = &tmp->sibling;
if (tmp->end < start) 
continue;
return tmp;
}
}
我们用个例子来说明一下上面的程序:
如果有四个资源的申请,前三次申请的资源都没有出现交集,那么前三次的资源就会形成如下的关系:每个资源的parent都指向root,root的child指向第三次申请的资源,第三次申请的资源的sibling指向第二次申请的资源,第二次申请的资源的sibling指向第一次申请的资源,第一次申请的资源的sibling指向null。如下图所示:

linux中request_region()函数的分析 - 小白 - 小白的博客

现在开始第四次申请资源,判断res3->start是否大于本次申请资源的结束地址,如果是的话,说明没有交集,就会重复以上工作,然后返回!如果不成立的话,说明可能有交集,会让p指向res2,并判断res3->end是否小于本次资源的起始地址,如果是的话,说明没有交集就会结束本次循环,开始下一次循环。下一次循环会跟res2比较有无交集,如果没有交集会跟res1比较,如果还是没有交集的话,下一次的循环tmp=NULL,就会成功返回,一旦发现申请的资源跟之前申请的资源存在交集的话,就会出错返回,返回值是与本次申请出现交集的资源的地址!

经过上面的分析就很清楚了,request_region这个函数实际上就是为了保证对资源的互斥访问!
  评论这张
 
阅读(2527)| 评论(0)
推荐 转载

历史上的今天

评论

<#--最新日志,群博日志--> <#--推荐日志--> <#--引用记录--> <#--博主推荐--> <#--随机阅读--> <#--首页推荐--> <#--历史上的今天--> <#--被推荐日志--> <#--上一篇,下一篇--> <#-- 热度 --> <#-- 网易新闻广告 --> <#--右边模块结构--> <#--评论模块结构--> <#--引用模块结构--> <#--博主发起的投票-->
 
 
 
 
 
 
 
 
 
 
 
 
 
 

页脚

网易公司版权所有 ©1997-2017