//--------------------------------------RETRYING STUFF------------------------- //repeatedly called by the main loop (once after each loop) //this function will send a message on any channel that has an expired timestamp and stuff //waiting to be sent //effects: decrements timestamps on channels with messages waiting to be sent //modifies: channelQueuesArray void randomBackoffRetry() { uint8_t channel, qNumber; for (channel = 1; channel <= MAX_CHANNELS; channel++) { disableRTC2(); //needs to be disabled before reading or writing the channelSendWaitTime variable qNumber = channel - 1; /*putnum_uh(channel); putstring(" "); putnum_uh(channelQueuesArray[qNumber].channelRetryLevel); putstring(" "); putnum_uh(channelQueuesArray[qNumber].channelSendWaitTime); putstring(" "); putnum_uh(channelQueuesArray[qNumber].numMessagesOnQueue); putstring("\n"); */ //check if a channel has messages queued up; if it does, then see if that timestamp has expired //expired or not, subtract from the time stamp if ((channelQueuesArray[qNumber].numMessagesOnQueue > 0) && (channelQueuesArray[qNumber].channelRetryLevel < MAX_RANDOM_BACKOFF_RETRIES) && (channelQueuesArray[qNumber].channelSendWaitTime == 0)) { //---retry sending if (rbSendMessageHelper(channel, channelQueuesArray[qNumber].packetList[0].message, channelQueuesArray[qNumber].packetList[0].messageLength) == TRUE) { //putstring("\nSuccesfully sent a message (FROM a queue) on channel, retry level, num messages: "); putnum_uh(channel); putstring(" "); //putnum_uh(channelQueuesArray[qNumber].channelRetryLevel); putstring(" "); putnum_uh(channelQueuesArray[qNumber].numMessagesOnQueue); //putstring("CHANNEL IS NOW GOOD: queue, channel "); putnum_uh(qNumber); putstring(" "); putnum_uh(channel); removeFirstMessageFromQueue(qNumber); //sent this message, so take it off the queue refreshChannel(channel); //NOTE: we are setting the time stamp to 0 //channel works, so don't need a high retry level now //since the channel became good, and we want to send all the stuff w/o delay (actually we'll delay 1 main loop) } else { //channel is still bad, don't remove the message from the queue. //increase the time stamp //putstring("CHANNEL IS STILL BAD: queue, channel"); putnum_uh(qNumber); putstring(" "); putnum_uh(channel); /*if (channel == 1) { putstring("\n failed retry on ch 1: level = "); putnum_ud(channelQueuesArray[qNumber].channelRetryLevel); }*/ disableRTC2(); channelQueuesArray[qNumber].channelSendWaitTime = getRandomWaitTime(channelQueuesArray[qNumber].channelRetryLevel); channelQueuesArray[qNumber].channelRetryLevel++; //up the rety time //putstring("\nNEW WAIT TIME = "); putnum_uh(channelQueuesArray[qNumber].channelSendWaitTime); putstring("\n"); //clear the queue if it times out, so we don't keep old messages lying around if (channelQueuesArray[qNumber].channelRetryLevel == MAX_RANDOM_BACKOFF_RETRIES) { channelQueuesArray[qNumber].numMessagesOnQueue = 0; } } } } enableRTC2(); }
/**Sends the message to sendList. If sending fails on one of the channels, the message will be queued up and an attempt to resend will be made later (randomBackoff style). * @param sendList the list of channels to send the message to * @param message the message to be sent * @param messageLength the length of the message @modifies channelQueuesArray @effects adds the message to channels in channelQueuesArray if that channel has something queued up or if that channel has exceeded the max number of retries **/ void rbmSend(uint8_t sendList, uint8_t message[], uint8_t messageLength) { //send one channel at a time uint8_t send_mask = 0x01; uint8_t channel; for (channel=1; channel<=MAX_CHANNELS; channel++) { uint8_t qNumber = channel - 1; if (!(sendList & send_mask)) { send_mask <<= 1; // try sending to the next channel continue; //channel is not in the send list } send_mask <<= 1; //for the next time around //---don't bother sending the message if the channel to send on has something queued up if (channelQueuesArray[qNumber].channelRetryLevel > MAX_RANDOM_BACKOFF_RETRIES) { //we've already tried too many times to send a message on this channel //putstring("\nNOT SENDING MESSAGE. Exceeded Max Number of tries on channel: "); putnum_uh(channel); putstring(" "); putnum_uh(channel); continue; //channel is no good, so don't waste time sending on it } else if (channelQueuesArray[qNumber].numMessagesOnQueue > 0) { //something is queued up and we're currently waiting a random amount of time before sending anything //putstring("\nSTUFF ON QUEUE. ADDING MESSAGE TO CHANNEL, retry level, num messages: "); putnum_uh(channel); putstring(" "); //putnum_uh(channelQueuesArray[qNumber].channelRetryLevel); putstring(" "); putnum_uh(channelQueuesArray[qNumber].numMessagesOnQueue); putMessageOnQueue(qNumber, message, messageLength); //add the message to the queue continue; } //------------------------------try and send the message. if sending fails, put it on the queue if (rbSendMessageHelper(channel, message, messageLength) == TRUE) { //putstring("\nSuccesfully sent a message (not from a queue) on channel, retry level, num messages: "); putnum_uh(channel); putstring(" "); //putnum_uh(channelQueuesArray[qNumber].channelRetryLevel); putstring(" "); putnum_uh(channelQueuesArray[qNumber].numMessagesOnQueue); refreshChannel(channel); continue; } //----sending failed! put the message on the queue //didn't succeed, so put the message on the queue and add a time stamp //putstring("\nFAILED SENDING: ADDING MESSAGE TO channel, retry level, num messages: "); putnum_uh(channel); putstring(" "); //putnum_uh(channelQueuesArray[qNumber].channelRetryLevel); putstring(" "); putnum_uh(channelQueuesArray[qNumber].numMessagesOnQueue); putMessageOnQueue(qNumber, message, messageLength); disableRTC2(); //the interrupt modifies the channelSendWaitTime variable, so we need to make sure the interrupt doesn't occur during a read or write channelQueuesArray[qNumber].channelSendWaitTime = getRandomWaitTime(channelQueuesArray[qNumber].channelRetryLevel++); //putstring("\nNEW WAIT TIME = "); putnum_uh(channelQueuesArray[qNumber].channelSendWaitTime); putstring("\n"); enableRTC2(); } }
void* taFn(void* arg) { while (1) { int* studentId; TA_PRINT("I am sleeping, wake me up when you need me!"); sig_wait_for_signal(&wakeupSignal); // we dequeue the student immediately, as he is not on a chair, // and we do not want to take the place of someone else. studentId = queue_dequeue(&chairsQueue); TA_PRINT("I am awake now :("); do { student* s = &students[*studentId - 1]; // just in case the semaphore was not set yet, so we try to wait // until it's been set. while (!s->waitSem); // notify the student that their turn is now. sem_post(s->waitSem); // wait for the help time. int waitTime = getRandomWaitTime(); TA_PRINT("Helping student #%d for %d seconds.", *studentId, waitTime); sleep(waitTime); // notify the student that we're done helping them. sem_post(&taHelping); // tiny wait to allow the student to print out debugging // statements before the next student does. usleep(1000); } while ((studentId = queue_dequeue(&chairsQueue)) != NULL); } return NULL; }