1/* linux-dp.c --- dining philosophers, on LinuxThreads
2   Jim Blandy <jimb@cygnus.com> --- March 1999  */
3
4/* It's okay to edit this file and shift line numbers around.  The
5   tests use gdb_get_line_number to find source locations, so they
6   don't depend on having certain line numbers in certain places.  */
7
8#include <stdarg.h>
9#include <stdlib.h>
10#include <stdio.h>
11#include <pthread.h>
12#include <sys/time.h>
13#include <sys/types.h>
14
15/* The number of philosophers at the table.  */
16int num_philosophers;
17
18/* Mutex ordering -
19   If you want to lock a mutex M, all the mutexes you have locked
20   already must appear before M on this list.
21
22   fork_mutex[0]
23   fork_mutex[1]
24   ...
25   fork_mutex[num_philosophers - 1]
26   stdout_mutex
27   random_mutex
28*/
29
30/* You must hold this mutex while writing to stdout.  */
31pthread_mutex_t stdout_mutex;
32
33/* You must hold this mutex while calling any of the random number
34   generation routines.  */
35pthread_mutex_t random_mutex;
36
37/* array of mutexes, one for each fork; fork_mutex[i] is to the left
38   of philosopher i.  A philosopher is holding fork i iff his/her
39   thread has locked fork_mutex[i].  */
40pthread_mutex_t *fork_mutex;
41
42/* array of threads, one representing each philosopher.  */
43pthread_t *philosophers;
44
45void *
46xmalloc (size_t n)
47{
48  void *p = malloc (n);
49
50  if (! p)
51    {
52      fprintf (stderr, "out of memory\n");
53      exit (2);
54    }
55
56  return p;
57}
58
59void
60shared_printf (char *format, ...)
61{
62  va_list ap;
63
64  va_start (ap, format);
65  pthread_mutex_lock (&stdout_mutex);
66  vprintf (format, ap);
67  pthread_mutex_unlock (&stdout_mutex);
68  va_end (ap);
69}
70
71int
72shared_random ()
73{
74  static unsigned int seed;
75  int result;
76
77  pthread_mutex_lock (&random_mutex);
78  result = rand_r (&seed);
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