免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
最近访问板块 发新帖
查看: 4062 | 回复: 8
打印 上一主题 下一主题

中断服务程序队列未加锁 并发访问? [复制链接]

论坛徽章:
0
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2011-08-10 20:21 |只看该作者 |倒序浏览
内核版本 2.4.28-8 或者 2.4.0
文件:irq.c

do_IRQ() 中

  1. for (;;) {
  2.                 /* 这里解开了IRQ descriptor 的锁,其它cpu便可以竞争这个锁啦*/
  3.                 spin_unlock(&desc->lock);
  4.                 /* 这里运行IRQ descriptor 中的每一个中断服务程序*/
  5.                 handle_IRQ_event(irq, &regs, action);
  6.                 spin_lock(&desc->lock);

  7.                 if (!(desc->status & IRQ_PENDING))
  8.                         break;
  9.                 desc->status &= ~IRQ_PENDING;
  10.         }
  11.         desc->status &= ~IRQ_INPROGRESS;
复制代码
do_IRQ()->handle_IRQ_event() 中

  1. /* 这里取出每一个中断服务程序,没有什么保护措施?*/
  2. do {
  3.                 status |= action->flags;
  4.                 action->handler(irq, action->dev_id, regs);
  5.                 action = action->next;
  6.         } while (action);
复制代码
如果有另外一个cpu通过
request_irq()->setup_irq()

  1. /* 此处等待IRQ descriptor解锁*/
  2. spin_lock_irqsave(&desc->lock,flags);

  3.         /* 向IRQ descriptor上增加中断服务程序*/
  4.         p = &desc->action;
  5.         if ((old = *p) != NULL) {
  6.                 /* Can't share interrupts unless both agree to */
  7.                 if (!(old->flags & new->flags & SA_SHIRQ)) {
  8.                         spin_unlock_irqrestore(&desc->lock,flags);
  9.                         return -EBUSY;
  10.                 }

  11.                 /* add new interrupt at end of irq queue */
  12.                 do {
  13.                         p = &old->next;
  14.                         old = *p;
  15.                 } while (old);
  16.                 shared = 1;
  17.         }

  18.         *p = new;

  19.         if (!shared) {
  20.                 desc->depth = 0;
  21.                 desc->status &= ~(IRQ_DISABLED | IRQ_AUTODETECT | IRQ_WAITING);
  22.                 desc->handler->startup(irq);
  23.         }
  24. spin_unlock_irqrestore(&desc->lock,flags);
复制代码
问题是:一个cpu正在handle_IRQ_event()调用每一个中断服务程序,而另一个cpu在setup_irq()增加中断服务程序,这是否存在并发问题?还是在哪儿做了互斥保护的?求指教!

评分

参与人数 1可用积分 +2 收起 理由
smalloc + 2

查看全部评分

论坛徽章:
7
丑牛
日期:2013-10-18 14:43:21技术图书徽章
日期:2013-11-03 09:58:03辰龙
日期:2014-01-15 22:57:50午马
日期:2014-09-15 07:04:39丑牛
日期:2014-10-16 14:25:222015年亚洲杯之伊朗
日期:2015-03-16 10:24:352015亚冠之城南
日期:2015-05-31 09:52:32
2 [报告]
发表于 2011-08-11 00:40 |只看该作者
本帖最后由 smalloc 于 2011-08-11 00:41 编辑

感觉这段确实有问题。估计是一个不严密的折中设计吧。
假设handle_IRQ_event之前有任何自旋锁上锁,那么就决定了同一个中断不能在多处理器间同时处理。这可能带来效率的损失。而定时器中断却是这样一个典型。

setup_irq的时候即使没上锁也不会产生多大问题,有顺序添加一个结构并不会导致访问空指针。倒是free-irq的时候会产生问题,一般系统free出问题是小概率概率事件,一般情况下也不会调用FREE

我只能勉强这样解释了。希望懂中断和锁的朋友给出解释

论坛徽章:
0
3 [报告]
发表于 2011-08-11 13:40 |只看该作者
free_irq貌似也不会有问题,一个结点从单链表里面删除,也就只需要一次赋值,不会有中间状态。

可能有问题的是:结点从链表中删除之后,要将对应的对象析构(释放空间、停处理线程、什么的)。如果一边析构,action一边又正在另一个CPU上被运行着,那么就可能有问题。

我看了2.6.35的代码,free_irq在删除一个结点之后,会调用synchronize_irq(irq),确保其他CPU上的action结束,之后都会开始析构动作。2.4的代码我没看,应该也有类似的操作。

论坛徽章:
0
4 [报告]
发表于 2011-08-11 13:47 |只看该作者
回复 2# smalloc
”假设handle_IRQ_event之前有任何自旋锁上锁,那么就决定了同一个中断不能在多处理器间同时处理。这可能带来效率的损失。而定时器中断却是这样一个典型“

