|
0
|
1 //========================================================================== |
|
|
2 // |
|
|
3 // philo.cxx |
|
|
4 // |
|
|
5 // A test of the dining philosophers problem |
|
|
6 // |
|
|
7 //========================================================================== |
|
|
8 //####COPYRIGHTBEGIN#### |
|
|
9 // |
|
|
10 // ------------------------------------------- |
|
|
11 // The contents of this file are subject to the Cygnus eCos Public License |
|
|
12 // Version 1.0 (the "License"); you may not use this file except in |
|
|
13 // compliance with the License. You may obtain a copy of the License at |
|
|
14 // http://sourceware.cygnus.com/ecos |
|
|
15 // |
|
|
16 // Software distributed under the License is distributed on an "AS IS" |
|
|
17 // basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the |
|
|
18 // License for the specific language governing rights and limitations under |
|
|
19 // the License. |
|
|
20 // |
|
|
21 // The Original Code is eCos - Embedded Cygnus Operating System, released |
|
|
22 // September 30, 1998. |
|
|
23 // |
|
|
24 // The Initial Developer of the Original Code is Cygnus. Portions created |
|
2
|
25 // by Cygnus are Copyright (C) 1998,1999 Cygnus Solutions. All Rights Reserved. |
|
0
|
26 // ------------------------------------------- |
|
|
27 // |
|
|
28 //####COPYRIGHTEND#### |
|
|
29 //========================================================================== |
|
|
30 //#####DESCRIPTIONBEGIN#### |
|
|
31 // |
|
|
32 // Author(s): dsm |
|
|
33 // Contributors: dsm |
|
|
34 // Date: 1998-02-24 |
|
|
35 // Description: A test of the dining philosophers problem |
|
|
36 //####DESCRIPTIONEND#### |
|
|
37 // |
|
|
38 |
|
|
39 #include <cyg/kernel/kernel.hxx> |
|
|
40 |
|
|
41 #include <cyg/hal/hal_io.h> |
|
|
42 |
|
|
43 // ------------------------------------------------------------------------- |
|
|
44 // Data for the philosophers problem |
|
|
45 |
|
2
|
46 #define PHILOSOPHERS 15 // number of philosophers |
|
0
|
47 #define STACKSIZE (2*1024) // size of thread stack |
|
|
48 |
|
2
|
49 #define NTHREADS PHILOSOPHERS |
|
|
50 #include "testaux.hxx" |
|
0
|
51 |
|
|
52 // array of chopsticks |
|
|
53 Cyg_Binary_Semaphore chopstick[PHILOSOPHERS]; |
|
|
54 |
|
|
55 |
|
|
56 //cyg_thread_entry Philosopher; |
|
|
57 |
|
|
58 // ------------------------------------------------------------------------- |
|
|
59 // State recording and display |
|
|
60 |
|
|
61 static char pstate[PHILOSOPHERS+1]; // state vector showing what each |
|
|
62 // philosopher is doing |
|
|
63 |
|
|
64 Cyg_Mutex state_mutex; |
|
|
65 |
|
|
66 #ifdef CYG_HAL_MN10300_MN103002 |
|
|
67 static cyg_count8 eaters = 0; |
|
|
68 #endif |
|
|
69 |
|
|
70 void change_state(int id, char newstate) |
|
|
71 { |
|
|
72 CYG_INSTRUMENT_USER( 1, 0, 0); |
|
|
73 state_mutex.lock(); |
|
|
74 CYG_INSTRUMENT_USER( 2, 0, 0); |
|
|
75 |
|
|
76 #ifdef CYG_HAL_MN10300_MN103002 |
|
|
77 if( pstate[id] == 'E' ) eaters--; |
|
|
78 if( newstate == 'E' ) eaters++; |
|
|
79 // led(eaters); |
|
|
80 #endif |
|
|
81 |
|
|
82 pstate[id] = newstate; |
|
|
83 |
|
|
84 diag_write_string(pstate); |
|
|
85 #if 0 |
|
|
86 diag_write_char(' '); |
|
|
87 diag_write_dec(Cyg_Scheduler::get_thread_switches()); |
|
|
88 #endif |
|
|
89 diag_write_char('\n'); |
|
|
90 |
|
|
91 CYG_INSTRUMENT_USER( 3, 0, 0); |
|
|
92 state_mutex.unlock(); |
|
|
93 CYG_INSTRUMENT_USER( 4, 0, 0); |
|
|
94 |
|
|
95 } |
|
|
96 |
|
|
97 char get_state( int id) |
|
|
98 { |
|
|
99 state_mutex.lock(); |
|
|
100 |
|
|
101 char s = pstate[id]; |
|
|
102 |
|
|
103 state_mutex.unlock(); |
|
|
104 |
|
|
105 return s; |
|
|
106 } |
|
|
107 |
|
|
108 // ------------------------------------------------------------------------- |
|
|
109 // Thread to behave like a philosopher |
|
|
110 |
|
|
111 void Philosopher( CYG_ADDRESS id ) |
|
|
112 { |
|
|
113 Cyg_Thread *self = Cyg_Thread::self(); |
|
|
114 Cyg_Binary_Semaphore *first_stick = &chopstick[id]; |
|
|
115 Cyg_Binary_Semaphore *second_stick = &chopstick[(id+1)%PHILOSOPHERS]; |
|
|
116 #ifdef CYGPKG_INFRA_DEBUG |
|
|
117 int left_philo = ((id==0)?PHILOSOPHERS:id)-1; |
|
|
118 int right_philo = (id==PHILOSOPHERS-1)?0:(id+1); |
|
|
119 #endif |
|
|
120 |
|
|
121 CYG_ASSERT( id >= 0 && id < PHILOSOPHERS, "Bad id"); |
|
|
122 |
|
|
123 // Deadlock avoidance. The easiest way to make the philosophers |
|
|
124 // behave is to make each pick up the lowest numbered stick |
|
|
125 // first. This is how it works out anyway for all the philosophers |
|
|
126 // except the last, who must have his sticks swapped. |
|
|
127 |
|
|
128 if( id == PHILOSOPHERS-1 ) |
|
|
129 { |
|
|
130 Cyg_Binary_Semaphore *t = first_stick; |
|
|
131 first_stick = second_stick; |
|
|
132 second_stick = t; |
|
|
133 } |
|
|
134 |
|
|
135 // The following variable is shared by all philosophers. |
|
|
136 // It is incremented unprotected, but this does not matter |
|
|
137 // since it is only present to introduce a little variability |
|
|
138 // into the think and eat times. |
|
|
139 |
|
|
140 static int cycle = 0; |
|
|
141 |
|
|
142 for(;;) |
|
|
143 { |
|
|
144 // Think for a bit |
|
|
145 |
|
|
146 self->delay((id+cycle++)%12); // Cogito ergo sum... |
|
|
147 |
|
|
148 // I am now hungry, try to get the chopsticks |
|
|
149 |
|
|
150 change_state(id,'H'); |
|
|
151 |
|
|
152 // Get the first stick |
|
|
153 CYG_INSTRUMENT_USER( 5, 0, 0); |
|
|
154 first_stick->wait(); |
|
|
155 CYG_INSTRUMENT_USER( 6, 0, 0); |
|
|
156 |
|
|
157 // Get the second stick |
|
|
158 CYG_INSTRUMENT_USER( 7, 0, 0); |
|
|
159 second_stick->wait(); |
|
|
160 CYG_INSTRUMENT_USER( 8, 0, 0); |
|
|
161 |
|
|
162 // Got them, now eat |
|
|
163 |
|
|
164 change_state(id,'E'); |
|
|
165 |
|
|
166 // Check that the world is as I think it is... |
|
|
167 CYG_ASSERT( !first_stick->posted(), "Not got first stick"); |
|
|
168 CYG_ASSERT( !second_stick->posted(), "Not got second stick"); |
|
|
169 CYG_ASSERT( get_state(left_philo) != 'E', "Left neighbour also eating!!"); |
|
|
170 CYG_ASSERT( get_state(right_philo) != 'E', "Right neighbour also eating!!"); |
|
|
171 |
|
|
172 self->delay((id+cycle++)%6); // munch munch |
|
|
173 |
|
|
174 // Finished eating, put down sticks. |
|
|
175 |
|
|
176 change_state(id,'T'); |
|
|
177 |
|
|
178 CYG_INSTRUMENT_USER( 9, 0, 0); |
|
|
179 first_stick->post(); |
|
|
180 CYG_INSTRUMENT_USER( 10, 0, 0); |
|
|
181 second_stick->post(); |
|
|
182 CYG_INSTRUMENT_USER( 11, 0, 0); |
|
|
183 |
|
|
184 // Cyg_Scheduler::lock(); |
|
|
185 // Cyg_Scheduler::unlock(); |
|
|
186 CYG_INSTRUMENT_USER( 12, 0, 0); |
|
|
187 |
|
|
188 } |
|
|
189 } |
|
|
190 |
|
|
191 // ------------------------------------------------------------------------- |
|
|
192 |
|
|
193 externC void |
|
|
194 cyg_start( void ) |
|
|
195 { |
|
|
196 diag_init(); |
|
|
197 |
|
|
198 diag_write_string("Philosophers\n"); |
|
|
199 diag_write_string("Started\n"); |
|
|
200 |
|
|
201 // Zero last element in state so it acts like |
|
|
202 // a string. |
|
|
203 pstate[PHILOSOPHERS] = 0; |
|
|
204 |
|
|
205 #if 1 |
|
|
206 for( int i = 0; i < PHILOSOPHERS; i++ ) |
|
|
207 { |
|
|
208 change_state(i,'T'); // starting state |
|
|
209 |
|
|
210 // Start the philosopher |
|
2
|
211 Cyg_Thread *t = new_thread( Philosopher, i ); |
|
0
|
212 |
|
|
213 // resume it |
|
|
214 t->resume(); |
|
|
215 |
|
|
216 // and make the matching chopstick present |
|
|
217 chopstick[i].post(); |
|
|
218 } |
|
|
219 #endif |
|
|
220 |
|
|
221 // Get the world going |
|
|
222 Cyg_Scheduler::scheduler.start(); |
|
|
223 |
|
|
224 } |
|
|
225 |
|
|
226 // ------------------------------------------------------------------------- |
|
|
227 // EOF philo.cxx |