diff options
author | Al Viro <viro@zeniv.linux.org.uk> | 2012-10-05 18:55:57 -0400 |
---|---|---|
committer | Al Viro <viro@zeniv.linux.org.uk> | 2012-10-14 19:36:37 -0400 |
commit | ff0ab8af9c3f36e7b6f716c3b9e8811a4202eec6 (patch) | |
tree | 78f5dba557a1f91b868fa0118516562b6cd28244 /arch/parisc/kernel/process.c | |
parent | 7f1f311ac7b7b9c779fd207a20369f7fa3a61ba6 (diff) |
parisc: optimizations in copy_thread() and friends
* in user thread case the registers had been copied as part of task_struct
already; no need to do it in copy_thread().
* no need to store kernel stack pointer into regs->r21; we know its offset
anyway.
* no need to clobber r3 in sys_fork_wrapper and friends - r28 will do just
as well and *it* will be overwritten anyway.
* no need to mess with storing the return address for child - it should just
use syscall_exit.
* no need to bother with separate stack frame for sys_clone() - just branch
there and be done with that.
* no need to bother with wrapper_exit - we need it only on the child_return,
so let's just do it there.
* use the same ksp for kernel threads and userland ones, while we are at it,
and let ret_from_kernel_execve() go through the normal syscall_exit. More
straightforward is better here...
[fixes from jejb folded]
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
Diffstat (limited to 'arch/parisc/kernel/process.c')
-rw-r--r-- | arch/parisc/kernel/process.c | 28 |
1 files changed, 8 insertions, 20 deletions
diff --git a/arch/parisc/kernel/process.c b/arch/parisc/kernel/process.c index 44e8534c52e9..38db36f64307 100644 --- a/arch/parisc/kernel/process.c +++ b/arch/parisc/kernel/process.c @@ -52,6 +52,7 @@ #include <asm/io.h> #include <asm/asm-offsets.h> +#include <asm/assembly.h> #include <asm/pdc.h> #include <asm/pdc_chassis.h> #include <asm/pgalloc.h> @@ -253,14 +254,16 @@ copy_thread(unsigned long clone_flags, unsigned long usp, #ifdef CONFIG_HPUX extern void * const hpux_child_return; #endif - - if (unlikely((p->flags & PF_KTHREAD) && usp != 0)) { + if (unlikely(p->flags & PF_KTHREAD)) { memset(cregs, 0, sizeof(struct pt_regs)); + if (!usp) /* idle thread */ + return 0; + /* kernel thread */ - cregs->ksp = (unsigned long)stack + THREAD_SZ_ALGN; /* Must exit via ret_from_kernel_thread in order * to call schedule_tail() */ + cregs->ksp = (unsigned long)stack + THREAD_SZ_ALGN + FRAME_SIZE; cregs->kpc = (unsigned long) &ret_from_kernel_thread; /* * Copy function and argument to be called from @@ -275,22 +278,8 @@ copy_thread(unsigned long clone_flags, unsigned long usp, cregs->gr[25] = arg; } else { /* user thread */ - /* - * Note that the fork wrappers are responsible - * for setting gr[21]. - */ - - *cregs = *pregs; - - /* Set the return value for the child. Note that this is not - actually restored by the syscall exit path, but we put it - here for consistency in case of signals. */ - cregs->gr[28] = 0; /* child */ - - /* Use same stack depth as parent */ - cregs->ksp = (unsigned long)stack - + (pregs->gr[21] & (THREAD_SIZE - 1)); cregs->gr[30] = usp; + cregs->ksp = (unsigned long)stack + THREAD_SZ_ALGN + FRAME_SIZE; if (personality(p->personality) == PER_HPUX) { #ifdef CONFIG_HPUX cregs->kpc = (unsigned long) &hpux_child_return; @@ -302,8 +291,7 @@ copy_thread(unsigned long clone_flags, unsigned long usp, } /* Setup thread TLS area from the 4th parameter in clone */ if (clone_flags & CLONE_SETTLS) - cregs->cr27 = pregs->gr[23]; - + cregs->cr27 = pregs->gr[23]; } return 0; |