[PATCH v4] i386: Use pthread_barrier for synchronization on tst-bz21269

Adhemerval Zanella Netto adhemerval.zanella@linaro.org
Thu Mar 2 16:55:43 GMT 2023



On 01/03/23 18:37, DJ Delorie wrote:
> Adhemerval Zanella <adhemerval.zanella@linaro.org> writes:
>>  static void *
>>  threadproc (void *ctx)
>>  {
>> -  while (1)
>> +  for (int i = 0; i < NITER; i++)
>>      {
>> -      futex ((int *) &ftx, FUTEX_WAIT, 1, NULL, NULL, 0);
>> -      while (atomic_load (&ftx) != 2)
>> -	{
>> -	  if (atomic_load (&ftx) >= 3)
>> -	    return NULL;
>> -	}
>> +      xpthread_barrier_wait (&barrier);
>>  
>>        /* clear LDT entry 0.  */
>>        const struct user_desc desc = { 0 };
>>        xmodify_ldt (1, &desc, sizeof (desc));
>>  
>> -      /* If ftx == 2, set it to zero,  If ftx == 100, quit.  */
>> -      if (atomic_fetch_add (&ftx, -2) != 2)
>> -	return NULL;
>> +      /* Wait for 'ss' set in main thread.  */
>> +      xpthread_barrier_wait (&barrier);
>>      }
>> +
>> +  return NULL;
>>  }
>>  
>>  
>> @@ -180,20 +163,21 @@ do_test (void)
>> -  for (int i = 0; i < 5; i++)
>> +  for (int i = 0; i < NITER; i++)
>>      {
>>        if (sigsetjmp (jmpbuf, 1) != 0)
>>  	continue;
>>  
>>        /* Make sure the thread is ready after the last test. */
>> -      while (atomic_load (&ftx) != 0)
>> -	;
>> +      xpthread_barrier_wait (&barrier);
>>  
>> -      struct user_desc desc = {
>> +      const struct user_desc desc = {
>>  	.entry_number       = 0,
>>  	.base_addr          = 0,
>>  	.limit              = 0xffff,
>> @@ -207,28 +191,20 @@ do_test (void)
>>  
>>        xmodify_ldt (0x11, &desc, sizeof (desc));
>>  
>> -      /* Arm the thread.  */
>> -      ftx = 1;
>> -      futex ((int*) &ftx, FUTEX_WAKE, 0, NULL, NULL, 0);
>> +      /* Wait thread clear LDT entry 0.  */
>> +      xpthread_barrier_wait (&barrier);
>>  
>>        asm volatile ("mov %0, %%ss" : : "r" (0x7));
>>  
>> -      /* Fire up thread modify_ldt call.  */
>> -      atomic_store (&ftx, 2);
>> -
>> -      while (atomic_load (&ftx) != 0)
>> -	;
>> -
>>        /* On success, modify_ldt will segfault us synchronously and we will
>>  	 escape via siglongjmp.  */
>>        support_record_failure ();
>>      }
> 
> this does...
> 
> child		parent
> -----		------
> 
> <nothing>	setjmp
> 
> barrier	-------	barrier
> 
> clear LDT	set LDT		<-- these happen at the "same time"

Yeah, ant is is clearly wrong...

> 
> barrier	-------	barrier
> 
> <nothing>	set ss
> 		support_record_failure (which hopefully segfaults before
> 			recording failure
> 
> 
> IIRC what's supposed to happen (based on the original test) is:
> 
> <nothing>	setjmp
> 
> barrier	-------	barrier
> 
> 		set LDT
> <nothing>	set ss
> 
>  -- do some syscall --
> 
> clear LDT	-- longjmp
> 
> 
> When the test fails, it does this:
> 		setjmp
> 		set LDT
> 		set ss
> - task switch -
> segfaults
> 
> Part of me wonders if the taken longjmp causes one of the barriers to be
> skipped, putting the test out of sync.  If so, we won't be able to use
> barriers this way.
> 
> Ok so I did some testing on the original test case, and it seems that
> the first syscall after setting %ss causes the signal, handler, and
> longjmp.  Which means two things:
> 
> 1. The test must have some sort of forced syscall (INT3) or other
>    stack-using operation after setting %ss, to trigger the test, and
> 
> 2. At that point, the parent longjumps to the top of the loop
> 
> I'm not sure how we can satisfy both of these with pthread barriers,
> since the one on the parent side would fault and not sync with the child
> side.
> 
> Atomics do no syscalls so do not care if %ss is bogus.

It makes sense, the problem is indeed the stack access that triggers
the expected failure.

> 
> However, I also found a bug in the original code:
> 
>       futex ((int*) &ftx, FUTEX_WAKE, 0, NULL, NULL, 0);
> 
> Per the manual, this wakes up at most zero threads.  The child thread
> avoids this because ftx is never set right and it's FUTEX_WAIT always
> returns with EAGAIN - except when it is right, and hangs.
> 
> /me is still investigating...
> 

Another possibility I was wondering was to just remove this test altogether,
it is already covered by kernel testing code.


More information about the Libc-alpha mailing list