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> | |
14 | ||
15 | /* The number of philosophers at the table. */ | |
16 | int 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. */ | |
31 | pthread_mutex_t stdout_mutex; | |
32 | ||
33 | /* You must hold this mutex while calling any of the random number | |
34 | generation routines. */ | |
35 | pthread_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]. */ | |
40 | pthread_mutex_t *fork_mutex; | |
41 | ||
42 | /* array of threads, one representing each philosopher. */ | |
43 | pthread_t *philosophers; | |
44 | ||
45 | void * | |
46 | xmalloc (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 | ||
59 | void | |
60 | shared_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 | ||
71 | int | |
72 | shared_random () | |
73 | { | |
917317f4 JM |
74 | int result; |
75 | ||
76 | pthread_mutex_lock (&random_mutex); | |
b111b805 | 77 | result = rand (); |
917317f4 JM |
78 | pthread_mutex_unlock (&random_mutex); |
79 | return result; | |
80 | } | |
81 | ||
82 | void | |
83 | my_usleep (long usecs) | |
84 | { | |
85 | struct timeval timeout; | |
86 | ||
87 | timeout.tv_sec = usecs / 1000000; | |
88 | timeout.tv_usec = usecs % 1000000; | |
89 | ||
90 | select (0, 0, 0, 0, &timeout); | |
91 | } | |
92 | ||
93 | void | |
94 | random_delay () | |
95 | { | |
96 | my_usleep ((shared_random () % 2000) * 100); | |
97 | } | |
98 | ||
99 | void | |
100 | print_philosopher (int n, char left, char right) | |
101 | { | |
102 | int i; | |
103 | ||
104 | shared_printf ("%*s%c %d %c\n", (n * 4) + 2, "", left, n, right); | |
105 | } | |
106 | ||
107 | void * | |
108 | philosopher (void *data) | |
109 | { | |
110 | int n = * (int *) data; | |
111 | ||
112 | print_philosopher (n, '_', '_'); | |
113 | ||
114 | #if 1 | |
115 | if (n == num_philosophers - 1) | |
116 | for (;;) | |
117 | { | |
118 | /* The last philosopher is different. He goes for his right | |
119 | fork first, so there is no cycle in the mutex graph. */ | |
120 | ||
121 | /* Grab the right fork. */ | |
122 | pthread_mutex_lock (&fork_mutex[(n + 1) % num_philosophers]); | |
123 | print_philosopher (n, '_', '!'); | |
124 | random_delay (); | |
125 | ||
126 | /* Then grab the left fork. */ | |
127 | pthread_mutex_lock (&fork_mutex[n]); | |
128 | print_philosopher (n, '!', '!'); | |
129 | random_delay (); | |
130 | ||
131 | print_philosopher (n, '_', '_'); | |
132 | pthread_mutex_unlock (&fork_mutex[n]); | |
133 | pthread_mutex_unlock (&fork_mutex[(n + 1) % num_philosophers]); | |
134 | random_delay (); | |
135 | } | |
136 | else | |
137 | #endif | |
138 | for (;;) | |
139 | { | |
140 | /* Grab the left fork. */ | |
141 | pthread_mutex_lock (&fork_mutex[n]); | |
142 | print_philosopher (n, '!', '_'); | |
143 | random_delay (); | |
144 | ||
145 | /* Then grab the right fork. */ | |
146 | pthread_mutex_lock (&fork_mutex[(n + 1) % num_philosophers]); | |
147 | print_philosopher (n, '!', '!'); | |
148 | random_delay (); | |
149 | ||
150 | print_philosopher (n, '_', '_'); | |
151 | pthread_mutex_unlock (&fork_mutex[n]); | |
152 | pthread_mutex_unlock (&fork_mutex[(n + 1) % num_philosophers]); | |
153 | random_delay (); | |
154 | } | |
04c3b3d4 MC |
155 | |
156 | return (void *) 0; | |
917317f4 JM |
157 | } |
158 | ||
159 | int | |
160 | main (int argc, char **argv) | |
161 | { | |
162 | num_philosophers = 5; | |
163 | ||
164 | /* Set up the mutexes. */ | |
165 | { | |
166 | pthread_mutexattr_t ma; | |
167 | int i; | |
168 | ||
169 | pthread_mutexattr_init (&ma); | |
170 | pthread_mutex_init (&stdout_mutex, &ma); | |
171 | pthread_mutex_init (&random_mutex, &ma); | |
172 | fork_mutex = xmalloc (num_philosophers * sizeof (fork_mutex[0])); | |
173 | for (i = 0; i < num_philosophers; i++) | |
174 | pthread_mutex_init (&fork_mutex[i], &ma); | |
175 | pthread_mutexattr_destroy (&ma); | |
176 | } | |
177 | ||
178 | /* Set off the threads. */ | |
179 | { | |
180 | int i; | |
181 | int *numbers = xmalloc (num_philosophers * sizeof (*numbers)); | |
182 | pthread_attr_t ta; | |
183 | ||
184 | philosophers = xmalloc (num_philosophers * sizeof (*philosophers)); | |
185 | ||
186 | pthread_attr_init (&ta); | |
187 | ||
188 | for (i = 0; i < num_philosophers; i++) | |
189 | { | |
190 | numbers[i] = i; | |
191 | /* linuxthreads.exp: create philosopher */ | |
192 | pthread_create (&philosophers[i], &ta, philosopher, &numbers[i]); | |
193 | } | |
194 | ||
195 | pthread_attr_destroy (&ta); | |
196 | } | |
197 | ||
198 | /* linuxthreads.exp: info threads 2 */ | |
199 | sleep (1000000); | |
200 | ||
201 | /* Drink yourself into oblivion. */ | |
202 | for (;;) | |
203 | sleep (1000000); | |
204 | ||
205 | return 0; | |
206 | } |