X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=kernel%2Fkthread.c;h=c848b20b2b083edb517e3b3423e606222e5d331d;hb=987b0145d94eecf292d8b301228356f44611ab7c;hp=fc0767d8461a1d66c950fff2a4b6dcc9de0fcac6;hpb=ec9397bab20a628530ce3051167d3d0fcc2c1af7;p=linux-2.6.git diff --git a/kernel/kthread.c b/kernel/kthread.c index fc0767d84..c848b20b2 100644 --- a/kernel/kthread.c +++ b/kernel/kthread.c @@ -14,6 +14,12 @@ #include #include +/* + * We dont want to execute off keventd since it might + * hold a semaphore our callers hold too: + */ +static struct workqueue_struct *helper_wq; + struct kthread_create_info { /* Information passed to kthread() from keventd. */ @@ -126,12 +132,13 @@ struct task_struct *kthread_create(int (*threadfn)(void *data), init_completion(&create.started); init_completion(&create.done); - /* If we're being called to start the first workqueue, we - * can't use keventd. */ - if (!keventd_up()) + /* + * The workqueue needs to start up first: + */ + if (!helper_wq) work.func(work.data); else { - schedule_work(&work); + queue_work(helper_wq, &work); wait_for_completion(&create.done); } if (!IS_ERR(create.result)) { @@ -157,6 +164,12 @@ void kthread_bind(struct task_struct *k, unsigned int cpu) EXPORT_SYMBOL(kthread_bind); int kthread_stop(struct task_struct *k) +{ + return kthread_stop_sem(k, NULL); +} +EXPORT_SYMBOL(kthread_stop); + +int kthread_stop_sem(struct task_struct *k, struct semaphore *s) { int ret; @@ -167,11 +180,14 @@ int kthread_stop(struct task_struct *k) /* Must init completion *before* thread sees kthread_stop_info.k */ init_completion(&kthread_stop_info.done); - wmb(); + smp_wmb(); /* Now set kthread_should_stop() to true, and wake it up. */ kthread_stop_info.k = k; - wake_up_process(k); + if (s) + up(s); + else + wake_up_process(k); put_task_struct(k); /* Once it dies, reset stop ptr, gather result and we're done. */ @@ -182,4 +198,14 @@ int kthread_stop(struct task_struct *k) return ret; } -EXPORT_SYMBOL(kthread_stop); +EXPORT_SYMBOL(kthread_stop_sem); + +static __init int helper_init(void) +{ + helper_wq = create_singlethread_workqueue("kthread"); + BUG_ON(!helper_wq); + + return 0; +} +core_initcall(helper_init); +