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 44e8534c52e..38db36f6430 100644 --- a/arch/parisc/kernel/process.c +++ b/arch/parisc/kernel/process.c | |||
@@ -52,6 +52,7 @@ | |||
52 | 52 | ||
53 | #include <asm/io.h> | 53 | #include <asm/io.h> |
54 | #include <asm/asm-offsets.h> | 54 | #include <asm/asm-offsets.h> |
55 | #include <asm/assembly.h> | ||
55 | #include <asm/pdc.h> | 56 | #include <asm/pdc.h> |
56 | #include <asm/pdc_chassis.h> | 57 | #include <asm/pdc_chassis.h> |
57 | #include <asm/pgalloc.h> | 58 | #include <asm/pgalloc.h> |
@@ -253,14 +254,16 @@ copy_thread(unsigned long clone_flags, unsigned long usp, | |||
253 | #ifdef CONFIG_HPUX | 254 | #ifdef CONFIG_HPUX |
254 | extern void * const hpux_child_return; | 255 | extern void * const hpux_child_return; |
255 | #endif | 256 | #endif |
256 | 257 | if (unlikely(p->flags & PF_KTHREAD)) { | |
257 | if (unlikely((p->flags & PF_KTHREAD) && usp != 0)) { | ||
258 | memset(cregs, 0, sizeof(struct pt_regs)); | 258 | memset(cregs, 0, sizeof(struct pt_regs)); |
259 | if (!usp) /* idle thread */ | ||
260 | return 0; | ||
261 | |||
259 | /* kernel thread */ | 262 | /* kernel thread */ |
260 | cregs->ksp = (unsigned long)stack + THREAD_SZ_ALGN; | ||
261 | /* Must exit via ret_from_kernel_thread in order | 263 | /* Must exit via ret_from_kernel_thread in order |
262 | * to call schedule_tail() | 264 | * to call schedule_tail() |
263 | */ | 265 | */ |
266 | cregs->ksp = (unsigned long)stack + THREAD_SZ_ALGN + FRAME_SIZE; | ||
264 | cregs->kpc = (unsigned long) &ret_from_kernel_thread; | 267 | cregs->kpc = (unsigned long) &ret_from_kernel_thread; |
265 | /* | 268 | /* |
266 | * Copy function and argument to be called from | 269 | * Copy function and argument to be called from |
@@ -275,22 +278,8 @@ copy_thread(unsigned long clone_flags, unsigned long usp, | |||
275 | cregs->gr[25] = arg; | 278 | cregs->gr[25] = arg; |
276 | } else { | 279 | } else { |
277 | /* user thread */ | 280 | /* user thread */ |
278 | /* | ||
279 | * Note that the fork wrappers are responsible | ||
280 | * for setting gr[21]. | ||
281 | */ | ||
282 | |||
283 | *cregs = *pregs; | ||
284 | |||
285 | /* Set the return value for the child. Note that this is not | ||
286 | actually restored by the syscall exit path, but we put it | ||
287 | here for consistency in case of signals. */ | ||
288 | cregs->gr[28] = 0; /* child */ | ||
289 | |||
290 | /* Use same stack depth as parent */ | ||
291 | cregs->ksp = (unsigned long)stack | ||
292 | + (pregs->gr[21] & (THREAD_SIZE - 1)); | ||
293 | cregs->gr[30] = usp; | 281 | cregs->gr[30] = usp; |
282 | cregs->ksp = (unsigned long)stack + THREAD_SZ_ALGN + FRAME_SIZE; | ||
294 | if (personality(p->personality) == PER_HPUX) { | 283 | if (personality(p->personality) == PER_HPUX) { |
295 | #ifdef CONFIG_HPUX | 284 | #ifdef CONFIG_HPUX |
296 | cregs->kpc = (unsigned long) &hpux_child_return; | 285 | cregs->kpc = (unsigned long) &hpux_child_return; |
@@ -302,8 +291,7 @@ copy_thread(unsigned long clone_flags, unsigned long usp, | |||
302 | } | 291 | } |
303 | /* Setup thread TLS area from the 4th parameter in clone */ | 292 | /* Setup thread TLS area from the 4th parameter in clone */ |
304 | if (clone_flags & CLONE_SETTLS) | 293 | if (clone_flags & CLONE_SETTLS) |
305 | cregs->cr27 = pregs->gr[23]; | 294 | cregs->cr27 = pregs->gr[23]; |
306 | |||
307 | } | 295 | } |
308 | 296 | ||
309 | return 0; | 297 | return 0; |