diff options
Diffstat (limited to 'sysdeps/unix/sysv/linux/aarch64/vfork.S')
-rw-r--r-- | sysdeps/unix/sysv/linux/aarch64/vfork.S | 29 |
1 files changed, 20 insertions, 9 deletions
diff --git a/sysdeps/unix/sysv/linux/aarch64/vfork.S b/sysdeps/unix/sysv/linux/aarch64/vfork.S index d9f2c70748..316cb65e9b 100644 --- a/sysdeps/unix/sysv/linux/aarch64/vfork.S +++ b/sysdeps/unix/sysv/linux/aarch64/vfork.S @@ -28,22 +28,33 @@ ENTRY (__vfork) -#ifdef SAVE_PID - SAVE_PID -#endif + /* Save the TCB-cached PID away in w3, and then negate the TCB + field. But if it's zero, set it to 0x80000000 instead. See + raise.c for the logic that relies on this value. */ + mrs x2, tpidr_el0 + sub x2, x2, #PTHREAD_SIZEOF + ldr w3, [x2, #PTHREAD_PID_OFFSET] + mov w1, #0x80000000 + negs w0, w3 + csel w0, w1, w0, eq + str w0, [x2, #PTHREAD_PID_OFFSET] + mov x0, #0x4111 /* CLONE_VM | CLONE_VFORK | SIGCHLD */ mov x1, sp DO_CALL (clone, 2) -#ifdef RESTORE_PID - RESTORE_PID -#endif + + /* Restore the original value of the TCB cache of the PID, if we're + the parent. But in the child (syscall return value equals zero), + leave things as they are. */ + cbz x0, 1f + str w3, [x2, #PTHREAD_PID_OFFSET] +1: cmn x0, #4095 - b.cs 1f + b.cs .Lsyscall_error RET -1: - b SYSCALL_ERROR PSEUDO_END (__vfork) libc_hidden_def (__vfork) weak_alias (__vfork, vfork) +strong_alias (__vfork, __libc_vfork) |