d27d16bfdc
The hang occurs when GDB tries to call inferior functions on two different threads with scheduler-locking turned on. The first call works fine, with the call to infrun_async(1) causing the signal_handler to be marked and the event to be handled, but then the event loop resets the "ready" member to zero, while leaving infrun_is_async set to 1. As a result, GDB hangs if the user switches to another thread and calls a second function because calling infrun_async(1) a second time has no effect, meaning the inferior call events are never handled. The added test case provokes the above issue. gdb/testsuite/ChangeLog: * gdb.threads/multiple-successive-infcall.c: New test. * gdb.threads/multiple-successive-infcall.exp: New file.
112 lines
3.1 KiB
C
112 lines
3.1 KiB
C
/* This testcase is part of GDB, the GNU debugger.
|
|
|
|
Copyright 2018 Free Software Foundation, Inc.
|
|
|
|
This program is free software; you can redistribute it and/or modify
|
|
it under the terms of the GNU General Public License as published by
|
|
the Free Software Foundation; either version 3 of the License, or
|
|
(at your option) any later version.
|
|
|
|
This program is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
GNU General Public License for more details.
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
along with this program. If not, see <http://www.gnu.org/licenses/>. */
|
|
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <pthread.h>
|
|
|
|
/* This defines the number of threads to spawn. */
|
|
#define THREADCOUNT 4
|
|
|
|
/* Global barrier type to control synchronization between threads. */
|
|
static pthread_barrier_t print_barrier;
|
|
|
|
/* Define global thread identifiers. */
|
|
static pthread_t threads[THREADCOUNT];
|
|
|
|
/* Hold values for each thread at the index supplied to the thread
|
|
on creation. */
|
|
static int thread_ids[THREADCOUNT];
|
|
|
|
/* Find the value associated with the calling thread. */
|
|
static int
|
|
get_value ()
|
|
{
|
|
for (int tid = 0; tid < THREADCOUNT; ++tid)
|
|
{
|
|
if (pthread_equal (threads[tid], pthread_self ()))
|
|
return thread_ids[tid];
|
|
}
|
|
/* Value for the main thread. */
|
|
return 1;
|
|
}
|
|
|
|
/* Return the nth Fibonacci number. */
|
|
static unsigned long
|
|
fast_fib (unsigned int n)
|
|
{
|
|
int a = 0;
|
|
int b = 1;
|
|
int t;
|
|
for (unsigned int i = 0; i < n; ++i)
|
|
{
|
|
t = b;
|
|
b = a + b;
|
|
a = t;
|
|
}
|
|
return a;
|
|
}
|
|
|
|
/* Encapsulate the synchronization of the threads. Perform a barrier before
|
|
and after the computation. */
|
|
static void *
|
|
thread_function (void *args)
|
|
{
|
|
int tid = *((int *) args);
|
|
int status = pthread_barrier_wait (&print_barrier);
|
|
if (status == PTHREAD_BARRIER_SERIAL_THREAD)
|
|
printf ("All threads entering compute region\n");
|
|
|
|
unsigned long result = fast_fib (100); /* testmarker01 */
|
|
status = pthread_barrier_wait (&print_barrier);
|
|
if (status == PTHREAD_BARRIER_SERIAL_THREAD)
|
|
printf ("All threads outputting results\n");
|
|
|
|
pthread_barrier_wait (&print_barrier);
|
|
printf ("Thread %d Result: %lu\n", tid, result);
|
|
}
|
|
|
|
int
|
|
main (void)
|
|
{
|
|
int err = pthread_barrier_init (&print_barrier, NULL, THREADCOUNT);
|
|
if (err != 0)
|
|
{
|
|
fprintf (stderr, "Barrier creation failed\n");
|
|
return EXIT_FAILURE;
|
|
}
|
|
/* Create the worker threads (main). */
|
|
printf ("Spawning worker threads\n");
|
|
for (int tid = 0; tid < THREADCOUNT; ++tid)
|
|
{
|
|
/* Add 2 so the value maps to the debugger's thread identifiers. */
|
|
thread_ids[tid] = tid + 2; /* prethreadcreationmarker */
|
|
err = pthread_create (&threads[tid], NULL, thread_function,
|
|
(void *) &thread_ids[tid]);
|
|
if (err != 0)
|
|
{
|
|
fprintf (stderr, "Thread creation failed\n");
|
|
return EXIT_FAILURE;
|
|
}
|
|
}
|
|
/* Wait for the threads to complete then exit. */
|
|
for (int tid = 0; tid < THREADCOUNT; ++tid)
|
|
pthread_join (threads[tid], NULL);
|
|
|
|
return EXIT_SUCCESS;
|
|
}
|