/* * CS560: Operating Systems * Jim Plank * dphil_b.c - Picking up a chopstick while your neighbor is dropping his/her chopstick * January, 2009 */ #include #include #include "cbthread.h" #include "dphil.h" #include "dllist.h" #define talloc(ty, sz) (ty *) malloc ((sz) * sizeof(ty)) #define BEGIN 0 #define WANTING_STICKS 1 #define GETTING_FIRST_STICK 2 #define GETTING_SECOND_STICK 3 #define GOT_BOTH_STICKS 4 #define DROPPING_FIRST_STICK 5 #define DROPPING_SECOND_STICK 6 #define FREE 0 #define ALLOCATED 1 #define USING 2 #define DROPPING 3 typedef struct { cbthread_gsem *sems; int *stick_states; int *my_pstates; double *hunger_time; } MyPhil; int test_philosopher(int pid, MyPhil *m, Simulation *s) { int before, after; if (m->my_pstates[pid] != WANTING_STICKS) return 0; after = (pid + 1) % s->nphil; if (m->my_pstates[after] == WANTING_STICKS && m->hunger_time[pid] - s->eatavg * 10 > m->hunger_time[after]) return 0; before = (pid + s->nphil - 1) % s->nphil; if (m->my_pstates[before] == WANTING_STICKS && m->hunger_time[pid] - s->eatavg * 10 > m->hunger_time[before]) return 0; if (m->stick_states[pid] == USING || m->stick_states[after] == USING) return 0; if (m->stick_states[pid] == ALLOCATED || m->stick_states[after] == ALLOCATED) return 0; if (m->stick_states[pid] == DROPPING && m->stick_states[after] == DROPPING) return 0; if (m->stick_states[pid] == DROPPING || m->stick_states[after] == DROPPING) return 1; return 2; } void i_am_hungry(Philosopher *p) { MyPhil *m; int s1, s2, first, second; m = (MyPhil *) p->s->v; s1 = p->id; s2 = (p->id + 1) % p->s->nphil; if (m->my_pstates[p->id] == BEGIN) { m->hunger_time[p->id] = cbthread_get_fake_time(); m->my_pstates[p->id] = WANTING_STICKS; } if (test_philosopher(p->id, m, p->s) != 0) { first = (m->stick_states[s1] == FREE) ? s1 : s2; second = (first == s1) ? s2 : s1; m->stick_states[first] = USING; if (m->stick_states[second] != DROPPING) m->stick_states[second] = ALLOCATED; m->my_pstates[p->id] = GETTING_FIRST_STICK; pick_up_stick(p, first, i_am_hungry); } else if (m->my_pstates[p->id] == WANTING_STICKS) { cbthread_gsem_P(m->sems[p->id], i_am_hungry, p); } else if (m->my_pstates[p->id] == GETTING_FIRST_STICK) { first = (m->stick_states[s1] == USING) ? s1 : s2; second = (first == s1) ? s2 : s1; if (m->stick_states[second] == DROPPING) { cbthread_yield(i_am_hungry, p); } m->stick_states[second] = USING; m->my_pstates[p->id] = GETTING_SECOND_STICK; pick_up_stick(p, second, i_am_hungry); } else { m->my_pstates[p->id] = GOT_BOTH_STICKS; p->state = GOTSTICKS; philosopher(p); cbthread_exit(); } } void i_am_sated(Philosopher *p) { MyPhil *m; int s1, s2; int before, after; m = (MyPhil *) p->s->v; s1 = p->id; s2 = (p->id+1)%p->s->nphil; before = (p->id + p->s->nphil - 1) % p->s->nphil; after = s2; if (m->my_pstates[p->id] == GOT_BOTH_STICKS) { m->my_pstates[p->id] = DROPPING_FIRST_STICK; m->stick_states[s1] = DROPPING; if (test_philosopher(before, m, p->s) != 0) cbthread_gsem_V(m->sems[before]); put_down_stick(p, s1, i_am_sated); } else if (m->my_pstates[p->id] == DROPPING_FIRST_STICK) { if (m->my_pstates[before] == GETTING_FIRST_STICK) { m->stick_states[s1] = ALLOCATED; } else { m->stick_states[s1] = FREE; } if (test_philosopher(before, m, p->s) == 1) cbthread_gsem_V(m->sems[before]); m->stick_states[s2] = DROPPING; if (test_philosopher(after, m, p->s) != 0) cbthread_gsem_V(m->sems[after]); m->my_pstates[p->id] = DROPPING_SECOND_STICK; put_down_stick(p, s2, i_am_sated); } else { if (m->my_pstates[after] == GETTING_FIRST_STICK) { m->stick_states[s2] = ALLOCATED; } else { m->stick_states[s2] = FREE; } if (test_philosopher(after, m, p->s) == 1) cbthread_gsem_V(m->sems[after]); m->my_pstates[p->id] = BEGIN; p->state = STARTING; philosopher(p); cbthread_exit(); } } void initialize_simulation(Simulation *s) { MyPhil *m; int i; m = talloc(MyPhil, 1); m->my_pstates = talloc(int, s->nphil); m->stick_states = talloc(int, s->nphil); m->sems = talloc(cbthread_gsem, s->nphil); m->hunger_time = talloc(double, s->nphil); for (i = 0; i < s->nphil; i++) { m->sems[i] = cbthread_make_gsem(0); m->my_pstates[i] = BEGIN; m->stick_states[i] = FREE; } s->v = (void *) m; return; }