diff options
| author | Al Viro <viro@zeniv.linux.org.uk> | 2012-10-21 15:52:04 -0400 |
|---|---|---|
| committer | Al Viro <viro@zeniv.linux.org.uk> | 2012-11-28 21:49:04 -0500 |
| commit | 25906730ec01be664534c9439d7cf5a373e8a4e4 (patch) | |
| tree | 0fc3a2d0a08e5bdd815d61371b52ea2ccdc8cfa2 /arch/alpha/kernel | |
| parent | b960f303448969c6cb76b4df9291e9e6213e2b9f (diff) | |
alpha: reorganize copy_process(), prepare to saner fork_idle()
Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
Diffstat (limited to 'arch/alpha/kernel')
| -rw-r--r-- | arch/alpha/kernel/process.c | 35 |
1 files changed, 14 insertions, 21 deletions
diff --git a/arch/alpha/kernel/process.c b/arch/alpha/kernel/process.c index ad86c099b6f5..a4dc79ba030f 100644 --- a/arch/alpha/kernel/process.c +++ b/arch/alpha/kernel/process.c | |||
| @@ -266,18 +266,22 @@ alpha_vfork(void) | |||
| 266 | int | 266 | int |
| 267 | copy_thread(unsigned long clone_flags, unsigned long usp, | 267 | copy_thread(unsigned long clone_flags, unsigned long usp, |
| 268 | unsigned long arg, | 268 | unsigned long arg, |
| 269 | struct task_struct * p, struct pt_regs * regs) | 269 | struct task_struct *p, struct pt_regs *wontuse) |
| 270 | { | 270 | { |
| 271 | extern void ret_from_fork(void); | 271 | extern void ret_from_fork(void); |
| 272 | extern void ret_from_kernel_thread(void); | 272 | extern void ret_from_kernel_thread(void); |
| 273 | 273 | ||
| 274 | struct thread_info *childti = task_thread_info(p); | 274 | struct thread_info *childti = task_thread_info(p); |
| 275 | struct pt_regs *childregs = task_pt_regs(p); | 275 | struct pt_regs *childregs = task_pt_regs(p); |
| 276 | struct pt_regs *regs = current_pt_regs(); | ||
| 276 | struct switch_stack *childstack, *stack; | 277 | struct switch_stack *childstack, *stack; |
| 277 | unsigned long settls; | 278 | unsigned long settls; |
| 278 | 279 | ||
| 279 | childstack = ((struct switch_stack *) childregs) - 1; | 280 | childstack = ((struct switch_stack *) childregs) - 1; |
| 280 | if (unlikely(!regs)) { | 281 | childti->pcb.ksp = (unsigned long) childstack; |
| 282 | childti->pcb.flags = 1; /* set FEN, clear everything else */ | ||
| 283 | |||
| 284 | if (unlikely(p->flags & PF_KTHREAD)) { | ||
| 281 | /* kernel thread */ | 285 | /* kernel thread */ |
| 282 | memset(childstack, 0, | 286 | memset(childstack, 0, |
| 283 | sizeof(struct switch_stack) + sizeof(struct pt_regs)); | 287 | sizeof(struct switch_stack) + sizeof(struct pt_regs)); |
| @@ -286,12 +290,17 @@ copy_thread(unsigned long clone_flags, unsigned long usp, | |||
| 286 | childstack->r10 = arg; | 290 | childstack->r10 = arg; |
| 287 | childregs->hae = alpha_mv.hae_cache, | 291 | childregs->hae = alpha_mv.hae_cache, |
| 288 | childti->pcb.usp = 0; | 292 | childti->pcb.usp = 0; |
| 289 | childti->pcb.ksp = (unsigned long) childstack; | ||
| 290 | childti->pcb.flags = 1; /* set FEN, clear everything else */ | ||
| 291 | return 0; | 293 | return 0; |
| 292 | } | 294 | } |
| 295 | /* Note: if CLONE_SETTLS is not set, then we must inherit the | ||
| 296 | value from the parent, which will have been set by the block | ||
| 297 | copy in dup_task_struct. This is non-intuitive, but is | ||
| 298 | required for proper operation in the case of a threaded | ||
| 299 | application calling fork. */ | ||
| 300 | if (clone_flags & CLONE_SETTLS) | ||
| 301 | childti->pcb.unique = regs->r20; | ||
| 302 | childti->pcb.usp = usp ?: rdusp(); | ||
| 293 | *childregs = *regs; | 303 | *childregs = *regs; |
| 294 | settls = regs->r20; | ||
| 295 | childregs->r0 = 0; | 304 | childregs->r0 = 0; |
| 296 | childregs->r19 = 0; | 305 | childregs->r19 = 0; |
| 297 | childregs->r20 = 1; /* OSF/1 has some strange fork() semantics. */ | 306 | childregs->r20 = 1; /* OSF/1 has some strange fork() semantics. */ |
| @@ -299,22 +308,6 @@ copy_thread(unsigned long clone_flags, unsigned long usp, | |||
| 299 | stack = ((struct switch_stack *) regs) - 1; | 308 | stack = ((struct switch_stack *) regs) - 1; |
| 300 | *childstack = *stack; | 309 | *childstack = *stack; |
| 301 | childstack->r26 = (unsigned long) ret_from_fork; | 310 | childstack->r26 = (unsigned long) ret_from_fork; |
| 302 | childti->pcb.usp = usp ?: rdusp(); | ||
| 303 | childti->pcb.ksp = (unsigned long) childstack; | ||
| 304 | childti->pcb.flags = 1; /* set FEN, clear everything else */ | ||
| 305 | |||
| 306 | /* Set a new TLS for the child thread? Peek back into the | ||
| 307 | syscall arguments that we saved on syscall entry. Oops, | ||
| 308 | except we'd have clobbered it with the parent/child set | ||
| 309 | of r20. Read the saved copy. */ | ||
| 310 | /* Note: if CLONE_SETTLS is not set, then we must inherit the | ||
| 311 | value from the parent, which will have been set by the block | ||
| 312 | copy in dup_task_struct. This is non-intuitive, but is | ||
| 313 | required for proper operation in the case of a threaded | ||
| 314 | application calling fork. */ | ||
| 315 | if (clone_flags & CLONE_SETTLS) | ||
| 316 | childti->pcb.unique = settls; | ||
| 317 | |||
| 318 | return 0; | 311 | return 0; |
| 319 | } | 312 | } |
| 320 | 313 | ||
