linux2.6.32_complete(完成量)

来源:互联网 发布:知乎广告文案 编辑:程序博客网 时间:2024/05/17 07:18


/*
1,完成量的核心是排他性的不可中断的等待队列节点。
       由代码可知,它类似FIFO性质,complete唤醒的总是先wait的进程
       从这里可以加深对kthread的细节理解
*/
#include <linux/wait.h>  //从这个头文件可看出,完成量是和等待队列有密切的联系


#define COMPLETION_INITIALIZER(work) \
 { 0, __WAIT_QUEUE_HEAD_INITIALIZER((work).wait) }

#define COMPLETION_INITIALIZER_ONSTACK(work) \
 ({ init_completion(&work); work; })

/**
 * DECLARE_COMPLETION: - declare and initialize a completion structure
 * @work:  identifier for the completion structure
 *
 * This macro declares and initializes a completion structure. Generally used
 * for static declarations. You should use the _ONSTACK variant for automatic
 * variables.
 */
#define DECLARE_COMPLETION(work) \
 struct completion work = COMPLETION_INITIALIZER(work)


//完成量是由等待队列的排他性节点进程所实现的
struct completion {             
 unsigned int done;
 wait_queue_head_t wait;
};

 

/**
 * init_completion: - Initialize a dynamically allocated completion
 * @x:  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_waitqueue_head(&x->wait);
}

/**
 * INIT_COMPLETION: - reinitialize a completion structure
 * @x:  completion structure to be reinitialized
 *
 * This macro should be used to reinitialize a completion structure so it can
 * be reused. This is especially important after complete_all() is used.
 */
#define INIT_COMPLETION(x) ((x).done = 0)

do_wait_for_common(struct completion *x, long timeout, int state)
{
//printk("!x->done=0x%x\n",!x->done);
 if (!x->done) {
  DECLARE_WAITQUEUE(wait, current);

  wait.flags |= WQ_FLAG_EXCLUSIVE;
  __add_wait_queue_tail(&x->wait, &wait);
  do {
   if (signal_pending_state(state, current)) {
    timeout = -ERESTARTSYS;
    break;
   }
   __set_current_state(state);
   spin_unlock_irq(&x->wait.lock);
//printk("timeout=0x%x\t",timeout);
   timeout = schedule_timeout(timeout);
//printk("timeout=0x%x\n",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;
}

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

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

/**
 * 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);
}


/**
 * 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.
 */
unsigned long __sched
wait_for_completion_timeout(struct completion *x, unsigned long timeout)
{
 return wait_for_common(x, timeout, TASK_UNINTERRUPTIBLE);
}


/**
 * wait_for_completion_interruptible: - waits for completion of a task (w/intr)
 * @x:  holds the state of this particular completion
 *
 * This waits for completion of a specific task to be signaled. It is
 * interruptible.
 */
int __sched wait_for_completion_interruptible(struct completion *x)
{
 long t = wait_for_common(x, MAX_SCHEDULE_TIMEOUT, TASK_INTERRUPTIBLE);
 if (t == -ERESTARTSYS)
  return t;
 return 0;
}
EXPORT_SYMBOL(wait_for_completion_interruptible);

/**
 * wait_for_completion_interruptible_timeout: - waits for completion (w/(to,intr))
 * @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. It is interruptible. The timeout is in jiffies.
 */
unsigned long __sched
wait_for_completion_interruptible_timeout(struct completion *x,
       unsigned long timeout)
{
 return wait_for_common(x, timeout, TASK_INTERRUPTIBLE);
}

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

 spin_lock_irqsave(&x->wait.lock, flags);
 x->done++;
 __wake_up_common(&x->wait, TASK_NORMAL, 1, 0, NULL);
 spin_unlock_irqrestore(&x->wait.lock, flags);
}


/**
 * complete_all: - signals all threads waiting on this completion
 * @x:  holds the state of this particular completion
 *
 * This will wake up all threads waiting on this particular completion event.
 *
 * It may be assumed that this function implies a write memory barrier before
 * changing the task state if and only if any tasks are woken up.
 */
void complete_all(struct completion *x)
{
 unsigned long flags;

 spin_lock_irqsave(&x->wait.lock, flags);
 x->done += UINT_MAX/2;
 __wake_up_common(&x->wait, TASK_NORMAL, 0, 0, NULL);
 spin_unlock_irqrestore(&x->wait.lock, flags);
}


/**
 * 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.
 *
 * It may be assumed that this function implies a write memory barrier before
 * changing the task state if and only if any tasks are woken up.
 */
void complete(struct completion *x)
{
 unsigned long flags;

 spin_lock_irqsave(&x->wait.lock, flags);
 x->done++;
 __wake_up_common(&x->wait, TASK_NORMAL, 1, 0, NULL);
 spin_unlock_irqrestore(&x->wait.lock, flags);
}