Commit | Line | Data |
---|---|---|
917317f4 JM |
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> | |
37bc665e | 14 | #include <unistd.h> |
917317f4 JM |
15 | |
16 | /* The number of philosophers at the table. */ | |
17 | int num_philosophers; | |
18 | ||
19 | /* Mutex ordering - | |
20 | If you want to lock a mutex M, all the mutexes you have locked | |
21 | already must appear before M on this list. | |
22 | ||
23 | fork_mutex[0] | |
24 | fork_mutex[1] | |
25 | ... | |
26 | fork_mutex[num_philosophers - 1] | |
27 | stdout_mutex | |
28 | random_mutex | |
29 | */ | |
30 | ||
31 | /* You must hold this mutex while writing to stdout. */ | |
32 | pthread_mutex_t stdout_mutex; | |
33 | ||
34 | /* You must hold this mutex while calling any of the random number | |
35 | generation routines. */ | |
36 | pthread_mutex_t random_mutex; | |
37 | ||
38 | /* array of mutexes, one for each fork; fork_mutex[i] is to the left | |
39 | of philosopher i. A philosopher is holding fork i iff his/her | |
40 | thread has locked fork_mutex[i]. */ | |
41 | pthread_mutex_t *fork_mutex; | |
42 | ||
43 | /* array of threads, one representing each philosopher. */ | |
44 | pthread_t *philosophers; | |
45 | ||
46 | void * | |
47 | xmalloc (size_t n) | |
48 | { | |
49 | void *p = malloc (n); | |
50 | ||
51 | if (! p) | |
52 | { | |
53 | fprintf (stderr, "out of memory\n"); | |
54 | exit (2); | |
55 | } | |
56 | ||
57 | return p; | |
58 | } | |
59 | ||
60 | void | |
61 | shared_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 | ||
72 | int | |
73 | shared_random () | |
74 | { | |
917317f4 JM |
75 | int result; |
76 | ||
77 | pthread_mutex_lock (&random_mutex); | |
b111b805 | 78 | result = rand (); |
917317f4 JM |
79 | pthread_mutex_unlock (&random_mutex); |
80 | return result; | |
81 | } | |
82 | ||
83 | void | |
84 | my_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 | ||
94 | void | |
95 | random_delay () | |
96 | { | |
97 | my_usleep ((shared_random () % 2000) * 100); | |
98 | } | |
99 | ||
100 | void | |
101 | print_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 | ||
108 | void * | |
109 | philosopher (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 | } | |
04c3b3d4 MC |
156 | |
157 | return (void *) 0; | |
917317f4 JM |
158 | } |
159 | ||
160 | int | |
161 | main (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 | } |