handle_IRQ_event()里面一般是在开中断的条件下运行的,如果在handle_IRQ_event()之前未将desc->lock解开,那么如果当前cpu响应了发生的一个同一中断,那么将再次请求加锁desc->lock,而desc->lock这个锁又没有解开,因此死锁。

在setup_irq()中,使用的是
spin_lock_irqsave(&desc->lock,flags);
这将防止当前cpu响应中断,和互斥其他cpu响应中断,从而并发访问IRQ descriptor。
既然这里考虑了”中断服务程序队列“的并发访问,为什么在handle_IRQ_event()中不考虑呢?

论坛徽章:
7
丑牛
日期:2013-10-18 14:43:21技术图书徽章
日期:2013-11-03 09:58:03辰龙
日期:2014-01-15 22:57:50午马
日期:2014-09-15 07:04:39丑牛
日期:2014-10-16 14:25:222015年亚洲杯之伊朗
日期:2015-03-16 10:24:352015亚冠之城南
日期:2015-05-31 09:52:32
5 [报告]
发表于 2011-08-11 13:57 |只看该作者
本帖最后由 smalloc 于 2011-08-11 14:14 编辑

回复 4# 魔血染青天


    自嵌可能是一个理由。不过,同级别的LEVEL中断是通过MASK保证不能嵌套的。至于能保证到哪段,就没细看了。
至于这个是是不是用来保证EDGE中断正常嵌套可以再看看。

论坛徽章:
0
6 [报告]
发表于 2011-08-11 14:16 |只看该作者
回复  smalloc
既然这里考虑了”中断服务程序队列“的并发访问,为什么在handle_IRQ_event()中不考虑呢?

魔血染青天 发表于 2011-08-11 13:47


setup_irq要同步的是写写并发,如果两个上下文同时写一个链表,肯定是有问题的。
而handle_IRQ_event对链表是只读的,只要操作小心,不需要与写者进行同步。

论坛徽章:
7
丑牛
日期:2013-10-18 14:43:21技术图书徽章
日期:2013-11-03 09:58:03辰龙
日期:2014-01-15 22:57:50午马
日期:2014-09-15 07:04:39丑牛
日期:2014-10-16 14:25:222015年亚洲杯之伊朗
日期:2015-03-16 10:24:352015亚冠之城南
日期:2015-05-31 09:52:32
7 [报告]
发表于 2011-08-11 20:04 |只看该作者
回复 4# 魔血染青天


    2。4中EDGE中断同级也是被MASK方式保护的。不可自嵌套。

论坛徽章:
0
8 [报告]
发表于 2011-09-13 13:23 |只看该作者
本帖最后由 魔血染青天 于 2011-09-13 13:32 编辑

这个问题,我自己找到了一个解释:

do_IRQ()->handle_IRQ_event() 中

/* 这里取出每一个中断服务程序,没有什么保护措施?*/
do {
                status |= action->flags;
                action->handler(irq, action->dev_id, regs);

               /* 这里对“action->next”读取的汇编指令应该是MOV,MOV的执行只要一个时
                * 钟周期,因此是原子性操作
                */

                action = action->next;
        } while (action);


request_irq()->setup_irq()


/* 此处等待IRQ descriptor解锁*/

/* 1 这里关中断是为了防止在获得desc->lock锁后,本cpu响应中断,从而再次请求对IRQ descriptor加
* 锁,从而死锁了
*/

spin_lock_irqsave(&desc->lock,flags);

        /* 向IRQ descriptor上增加中断服务程序*/
        p = &desc->action;
        if ((old = *p) != NULL) {
                /* Can't share interrupts unless both agree to */
                if (!(old->flags & new->flags & SA_SHIRQ)) {
                        spin_unlock_irqrestore(&desc->lock,flags);
                        return -EBUSY;
                }

                /* add new interrupt at end of irq queue */
                do {
                        p = &old->next;
                        old = *p;
                } while (old);
                shared = 1;
        }

/* 1 这里对“old->next”的写操作应该也是一条MOV指令,是原子性操作。因此,在写的时候是没有人在读
* 的。
* 2 另外,上面的desc->lock锁,除了保护IRQ descriptor外,还应该起到了防止写并发的作用!
*/

        *p = new;

        if (!shared) {
                desc->depth = 0;
                desc->status &= ~(IRQ_DISABLED | IRQ_AUTODETECT | IRQ_WAITING);
                desc->handler->startup(irq);
        }
spin_unlock_irqrestore(&desc->lock,flags);

论坛徽章:
4
酉鸡
日期:2014-03-21 23:19:50狮子座
日期:2014-08-01 22:11:40酉鸡
日期:2015-01-10 21:31:442015年辞旧岁徽章
日期:2015-03-03 16:54:15
9 [报告]
发表于 2011-10-07 09:04 |只看该作者
回复 8# 魔血染青天


    并发写要加锁, 是肯定的.
    增/删和读之间还是感觉是由于没有中间态, 所以不需要加锁啊.
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP