Linux内核同步:completion

定义

数据结构如下:

struct completion {
    unsigned int done; //指示等待的事件是否完成。初始化时为0。
                       //如果为0,则表示等待的事件未完成。大于0表示等待的事件已经完成
    wait_queue_head_t wait;//存放等待该事件完成的进程队列
};
初始化

1) init_completion(&completion)
init_completion()会将done字段初始化为0,wait字段的自旋锁为未锁,等待队列为空。
这说明调用该完成量的进程必须等待某事件完成(即另外一进程必须先调用completiom()唤醒该完成量)。

static inline void init_completion(struct completion *x)
{
    x->done = 0;
    init_waitqueue_head(&x->wait);
}

#define init_waitqueue_head(q)              \
    do {                        \
        static struct lock_class_key __key; \
                            \
        __init_waitqueue_head((q), #q, &__key); \
    } while (0)

void __init_waitqueue_head(wait_queue_head_t *q, const char *name, struct lock_class_key *key)
{
    spin_lock_init(&q->lock);
    lockdep_set_class_and_name(&q->lock, key, name);
    INIT_LIST_HEAD(&q->task_list);
}

2) DECLARE_COMPLETION(completion);
直接定义并初始化completion完成量,效果等同于以上定义方式

等待完成量

1) wait_for_completion()函数

void __sched wait_for_completion(struct completion *x)
{
    wait_for_common(x, MAX_SCHEDULE_TIMEOUT, TASK_UNINTERRUPTIBLE);
}

static long __sched
wait_for_common(struct completion *x, long timeout, int state)
{
    return __wait_for_common(x, schedule_timeout, timeout, state);
}

static inline long __sched
__wait_for_common(struct completion *x,
          long (*action)(long), long timeout, int state)
{
    might_sleep();

    spin_lock_irq(&x->wait.lock);
    timeout = do_wait_for_common(x, action, timeout, state);
    spin_unlock_irq(&x->wait.lock);
    return timeout;
}

static inline long __sched
do_wait_for_common(struct completion *x,
           long (*action)(long), long timeout, int state)
{
    if (!x->done) { 
        /*该函数相当于信号量中的down()操作。不过在操作中对使用其自身的自旋锁。如果done为0,
        则说明等待的事件没有完成,则调用DECLARE_WAITQUEUE()定义等待队列wait并将当前进程
        添加进等待队列wait。然后将wait添加进该完成量的等待队列的末尾,进入循环。
        设置当前进程为不可中断状态(TASK_UNINTERRUPTIBLE),释放自旋锁并让当前进程进入睡眠状态。
        一旦进程被调度唤醒据又获得自旋锁并查看等待的事件是否完成。如果完成(大于0),
        则从完成量的等待队列中删除等待的进程,并自减*/
        DECLARE_WAITQUEUE(wait, current);

        __add_wait_queue_tail_exclusive(&x->wait, &wait);
        do {
            if (signal_pending_state(state, current)) {
                timeout = -ERESTARTSYS;
                break;
            }
            __set_current_state(state);
            spin_unlock_irq(&x->wait.lock);
            timeout = action(timeout);
            spin_lock_irq(&x->wait.lock);
        } while (!x->done && timeout);
        __remove_wait_queue(&x->wait, &wait);
        if (!x->done)
            return timeout;
    }
    x->done--;
    return timeout ?: 1;
}

2) wait_for_completion_timeout()
也是等待完成量。与wait_for_completion()最大的区别是它等待超时的情况下返回。也就是说如果经过给定的时间该完成量还没有被唤醒,就直接返回。这样最大的好处是经过一定的时间该进程已经不需要等待某事件,那么就可以直接被唤醒继续执行。

3) wait_for_completion_interruptible()
这个函数的等待完成量的方式是可以被信号打断的。如果当前进程收到 如果收到TIF_SIGPENDING信号,则等待该完成量的进程会被从等待队列中删除,并返回ERESTARTSYS

4) wait_for_completion_interruptible_timeout()
可中断的并且可超时返回的等待完成量。

唤醒完成量

completion()函数 : 唤醒所有等待给完成量的进程

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值