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