Friday, November 25, 2016

Completions

Many parts of the kernel initiate certain activities as separate execution threads and then wait for those threads to complete. The completions interface made just for that.

Look at the example:

static DECLARE_COMPLETION(my_thread_completion);
static DECLARE_WAIT_QUEUE_HEAD(my_wait_queue);
int request_to_end_thread = 0;

static int my_thread(void *unused)
{
 DECLARE_WAITQUEUE(wait, current);
 daemonize("my_thread");
 add_wait_queue(&my_wait_queue, &wait);

 while (1)
 {
  //Request to opt out of the scheduler run queue.
  set_current_state(TASK_INTERRUPTIBLE);

  //asks the scheduler to choose and run a new task from its run queue.
  schedule();

        /* The thread is put back into the scheduler run queue.
  This could only happend because of an event over the wait queue. */
  if (request_to_end_thread) 
  {
   break;
  }
 }

 //Bail out of the wait queue
 __set_current_state(TASK_RUNNING);
 remove_wait_queue(&my_wait_queue, &wait);

 //Atomically signal completion and exit
 complete_and_exit(&my_thread_completion, 0);
}

static int __init my_init(void)
{
 kernel_thread(my_thread, NULL, CLONE_FS | CLONE_FILES | CLONE_SIGHAND | SIGCHLD);
}

static void __exit my_release(void)
{
 request_to_end_thread = 1;
 wake_up(&my_wait_queue);
 
        //this function blocks until my_thread exit. 
        wait_for_completion(&my_thread_completion);
}


Note: There may be more then 1 waiter for the same completion, so the thread which notify its completion may use:
void complete_all(struct completion *c);
to notify all waiters.

No comments:

Post a Comment