From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: by sourceware.org (Postfix, from userid 2130) id 27F7E3858C83; Tue, 16 May 2023 19:09:43 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 27F7E3858C83 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=sourceware.org; s=default; t=1684264183; bh=RLZKl3cAVrOAuosw/R8+cV3hqms6eNBrN+ucY4cZvZQ=; h=From:To:Subject:Date:From; b=Gi2i7HRQyLUCQpWaTInVef2ySW7aRGZxSXdi5sORB4DhWs95AVB7nVKqBbbFRwgOZ c2NMCownqoiv5CDnHmdzhd8GJfVQItN49vvZReGMhzBVuONwHNPBBCS+X6EXYZ414C Q90O8S5zjOjCGRbGiDSOyndn4iN3dXo1JCjpNQKE= Content-Type: text/plain; charset="us-ascii" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit From: DJ Delorie To: glibc-cvs@sourceware.org Subject: [glibc] i386: Use pthread_barrier for synchronization on tst-bz21269 X-Act-Checkin: glibc X-Git-Author: DJ Delorie X-Git-Refname: refs/heads/master X-Git-Oldrev: d877b52d58b1c73810751bdb48987b84bda87d5e X-Git-Newrev: 088136aa02de6fa13061ef6f754071a5652fdabd Message-Id: <20230516190943.27F7E3858C83@sourceware.org> Date: Tue, 16 May 2023 19:09:43 +0000 (GMT) List-Id: https://sourceware.org/git/gitweb.cgi?p=glibc.git;h=088136aa02de6fa13061ef6f754071a5652fdabd commit 088136aa02de6fa13061ef6f754071a5652fdabd Author: DJ Delorie Date: Mon May 15 22:50:35 2023 -0400 i386: Use pthread_barrier for synchronization on tst-bz21269 So I was able to reproduce the hangs in the original source, and debug it, and fix it. In doing so, I realized that we can't use anything complex to trigger the thread because that "anything" might also cause the expected segfault and force everything out of sync again. Here's what I ended up with, and it doesn't seem to hang where the original one hung quite often (in a tight while..end loop). The key changes are: 1. Calls to futex are error checked, with retries, to ensure that the futexes are actually doing what they're supposed to be doing. In the original code, nearly every futex call returned an error. 2. The main loop has checks for whether the thread ran or not, and "unlocks" the thread if it didn't (this is how the original source hangs). Note: the usleep() is not for timing purposes, but just to give the kernel an excuse to run the other thread at that time. The test will not hang without it, but is more likely to test the right bugfix if the usleep() is present. Diff: --- sysdeps/unix/sysv/linux/i386/tst-bz21269.c | 33 +++++++++++++++++++++++++----- 1 file changed, 28 insertions(+), 5 deletions(-) diff --git a/sysdeps/unix/sysv/linux/i386/tst-bz21269.c b/sysdeps/unix/sysv/linux/i386/tst-bz21269.c index 1850240c34..51d4a1b082 100644 --- a/sysdeps/unix/sysv/linux/i386/tst-bz21269.c +++ b/sysdeps/unix/sysv/linux/i386/tst-bz21269.c @@ -135,7 +135,14 @@ threadproc (void *ctx) { while (1) { - futex ((int *) &ftx, FUTEX_WAIT, 1, NULL, NULL, 0); + /* Continue to wait here until we've successfully waited, unless + we're supposed to be clearing the LDT already. */ + while (futex ((int *) &ftx, FUTEX_WAIT, 1, NULL, NULL, 0) < 0) + if (atomic_load (&ftx) >= 2) + break; + + /* Normally there's time to hit this busy loop and wait for ftx + to be set to 2. */ while (atomic_load (&ftx) != 2) { if (atomic_load (&ftx) >= 3) @@ -189,7 +196,14 @@ do_test (void) if (sigsetjmp (jmpbuf, 1) != 0) continue; - /* Make sure the thread is ready after the last test. */ + /* We may have longjmp'd before triggering the thread. If so, + trigger the thread now and wait for it. */ + if (atomic_load (&ftx) == 1) + atomic_store (&ftx, 2); + + /* Make sure the thread is ready after the last test. FTX is + initially zero for the first loop, and set to zero each time + the thread clears the LDT. */ while (atomic_load (&ftx) != 0) ; @@ -207,15 +221,24 @@ do_test (void) xmodify_ldt (0x11, &desc, sizeof (desc)); - /* Arm the thread. */ - ftx = 1; - futex ((int*) &ftx, FUTEX_WAKE, 0, NULL, NULL, 0); + /* Arm the thread. We loop here until we've woken up one thread. */ + atomic_store (&ftx, 1); + while (futex ((int*) &ftx, FUTEX_WAKE, 1, NULL, NULL, 0) < 1) + ; + + /* Give the thread a chance to get into it's busy loop. */ + usleep (5); + /* At *ANY* point after this instruction, we may segfault and + longjump back to the top of the loop. The intention is to + have this happen when the thread clears the LDT, but it could + happen elsewhen. */ asm volatile ("mov %0, %%ss" : : "r" (0x7)); /* Fire up thread modify_ldt call. */ atomic_store (&ftx, 2); + /* And wait for it. */ while (atomic_load (&ftx) != 0) ;