forked from Imagelibrary/binutils-gdb
This updates the copyright headers to include 2025. I did this by running gdb/copyright.py and then manually modifying a few files as noted by the script. Approved-By: Eli Zaretskii <eliz@gnu.org>
170 lines
4.1 KiB
C
170 lines
4.1 KiB
C
/* This testcase is part of GDB, the GNU debugger.
|
|
|
|
Copyright 2022-2025 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 <pthread.h>
|
|
#include <unistd.h>
|
|
#include <stdlib.h>
|
|
#include <errno.h>
|
|
#include <semaphore.h>
|
|
|
|
#define NUM_THREADS 5
|
|
|
|
/* Semaphores, used to track when threads have started, and to control
|
|
when the threads finish. */
|
|
sem_t startup_semaphore;
|
|
sem_t finish_semaphore;
|
|
sem_t thread_1_semaphore;
|
|
sem_t thread_2_semaphore;
|
|
|
|
/* Mutex to control when the first worker thread hit a breakpoint
|
|
location. */
|
|
pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
|
|
|
|
/* Global variable to poke, just so threads have something to do. */
|
|
volatile int global_var = 0;
|
|
|
|
int
|
|
condition_func ()
|
|
{
|
|
/* Let thread 2 run. */
|
|
if (sem_post (&thread_2_semaphore) != 0)
|
|
abort ();
|
|
|
|
/* Wait for thread 2 to complete its actions. */
|
|
if (sem_wait (&thread_1_semaphore) != 0)
|
|
abort ();
|
|
|
|
return 1;
|
|
}
|
|
|
|
void
|
|
do_segfault ()
|
|
{
|
|
volatile int *p = 0;
|
|
*p = 0; /* Segfault here. */
|
|
}
|
|
|
|
void *
|
|
worker_func (void *arg)
|
|
{
|
|
int tid = *((int *) arg);
|
|
|
|
/* Let the main thread know that this worker has started. */
|
|
if (sem_post (&startup_semaphore) != 0)
|
|
abort ();
|
|
|
|
switch (tid)
|
|
{
|
|
case 0:
|
|
/* Wait for MUTEX to become available, then pass through the
|
|
conditional breakpoint location. */
|
|
if (pthread_mutex_lock (&mutex) != 0)
|
|
abort ();
|
|
global_var = 99; /* Conditional breakpoint here. */
|
|
if (pthread_mutex_unlock (&mutex) != 0)
|
|
abort ();
|
|
break;
|
|
|
|
case 1:
|
|
if (sem_wait (&thread_2_semaphore) != 0)
|
|
abort ();
|
|
do_segfault ();
|
|
if (sem_post (&thread_1_semaphore) != 0)
|
|
abort ();
|
|
|
|
/* Fall through. */
|
|
default:
|
|
/* Wait until we are allowed to finish. */
|
|
if (sem_wait (&finish_semaphore) != 0)
|
|
abort ();
|
|
break;
|
|
}
|
|
}
|
|
|
|
void
|
|
stop_marker ()
|
|
{
|
|
global_var = 99; /* Stop marker. */
|
|
}
|
|
|
|
/* The main program entry point. */
|
|
|
|
int
|
|
main ()
|
|
{
|
|
pthread_t threads[NUM_THREADS];
|
|
int args[NUM_THREADS];
|
|
void *retval;
|
|
|
|
/* An alarm, just in case the thread deadlocks. */
|
|
alarm (300);
|
|
|
|
/* Semaphore initialization. */
|
|
if (sem_init (&startup_semaphore, 0, 0) != 0)
|
|
abort ();
|
|
if (sem_init (&finish_semaphore, 0, 0) != 0)
|
|
abort ();
|
|
if (sem_init (&thread_1_semaphore, 0, 0) != 0)
|
|
abort ();
|
|
if (sem_init (&thread_2_semaphore, 0, 0) != 0)
|
|
abort ();
|
|
|
|
/* Lock MUTEX, this prevents the first worker thread from rushing ahead. */
|
|
if (pthread_mutex_lock (&mutex) != 0)
|
|
abort ();
|
|
|
|
/* Worker thread creation. */
|
|
for (int i = 0; i < NUM_THREADS; i++)
|
|
{
|
|
args[i] = i;
|
|
pthread_create (&threads[i], NULL, worker_func, &args[i]);
|
|
}
|
|
|
|
/* Wait for every thread to start. */
|
|
for (int i = 0; i < NUM_THREADS; i++)
|
|
{
|
|
if (sem_wait (&startup_semaphore) != 0)
|
|
abort ();
|
|
}
|
|
|
|
/* Unlock the first thread so it can proceed. */
|
|
if (pthread_mutex_unlock (&mutex) != 0)
|
|
abort ();
|
|
|
|
/* Wait for the first thread only. */
|
|
pthread_join (threads[0], &retval);
|
|
|
|
/* Now post FINISH_SEMAPHORE to allow all the other threads to finish. */
|
|
for (int i = 1; i < NUM_THREADS; i++)
|
|
sem_post (&finish_semaphore);
|
|
|
|
/* Now wait for the remaining threads to complete. */
|
|
for (int i = 1; i < NUM_THREADS; i++)
|
|
pthread_join (threads[i], &retval);
|
|
|
|
/* Semaphore cleanup. */
|
|
sem_destroy (&finish_semaphore);
|
|
sem_destroy (&startup_semaphore);
|
|
sem_destroy (&thread_1_semaphore);
|
|
sem_destroy (&thread_2_semaphore);
|
|
|
|
stop_marker ();
|
|
|
|
return 0;
|
|
}
|