1193323Sed/* linux-dp.c --- dining philosophers, on LinuxThreads 2193323Sed Jim Blandy <jimb@cygnus.com> --- March 1999 */ 3193323Sed 4193323Sed/* It's okay to edit this file and shift line numbers around. The 5193323Sed tests use gdb_get_line_number to find source locations, so they 6193323Sed don't depend on having certain line numbers in certain places. */ 7193323Sed 8193323Sed#include <stdarg.h> 9193323Sed#include <stdlib.h> 10193323Sed#include <stdio.h> 11193323Sed#include <pthread.h> 12193323Sed#include <sys/time.h> 13193323Sed#include <sys/types.h> 14193323Sed#include <unistd.h> 15193323Sed 16193323Sed/* The number of philosophers at the table. */ 17193323Sedint num_philosophers; 18195340Sed 19193323Sed/* Mutex ordering - 20193323Sed If you want to lock a mutex M, all the mutexes you have locked 21193323Sed already must appear before M on this list. 22193323Sed 23193323Sed fork_mutex[0] 24195340Sed fork_mutex[1] 25195340Sed ... 26193323Sed fork_mutex[num_philosophers - 1] 27195340Sed stdout_mutex 28193323Sed random_mutex 29195340Sed*/ 30195340Sed 31193323Sed/* You must hold this mutex while writing to stdout. */ 32193323Sedpthread_mutex_t stdout_mutex; 33193323Sed 34195340Sed/* You must hold this mutex while calling any of the random number 35195340Sed generation routines. */ 36195340Sedpthread_mutex_t random_mutex; 37195340Sed 38195340Sed/* array of mutexes, one for each fork; fork_mutex[i] is to the left 39193323Sed of philosopher i. A philosopher is holding fork i iff his/her 40193323Sed thread has locked fork_mutex[i]. */ 41193323Sedpthread_mutex_t *fork_mutex; 42193323Sed 43193323Sed/* array of threads, one representing each philosopher. */ 44195340Sedpthread_t *philosophers; 45195340Sed 46195340Sedvoid * 47195340Sedxmalloc (size_t n) 48195340Sed{ 49195340Sed void *p = malloc (n); 50195340Sed 51193323Sed if (! p) 52193323Sed { 53193323Sed fprintf (stderr, "out of memory\n"); 54195340Sed exit (2); 55193323Sed } 56193323Sed 57195340Sed return p; 58195340Sed} 59193323Sed 60193323Sedvoid 61193323Sedshared_printf (char *format, ...) 62{ 63 va_list ap; 64 65 va_start (ap, format); 66 pthread_mutex_lock (&stdout_mutex); 67 vprintf (format, ap); 68 pthread_mutex_unlock (&stdout_mutex); 69 va_end (ap); 70} 71 72int 73shared_random () 74{ 75 int result; 76 77 pthread_mutex_lock (&random_mutex); 78 result = rand (); 79 pthread_mutex_unlock (&random_mutex); 80 return result; 81} 82 83void 84my_usleep (long usecs) 85{ 86 struct timeval timeout; 87 88 timeout.tv_sec = usecs / 1000000; 89 timeout.tv_usec = usecs % 1000000; 90 91 select (0, 0, 0, 0, &timeout); 92} 93 94void 95random_delay () 96{ 97 my_usleep ((shared_random () % 2000) * 100); 98} 99 100void 101print_philosopher (int n, char left, char right) 102{ 103 int i; 104 105 shared_printf ("%*s%c %d %c\n", (n * 4) + 2, "", left, n, right); 106} 107 108void * 109philosopher (void *data) 110{ 111 int n = * (int *) data; 112 113 print_philosopher (n, '_', '_'); 114 115#if 1 116 if (n == num_philosophers - 1) 117 for (;;) 118 { 119 /* The last philosopher is different. He goes for his right 120 fork first, so there is no cycle in the mutex graph. */ 121 122 /* Grab the right fork. */ 123 pthread_mutex_lock (&fork_mutex[(n + 1) % num_philosophers]); 124 print_philosopher (n, '_', '!'); 125 random_delay (); 126 127 /* Then grab the left fork. */ 128 pthread_mutex_lock (&fork_mutex[n]); 129 print_philosopher (n, '!', '!'); 130 random_delay (); 131 132 print_philosopher (n, '_', '_'); 133 pthread_mutex_unlock (&fork_mutex[n]); 134 pthread_mutex_unlock (&fork_mutex[(n + 1) % num_philosophers]); 135 random_delay (); 136 } 137 else 138#endif 139 for (;;) 140 { 141 /* Grab the left fork. */ 142 pthread_mutex_lock (&fork_mutex[n]); 143 print_philosopher (n, '!', '_'); 144 random_delay (); 145 146 /* Then grab the right fork. */ 147 pthread_mutex_lock (&fork_mutex[(n + 1) % num_philosophers]); 148 print_philosopher (n, '!', '!'); 149 random_delay (); 150 151 print_philosopher (n, '_', '_'); 152 pthread_mutex_unlock (&fork_mutex[n]); 153 pthread_mutex_unlock (&fork_mutex[(n + 1) % num_philosophers]); 154 random_delay (); 155 } 156 157 return (void *) 0; 158} 159 160int 161main (int argc, char **argv) 162{ 163 num_philosophers = 5; 164 165 /* Set up the mutexes. */ 166 { 167 pthread_mutexattr_t ma; 168 int i; 169 170 pthread_mutexattr_init (&ma); 171 pthread_mutex_init (&stdout_mutex, &ma); 172 pthread_mutex_init (&random_mutex, &ma); 173 fork_mutex = xmalloc (num_philosophers * sizeof (fork_mutex[0])); 174 for (i = 0; i < num_philosophers; i++) 175 pthread_mutex_init (&fork_mutex[i], &ma); 176 pthread_mutexattr_destroy (&ma); 177 } 178 179 /* Set off the threads. */ 180 { 181 int i; 182 int *numbers = xmalloc (num_philosophers * sizeof (*numbers)); 183 pthread_attr_t ta; 184 185 philosophers = xmalloc (num_philosophers * sizeof (*philosophers)); 186 187 pthread_attr_init (&ta); 188 189 for (i = 0; i < num_philosophers; i++) 190 { 191 numbers[i] = i; 192 /* linuxthreads.exp: create philosopher */ 193 pthread_create (&philosophers[i], &ta, philosopher, &numbers[i]); 194 } 195 196 pthread_attr_destroy (&ta); 197 } 198 199 /* linuxthreads.exp: info threads 2 */ 200 sleep (1000000); 201 202 /* Drink yourself into oblivion. */ 203 for (;;) 204 sleep (1000000); 205 206 return 0; 207} 208