summaryrefslogtreecommitdiffstats
path: root/arch/parisc/kernel/process.c
diff options
context:
space:
mode:
authorAl Viro <viro@zeniv.linux.org.uk>2012-10-05 18:55:57 -0400
committerAl Viro <viro@zeniv.linux.org.uk>2012-10-14 19:36:37 -0400
commitff0ab8af9c3f36e7b6f716c3b9e8811a4202eec6 (patch)
tree78f5dba557a1f91b868fa0118516562b6cd28244 /arch/parisc/kernel/process.c
parent7f1f311ac7b7b9c779fd207a20369f7fa3a61ba6 (diff)
downloadlinux-stable-ff0ab8af9c3f36e7b6f716c3b9e8811a4202eec6.tar.gz
linux-stable-ff0ab8af9c3f36e7b6f716c3b9e8811a4202eec6.tar.bz2
linux-stable-ff0ab8af9c3f36e7b6f716c3b9e8811a4202eec6.zip
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.c28
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;