内核完成量是一种轻量级的机制,它允许一个线程告诉另一个线程工作已经完成。
完成量的定义
completion 结构体的定义
/*
* struct completion - structure used to maintain state for a "completion"
*
* This is the opaque structure used to maintain the state for a "completion".
* Completions currently use a FIFO to queue threads that have to wait for
* the "completion" event.
*
* See also: complete(), wait_for_completion() (and friends _timeout,
* _interruptible, _interruptible_timeout, and _killable), init_completion(),
* reinit_completion(), and macros DECLARE_COMPLETION(),
* DECLARE_COMPLETION_ONSTACK().
*/
struct completion {
unsigned int done;
struct swait_queue_head wait;
};
struct swait_queue_head {
raw_spinlock_t lock;
struct list_head task_list;
};
完成量的初始化
/**
* init_completion - Initialize a dynamically allocated completion
* @x: pointer to completion structure that is to be initialized
*
* This inline function will initialize a dynamically created completion
* structure.
*/
static inline void init_completion(struct completion *x)
{
x->done = 0;
init_swait_queue_head(&x->wait);
}
等待完成量
/**
* 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 inline long __sched
do_wait_for_common(struct completion *x,
long (*action)(long), long timeout, int state)
{
if (!x->done) {
DECLARE_SWAITQUEUE(wait);
do {
if (signal_pending_state(state, current)) {
timeout = -ERESTARTSYS;
break;
}
__prepare_to_swait(&x->wait, &wait);
__set_current_state(state);
raw_spin_unlock_irq(&x->wait.lock);
timeout = action(timeout);
raw_spin_lock_irq(&x->wait.lock);
} while (!x->done && timeout);
__finish_swait(&x->wait, &wait);
if (!x->done)
return timeout;
}
if (x->done != UINT_MAX)
x->done--;
return timeout ?: 1;
}
static inline long __sched
__wait_for_common(struct completion *x,
long (*action)(long), long timeout, int state)
{
might_sleep();
complete_acquire(x);
raw_spin_lock_irq(&x->wait.lock);
timeout = do_wait_for_common(x, action, timeout, state);
raw_spin_unlock_irq(&x->wait.lock);
complete_release(x);
return timeout;
}
static long __sched
wait_for_common(struct completion *x, long timeout, int state)
{
return __wait_for_common(x, schedule_timeout, timeout, state);
}
通知完成量
/**
* complete: - signals a single thread waiting on this completion
* @x: holds the state of this particular completion
*
* This will wake up a single thread waiting on this completion. Threads will be
* awakened in the same order in which they were queued.
*
* See also complete_all(), wait_for_completion() and related routines.
*
* If this function wakes up a task, it executes a full memory barrier before
* accessing the task state.
*/
void complete(struct completion *x)
{
unsigned long flags;
raw_spin_lock_irqsave(&x->wait.lock, flags);
if (x->done != UINT_MAX)
x->done++;
swake_up_locked(&x->wait);
raw_spin_unlock_irqrestore(&x->wait.lock, flags);
}
EXPORT_SYMBOL(complete);
完成量的使用
1、完成量的初始化
a)动态初始化
struct completion my_comp;
init_completion(&my_comp);
b)静态初始化
DECLARE_COMPLETION(my_comp);
2、等待完成量
//等待完成量唤醒且不会被外部信号打断
void wait_for_completion(struct completion *comp);
//等待一个完成量被唤醒;但是它可以被外部信号打断;
int wait_for_completion_interruptible(struct completion* comp):
//该函数等待一个完成量被唤醒,如果没有唤醒也会超时返回
unsigned long wait_for_completion_timeout(struct completion* comp, unsigned long timeout):
3、唤醒等待的线程
//只唤醒一个正在等待完成量comp的执行单元;
void complete(struct completion* comp):
//唤醒所有正在等待同一个完成量comp的执行单元;
void complete_all(struct completion* comp):
实例
struct cyttsp {
......
struct completion bl_ready;
......
}
init_completion(&ts->bl_ready);
static int cyttsp_soft_reset(struct cyttsp *ts)
{
int retval;
/* wait for interrupt to set ready completion */
reinit_completion(&ts->bl_ready);
ts->state = CY_BL_STATE;
enable_irq(ts->irq);
retval = ttsp_send_command(ts, CY_SOFT_RESET_MODE);
if (retval) {
dev_err(ts->dev, "failed to send soft reset\n");
goto out;
}
if (!wait_for_completion_timeout(&ts->bl_ready,
msecs_to_jiffies(CY_DELAY_DFLT * CY_DELAY_MAX))) {
dev_err(ts->dev, "timeout waiting for soft reset\n");
retval = -EIO;
}
out:
ts->state = CY_IDLE_STATE;
disable_irq(ts->irq);
return retval;
}
static irqreturn_t cyttsp_irq(int irq, void *handle)
{
struct cyttsp *ts = handle;
int error;
if (unlikely(ts->state == CY_BL_STATE)) {
complete(&ts->bl_ready);
goto out;
}
/* Get touch data from CYTTSP device */
error = ttsp_read_block_data(ts, CY_REG_BASE,
sizeof(struct cyttsp_xydata), &ts->xy_data);
if (error)
goto out;
/* provide flow control handshake */
error = cyttsp_handshake(ts);
if (error)
goto out;
if (unlikely(ts->state == CY_IDLE_STATE))
goto out;
if (GET_BOOTLOADERMODE(ts->xy_data.tt_mode)) {
/*
* TTSP device has reset back to bootloader mode.
* Restore to operational mode.
*/
error = cyttsp_exit_bl_mode(ts);
if (error) {
dev_err(ts->dev,
"Could not return to operational mode, err: %d\n",
error);
ts->state = CY_IDLE_STATE;
}
} else {
cyttsp_report_tchdata(ts);
}
out:
return IRQ_HANDLED;
}