mirror of
https://sourceware.org/git/binutils-gdb.git
synced 2024-12-12 03:43:33 +08:00
[gdb/testsuite] Fix failure in gdb.threads/signal-sigtrap.exp
The test-case gdb.threads/signal-sigtrap.exp: - installs a signal handler called sigtrap_handler for SIGTRAP, - sets a breakpoint on sigtrap_handler, and - expects the breakpoint to trigger after issuing "signal SIGTRAP". Usually, that happens indeed: ... (gdb) signal SIGTRAP^M Continuing with signal SIGTRAP.^M ^M Thread 1 "signal-sigtrap" hit Breakpoint 2, sigtrap_handler (sig=5)^M 28 }^M (gdb) PASS: $exp: sigtrap thread 1: signal SIGTRAP reaches handler ... Occasionally, I run into this failure on openSUSE Tumbleweed: ... (gdb) signal SIGTRAP^M Continuing with signal SIGTRAP.^M ^M Thread 1 "signal-sigtrap" received signal SIGTRAP, Trace/breakpoint trap.^M __pthread_create_2_1 () at pthread_create.c:843^M (gdb) FAIL: $exp: sigtrap thread 1: signal SIGTRAP reaches handler ... AFAIU, the problem is in the situation that is setup before issuing that command, by running to a breakpoint in thread_function: ... void *thread_function (void *arg) { return NULL; } int main (void) { pthread_t child_thread; signal (SIGTRAP, sigtrap_handler); pthread_create (&child_thread, NULL, thread_function, NULL); pthread_join (child_thread, NULL); return 0; } ... In the passing case, thread 2 is stopped in thread_function, and thread 1 is stopped somewhere in pthread_join: ... (gdb) info threads^M Id Target Id Frame ^M 1 Thread ... (LWP ...) "signal-sigtrap" __futex_abstimed_wait_common64 () * 2 Thread ... (LWP ...) "signal-sigtrap" thread_function () ... In the failing case, thread 2 is stopped in thread_function, but thread 1 is stopped somewhere in pthread_create: ... (gdb) info threads^M Id Target Id Frame ^M 1 Thread ... (LWP ...) "signal-sigtrap" __GI___clone3 () * 2 Thread ... (LWP ...) "signal-sigtrap" thread_function () ... What I think happens is that pthread_create blocks SIGTRAP at some point, and if the "signal SIGTRAP" command is issued while that is the case, the signal becomes pending and consequently there's no longer a guarantee that the signal will be delivered to the inferior. Instead the signal will be handled by gdb like this: ... (gdb) info signals SIGTRAP Signal Stop Print Pass to program Description SIGTRAP Yes Yes No Trace/breakpoint trap ... Fix this by adding a barrier that ensures that pthread_create is done before we issue the "signal SIGTRAP" command. Likewise in test-case gdb.threads/signal-command-handle-nopass.exp. Using the fixed test-case, I tested my theory by explicitly blocking SIGTRAP: ... + sigset_t old_ss, new_ss; + sigemptyset (&new_ss); + sigaddset (&new_ss, SIGTRAP); + sigprocmask (SIG_BLOCK, &new_ss, &old_ss); + /* Make sure that pthread_create is done once the breakpoint on thread_function triggers. */ pthread_barrier_wait (&barrier); pthread_join (child_thread, NULL); + sigprocmask (SIG_SETMASK, &old_ss, NULL); ... and managed to reproduce the same failure: ... (gdb) signal SIGTRAP^M Continuing with signal SIGTRAP.^M [Thread 0x7ffff7c00700 (LWP 13254) exited]^M ^M Thread 1 "signal-sigtrap" received signal SIGTRAP, Trace/breakpoint trap.^M 0x00007ffff7c80056 in __GI___sigprocmask () sigprocmask.c:39^M (gdb) FAIL: $exp: sigtrap thread 1: signal SIGTRAP reaches handler ... Tested on x86_64-linux. PR testsuite/26867 Bug: https://sourceware.org/bugzilla/show_bug.cgi?id=26867
This commit is contained in:
parent
bee9d00688
commit
dca18cb6a1
@ -21,6 +21,8 @@
|
||||
#include <pthread.h>
|
||||
#include <signal.h>
|
||||
|
||||
static pthread_barrier_t barrier;
|
||||
|
||||
void
|
||||
handler (int sig)
|
||||
{
|
||||
@ -35,6 +37,13 @@ thread_function (void *arg)
|
||||
usleep (1);
|
||||
}
|
||||
|
||||
void *
|
||||
thread_function_sync (void *arg)
|
||||
{
|
||||
pthread_barrier_wait (&barrier);
|
||||
return thread_function (arg);
|
||||
}
|
||||
|
||||
int
|
||||
main (void)
|
||||
{
|
||||
@ -42,7 +51,15 @@ main (void)
|
||||
int i;
|
||||
|
||||
signal (SIGUSR1, handler);
|
||||
pthread_create (&child_thread, NULL, thread_function, NULL);
|
||||
|
||||
pthread_barrier_init (&barrier, NULL, 2);
|
||||
|
||||
pthread_create (&child_thread, NULL, thread_function_sync, NULL);
|
||||
|
||||
/* Make sure that pthread_create is done once the breakpoint on
|
||||
thread_function triggers. */
|
||||
pthread_barrier_wait (&barrier);
|
||||
|
||||
pthread_join (child_thread, NULL);
|
||||
|
||||
return 0;
|
||||
|
@ -20,6 +20,8 @@
|
||||
#include <pthread.h>
|
||||
#include <signal.h>
|
||||
|
||||
static pthread_barrier_t barrier;
|
||||
|
||||
void
|
||||
sigtrap_handler (int sig)
|
||||
{
|
||||
@ -31,6 +33,13 @@ thread_function (void *arg)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void *
|
||||
thread_function_sync (void *arg)
|
||||
{
|
||||
pthread_barrier_wait (&barrier);
|
||||
return thread_function (arg);
|
||||
}
|
||||
|
||||
int
|
||||
main (void)
|
||||
{
|
||||
@ -38,7 +47,13 @@ main (void)
|
||||
|
||||
signal (SIGTRAP, sigtrap_handler);
|
||||
|
||||
pthread_create (&child_thread, NULL, thread_function, NULL);
|
||||
pthread_barrier_init (&barrier, NULL, 2);
|
||||
|
||||
pthread_create (&child_thread, NULL, thread_function_sync, NULL);
|
||||
|
||||
/* Make sure that pthread_create is done once the breakpoint on
|
||||
thread_function triggers. */
|
||||
pthread_barrier_wait (&barrier);
|
||||
|
||||
pthread_join (child_thread, NULL);
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user