#include <linux/err.h>
#include <linux/unistd.h>
#include <linux/file.h>
+#include <linux/module.h>
#include <asm/semaphore.h>
+/*
+ * 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. */
{
return (kthread_stop_info.k == current);
}
-
+EXPORT_SYMBOL(kthread_should_stop);
static void kthread_exit_files(void)
{
void *data;
sigset_t blocked;
int ret = -EINTR;
- cpumask_t mask = CPU_MASK_ALL;
kthread_exit_files();
flush_signals(current);
/* By default we can run anywhere, unlike keventd. */
- set_cpus_allowed(current, mask);
+ set_cpus_allowed(current, CPU_MASK_ALL);
/* OK, tell user we're spawned, wait for stop or wakeup */
__set_current_state(TASK_INTERRUPTIBLE);
create->result = ERR_PTR(pid);
} else {
wait_for_completion(&create->started);
- create->result = find_task_by_pid(pid);
+ create->result = find_task_by_real_pid(pid);
}
complete(&create->done);
}
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)) {
return create.result;
}
+EXPORT_SYMBOL(kthread_create);
void kthread_bind(struct task_struct *k, unsigned int cpu)
{
set_task_cpu(k, cpu);
k->cpus_allowed = cpumask_of_cpu(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;
/* 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. */
return ret;
}
+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);
+