|
@@ -59,8 +59,6 @@ asmlinkage extern void ret_from_fork(void);
|
|
|
DEFINE_PER_CPU(unsigned long, old_rsp);
|
|
|
static DEFINE_PER_CPU(unsigned char, is_idle);
|
|
|
|
|
|
-unsigned long kernel_thread_flags = CLONE_VM | CLONE_UNTRACED;
|
|
|
-
|
|
|
static ATOMIC_NOTIFIER_HEAD(idle_notifier);
|
|
|
|
|
|
void idle_notifier_register(struct notifier_block *n)
|
|
@@ -231,6 +229,35 @@ void show_regs(struct pt_regs *regs)
|
|
|
show_trace(NULL, regs, (void *)(regs + 1), regs->bp);
|
|
|
}
|
|
|
|
|
|
+/*
|
|
|
+ * This gets run with %si containing the
|
|
|
+ * function to call, and %di containing
|
|
|
+ * the "args".
|
|
|
+ */
|
|
|
+extern void kernel_thread_helper(void);
|
|
|
+
|
|
|
+/*
|
|
|
+ * Create a kernel thread
|
|
|
+ */
|
|
|
+int kernel_thread(int (*fn)(void *), void *arg, unsigned long flags)
|
|
|
+{
|
|
|
+ struct pt_regs regs;
|
|
|
+
|
|
|
+ memset(®s, 0, sizeof(regs));
|
|
|
+
|
|
|
+ regs.si = (unsigned long) fn;
|
|
|
+ regs.di = (unsigned long) arg;
|
|
|
+
|
|
|
+ regs.orig_ax = -1;
|
|
|
+ regs.ip = (unsigned long) kernel_thread_helper;
|
|
|
+ regs.cs = __KERNEL_CS;
|
|
|
+ regs.flags = X86_EFLAGS_IF;
|
|
|
+
|
|
|
+ /* Ok, create the new process.. */
|
|
|
+ return do_fork(flags | CLONE_VM | CLONE_UNTRACED, ~0UL, ®s, 0, NULL, NULL);
|
|
|
+}
|
|
|
+EXPORT_SYMBOL(kernel_thread);
|
|
|
+
|
|
|
void release_thread(struct task_struct *dead_task)
|
|
|
{
|
|
|
if (dead_task->mm) {
|