linux中request_region()函数的分析

linux中request_region()函数的分析  



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这个函数实际上就是为了保证对资源的互斥访问!
  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值