]> git.hungrycats.org Git - linux/commitdiff
[ARM] Avoid using clone syscall from kernel_thread()
authorRussell King <rmk@flint.arm.linux.org.uk>
Sun, 21 Sep 2003 12:29:53 +0000 (13:29 +0100)
committerRussell King <rmk@flint.arm.linux.org.uk>
Sun, 21 Sep 2003 12:29:53 +0000 (13:29 +0100)
Don't issue a system call from kernel_thread(), but call do_fork()
directly.  This avoids all the unnecessary syscall overhead.

arch/arm/kernel/process.c

index 8cded69884473bee24cd7b7a45373ba12de9b811..4a4532e91896e23b3a4b8ebbbe256fefb9b3b480 100644 (file)
@@ -312,8 +312,8 @@ void release_thread(struct task_struct *dead_task)
 asmlinkage void ret_from_fork(void) __asm__("ret_from_fork");
 
 int
-copy_thread(int nr, unsigned long clone_flags, unsigned long esp,
-           unsigned long unused, struct task_struct *p, struct pt_regs *regs)
+copy_thread(int nr, unsigned long clone_flags, unsigned long stack_start,
+           unsigned long stk_sz, struct task_struct *p, struct pt_regs *regs)
 {
        struct thread_info *thread = p->thread_info;
        struct pt_regs *childregs;
@@ -321,7 +321,7 @@ copy_thread(int nr, unsigned long clone_flags, unsigned long esp,
        childregs = ((struct pt_regs *)((unsigned long)thread + THREAD_SIZE - 8)) - 1;
        *childregs = *regs;
        childregs->ARM_r0 = 0;
-       childregs->ARM_sp = esp;
+       childregs->ARM_sp = stack_start;
 
        memset(&thread->cpu_context, 0, sizeof(struct cpu_context_save));
        thread->cpu_context.sp = (unsigned long)childregs;
@@ -373,33 +373,35 @@ void dump_thread(struct pt_regs * regs, struct user * dump)
 }
 
 /*
- * This is the mechanism for creating a new kernel thread.
- *
- * NOTE! Only a kernel-only process(ie the swapper or direct descendants
- * who haven't done an "execve()") should use this: it will work within
- * a system call from a "real" process, but the process memory space will
- * not be free'd until both the parent and the child have exited.
+ * Shuffle the argument into the correct register before calling the
+ * thread function.  r1 is the thread argument, r2 is the pointer to
+ * the thread function, and r3 points to the exit function.
+ */
+extern void kernel_thread_helper(void);
+asm(   ".align\n"
+"      .type   kernel_thread_helper, #function\n"
+"kernel_thread_helper:\n"
+"      mov     r0, r1\n"
+"      mov     lr, r3\n"
+"      mov     pc, r2\n"
+"      .size   kernel_thread_helper, . - kernel_thread_helper");
+
+/*
+ * Create a kernel thread.
  */
 pid_t kernel_thread(int (*fn)(void *), void *arg, unsigned long flags)
 {
-       register unsigned int r0 asm("r0") = flags | CLONE_VM | CLONE_UNTRACED;
-       register unsigned int r1 asm("r1") = 0;
-       register pid_t __ret asm("r0");
-
-       __asm__ __volatile__(
-       __syscall(clone)"       @ kernel_thread sys_clone       \n\
-       movs    %0, r0          @ if we are the child           \n\
-       bne     1f                                              \n\
-       mov     fp, #0          @ ensure that fp is zero        \n\
-       mov     r0, %4                                          \n\
-       mov     lr, pc                                          \n\
-       mov     pc, %3                                          \n\
-       b       sys_exit                                        \n\
-1:     "
-        : "=r" (__ret)
-        : "0" (r0), "r" (r1), "r" (fn), "r" (arg)
-       : "lr");
-       return __ret;
+       struct pt_regs regs;
+
+       memset(&regs, 0, sizeof(regs));
+
+       regs.ARM_r1 = (unsigned long)arg;
+       regs.ARM_r2 = (unsigned long)fn;
+       regs.ARM_r3 = (unsigned long)do_exit;
+       regs.ARM_pc = (unsigned long)kernel_thread_helper;
+       regs.ARM_cpsr = SVC_MODE;
+
+       return do_fork(flags|CLONE_VM|CLONE_UNTRACED, 0, &regs, 0, NULL, NULL);
 }
 
 /*