about summary refs log tree commit diff
path: root/sysdeps/unix/sysv/linux/i386/tst-bz21269.c
diff options
context:
space:
mode:
Diffstat (limited to 'sysdeps/unix/sysv/linux/i386/tst-bz21269.c')
-rw-r--r--sysdeps/unix/sysv/linux/i386/tst-bz21269.c33
1 files 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)
 	;