/****************************************************************************** dine_p.c: Dining philosophers. Philosophers sit around a table to optimise their eating and thinking. - A philosopher eats until he is no longer hungry, and then thinks. - After a time of thinking, he becomes hungry again, and desires to eat. - A philosopher needs two forks to eat. - There are as many forks as philosophers; one fork between each two philosophers. - If a philosopher is eating, the philosophers on his left and right can not. Once philosophers acquire two forks, they spend a random time up to EAT_MAX eating. Once they are no longer hungry, they spend a random time up to THINK_MAX time thinking. Their goal is to spend the minimum time hungry. P F P F P F P F P F H00 \ E00 / T00 . T00 . T00 . ******************************************************************************/ #include #include #include #include "af.h" /* Active Framework */ #define NR_PHILOSOPHERS 5 /* philosophers and forks */ #define EQ_SIZE 4 /* one bigger than event queue size */ void print_states (void); /* display the states of everything */ /*---------------------------------------------------------------------------*/ /* Simulation object generates ticks. The sim is the lowest priority object - if sim runs, there's nothing else to do: call the timer tick and wait for next tick. */ #define END_SIM 100 /* Stop simulation after this many ticks */ static unsigned long Ticks = 0; /* How long simulation has been running */ static concurrent_t * Simulation = 0; /* object runs the simulation */ /* Something in the sim changed. print stuff out */ static unsigned State_change = 0; enum { E_STATE_CHANGE = E_APP }; state_fn sim_fn; /* The sim has only one state */ static state_defn_t Simulation_states [] = {{ FSM_STATE (sim_fn) }}; uint8 sim_fn (sm_t * psm, event_t e) { switch (e) { case E_ENTRY: /* Start of simulation */ cc_send_event (cc_of (psm), E_TIME); timer_tick (); break; case E_TIME: if (State_change) { print_states (); State_change = 0; } ++Ticks; cc_send_event (cc_of (psm), E_TIME); timer_tick (); break; case E_STATE_CHANGE: State_change = 1; break; } return (1); } /*---------------------------------------------------------------------------*/ /* Get a random timeout between 1 .. n */ #define rand_time(n) (random (n-1) + 1) /*---------------------------------------------------------------------------*/ /*** PHILOSOPHER STATE MACHINE ***/ /* Creating a state machine: 1) define the input events. Assign the first to E_APP 2) Declare the state handler functions - one per state. 3) Create and initialise a state table containing pointers to the handlers 4) Declare an enumeration for the states that maps on to the state table. 5) Declare any auxiliary variables that will be used by the state machine. The first (init) handler function should initialise them. 6) Define the handler functions - the entry event of the first state handler should perform initialisation */ unsigned acquire_forks (concurrent_t * pcc); /* Get forks before eating */ void release_forks (concurrent_t * pcc); /* Finished eating */ unsigned have_forks (concurrent_t * pcc); /* Do we have both forks ? */ enum /* Philosopher events */ { E_HUNGRY = E_APP, /* self - finished thinking */ E_SATED, /* self - done eating */ }; state_fn ps_thinking; state_fn ps_hungry; state_fn ps_eating; /* philosopher states */ enum { P_THINKING, P_HUNGRY, P_EATING }; static state_defn_t Philosopher_states [] = { { FSM_STATE (ps_thinking) }, { FSM_STATE (ps_hungry ) }, { FSM_STATE (ps_eating ) }, }; uint8 ps_thinking (sm_t * psm, event_t e) { switch (e) { case E_ENTRY: print_states (); cc_timer_start (cc_of (psm), rand_time(10)); break; case E_TIME : /* Timeout while thinking -> hungry */ if (acquire_forks (cc_of (psm))) { sm_goto (psm, P_EATING); } else { sm_goto (psm, P_HUNGRY); } break; } return (1); } /* What do philosophers do when they're hungry ? */ uint8 ps_hungry (sm_t * psm, event_t e) { switch (e) { case E_ENTRY: print_states (); break; case E_TIME : break; } return (1); } uint8 ps_eating (sm_t * psm, event_t e) { concurrent_t * pcc = cc_of (psm); /* concurrent obj from sm */ switch (e) { case E_ENTRY: /* eat for a time before thinking again... */ print_states (); assert (have_forks (pcc)); /* is Simulation well behaved ? */ cc_timer_start (pcc, rand_time(10)); break; case E_TIME : assert (have_forks (pcc)); /* is Simulation well behaved ? */ release_forks (pcc); sm_goto (psm, P_THINKING); break; } return (1); } /*---------------------------------------------------------------------------*/ /* fork_states */ enum { F_AVAILABLE, F_ALLOCATED_LEFT, F_ALLOCATED_RIGHT }; unsigned Forks [NR_PHILOSOPHERS] = { F_AVAILABLE, F_AVAILABLE, F_AVAILABLE, F_AVAILABLE, F_AVAILABLE, }; /*---------------------------------------------------------------------------*/ /* Philosophers */ concurrent_t Philosophers [NR_PHILOSOPHERS]; /* Index of pcc in Philosophers array */ #define ix (pcc - Philosophers) #define left(i) (i) #define right(i) ((i + 1) % NR_PHILOSOPHERS) /* Get forks before eating */ unsigned acquire_forks (concurrent_t * pcc) { Forks [left (ix)] = F_ALLOCATED_LEFT; Forks [right (ix)] = F_ALLOCATED_RIGHT; return (1); } /* Finished eating */ void release_forks (concurrent_t * pcc) { Forks [left (ix)] = F_AVAILABLE; Forks [right (ix)] = F_AVAILABLE; } /* Do we have both forks ? */ unsigned have_forks (concurrent_t * pcc) { return ( Forks [left (ix)] == F_ALLOCATED_LEFT && Forks [right (ix)] == F_ALLOCATED_RIGHT ); } /* Print out the philosopher and fork states */ void print_states (void) { unsigned i; printf ("%9lu ", Ticks); for (i=0; i END_SIM); } /*---------------------------------------------------------------------------*/ /* Print out the philosopher and fork states */ int main (void) { concurrent_t * all_objects = 0; /* list of concurrent objects */ concurrent_t * pcc; unsigned i; /* create clock and put on list */ Simulation = cc_new (16, Simulation_states); cc_add_front (&all_objects, Simulation); // printf ("left (0) = %u\n", left (0)); // printf ("right (0) = %u\n", right (0)); // printf ("left (1) = %u\n", left (1)); // printf ("right (1) = %u\n", right (1)); // printf ("left (2) = %u\n", left (2)); // printf ("right (2) = %u\n", right (2)); // printf ("left (3) = %u\n", left (3)); // printf ("right (3) = %u\n", right (3)); // printf ("left (4) = %u\n", left (4)); // printf ("right (4) = %u\n", right (4)); for (i=0; i