|
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 |
|
|
25 // by Cygnus are Copyright (C) 1998 Cygnus Solutions. All Rights Reserved. |
|
|
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 |
|
|
46 #define PHILOSOPHERS 15 // number of philosophers |
|
|
47 #define STACKSIZE (2*1024) // size of thread stack |
|
|
48 |
|
|
49 // array of stacks for philosopher threads |
|
|
50 char thread_stack[PHILOSOPHERS][STACKSIZE]; |
|
|
51 |
|
|
52 // array of threads. We use the new operator defined |
|
|
53 // below to make these into real threads. |
|
|
54 char thread[PHILOSOPHERS][sizeof(Cyg_Thread)]; |
|
|
55 |
|
|
56 inline void *operator new(size_t size, void *ptr) { return ptr; }; |
|
|
57 |
|
|
58 // array of chopsticks |
|
|
59 Cyg_Binary_Semaphore chopstick[PHILOSOPHERS]; |
|
|
60 |
|
|
61 |
|
|
62 //cyg_thread_entry Philosopher; |
|
|
63 |
|
|
64 // ------------------------------------------------------------------------- |
|
|
65 // State recording and display |
|
|
66 |
|
|
67 static char pstate[PHILOSOPHERS+1]; // state vector showing what each |
|
|
68 // philosopher is doing |
|
|
69 |
|
|
70 Cyg_Mutex state_mutex; |
|
|
71 |
|
|
72 #ifdef CYG_HAL_MN10300_MN103002 |
|
|
73 static cyg_count8 eaters = 0; |
|
|
74 #endif |
|
|
75 |
|
|
76 void change_state(int id, char newstate) |
|
|
77 { |
|
|
78 CYG_INSTRUMENT_USER( 1, 0, 0); |
|
|
79 state_mutex.lock(); |
|
|
80 CYG_INSTRUMENT_USER( 2, 0, 0); |
|
|
81 |
|
|
82 #ifdef CYG_HAL_MN10300_MN103002 |
|
|
83 if( pstate[id] == 'E' ) eaters--; |
|
|
84 if( newstate == 'E' ) eaters++; |
|
|
85 // led(eaters); |
|
|
86 #endif |
|
|
87 |
|
|
88 pstate[id] = newstate; |
|
|
89 |
|
|
90 diag_write_string(pstate); |
|
|
91 #if 0 |
|
|
92 diag_write_char(' '); |
|
|
93 diag_write_dec(Cyg_Scheduler::get_thread_switches()); |
|
|
94 #endif |
|
|
95 diag_write_char('\n'); |
|
|
96 |
|
|
97 CYG_INSTRUMENT_USER( 3, 0, 0); |
|
|
98 state_mutex.unlock(); |
|
|
99 CYG_INSTRUMENT_USER( 4, 0, 0); |
|
|
100 |
|
|
101 } |
|
|
102 |
|
|
103 char get_state( int id) |
|
|
104 { |
|
|
105 state_mutex.lock(); |
|
|
106 |
|
|
107 char s = pstate[id]; |
|
|
108 |
|
|
109 state_mutex.unlock(); |
|
|
110 |
|
|
111 return s; |
|
|
112 } |
|
|
113 |
|
|
114 // ------------------------------------------------------------------------- |
|
|
115 // Thread to behave like a philosopher |
|
|
116 |
|
|
117 void Philosopher( CYG_ADDRESS id ) |
|
|
118 { |
|
|
119 Cyg_Thread *self = Cyg_Thread::self(); |
|
|
120 Cyg_Binary_Semaphore *first_stick = &chopstick[id]; |
|
|
121 Cyg_Binary_Semaphore *second_stick = &chopstick[(id+1)%PHILOSOPHERS]; |
|
|
122 #ifdef CYGPKG_INFRA_DEBUG |
|
|
123 int left_philo = ((id==0)?PHILOSOPHERS:id)-1; |
|
|
124 int right_philo = (id==PHILOSOPHERS-1)?0:(id+1); |
|
|
125 #endif |
|
|
126 |
|
|
127 CYG_ASSERT( id >= 0 && id < PHILOSOPHERS, "Bad id"); |
|
|
128 |
|
|
129 // Deadlock avoidance. The easiest way to make the philosophers |
|
|
130 // behave is to make each pick up the lowest numbered stick |
|
|
131 // first. This is how it works out anyway for all the philosophers |
|
|
132 // except the last, who must have his sticks swapped. |
|
|
133 |
|
|
134 if( id == PHILOSOPHERS-1 ) |
|
|
135 { |
|
|
136 Cyg_Binary_Semaphore *t = first_stick; |
|
|
137 first_stick = second_stick; |
|
|
138 second_stick = t; |
|
|
139 } |
|
|
140 |
|
|
141 // The following variable is shared by all philosophers. |
|
|
142 // It is incremented unprotected, but this does not matter |
|
|
143 // since it is only present to introduce a little variability |
|
|
144 // into the think and eat times. |
|
|
145 |
|
|
146 static int cycle = 0; |
|
|
147 |
|
|
148 for(;;) |
|
|
149 { |
|
|
150 // Think for a bit |
|
|
151 |
|
|
152 self->delay((id+cycle++)%12); // Cogito ergo sum... |
|
|
153 |
|
|
154 // I am now hungry, try to get the chopsticks |
|
|
155 |
|
|
156 change_state(id,'H'); |
|
|
157 |
|
|
158 // Get the first stick |
|
|
159 CYG_INSTRUMENT_USER( 5, 0, 0); |
|
|
160 first_stick->wait(); |
|
|
161 CYG_INSTRUMENT_USER( 6, 0, 0); |
|
|
162 |
|
|
163 // Get the second stick |
|
|
164 CYG_INSTRUMENT_USER( 7, 0, 0); |
|
|
165 second_stick->wait(); |
|
|
166 CYG_INSTRUMENT_USER( 8, 0, 0); |
|
|
167 |
|
|
168 // Got them, now eat |
|
|
169 |
|
|
170 change_state(id,'E'); |
|
|
171 |
|
|
172 // Check that the world is as I think it is... |
|
|
173 CYG_ASSERT( !first_stick->posted(), "Not got first stick"); |
|
|
174 CYG_ASSERT( !second_stick->posted(), "Not got second stick"); |
|
|
175 CYG_ASSERT( get_state(left_philo) != 'E', "Left neighbour also eating!!"); |
|
|
176 CYG_ASSERT( get_state(right_philo) != 'E', "Right neighbour also eating!!"); |
|
|
177 |
|
|
178 self->delay((id+cycle++)%6); // munch munch |
|
|
179 |
|
|
180 // Finished eating, put down sticks. |
|
|
181 |
|
|
182 change_state(id,'T'); |
|
|
183 |
|
|
184 CYG_INSTRUMENT_USER( 9, 0, 0); |
|
|
185 first_stick->post(); |
|
|
186 CYG_INSTRUMENT_USER( 10, 0, 0); |
|
|
187 second_stick->post(); |
|
|
188 CYG_INSTRUMENT_USER( 11, 0, 0); |
|
|
189 |
|
|
190 // Cyg_Scheduler::lock(); |
|
|
191 // Cyg_Scheduler::unlock(); |
|
|
192 CYG_INSTRUMENT_USER( 12, 0, 0); |
|
|
193 |
|
|
194 } |
|
|
195 } |
|
|
196 |
|
|
197 // ------------------------------------------------------------------------- |
|
|
198 |
|
|
199 externC void |
|
|
200 cyg_start( void ) |
|
|
201 { |
|
|
202 diag_init(); |
|
|
203 |
|
|
204 diag_write_string("Philosophers\n"); |
|
|
205 diag_write_string("Started\n"); |
|
|
206 |
|
|
207 // Zero last element in state so it acts like |
|
|
208 // a string. |
|
|
209 pstate[PHILOSOPHERS] = 0; |
|
|
210 |
|
|
211 #if 1 |
|
|
212 for( int i = 0; i < PHILOSOPHERS; i++ ) |
|
|
213 { |
|
|
214 change_state(i,'T'); // starting state |
|
|
215 |
|
|
216 // Start the philosopher |
|
|
217 Cyg_Thread *t = new((void *)&thread[i]) Cyg_Thread(Philosopher, |
|
|
218 i, |
|
|
219 STACKSIZE, |
|
|
220 CYG_ADDRESS(&thread_stack[i]) |
|
|
221 ); |
|
|
222 |
|
|
223 // resume it |
|
|
224 t->resume(); |
|
|
225 |
|
|
226 // and make the matching chopstick present |
|
|
227 chopstick[i].post(); |
|
|
228 } |
|
|
229 #endif |
|
|
230 |
|
|
231 // Get the world going |
|
|
232 Cyg_Scheduler::scheduler.start(); |
|
|
233 |
|
|
234 } |
|
|
235 |
|
|
236 // ------------------------------------------------------------------------- |
|
|
237 // EOF philo.cxx |