Home | History | Annotate | Line # | Download | only in gdb.threads
      1 /* Copyright 2022-2024 Free Software Foundation, Inc.
      2 
      3    This file is part of GDB.
      4 
      5    This program is free software; you can redistribute it and/or modify
      6    it under the terms of the GNU General Public License as published by
      7    the Free Software Foundation; either version 3 of the License, or
      8    (at your option) any later version.
      9 
     10    This program is distributed in the hope that it will be useful,
     11    but WITHOUT ANY WARRANTY; without even the implied warranty of
     12    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     13    GNU General Public License for more details.
     14 
     15    You should have received a copy of the GNU General Public License
     16    along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
     17 
     18 #include <pthread.h>
     19 #include <unistd.h>
     20 #include <semaphore.h>
     21 #include <stdlib.h>
     22 
     23 #define NUM_THREADS 5
     24 
     25 /* Semaphores, used to track when threads have started, and to control
     26    when the threads finish.  */
     27 sem_t startup_semaphore;
     28 sem_t finish_semaphore;
     29 
     30 /* Mutex to control when the first worker thread hit a breakpoint
     31    location.  */
     32 pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER;
     33 
     34 /* Global variable to poke, just so threads have something to do.  */
     35 volatile int global_var = 0;
     36 
     37 int
     38 return_true ()
     39 {
     40   return 1;
     41 }
     42 
     43 int
     44 return_false ()
     45 {
     46   return 0;
     47 }
     48 
     49 void *
     50 worker_func (void *arg)
     51 {
     52   int tid = *((int *) arg);
     53 
     54   switch (tid)
     55     {
     56     case 0:
     57       /* Wait for MUTEX to become available, then pass through the
     58 	 conditional breakpoint location.  */
     59       if (pthread_mutex_lock (&mutex) != 0)
     60 	abort ();
     61       global_var = 99;	/* Conditional breakpoint here.  */
     62       if (pthread_mutex_unlock (&mutex) != 0)
     63 	abort ();
     64       break;
     65 
     66     default:
     67       /* Notify the main thread that the thread has started, then wait for
     68 	 the main thread to tell us to finish.  */
     69       sem_post (&startup_semaphore);
     70       if (sem_wait (&finish_semaphore) != 0)
     71 	abort ();
     72       break;
     73     }
     74 }
     75 
     76 void
     77 stop_marker ()
     78 {
     79   global_var = 99;	/* Stop marker.  */
     80 }
     81 
     82 int
     83 main ()
     84 {
     85   pthread_t threads[NUM_THREADS];
     86   int args[NUM_THREADS];
     87   void *retval;
     88 
     89   /* An alarm, just in case the thread deadlocks.  */
     90   alarm (300);
     91 
     92   /* Semaphore initialization.  */
     93   if (sem_init (&startup_semaphore, 0, 0) != 0)
     94     abort ();
     95   if (sem_init (&finish_semaphore, 0, 0) != 0)
     96     abort ();
     97 
     98   /* Lock MUTEX, this prevents the first worker thread from rushing ahead.  */
     99   if (pthread_mutex_lock (&mutex) != 0)
    100     abort ();
    101 
    102   /* Worker thread creation.  */
    103   for (int i = 0; i < NUM_THREADS; i++)
    104     {
    105       args[i] = i;
    106       pthread_create (&threads[i], NULL, worker_func, &args[i]);
    107     }
    108 
    109   /* Wait for every thread (other than the first) to tell us it has started
    110      up.  */
    111   for (int i = 1; i < NUM_THREADS; i++)
    112     {
    113       if (sem_wait (&startup_semaphore) != 0)
    114 	abort ();
    115     }
    116 
    117   /* Unlock the first thread so it can proceed.  */
    118   if (pthread_mutex_unlock (&mutex) != 0)
    119     abort ();
    120 
    121   /* Wait for the first thread only.  */
    122   pthread_join (threads[0], &retval);
    123 
    124   /* Now post FINISH_SEMAPHORE to allow all the other threads to finish.  */
    125   for (int i = 1; i < NUM_THREADS; i++)
    126     sem_post (&finish_semaphore);
    127 
    128   /* Now wait for the remaining threads to complete.  */
    129   for (int i = 1; i < NUM_THREADS; i++)
    130     pthread_join (threads[i], &retval);
    131 
    132   /* Semaphore cleanup.  */
    133   sem_destroy (&finish_semaphore);
    134   sem_destroy (&startup_semaphore);
    135 
    136   stop_marker ();
    137 
    138   return 0;
    139 }
    140