context.c
上传用户:lgb322
上传日期:2013-02-24
资源大小:30529k
文件大小:5k
- /*
- * linux/kernel/context.c
- *
- * Mechanism for running arbitrary tasks in process context
- *
- * dwmw2@redhat.com: Genesis
- *
- * andrewm@uow.edu.au: 2.4.0-test12
- * - Child reaping
- * - Support for tasks which re-add themselves
- * - flush_scheduled_tasks.
- */
- #define __KERNEL_SYSCALLS__
- #include <linux/module.h>
- #include <linux/kernel.h>
- #include <linux/sched.h>
- #include <linux/init.h>
- #include <linux/unistd.h>
- #include <linux/signal.h>
- #include <linux/completion.h>
- static DECLARE_TASK_QUEUE(tq_context);
- static DECLARE_WAIT_QUEUE_HEAD(context_task_wq);
- static DECLARE_WAIT_QUEUE_HEAD(context_task_done);
- static int keventd_running;
- static struct task_struct *keventd_task;
- static int need_keventd(const char *who)
- {
- if (keventd_running == 0)
- printk(KERN_ERR "%s(): keventd has not startedn", who);
- return keventd_running;
- }
-
- int current_is_keventd(void)
- {
- int ret = 0;
- if (need_keventd(__FUNCTION__))
- ret = (current == keventd_task);
- return ret;
- }
- /**
- * schedule_task - schedule a function for subsequent execution in process context.
- * @task: pointer to a &tq_struct which defines the function to be scheduled.
- *
- * May be called from interrupt context. The scheduled function is run at some
- * time in the near future by the keventd kernel thread. If it can sleep, it
- * should be designed to do so for the minimum possible time, as it will be
- * stalling all other scheduled tasks.
- *
- * schedule_task() returns non-zero if the task was successfully scheduled.
- * If @task is already residing on a task queue then schedule_task() fails
- * to schedule your task and returns zero.
- */
- int schedule_task(struct tq_struct *task)
- {
- int ret;
- need_keventd(__FUNCTION__);
- ret = queue_task(task, &tq_context);
- wake_up(&context_task_wq);
- return ret;
- }
- static int context_thread(void *startup)
- {
- struct task_struct *curtask = current;
- DECLARE_WAITQUEUE(wait, curtask);
- struct k_sigaction sa;
- daemonize();
- strcpy(curtask->comm, "keventd");
- keventd_running = 1;
- keventd_task = curtask;
- spin_lock_irq(&curtask->sigmask_lock);
- siginitsetinv(&curtask->blocked, sigmask(SIGCHLD));
- recalc_sigpending(curtask);
- spin_unlock_irq(&curtask->sigmask_lock);
- complete((struct completion *)startup);
- /* Install a handler so SIGCLD is delivered */
- sa.sa.sa_handler = SIG_IGN;
- sa.sa.sa_flags = 0;
- siginitset(&sa.sa.sa_mask, sigmask(SIGCHLD));
- do_sigaction(SIGCHLD, &sa, (struct k_sigaction *)0);
- /*
- * If one of the functions on a task queue re-adds itself
- * to the task queue we call schedule() in state TASK_RUNNING
- */
- for (;;) {
- set_task_state(curtask, TASK_INTERRUPTIBLE);
- add_wait_queue(&context_task_wq, &wait);
- if (TQ_ACTIVE(tq_context))
- set_task_state(curtask, TASK_RUNNING);
- schedule();
- remove_wait_queue(&context_task_wq, &wait);
- run_task_queue(&tq_context);
- wake_up(&context_task_done);
- if (signal_pending(curtask)) {
- while (waitpid(-1, (unsigned int *)0, __WALL|WNOHANG) > 0)
- ;
- spin_lock_irq(&curtask->sigmask_lock);
- flush_signals(curtask);
- recalc_sigpending(curtask);
- spin_unlock_irq(&curtask->sigmask_lock);
- }
- }
- }
- /**
- * flush_scheduled_tasks - ensure that any scheduled tasks have run to completion.
- *
- * Forces execution of the schedule_task() queue and blocks until its completion.
- *
- * If a kernel subsystem uses schedule_task() and wishes to flush any pending
- * tasks, it should use this function. This is typically used in driver shutdown
- * handlers.
- *
- * The caller should hold no spinlocks and should hold no semaphores which could
- * cause the scheduled tasks to block.
- */
- static struct tq_struct dummy_task;
- void flush_scheduled_tasks(void)
- {
- int count;
- DECLARE_WAITQUEUE(wait, current);
- /*
- * Do it twice. It's possible, albeit highly unlikely, that
- * the caller queued a task immediately before calling us,
- * and that the eventd thread was already past the run_task_queue()
- * but not yet into wake_up(), so it woke us up before completing
- * the caller's queued task or our new dummy task.
- */
- add_wait_queue(&context_task_done, &wait);
- for (count = 0; count < 2; count++) {
- set_current_state(TASK_UNINTERRUPTIBLE);
- /* Queue a dummy task to make sure we get kicked */
- schedule_task(&dummy_task);
- /* Wait for it to complete */
- schedule();
- }
- remove_wait_queue(&context_task_done, &wait);
- }
-
- int start_context_thread(void)
- {
- static struct completion startup __initdata = COMPLETION_INITIALIZER(startup);
- kernel_thread(context_thread, &startup, CLONE_FS | CLONE_FILES);
- wait_for_completion(&startup);
- return 0;
- }
- EXPORT_SYMBOL(schedule_task);
- EXPORT_SYMBOL(flush_scheduled_tasks);