內核同步機制之完成量

1. 基礎知識

    a. 完成量結構

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

    b. 定義完成量

    struct completion my_completion;

    c. 初始化完成量

	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);         // 不定義CONFIG_LOCKDEP(死鎖檢測)時,什麼也不做
		INIT_LIST_HEAD(&q->task_list);                           // 初始化 task_let 鏈表頭
	}
	
	static inline void reinit_completion(struct completion *x)        // 重新初始化一個完成量使之可以再利用
	{
		x->done = 0;
	}

    d. 等待完成量

	/**
	 * 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);
	
	#define	MAX_SCHEDULE_TIMEOUT	LONG_MAX
	#define LONG_MAX	((long)(~0UL>>1))
	#define TASK_UNINTERRUPTIBLE	2                // 任務標誌位,表示不可中斷
	
	/**
	 * wait_for_completion_timeout: - waits for completion of a task (w/timeout)
	 * @x:  holds the state of this particular completion
	 * @timeout:  timeout value in jiffies
	 *
	 * This waits for either a completion of a specific task to be signaled or for a
	 * specified timeout to expire. The timeout is in jiffies. It is not
	 * interruptible.
	 *
	 * Return: 0 if timed out, and positive (at least 1, or number of jiffies left
	 * till timeout) if completed.
	 */
	unsigned long __sched
	wait_for_completion_timeout(struct completion *x, unsigned long timeout)                // 有超時時間
	{
		return wait_for_common(x, timeout, TASK_UNINTERRUPTIBLE);
	}
	EXPORT_SYMBOL(wait_for_completion_timeout);

    e. 喚醒完成量

	void complete(struct completion *x)                        // 只喚醒一個等待的執行單元
	{
		unsigned long flags;
	
		spin_lock_irqsave(&x->wait.lock, flags);
		x->done++;
		__wake_up_locked(&x->wait, TASK_NORMAL, 1);
		spin_unlock_irqrestore(&x->wait.lock, flags);
	}
	EXPORT_SYMBOL(complete);
	
	void complete_all(struct completion *x)                     // 釋放所有等待同一完成量的執行單元
	{
		unsigned long flags;
	
		spin_lock_irqsave(&x->wait.lock, flags);
		x->done += UINT_MAX/2;
		__wake_up_locked(&x->wait, TASK_NORMAL, 0);
		spin_unlock_irqrestore(&x->wait.lock, flags);
	}
	EXPORT_SYMBOL(complete_all);

    f. 完成量同於同步的流程:

	進程 P1         進程 P2
	代碼區C1;       wait_for_completion(&done);
	complete(&done);
			代碼區C2; 

2. 相關代碼舉例

代碼位置:drivers/scsi/libsas/sas_expander.c
函數smp_execute_task()中 struct sas_task *task 先建立一個sas_task 並初始化,然後調用wait_for_completion函數

pr_debug("file:%s func:%s line:%d dr->attached_sas_addr = 0x%016llx retry = %d \n",__FILE__, __func__, __LINE__,SAS_ADDR(dr->attached_sas_addr),retry);
wait_for_completion(&task->slow_task->completion);
pr_debug("file:%s func:%s line:%d dr->attached_sas_addr = 0x%016llx retry = %d \n",__FILE__, __func__, __LINE__,SAS_ADDR(dr->attached_sas_addr),retry);

而該完成量在函數 smp_task_done() 中被喚醒
static void smp_task_done(struct sas_task *task)
{
	pr_debug("file:%s func:%s line:%d \n",__FILE__, __func__, __LINE__);
	if (!del_timer(&task->slow_task->timer))
		return;
	complete(&task->slow_task->completion);
}

而該函數由中斷處理函數mvs_interrupt()中調用,調用過程:
mvs_interrupt->mvs_94xx_isr()->mvs_int_full()->mvs_int_rx()->mvs_slot_complete()->smp_task_done()


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章