diff options
author | dan <dan@7b3dc134-2b1b-0410-93df-9e9f96275f8d> | 2008-02-24 02:23:44 +0000 |
---|---|---|
committer | dan <dan@7b3dc134-2b1b-0410-93df-9e9f96275f8d> | 2008-02-24 02:23:44 +0000 |
commit | 6cbd6ebdc016630c272f139f915fac44a7b004cc (patch) | |
tree | d80ad282854b2c23ea8be47477fe4f27a34a0c7b | |
parent | a496d8c4c1779368d4025206d9e95e8e7d794058 (diff) | |
download | eglibc2-6cbd6ebdc016630c272f139f915fac44a7b004cc.tar.gz |
PR nptl/3270
nptl/
* allocatestack.c (setxid_mark_thread, setxid_unmark_thread): New.
(setxid_signal_thread): Return a successful signal indicator. Just
skip threads without SETXID_BITMASK.
(__nptl_setxid): Use separate marking and unmarking loops. Repeat
signalling if necessary.
* init.c (sighandler_setxid): Use atomic operations for
cancelhandling. Wake __nptl_setxid last.
git-svn-id: svn://svn.eglibc.org/branches/eglibc-2_5@5288 7b3dc134-2b1b-0410-93df-9e9f96275f8d
-rw-r--r-- | libc/ChangeLog.eglibc | 12 | ||||
-rw-r--r-- | libc/nptl/allocatestack.c | 123 | ||||
-rw-r--r-- | libc/nptl/init.c | 16 |
3 files changed, 127 insertions, 24 deletions
diff --git a/libc/ChangeLog.eglibc b/libc/ChangeLog.eglibc index 0feedf273..4778a2bec 100644 --- a/libc/ChangeLog.eglibc +++ b/libc/ChangeLog.eglibc @@ -1,3 +1,15 @@ +2008-02-23 Daniel Jacobowitz <dan@codesourcery.com> + + PR nptl/3270 + nptl/ + * allocatestack.c (setxid_mark_thread, setxid_unmark_thread): New. + (setxid_signal_thread): Return a successful signal indicator. Just + skip threads without SETXID_BITMASK. + (__nptl_setxid): Use separate marking and unmarking loops. Repeat + signalling if necessary. + * init.c (sighandler_setxid): Use atomic operations for + cancelhandling. Wake __nptl_setxid last. + 2008-02-17 Joseph Myers <joseph@codesourcery.com> Backport: diff --git a/libc/nptl/allocatestack.c b/libc/nptl/allocatestack.c index c05cd47df..65cb226c0 100644 --- a/libc/nptl/allocatestack.c +++ b/libc/nptl/allocatestack.c @@ -852,22 +852,53 @@ __find_thread_by_id (pid_t tid) static void internal_function -setxid_signal_thread (struct xid_command *cmdp, struct pthread *t) +setxid_mark_thread (struct xid_command *cmdp, struct pthread *t) { - if (! IS_DETACHED (t)) + int ch; + + /* Don't let the thread exit before the setxid handler runs. */ + t->setxid_futex = 0; + + do { - int ch; - do - { - ch = t->cancelhandling; + ch = t->cancelhandling; - /* If the thread is exiting right now, ignore it. */ - if ((ch & EXITING_BITMASK) != 0) - return; - } - while (atomic_compare_and_exchange_bool_acq (&t->cancelhandling, - ch | SETXID_BITMASK, ch)); + /* If the thread is exiting right now, ignore it. */ + if ((ch & EXITING_BITMASK) != 0) + return; + } + while (atomic_compare_and_exchange_bool_acq (&t->cancelhandling, + ch | SETXID_BITMASK, ch)); +} + + +static void +internal_function +setxid_unmark_thread (struct xid_command *cmdp, struct pthread *t) +{ + int ch; + + do + { + ch = t->cancelhandling; + if ((ch & SETXID_BITMASK) == 0) + return; } + while (atomic_compare_and_exchange_bool_acq (&t->cancelhandling, + ch & ~SETXID_BITMASK, ch)); + + /* Release the futex just in case. */ + t->setxid_futex = 1; + lll_futex_wake (&t->setxid_futex, 1); +} + + +static int +internal_function +setxid_signal_thread (struct xid_command *cmdp, struct pthread *t) +{ + if ((t->cancelhandling & SETXID_BITMASK) == 0) + return 0; int val; INTERNAL_SYSCALL_DECL (err); @@ -884,8 +915,14 @@ setxid_signal_thread (struct xid_command *cmdp, struct pthread *t) val = INTERNAL_SYSCALL (tkill, err, 2, t->tid, SIGSETXID); #endif + /* If this failed, it must have had not started yet or else exited. */ if (!INTERNAL_SYSCALL_ERROR_P (val, err)) - atomic_increment (&cmdp->cntr); + { + atomic_increment (&cmdp->cntr); + return 1; + } + else + return 0; } @@ -893,6 +930,7 @@ int attribute_hidden __nptl_setxid (struct xid_command *cmdp) { + int signalled; int result; lll_lock (stack_cache_lock); @@ -909,7 +947,7 @@ __nptl_setxid (struct xid_command *cmdp) if (t == self) continue; - setxid_signal_thread (cmdp, t); + setxid_mark_thread (cmdp, t); } /* Now the list with threads using user-allocated stacks. */ @@ -919,14 +957,61 @@ __nptl_setxid (struct xid_command *cmdp) if (t == self) continue; - setxid_signal_thread (cmdp, t); + setxid_mark_thread (cmdp, t); + } + + /* Iterate until we don't succeed in signalling anyone. That means + we have gotten all running threads, and their children will be + automatically correct once started. */ + do + { + signalled = 0; + + list_for_each (runp, &stack_used) + { + struct pthread *t = list_entry (runp, struct pthread, list); + if (t == self) + continue; + + signalled += setxid_signal_thread (cmdp, t); + } + + list_for_each (runp, &__stack_user) + { + struct pthread *t = list_entry (runp, struct pthread, list); + if (t == self) + continue; + + signalled += setxid_signal_thread (cmdp, t); + } + + int cur = cmdp->cntr; + while (cur != 0) + { + lll_futex_wait (&cmdp->cntr, cur); + cur = cmdp->cntr; + } + } + while (signalled != 0); + + /* Clean up flags, so that no thread blocks during exit waiting + for a signal which will never come. */ + list_for_each (runp, &stack_used) + { + struct pthread *t = list_entry (runp, struct pthread, list); + if (t == self) + continue; + + setxid_unmark_thread (cmdp, t); } - int cur = cmdp->cntr; - while (cur != 0) + list_for_each (runp, &__stack_user) { - lll_futex_wait (&cmdp->cntr, cur); - cur = cmdp->cntr; + struct pthread *t = list_entry (runp, struct pthread, list); + if (t == self) + continue; + + setxid_unmark_thread (cmdp, t); } /* This must be last, otherwise the current thread might not have diff --git a/libc/nptl/init.c b/libc/nptl/init.c index 61ba8ec7f..3a1b1fc6e 100644 --- a/libc/nptl/init.c +++ b/libc/nptl/init.c @@ -236,17 +236,23 @@ sighandler_setxid (int sig, siginfo_t *si, void *ctx) INTERNAL_SYSCALL_NCS (__xidcmd->syscall_no, err, 3, __xidcmd->id[0], __xidcmd->id[1], __xidcmd->id[2]); - if (atomic_decrement_val (&__xidcmd->cntr) == 0) - lll_futex_wake (&__xidcmd->cntr, 1); - /* Reset the SETXID flag. */ struct pthread *self = THREAD_SELF; - int flags = THREAD_GETMEM (self, cancelhandling); - THREAD_SETMEM (self, cancelhandling, flags & ~SETXID_BITMASK); + int flags, newval; + do + { + flags = THREAD_GETMEM (self, cancelhandling); + newval = THREAD_ATOMIC_CMPXCHG_VAL (self, cancelhandling, + flags & ~SETXID_BITMASK, flags); + } + while (flags != newval); /* And release the futex. */ self->setxid_futex = 1; lll_futex_wake (&self->setxid_futex, 1); + + if (atomic_decrement_val (&__xidcmd->cntr) == 0) + lll_futex_wake (&__xidcmd->cntr, 1); } |