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