void mcast_accept_msg(struct state_info info) { char diag[200]; GQueue *waiting_req_q = (*info.my_lift_number == LIFT_1) ? info.waiting_req_q1 : info.waiting_req_q2; int len = g_queue_get_length(waiting_req_q); // diag_msg(info.mstrtid, info.mytid, "*** 0"); int *tids = malloc(len * sizeof(int)); int i = 0; sprintf(diag, "*** %d processes awaiting accepts", g_queue_get_length(info.waiting_req_q)); diag_msg(info.mstrtid, info.mytid, diag); while (!g_queue_is_empty(waiting_req_q)) { int *tid = g_queue_pop_head(waiting_req_q); int *sender_weight_ptr = g_hash_table_lookup(info.skiers_weights, tid); int *lift_free = (*info.my_lift_number == LIFT_1) ? info.lift1_free : info.lift2_free; *lift_free -= *sender_weight_ptr; tids[i] = *tid; i++; sprintf(diag, "*** mcast MSG_ACCEPT to %d [weight=%d]", *tid, *sender_weight_ptr); diag_msg(info.mstrtid, info.mytid, diag); } *info.local_clock += 1; int tag = MSG_ACCEPT; pvm_initsend(PvmDataDefault); pvm_pkint(&tag, 1, 1); pvm_pkint(&info.mytid, 1, 1); pvm_pkint(info.local_clock, 1, 1); pvm_mcast(tids, len, tag); sprintf(diag, "mcast MSG_ACCEPT to %d waiting processes [timestamp=%d]", len, *info.local_clock); diag_msg(info.mstrtid, info.mytid, diag); }
void handle_request(struct msg incoming_msg, struct state_info info) { // handle Lamport clocks char diag[200]; update_lamport_recv(incoming_msg.timestamp, info.local_clock); int *my_weight_ptr = g_hash_table_lookup(info.skiers_weights, &info.mytid); int my_weight = *my_weight_ptr; int *sender_weight_ptr = g_hash_table_lookup(info.skiers_weights, &incoming_msg.sender_tid); int sender_weight = *sender_weight_ptr; if (info.phase != PHASE_WAIT_ACCEPTS) { // Always send ACCEPT, don't care about priorities in those phases send_accept_msg(incoming_msg.sender_tid, info); } else { // Send ACCEPT only if: // a) my priority is worse than the sender's priority, // b) or my priority is better but we both can fit // c) or I want the other lift if (*info.my_lift_number != incoming_msg.lift_number) { // I want the other lift send_accept_msg(incoming_msg.sender_tid, info); return; } // my priority is worse else if (*info.my_request_timestamp > incoming_msg.timestamp) { send_accept_msg(incoming_msg.sender_tid, info); return; } else if (*info.my_request_timestamp == incoming_msg.timestamp) { if (incoming_msg.timestamp % 2 == 0) { // admit the heavier skier if (my_weight > sender_weight) { send_accept_msg(incoming_msg.sender_tid, info); return; } } else { // admit the lighter skier if (my_weight <= sender_weight) { send_accept_msg(incoming_msg.sender_tid, info); return; } } } // my priority is better // ELSE if (my_weight + sender_weight <= *info.lift_free) { send_accept_msg(incoming_msg.sender_tid, info); } else { // add the sender to the queue of waiting requests for the lift int *tid = malloc(sizeof(int)); memcpy(tid, &incoming_msg.sender_tid, sizeof(int)); g_queue_push_tail(info.waiting_req_q, tid); int *pushed = g_queue_peek_tail(info.waiting_req_q); sprintf(diag, "*** pushed tid=%d", *pushed); diag_msg(info.mstrtid, info.mytid, diag); } } };
void handle_message(struct msg incoming_msg, struct state_info info) { char diag[200]; sprintf(diag,"receive %s from %d [phase=%s, timestamp=%d, lift_number=%s]", stringify(incoming_msg.tag), incoming_msg.sender_tid, stringify(info.phase), incoming_msg.timestamp, stringify(incoming_msg.tag == MSG_ACCEPT ? -1 : incoming_msg.lift_number)); diag_msg(info.mstrtid, info.mytid, diag); switch (incoming_msg.tag) { case MSG_REQUEST: handle_request(incoming_msg, info); break; case MSG_ACCEPT: handle_accept (incoming_msg, info); break; case MSG_RELEASE: handle_release(incoming_msg, info); break; } }
void handle_accept (struct msg incoming_msg, struct state_info info) { char diag[200]; update_lamport_recv(incoming_msg.timestamp, info.local_clock); int *my_weight_ptr = g_hash_table_lookup(info.skiers_weights, &info.mytid); int my_weight = *my_weight_ptr; int *sender_weight_ptr = g_hash_table_lookup(info.skiers_weights, &incoming_msg.sender_tid); int sender_weight = *sender_weight_ptr; // decrement the pending_accepts_sum by sender weight *info.pending_accepts_sum -= sender_weight; *info.accepts_received += 1; sprintf(diag, "*** my_lift_number=%s", stringify(*info.my_lift_number)); diag_msg(info.mstrtid, info.mytid, diag); int *lift_free = (*info.my_lift_number == LIFT_1 ? info.lift1_free : info.lift2_free); sprintf(diag, "free space on lift %d, pending accepts sum %d, accepts received %d, my weight %d", *lift_free, *info.pending_accepts_sum, *info.accepts_received, my_weight); diag_msg(info.mstrtid, info.mytid, diag); if (*lift_free - *info.pending_accepts_sum >= my_weight) { sprintf(diag, "can enter lift now"); *lift_free -= my_weight; *info.can_enter_lift = 1; } else if (g_hash_table_size(info.skiers_weights) - 1 == *info.accepts_received) { sprintf(diag, "n-1 accepts - can enter lift now"); *lift_free -= my_weight; *info.can_enter_lift = 1; } else { sprintf(diag, "not entering the lift yet"); *info.can_enter_lift = 0; } diag_msg(info.mstrtid, info.mytid, diag); };
void bcast_request_msg(struct state_info info) { int tag = MSG_REQUEST; *info.local_clock += 1; pvm_initsend(PvmDataDefault); pvm_pkint(&tag, 1, 1); pvm_pkint(&info.mytid, 1, 1); pvm_pkint(info.local_clock, 1, 1); pvm_pkint(info.my_lift_number, 1, 1); pvm_bcast(GROUP, MSG_REQUEST); *info.my_request_timestamp = *info.local_clock; char diag[200]; sprintf(diag, "bcast MSG_REQUEST [timestamp=%d, lift_number=%s]", *info.local_clock, stringify(*info.my_lift_number)); diag_msg(info.mstrtid, info.mytid, diag); }
void send_accept_msg(int dest_tid, struct state_info info) { int *sender_weight_ptr = g_hash_table_lookup(info.skiers_weights, &dest_tid); int old_free = *info.lift_free; *info.lift_free -= *sender_weight_ptr; *info.local_clock += 1; int tag = MSG_ACCEPT; pvm_initsend(PvmDataDefault); pvm_pkint(&tag, 1, 1); pvm_pkint(&info.mytid, 1, 1); pvm_pkint(info.local_clock, 1, 1); pvm_send(dest_tid, tag); char diag[200]; sprintf(diag, "sent MSG_ACCEPT to %d [timestamp=%d], was %d now %d", dest_tid, *info.local_clock, old_free, *info.lift_free); diag_msg(info.mstrtid, info.mytid, diag); }
void bcast_release_msg(struct state_info info) { int tag = MSG_RELEASE; *info.local_clock += 1; pvm_initsend(PvmDataDefault); pvm_pkint(&tag, 1, 1); pvm_pkint(&info.mytid, 1, 1); pvm_pkint(info.local_clock, 1, 1); pvm_pkint(info.my_lift_number, 1, 1); pvm_bcast(GROUP, MSG_RELEASE); // Unallocate space on the lift int *my_weight_ptr = g_hash_table_lookup(info.skiers_weights, &info.mytid); int my_weight = *my_weight_ptr; int *lift_free = (*info.my_lift_number == LIFT_1 ? info.lift1_free : info.lift2_free); *lift_free += my_weight; char diag[200]; sprintf(diag, "bcast MSG_RELEASE [timestamp=%d, lift_number=%s]", *info.local_clock, stringify(*info.my_lift_number)); diag_msg(info.mstrtid, info.mytid, diag); }
static void hash_table_resize(hash_table * hash_t) { hash_node **new_nodes; hash_node *node; hash_node *next; long hash_val; long new_size; long i; if ((hash_t->size >= 3 * hash_t->nnodes && hash_t->size > HASH_TABLE_MIN_SIZE) || (3 * hash_t->size <= hash_t->nnodes && hash_t->size < HASH_TABLE_MAX_SIZE)) { new_size = get_closest(hash_t->nnodes); new_nodes = (hash_node **) diag_malloc(sizeof(hash_node *) * new_size); if (new_nodes == NULL) { diag_msg("Unable to allocate memory\n"); return; } memset(new_nodes, 0, sizeof(hash_node *) * new_size); for (i = 0; i < hash_t->size; i++) for (node = hash_t->nodes[i]; node; node = next) { next = node->next; hash_val = (*hash_t->hash_func) (node->key, new_size); node->next = new_nodes[hash_val]; new_nodes[hash_val] = node; } diag_free(hash_t->nodes); hash_t->nodes = new_nodes; hash_t->size = new_size; } }
main() { GHashTable* skiers_weights = g_hash_table_new(g_str_hash, g_str_equal); GQueue *waiting_req_q1 = g_queue_new(); GQueue *waiting_req_q2 = g_queue_new(); int first_lift_free, second_lift_free; int mytid, mstrtid, myind, number_of_skiers, *tids, first_lift_capacity, second_lift_capacity, i, phase, local_clock; time_t t; char slave_name[NAMESIZE]; char diag[200]; struct state_info info; mytid = pvm_mytid(); srand(time(NULL) + mytid); gethostname(slave_name, NAMESIZE); pvm_joingroup(GROUP); get_initial_values(&mstrtid, &number_of_skiers, &tids, &skiers_weights, &first_lift_capacity, &second_lift_capacity); info.mstrtid = mstrtid; first_lift_free = first_lift_capacity; second_lift_free = second_lift_capacity; int *my_weight_ptr = g_hash_table_lookup(skiers_weights, &mytid); int my_weight = *my_weight_ptr; int all_skiers_weight = 0; for(i=0; i<number_of_skiers; i++) { int *lookup = g_hash_table_lookup(skiers_weights, &tids[i]); all_skiers_weight += *lookup; } all_skiers_weight -= my_weight; sprintf(diag, "sum of all other skiers' weights = %d", all_skiers_weight); diag_msg(mstrtid, mytid, diag); i=0; while (tids[i] != mytid) { i++; } pvm_initsend(PvmDataDefault); pvm_pkint(&mytid, 1, 1); pvm_pkstr(slave_name); int *wat_to_send = g_hash_table_lookup(skiers_weights, &mytid); pvm_pkint(wat_to_send, 1, 1); pvm_send(mstrtid, MSG_SLV); // bariera local_clock = 0; pvm_barrier(GROUP, number_of_skiers); int time_to_wait; // main loop diag_msg(mstrtid, mytid, "entering main loop"); while (1) { int can_enter_lift = 0; int chosen_lift = -1; int accepts_received = 0; int my_request_timestamp = -1; info.accepts_received = &accepts_received; info.my_request_timestamp = &my_request_timestamp; phase = PHASE_DOWNHILL; struct timeval timeout; random_timeout(&timeout, 3, 10); struct timeval start_time; gettimeofday(&start_time, NULL); struct timeval elapsed; elapsed.tv_sec = 0; elapsed.tv_usec = 0; sprintf(diag, "entered %s, time=%zu.%zu", stringify(phase), timeout.tv_sec, timeout.tv_usec); diag_msg(mstrtid, mytid, diag); while (1) { int bufid = pvm_trecv(-1, -1, &timeout); if (bufid) { // diag_msg(mstrtid, mytid, "Got message in PHASE_DOWNHILL"); struct msg incoming_msg; unpack(&incoming_msg); int *sender_weight = g_hash_table_lookup(skiers_weights, &incoming_msg.sender_tid); // handle the message accordingly prepare_info(&info, mytid, &local_clock, phase, &chosen_lift, &can_enter_lift, &first_lift_free, &second_lift_free, incoming_msg, waiting_req_q1, waiting_req_q2); info.skiers_weights = skiers_weights; handle_message(incoming_msg, info); } // break the loop if time elapsed is more than the timeout, else wait for another message struct timeval current_time; gettimeofday(¤t_time, NULL); timeval_subtract(&elapsed, ¤t_time, &start_time); if (elapsed.tv_sec * 1000000 + elapsed.tv_usec >= timeout.tv_sec * 1000000 + timeout.tv_usec) break; else timeval_subtract(&timeout, &timeout, &elapsed); } // want to go up diag_msg(mstrtid, mytid, ""); phase = PHASE_WAIT_REQUEST; // choose the lift (1 or 2) // determine if we can fit on the lift (based on our knowledge from the accepts we had sent) sprintf(diag, "entered PHASE_WAIT_REQUEST, weight=%d, LIFT_1=%d, LIFT_2=%d",my_weight,first_lift_free,second_lift_free); diag_msg(mstrtid, mytid, diag); if (my_weight > first_lift_free && my_weight > second_lift_free) { // no lift for us // wait for RELEASE messages until we can fit in the lift // meanwhile: handle all incoming messages, responding accordingly (ALWAYS respond with accepts) while (1) { sprintf(diag, "no space in lifts, weight=%d, LIFT_1=%d, LIFT_2=%d",my_weight,first_lift_free,second_lift_free); diag_msg(mstrtid, mytid, diag); int bufid = pvm_recv(-1, -1); struct msg incoming_msg; unpack(&incoming_msg); prepare_info(&info, mytid, &local_clock, phase, &chosen_lift, &can_enter_lift, &first_lift_free, &second_lift_free, incoming_msg, waiting_req_q1, waiting_req_q2); info.skiers_weights = skiers_weights; handle_message(incoming_msg, info); // now check if we should break the loop and go to the next phase! if (chosen_lift == LIFT_1 || chosen_lift == LIFT_2) { sprintf(diag, "weight=%d, LIFT_1=%d, LIFT_2=%d, choosing %s", my_weight, first_lift_free, second_lift_free, stringify(chosen_lift)); diag_msg(mstrtid, mytid, diag); // broadcast a request with our chosen lift and go to (*) bcast_request_msg(info); break; } } } else { // if there is a fitting lift if (my_weight <= first_lift_free && my_weight > second_lift_free) { // can only go to first lift chosen_lift = LIFT_1; } else if (my_weight > first_lift_free && my_weight <= second_lift_free) { // can only go to second lift chosen_lift = LIFT_2; } else { // can go to either lift - worst fit if (first_lift_free > second_lift_free) chosen_lift = LIFT_1; else if (first_lift_free < second_lift_free) chosen_lift = LIFT_2; else // equal chosen_lift = (rand() % 2 == 1) ? LIFT_1 : LIFT_2; } info.my_lift_number = &chosen_lift; info.mytid = mytid; info.local_clock = &local_clock; info.skiers_weights = skiers_weights; // broadcast a request with our chosen lift and go to (*) bcast_request_msg(info); // sprintf(diag,"So I am here just before broadcasting REQUEST and I choose lift %d and in info %d",chosen_lift, *info.my_lift_number); sprintf(diag, "weight=%d, LIFT_1=%d, LIFT_2=%d, choosing %s", my_weight, first_lift_free, second_lift_free, stringify(chosen_lift)); diag_msg(mstrtid, mytid, diag); } sprintf(diag, "*** chosen_lift=%s", stringify(chosen_lift)); // waiting for accepts (*) // wait for enough accepts or just as much as required to be sure that we can get in // meanwhile: handle all incoming messages, responding accordingly (not send back accept only to those with worse priority that can't fit together with us) // diag_msg(mstrtid, mytid, "entering PHASE_WAIT_ACCEPTS"); phase = PHASE_WAIT_ACCEPTS; int pending = all_skiers_weight; info.pending_accepts_sum = &pending; sprintf(diag, "entered PHASE_WAIT_ACCEPTS, lift=%s", stringify(chosen_lift)); diag_msg(mstrtid, mytid, diag); while (1) { int bufid = pvm_recv(-1, -1); struct msg incoming_msg; unpack(&incoming_msg); prepare_info(&info, mytid, &local_clock, phase, &chosen_lift, &can_enter_lift, &first_lift_free, &second_lift_free, incoming_msg, waiting_req_q1, waiting_req_q2); handle_message(incoming_msg, info); // check if there are enough amount of acceptes - can break the loop and go to the critical section if (can_enter_lift) { break; } } // random waiting up to the hill - critical section phase = PHASE_CRITICAL; random_timeout(&timeout, 3, 10); gettimeofday(&start_time, NULL); elapsed.tv_sec = 0; elapsed.tv_usec = 0; sprintf(diag, "entered PHASE_CRITICAL, lift=%s, time=%zu.%zu", stringify(chosen_lift), timeout.tv_sec, timeout.tv_usec); diag_msg(mstrtid, mytid, diag); while (1) { int bufid = pvm_trecv(-1, -1, &timeout); if (bufid) { // unpack the received message struct msg incoming_msg; // int msgtag = -1, sender_tid = -1, lift_number = -1, timestamp = -1; unpack(&incoming_msg); // handle the message accordingly prepare_info(&info, mytid, &local_clock, phase, &chosen_lift, &can_enter_lift, &first_lift_free, &second_lift_free, incoming_msg, waiting_req_q1, waiting_req_q2); handle_message(incoming_msg, info); } // break the loop if time elapsed is more than the timeout, else wait for another message struct timeval current_time; gettimeofday(¤t_time, NULL); timeval_subtract(&elapsed, ¤t_time, &start_time); if (elapsed.tv_sec * 1000000 + elapsed.tv_usec >= timeout.tv_sec * 1000000 + timeout.tv_usec) break; else timeval_subtract(&timeout, &timeout, &elapsed); } // release - broadcast the RELEASE message to all others info.mytid = mytid; info.local_clock = &local_clock; info.my_lift_number = &chosen_lift; bcast_release_msg(info); // send all the requests stored in the queue (mcast automatically clears it) mcast_accept_msg(info); } pvm_exit(); }