#include #include #include "cbthread.h" #include "stockroom.h" #include "jrb.h" #include "dllist.h" #define talloc(ty, sz) (ty *) malloc ((sz) * sizeof(ty)) typedef struct { int *shelves; int robot_next_item; int cust_counter; JRB *bay_items; Customer **customers; int *itemgen; double profit; int calling_item_stocked; } Private; void new_customer_at_bay(Customer *c) { Private *p; int i; int index; p = (Private *) c->s->private; p->customers[c->bay] = c; p->bay_items[c->bay] = make_jrb(); c->id = p->cust_counter; p->cust_counter++; c->nitems = lrand48()%c->s->max_items_per_cust + 1; c->items = talloc(int, c->nitems); for (i = 0; i < c->nitems; i++) { index = lrand48()%(c->nitems-i)+i; c->items[i] = p->itemgen[index]; p->itemgen[index] = p->itemgen[i]; p->itemgen[i] = c->items[i]; } if (c->s->verbose) { printf("%10.3lf: New customer %03d at bay %03d:", cbthread_get_fake_time(), c->id, c->bay); for (i = 0; i < c->nitems; i++) printf(" %d", c->items[i]); printf("\n"); fflush(stdout); } new_customer(c); cbthread_exit(); } void fork_new_customer(Customer *c) { double sleeptime; sleeptime = c->arrival_time - cbthread_get_fake_time(); if (sleeptime < 0) sleeptime = 0; cbthread_fake_sleep(sleeptime, new_customer_at_bay, c); } void create_new_customer(Simulation *s, int bay, double wait_time) { Customer *c; c = talloc(Customer, 1); c->s = s; c->bay = bay; c->arrival_time = cbthread_get_fake_time() + wait_time; cbthread_fork(fork_new_customer, c); } void customer_done(Customer *c) { Simulation *s; Private *p; int bay; double profit; int i; JRB tmp; s = c->s; p = (Private *) s->private; bay = c->bay; if (p->bay_items[bay] == NULL) { fprintf(stderr, "Customer_done called on an empty bay (Customer %d, Bay %d)\n", c->id, bay); exit(1); } for (i = 0; i < c->nitems; i++) { tmp = jrb_find_int(p->bay_items[bay], c->items[i]); if (tmp == NULL) { fprintf(stderr, "Customer_done called on customer %d and bay %d doesn't have item %d.\n", c->id, bay, c->items[i]); exit(1); } jrb_delete_node(tmp); } jrb_free_tree(p->bay_items[bay]); p->bay_items[bay] = NULL; profit = c->nitems * 2 - 1; if (s->verbose) { printf("%10.3lf: Customer %03d Bay %03d done. Profit = $%.0lf\n", cbthread_get_fake_time(), c->id, c->bay, profit); fflush(stdout); } p->profit += profit; free(c->items); free(c); create_new_customer(s, bay, s->cust_time); cbthread_exit(); } void robot_thread(Simulation *s) { Private *p; p = (Private *) s->private; if (p->shelves[p->robot_next_item] < s->max_items_on_shelves) { p->shelves[p->robot_next_item]++; if (s->verbose) { printf("%10.3lf: Robot stocking item %03d (%d on shelf)\n", cbthread_get_fake_time(), p->robot_next_item, p->shelves[p->robot_next_item]); fflush(stdout); } p->calling_item_stocked = 1; item_stocked(s, p->robot_next_item); p->calling_item_stocked = 0; } else { if (s->verbose) { printf("%10.3lf: Robot skipping item %03d\n", cbthread_get_fake_time(), p->robot_next_item); fflush(stdout); } } p->robot_next_item++; if (p->robot_next_item == s->nitems) p->robot_next_item = 0; cbthread_fake_sleep(s->robot_time, robot_thread, s); } void finish_thread(Simulation *s) { Private *p; p = (Private *) s->private; printf("Simulation Over. Profit = %10.2lf\n", p->profit); exit(0); } void move_item_to_bay(Simulation *s, int item, int bay) { Private *p; p = (Private *) s->private; if (s->verbose) { printf("%10.3lf: Moving item %03d to bay %03d\n", cbthread_get_fake_time(), item, bay); fflush(stdout); } if (p->calling_item_stocked) { fprintf(stderr, "Error: called move_item_to_bay() inside item_stocked().\n"); exit(1); } if (p->shelves[item] == 0) { fprintf(stderr, "Error -- no item %d on the shelves\n", item); exit(1); } p->shelves[item]--; if (p->bay_items[bay] == NULL) { fprintf(stderr, "Error -- no customer at bay %d\n", bay); exit(1); } jrb_insert_int(p->bay_items[bay], item, new_jval_i(0)); } void usage(char *s) { fprintf(stderr, "usage: stockroom nitems nbays max_items_on_shelves max_items_per_cust cust_time robot_time duration verbose seed\n"); if (s != NULL) fprintf(stderr, "%s\n", s); exit(1); } main(int argc, char **argv) { Simulation *s; Private *p; int i, j; int seed; s = talloc(Simulation, 1); if (argc != 10) usage(NULL); if (sscanf(argv[1], "%d", &s->nitems) == 0 || s->nitems <= 0) usage("Bad nitems"); if (sscanf(argv[2], "%d", &s->nbays) == 0 || s->nbays <= 0) usage("Bad nbays"); if (sscanf(argv[3], "%d", &s->max_items_on_shelves) == 0 || s->max_items_on_shelves <= 0) usage("Bad max_items_on_shelves"); if (sscanf(argv[4], "%d", &s->max_items_per_cust) == 0 || s->max_items_per_cust <= 0 || s->max_items_per_cust > s->nitems) usage("Bad max_items_per_cust"); if (sscanf(argv[5], "%lf", &s->cust_time) == 0 || s->cust_time < 0) usage("Bad cust_time"); if (sscanf(argv[6], "%lf", &s->robot_time) == 0 || s->robot_time <= 0) usage("Bad robot_time"); if (sscanf(argv[7], "%lf", &s->duration) == 0 || s->duration <= 0) usage("Bad duration"); s->verbose = (argv[8][0] == 'y' || argv[8][0] == 'Y'); if (sscanf(argv[9], "%d", &seed) == 0) usage("Bad seed"); srand48(seed); p = talloc(Private, 1); s->private = (void *) p; int cust_counter; JRB *bay_items; double profit; p->shelves = talloc(int, s->nitems); for (i = 0; i < s->nitems; i++) p->shelves[i] = 0; p->robot_next_item = 0; p->cust_counter = 0; p->calling_item_stocked = 0; p->bay_items = talloc(JRB, s->nbays); for (i = 0; i < s->nbays; i++) p->bay_items[i] = NULL; p->customers = talloc(Customer *, s->nbays); for (i = 0; i < s->nbays; i++) p->customers[i] = NULL; p->itemgen = talloc(int, s->nitems); for (i = 0; i < s->nitems; i++) p->itemgen[i] = i; p->profit = 0; initialize_simulation(s); cbthread_fork(robot_thread, s); for (i = 0; i < s->nbays; i++) { create_new_customer(s, i, drand48()*s->cust_time); } cbthread_fake_sleep(s->duration, finish_thread, s); }