mirror of
https://sourceware.org/git/binutils-gdb.git
synced 2024-12-27 04:52:05 +08:00
4a94e36819
This commit brings all the changes made by running gdb/copyright.py as per GDB's Start of New Year Procedure. For the avoidance of doubt, all changes in this commits were performed by the script.
203 lines
4.7 KiB
C
203 lines
4.7 KiB
C
/* This testcase is part of GDB, the GNU debugger.
|
|
|
|
Copyright 2020-2022 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 <pthread.h>
|
|
#include <sys/types.h>
|
|
#include <stdio.h>
|
|
#include <unistd.h>
|
|
#include <stdlib.h>
|
|
#include <pthread.h>
|
|
|
|
/* The number of threads to create. */
|
|
int thread_count = 3;
|
|
|
|
/* Counter accessed from threads to ensure that all threads have been
|
|
started. Is initialised to THREAD_COUNT and each thread decrements it
|
|
upon startup. */
|
|
volatile int counter;
|
|
|
|
/* Lock guarding COUNTER. */
|
|
pthread_mutex_t counter_mutex = PTHREAD_MUTEX_INITIALIZER;
|
|
|
|
/* Is initialised with our pid, GDB will read this. */
|
|
pid_t global_pid;
|
|
|
|
/* Just somewhere to put a breakpoint. */
|
|
static void
|
|
breakpt ()
|
|
{
|
|
/* Nothing. */
|
|
}
|
|
|
|
/* Thread safe decrement of the COUNTER global. */
|
|
static void
|
|
decrement_counter ()
|
|
{
|
|
if (pthread_mutex_lock (&counter_mutex) != 0)
|
|
abort ();
|
|
--counter;
|
|
if (pthread_mutex_unlock (&counter_mutex) != 0)
|
|
abort ();
|
|
}
|
|
|
|
/* Thread safe read of the COUNTER global. */
|
|
static int
|
|
read_counter ()
|
|
{
|
|
int val;
|
|
|
|
if (pthread_mutex_lock (&counter_mutex) != 0)
|
|
abort ();
|
|
val = counter;
|
|
if (pthread_mutex_unlock (&counter_mutex) != 0)
|
|
abort ();
|
|
|
|
return val;
|
|
}
|
|
|
|
#if defined DO_EXIT_TEST
|
|
|
|
/* Thread entry point. ARG is a pointer to a single integer, the ID for
|
|
this thread numbered 1 to THREAD_COUNT (a global). */
|
|
static void *
|
|
thread_worker_exiting (void *arg)
|
|
{
|
|
int id;
|
|
|
|
id = *((int *) arg);
|
|
|
|
decrement_counter ();
|
|
|
|
if (id != thread_count)
|
|
{
|
|
int i;
|
|
|
|
/* All threads except the last one will wait here while the test is
|
|
carried out. Don't wait forever though, just in case the test
|
|
goes wrong. */
|
|
for (i = 0; i < 60; ++i)
|
|
sleep (1);
|
|
}
|
|
else
|
|
{
|
|
/* The last thread waits here until all other threads have been
|
|
created. */
|
|
while (read_counter () > 0)
|
|
sleep (1);
|
|
|
|
/* Hit the breakpoint so GDB can stop. */
|
|
breakpt ();
|
|
|
|
/* And exit all threads. */
|
|
exit (0);
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
#define thread_worker thread_worker_exiting
|
|
|
|
#elif defined DO_SIGNAL_TEST
|
|
|
|
/* Thread entry point. ARG is a pointer to a single integer, the ID for
|
|
this thread numbered 1 to THREAD_COUNT (a global). */
|
|
static void *
|
|
thread_worker_signalling (void *arg)
|
|
{
|
|
int i, id;
|
|
|
|
id = *((int *) arg);
|
|
|
|
decrement_counter ();
|
|
|
|
if (id == thread_count)
|
|
{
|
|
/* The last thread waits here until all other threads have been
|
|
created. */
|
|
while (read_counter () > 0)
|
|
sleep (1);
|
|
|
|
/* Hit the breakpoint so GDB can stop. */
|
|
breakpt ();
|
|
}
|
|
|
|
/* All threads wait here while the testsuite sends us a signal. Don't
|
|
block forever though, just in case the test goes wrong. */
|
|
for (i = 0; i < 60; ++i)
|
|
sleep (1);
|
|
|
|
return NULL;
|
|
}
|
|
|
|
#define thread_worker thread_worker_signalling
|
|
|
|
#else
|
|
|
|
#error "Compile with DO_EXIT_TEST or DO_SIGNAL_TEST defined"
|
|
|
|
#endif
|
|
|
|
struct thread_info
|
|
{
|
|
pthread_t thread;
|
|
int id;
|
|
};
|
|
|
|
int
|
|
main ()
|
|
{
|
|
int i, max = thread_count;
|
|
|
|
/* Put the pid somewhere easy for GDB to read. */
|
|
global_pid = getpid ();
|
|
|
|
/* Space to hold all of the thread_info objects. */
|
|
struct thread_info *info = malloc (sizeof (struct thread_info) * max);
|
|
if (info == NULL)
|
|
abort ();
|
|
|
|
/* Initialise the counter. Don't do this under lock as we only have the
|
|
main thread at this point. */
|
|
counter = thread_count;
|
|
|
|
/* Create all of the threads. */
|
|
for (i = 0; i < max; ++i)
|
|
{
|
|
struct thread_info *thr = &info[i];
|
|
thr->id = i + 1;
|
|
if (pthread_create (&thr->thread, NULL, thread_worker, &thr->id) != 0)
|
|
abort ();
|
|
}
|
|
|
|
/* Gather in all of the threads. This never completes, as the
|
|
final thread created will exit the process, and all of the other
|
|
threads block forever. Still, it gives the main thread something to
|
|
do. */
|
|
for (i = 0; i < max; ++i)
|
|
{
|
|
struct thread_info *thr = &info[i];
|
|
if (pthread_join (thr->thread, NULL) != 0)
|
|
abort ();
|
|
}
|
|
|
|
free (info);
|
|
|
|
/* Return non-zero. We should never get here, but if we do make sure we
|
|
indicate something has gone wrong. */
|
|
return 1;
|
|
}
|