From c0ecb80a43103964d30d8629ce45098fca307081 Mon Sep 17 00:00:00 2001 From: Ulrich Drepper Date: Sat, 20 Dec 2003 23:39:42 +0000 Subject: Update. 2003-12-20 Ulrich Drepper * elf/rtld.c (dl_main): Optimize order or subexpressions in if(). --- nptl/ChangeLog | 9 +++++++++ nptl/pthread_cancel.c | 6 ++++++ nptl/pthread_getattr_np.c | 2 +- nptl/sysdeps/unix/sysv/linux/fork.c | 11 ++++++++++- nptl/sysdeps/unix/sysv/linux/getpid.c | 26 ++++++++++++++++++-------- nptl/sysdeps/unix/sysv/linux/pt-raise.c | 17 +++++++++++++---- nptl/sysdeps/unix/sysv/linux/pthread_kill.c | 5 +++++ nptl/sysdeps/unix/sysv/linux/raise.c | 20 ++++++++++++++++---- 8 files changed, 78 insertions(+), 18 deletions(-) (limited to 'nptl') diff --git a/nptl/ChangeLog b/nptl/ChangeLog index 5e81694058..69fb0ec703 100644 --- a/nptl/ChangeLog +++ b/nptl/ChangeLog @@ -2,6 +2,15 @@ * sysdeps/unix/sysv/linux/Makefile (CFLAGS-getpid.c): Define. * sysdeps/unix/sysv/linux/getpid.c: New file. + * pthread_cancel.c: Add comment explaining use of PID field. + * sysdeps/unix/sysv/linux/pthread_kill.c: Likewise. + * pthread_getattr_np.c: Use abs() when comparing PID and TID fields. + * sysdeps/unix/sysv/linux/fork.c: Negate PID field of parent + temporarily to signal the field must not be relied on and updated + by getpid(). + * sysdeps/unix/sysv/linux/pt-raise.c: Handle case where PID is + temporarily negative. + * sysdeps/unix/sysv/linux/raise.c: Likewise. 2003-12-19 Ulrich Drepper diff --git a/nptl/pthread_cancel.c b/nptl/pthread_cancel.c index 1523da82aa..8d1b8640f8 100644 --- a/nptl/pthread_cancel.c +++ b/nptl/pthread_cancel.c @@ -65,6 +65,12 @@ pthread_cancel (th) thread as canceled. */ INTERNAL_SYSCALL_DECL (err); + /* One comment: The PID field in the TCB can temporarily be + changed (in fork). But this must not affect this code + here. Since this function would have to be called while + the thread is executing fork, it would have to happen in + a signal handler. But this is no allowed, pthread_cancel + is not guaranteed to be async-safe. */ int val; #if __ASSUME_TGKILL val = INTERNAL_SYSCALL (tgkill, err, 3, diff --git a/nptl/pthread_getattr_np.c b/nptl/pthread_getattr_np.c index 9cc948f4c6..f66e97fa68 100644 --- a/nptl/pthread_getattr_np.c +++ b/nptl/pthread_getattr_np.c @@ -70,7 +70,7 @@ pthread_getattr_np (thread_id, attr) { /* No stack information available. This must be for the initial thread. Get the info in some magical way. */ - assert (thread->pid == thread->tid); + assert (abs (thread->pid) == thread->tid); /* Defined in ld.so. */ extern void *__libc_stack_end; diff --git a/nptl/sysdeps/unix/sysv/linux/fork.c b/nptl/sysdeps/unix/sysv/linux/fork.c index 84bf3793b6..840974401b 100644 --- a/nptl/sysdeps/unix/sysv/linux/fork.c +++ b/nptl/sysdeps/unix/sysv/linux/fork.c @@ -117,6 +117,12 @@ __libc_fork (void) pid_t ppid = THREAD_GETMEM (THREAD_SELF, tid); #endif + /* We need to prevent the getpid() code to update the PID field so + that, if a signal arrives in the child very early and the signal + handler uses getpid(), the value returned is correct. */ + pid_t parentpid = THREAD_GETMEM (THREAD_SELF, pid); + THREAD_SETMEM (THREAD_SELF, pid, -parentpid); + #ifdef ARCH_FORK pid = ARCH_FORK (); #else @@ -135,7 +141,7 @@ __libc_fork (void) *__fork_generation_pointer += 4; /* Adjust the PID field for the new process. */ - self->pid = self->tid; + THREAD_SETMEM (self, pid, THREAD_GETMEM (self, tid)); #if HP_TIMING_AVAIL /* The CPU clock of the thread and process have to be set to zero. */ @@ -180,6 +186,9 @@ __libc_fork (void) { assert (THREAD_GETMEM (THREAD_SELF, tid) == ppid); + /* Restore the PID value. */ + THREAD_SETMEM (THREAD_SELF, pid, parentpid); + /* We execute this even if the 'fork' call failed. */ _IO_list_unlock (); diff --git a/nptl/sysdeps/unix/sysv/linux/getpid.c b/nptl/sysdeps/unix/sysv/linux/getpid.c index 75decc1385..7efe3f2768 100644 --- a/nptl/sysdeps/unix/sysv/linux/getpid.c +++ b/nptl/sysdeps/unix/sysv/linux/getpid.c @@ -22,21 +22,31 @@ #include +#ifndef NOT_IN_libc +static pid_t really_getpid (pid_t oldval); +#endif + + pid_t __getpid (void) { - pid_t result; #ifndef NOT_IN_libc - result = THREAD_GETMEM (THREAD_SELF, pid); - if (__builtin_expect (result == 0, 0)) + pid_t result = THREAD_GETMEM (THREAD_SELF, pid); + if (__builtin_expect (result <= 0, 0)) + result = really_getpid (result); + return result; +} + +static pid_t +really_getpid (pid_t oldval) +{ #endif - { - INTERNAL_SYSCALL_DECL (err); - result = INTERNAL_SYSCALL (getpid, err, 0); + INTERNAL_SYSCALL_DECL (err); + pid_t result = INTERNAL_SYSCALL (getpid, err, 0); #ifndef NOT_IN_libc - THREAD_SETMEM (THREAD_SELF, pid, result); + if (oldval == 0) + THREAD_SETMEM (THREAD_SELF, pid, result); #endif - } return result; } libc_hidden_def (__getpid) diff --git a/nptl/sysdeps/unix/sysv/linux/pt-raise.c b/nptl/sysdeps/unix/sysv/linux/pt-raise.c index 2efd7616bf..9161e29e28 100644 --- a/nptl/sysdeps/unix/sysv/linux/pt-raise.c +++ b/nptl/sysdeps/unix/sysv/linux/pt-raise.c @@ -28,13 +28,22 @@ int raise (sig) int sig; { +#if __ASSUME_TGKILL || defined __NR_tgkill + /* raise is an async-safe function. It could be called while the + fork function temporarily invalidated the PID field. Adjust for + that. */ + pid_t pid = THREAD_GETMEM (THREAD_SELF, pid); + if (__builtin_expect (pid < 0, 0)) + pid = -pid; +#endif + #if __ASSUME_TGKILL - return INLINE_SYSCALL (tgkill, 3, THREAD_GETMEM (THREAD_SELF, pid), - THREAD_GETMEM (THREAD_SELF, tid), sig); + return INLINE_SYSCALL (tgkill, 3, pid, THREAD_GETMEM (THREAD_SELF, tid), + sig); #else # ifdef __NR_tgkill - int res = INLINE_SYSCALL (tgkill, 3, THREAD_GETMEM (THREAD_SELF, pid), - THREAD_GETMEM (THREAD_SELF, tid), sig); + int res = INLINE_SYSCALL (tgkill, 3, pid, THREAD_GETMEM (THREAD_SELF, tid), + sig); if (res != -1 || errno != ENOSYS) return res; # endif diff --git a/nptl/sysdeps/unix/sysv/linux/pthread_kill.c b/nptl/sysdeps/unix/sysv/linux/pthread_kill.c index 6967acd92b..87577be4dc 100644 --- a/nptl/sysdeps/unix/sysv/linux/pthread_kill.c +++ b/nptl/sysdeps/unix/sysv/linux/pthread_kill.c @@ -44,6 +44,11 @@ __pthread_kill (threadid, signo) /* We have a special syscall to do the work. */ INTERNAL_SYSCALL_DECL (err); + /* One comment: The PID field in the TCB can temporarily be changed + (in fork). But this must not affect this code here. Since this + function would have to be called while the thread is executing + fork, it would have to happen in a signal handler. But this is + no allowed, pthread_kill is not guaranteed to be async-safe. */ int val; #if __ASSUME_TGKILL val = INTERNAL_SYSCALL (tgkill, err, 3, THREAD_GETMEM (THREAD_SELF, pid), diff --git a/nptl/sysdeps/unix/sysv/linux/raise.c b/nptl/sysdeps/unix/sysv/linux/raise.c index 25d3ed8afd..268ba87b29 100644 --- a/nptl/sysdeps/unix/sysv/linux/raise.c +++ b/nptl/sysdeps/unix/sysv/linux/raise.c @@ -29,6 +29,9 @@ raise (sig) int sig; { struct pthread *pd = THREAD_SELF; +#if __ASSUME_TGKILL || defined __NR_tgkill + pid_t pid = THREAD_GETMEM (pd, pid); +#endif pid_t selftid = THREAD_GETMEM (pd, tid); if (selftid == 0) { @@ -41,15 +44,24 @@ raise (sig) #endif THREAD_SETMEM (pd, tid, selftid); - /* In this case the TID and PID are the same. */ - THREAD_SETMEM (pd, pid, selftid); + /* We do not set the PID field in the TID here since we might be + called from a signal handler while the thread executes fork. */ + pid = selftid; } +#if __ASSUME_TGKILL || defined __NR_tgkill + else + /* raise is an async-safe function. It could be called while the + fork function temporarily invalidated the PID field. Adjust for + that. */ + if (__builtin_expect (pid < 0, 0)) + pid = -pid; +#endif #if __ASSUME_TGKILL - return INLINE_SYSCALL (tgkill, 3, THREAD_GETMEM (pd, pid), selftid, sig); + return INLINE_SYSCALL (tgkill, 3, pid, selftid, sig); #else # ifdef __NR_tgkill - int res = INLINE_SYSCALL (tgkill, 3, THREAD_GETMEM (pd, pid), selftid, sig); + int res = INLINE_SYSCALL (tgkill, 3, pid, selftid, sig); if (res != -1 || errno != ENOSYS) return res; # endif -- cgit v1.2.3