Linux 内核Complete和wait_for_completion

来源:互联网 发布:哆点 for mac 编辑:程序博客网 时间:2024/06/05 16:04

1. Linux中很多同步机制,completion是其中一种,其核心数据结构相对简单

include/linux/completion.h

struct completion {
        unsigned int done;
        wait_queue_head_t wait;
};

常用的接口函数:

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

extern void complete(struct completion *);

extern void wait_for_completion(struct completion *);

在本文中,主要讲述complete 和 wait_for_completion,其余的可以在此基础掌握。


2. wait_for_completion(struct completion *)

kernel/sched/core.c


/**
 * wait_for_completion: - waits for completion of a task
 * @x:  holds the state of this particular completion
 *
 * This waits to be signaled for completion of a specific task. It is NOT
 * interruptible and there is no timeout.
 *
 * See also similar routines (i.e. wait_for_completion_timeout()) with timeout
 * and interrupt capability. Also see complete().
 */
void __sched wait_for_completion(struct completion *x)
{
        wait_for_common(x, MAX_SCHEDULE_TIMEOUT, TASK_UNINTERRUPTIBLE);
}
EXPORT_SYMBOL(wait_for_completion);


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) {
                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);                                       //设置当前进程的状态TASK_UNINTERRUPTIBLE。
                        spin_unlock_irq(&x->wait.lock);
                        timeout = action(timeout);                                         //调度和返回
                        spin_lock_irq(&x->wait.lock);
                } while (!x->done && timeout);                                         // 检查x-》done 是否大于零,是不是有其它进程设置了该变量。
                __remove_wait_queue(&x->wait, &wait);
                if (!x->done)
                        return timeout;
        }
        x->done--;
        return timeout ?: 1;
}


总之,wait_for_completion的作用是使当前进程处于TASK_UNINTERRUPTIBLE,处于等待队列,不再运行。进一步说,就是该函数只能在有进程上下文的情况下调用。


3. complete(struct completion *)

void complete(struct completion *x)
{
        unsigned long flags;

        spin_lock_irqsave(&x->wait.lock, flags);
        x->done++;                                                                              // 设置x->done,
        __wake_up_common(&x->wait, TASK_NORMAL, 1, 0, NULL); //唤醒等待进程。
        spin_unlock_irqrestore(&x->wait.lock, flags);
}
EXPORT_SYMBOL(complete);


非常简单易用的同步机制。



0 0
原创粉丝点击