void offlineInit() { #ifdef INSERTION_TEST gettimeofday(&offlineInitDate, NULL); #endif /* INSERTION_TEST */ participate(true); succ = searchSucc(myAddress); if (addrIsMine(succ)) { signalArrival(myAddress, (addressSet) myAddress); bqueueEnqueue(wagonsToDeliver, wagonToSend); wagonToSend = newWiw(); automatonState = ALONE_INSERT_WAIT; //printf("Nextstate(fake) = %s\n", stateToStr(automatonState)); int rc = sem_post(sem_init_done); if (rc) ERROR_AT_LINE(EXIT_FAILURE, errno, __FILE__, __LINE__, "error in sem_post"); prec = myAddress; return; } sendOther(succ, false, INSERT, myAddress); automatonState = OFFLINE_CONNECTION_ATTEMPT; //printf("Nextstate(fake) = %s\n", stateToStr(automatonState)); return; }
void automatonInit() { int id; int round; srand(getpid() + time(NULL )); pthread_mutex_init(&stateMachineMutex, NULL ); lis = ntr - 1; for (id = 0; id < ntr; id++) { //(lts[id]).lng is not initialized because lng is only set in sendTrain() (lts[id]).type = TRAIN; (lts[id]).stamp.id = id; (lts[id]).stamp.lc = 0; (lts[id]).stamp.round = 0; (lts[id]).circuit = 0; (lts[id]).w.w_w.p_wagon = NULL; (lts[id]).w.w_w.p_womim = NULL; (lts[id]).w.len = 0; (lts[id]).p_wtosend = NULL; for (round = 0; round < NR; round++) { unstableWagons[id][round] = newList(); } } cameProc = 0; goneProc = 0; wagonToSend = newWiw(); wagonsToDeliver = newBqueue(); prec = 0; succ = 0; MUTEX_LOCK(stateMachineMutex); nextState(OFFLINE_CONNECTION_ATTEMPT); MUTEX_UNLOCK(stateMachineMutex); }
int main(int argc, char *argv[]){ int i, j; int rc; int msgCounter; int wagonSizes[] = { 1024, 2048, 4096, 8192, 16384, 32768, 65536 }; int payloadSizes[] = { 10, 100, 200, 500, 1000, 2000, 5000, 10000, 15000, 20000 }; struct timeval debut, fin, duree; struct rusage debutCPU, finCPU, dureeCPU; long elapsedTime, cpuTime; MUTEX_LOCK(stateMachineMutex); automatonState = SEVERAL; MUTEX_UNLOCK(stateMachineMutex); printf("Début de l'experience\n"); for (i = 0; i < 7; i++) { for (j = 0; j < 10; j++) { // initialisation du wagon wagonMaxLen = wagonSizes[i]; wagonToSend = newWiw(); msgCounter = 0; // start timers printf("Début du remplissage...\n"); getrusage(RUSAGE_SELF, &debutCPU); gettimeofday(&debut, NULL ); // remplissage du wagon while (wagonToSend->p_wagon->header.len + payloadSizes[j] + sizeof(messageHeader) < wagonMaxLen) { message *mp = newmsg(payloadSizes[j]); if (mp == NULL ) { trError_at_line(rc, trErrno, __FILE__, __LINE__, "newmsg()"); exit(EXIT_FAILURE); } if (utoBroadcast(mp) < 0) { trError_at_line(rc, trErrno, __FILE__, __LINE__, "utoBroadcast()"); exit(EXIT_FAILURE); } msgCounter++; } // stop timers gettimeofday(&fin, NULL ); getrusage(RUSAGE_SELF, &finCPU); printf("Remplissage terminé\n"); // calculs timersub(&(finCPU.ru_utime), &(debutCPU.ru_utime), &(dureeCPU.ru_utime)); timersub(&(finCPU.ru_stime), &(debutCPU.ru_stime), &(dureeCPU.ru_stime)); timersub(&fin, &debut, &duree); elapsedTime = (1000000 * duree.tv_sec + duree.tv_usec); cpuTime = ((1000000 * (dureeCPU.ru_utime.tv_sec + dureeCPU.ru_stime.tv_sec)) + dureeCPU.ru_utime.tv_usec + dureeCPU.ru_stime.tv_usec); printf("********************************\n" "*********************************\n" "Messages de %d octets dans un wagon de %d octets\n", payloadSizes[j], wagonSizes[i]); printf("%d messages écrits\n", msgCounter); if (msgCounter > 0) { printf( "Temps absolu écoulé : %9ld usec par message (%9ld au total)\n", elapsedTime / msgCounter, elapsedTime); printf( "Temps CPU (user+sys) écoulé : %9ld usec par message (%9ld au total)\n", cpuTime / msgCounter, cpuTime); } printf("**************************\n"); // free ressources freeWiw(wagonToSend); } } return EXIT_SUCCESS; }
void stateMachine(womim* p_womim) { int id; MUTEX_LOCK(stateMachineMutex); //printf("State = %s, receive message = %s\n", stateToStr(automatonState), msgTypeToStr(p_womim->msg.type)); switch (automatonState) { case OFFLINE_CONNECTION_ATTEMPT: switch (p_womim->msg.type) { case NAK_INSERT: case DISCONNECT_PRED: case DISCONNECT_SUCC: freeWomim(p_womim); nextState(WAIT); break; case INSERT: prec = p_womim->msg.body.insert.sender; sendOther(p_womim->msg.body.insert.sender, true, NAK_INSERT, myAddress); freeWomim(p_womim); break; case ACK_INSERT: prec = p_womim->msg.body.ackInsert.sender; openConnection(prec, true); sendOther(prec, true, NEWSUCC, myAddress); freeWomim(p_womim); nextState(OFFLINE_CONFIRMATION_WAIT); break; default: ERROR_AT_LINE_WITHOUT_ERRNUM(EXIT_FAILURE, __FILE__, __LINE__, "unexpected case : received message %s in state %s", msgTypeToStr(p_womim->msg.type), stateToStr(automatonState)); break; } break; case OFFLINE_CONFIRMATION_WAIT: switch (p_womim->msg.type) { case NEWSUCC: case DISCONNECT_PRED: case DISCONNECT_SUCC: freeWomim(p_womim); nextState(WAIT); break; case INSERT: sendOther(p_womim->msg.body.insert.sender, true, NAK_INSERT, myAddress); freeWomim(p_womim); break; case TRAIN: id = (int) p_womim->msg.body.train.stamp.id; if (addrIsMember(myAddress, p_womim->msg.body.train.circuit)) { p_womim->msg.body.train.stamp.lc++; } releaseWiw(&(lts[id].w.w_w)); lts[id].w.len = 0; if (firstWagon(&(p_womim->msg)) != NULL ) { lts[id].w.w_w.p_wagon = firstWagon(&(p_womim->msg)); lts[id].w.w_w.p_womim = p_womim; lts[id].w.len = (p_womim->msg.len - sizeof(stamp) - sizeof(int) - sizeof(MType) - sizeof(address)); // We do not need to lock the p_womim->pfx.mutex as we are the only thread // accessing to counter p_womim->pfx.counter++; } lts[id].circuit = p_womim->msg.body.train.circuit; lts[id].stamp = p_womim->msg.body.train.stamp; sendTrain(succ, false, lts[id]); if (isInLts(myAddress, lts)) { #ifdef INSERTION_TEST gettimeofday(&trainDate, NULL); timersub(&trainDate, &offlineInitDate, &insertionDuration); floatInsertionDuration = ((double) insertionDuration.tv_sec) * 1000 + ((double) insertionDuration.tv_usec) / 1000; printf("My insertion duration : %.3lfms\n", floatInsertionDuration); printf("number of times automaton has been in state WAIT ; %llu\n", counters.wait_states); #endif /* INSERTION_TEST */ lis = p_womim->msg.body.train.stamp.id; signalArrival(myAddress, lts[lis].circuit); nextState(SEVERAL); int rc = sem_post(sem_init_done); if (rc) ERROR_AT_LINE(EXIT_FAILURE, errno, __FILE__, __LINE__, "error in sem_post"); } freeWomim(p_womim); break; default: ERROR_AT_LINE_WITHOUT_ERRNUM(EXIT_FAILURE, __FILE__, __LINE__, "unexpected case : received message %s in state %s", msgTypeToStr(p_womim->msg.type), stateToStr(automatonState)); freeWomim(p_womim); break; } break; case WAIT: freeWomim(p_womim); break; case ALONE_INSERT_WAIT: switch (p_womim->msg.type) { case DISCONNECT_PRED: case DISCONNECT_SUCC: // May happen in case there are 2 processes on the circuit and one process dies // The other process receives DISCONNECT in SEVERAL state and switched to // ALONE_INSERT_WAIT state, where it receives the DISCONNECT corresponding // to the loss of the second connection freeWomim(p_womim); break; case INSERT: MUTEX_LOCK(mutexWagonToSend); sendOther(p_womim->msg.body.insert.sender, true, ACK_INSERT, myAddress); prec = p_womim->msg.body.insert.sender; freeWomim(p_womim); nextState(ALONE_CONNECTION_WAIT); MUTEX_UNLOCK(mutexWagonToSend); break; default: ERROR_AT_LINE_WITHOUT_ERRNUM(EXIT_FAILURE, __FILE__, __LINE__, "unexpected case : received message %s in state %s", msgTypeToStr(p_womim->msg.type), stateToStr(automatonState)); freeWomim(p_womim); break; } break; case ALONE_CONNECTION_WAIT: switch (p_womim->msg.type) { case DISCONNECT_PRED: nextState(ALONE_INSERT_WAIT); freeWomim(p_womim); break; case INSERT: // In the PhD-thesis algorithm, we are supposed to do a // saveUntilNextstate(p_womim). Sending a NAK_INSERT is more simple. sendOther(p_womim->msg.body.insert.sender, true, NAK_INSERT, myAddress); freeWomim(p_womim); break; case NEWSUCC: succ = p_womim->msg.body.newSucc.sender; int i; for (i = 1; i <= ntr; i++) { int id = ((lis + i) % ntr); (lts[(int) id]).stamp.lc += 1; (lts[(int) id]).circuit = myAddress | prec; (lts[(int) id]).w.w_w.p_wagon = NULL; (lts[(int) id]).w.w_w.p_womim = NULL; (lts[(int) id]).w.len = 0; sendTrain(succ, false, lts[(int) id]); } freeWomim(p_womim); nextState(SEVERAL); break; default: ERROR_AT_LINE_WITHOUT_ERRNUM(EXIT_FAILURE, __FILE__, __LINE__, "unexpected case : received message %s in state %s", msgTypeToStr(p_womim->msg.type), stateToStr(automatonState)); freeWomim(p_womim); break; } break; case SEVERAL: switch (p_womim->msg.type) { case TRAIN: if (addrIsMember(myAddress, p_womim->msg.body.train.circuit)) { if (isRecentTrain(p_womim->msg.body.train.stamp, lts, lis)) { #ifdef INSERTION_TEST if (theLostPrec != 0) { if (recentlyLostMyPred) { gettimeofday(&firstRecentTrainDate, NULL); recentlyLostMyPred = false; } if (!isInLts(theLostPrec,lts)) { gettimeofday(&firstNewCircuitDate, NULL); theLostPrec = 0; timersub(&firstRecentTrainDate, &discoPredDate, &recoveryRecentTrainDuration); timersub(&firstNewCircuitDate, &discoPredDate, &recoveryNewCircuitDuration); floatRecoveryRecentTrainDuration = ((double) recoveryRecentTrainDuration.tv_sec) * 1000 + ((double) recoveryRecentTrainDuration.tv_usec) / 1000; floatRecoveryNewCircuitDuration = ((double) recoveryNewCircuitDuration.tv_sec) * 1000 + ((double) recoveryNewCircuitDuration.tv_usec) / 1000; printf("Disconnection pred recovery :\n"); printf("\t- First recent train after %.3lfms\n", floatRecoveryRecentTrainDuration); printf("\t- Up-to-date circuit received after %.3lfms\n", floatRecoveryNewCircuitDuration); } } #endif /* INSERTION_TEST */ trainHandling(p_womim); lis = p_womim->msg.body.train.stamp.id; if (succ != 0) sendTrain(succ, false, lts[lis]); } } else { ERROR_AT_LINE_WITHOUT_ERRNUM(EXIT_FAILURE, __FILE__, __LINE__, "myAddress not in the circuit ==> Suicide"); } freeWomim(p_womim); break; case INSERT: closeConnection(prec, true); sendOther(p_womim->msg.body.insert.sender, true, ACK_INSERT, prec); prec = p_womim->msg.body.insert.sender; addrAppendArrived(&cameProc, prec); freeWomim(p_womim); break; case NEWSUCC: if (succ != 0) closeConnection(succ, false); succ = p_womim->msg.body.newSucc.sender; int i; for (i = 1; i <= ntr; i++) { sendTrain(succ, false, lts[(lis + i) % ntr]); } freeWomim(p_womim); break; case DISCONNECT_PRED: #ifdef INSERTION_TEST gettimeofday(&discoPredDate, NULL); recentlyLostMyPred = true; theLostPrec = prec; #endif /* INSERTION_TEST */ MUTEX_LOCK(mutexWagonToSend); while (!(addrIsEqual(prec,myAddress))) { if (openConnection(prec, true) != (-1)) { sendOther(prec, true, NEWSUCC, myAddress); freeWomim(p_womim); nextState(SEVERAL); MUTEX_UNLOCK(stateMachineMutex); MUTEX_UNLOCK(mutexWagonToSend); return; } addrAppendGone(&cameProc, &goneProc, prec); prec = addrPrec(prec, lts[lis].circuit); } signalDepartures(goneProc, lts[lis].circuit, true); goneProc = 0; int aRound; for (aRound = 1; aRound <= NR; aRound++) { int i; for (i = 1; i <= ntr; i++) { int id = (lis + i) % ntr; int round = (lts[id].stamp.round + aRound) % NR; bqueueExtend(wagonsToDeliver, unstableWagons[id][round]); cleanList(unstableWagons[id][round]); } } bqueueEnqueue(wagonsToDeliver, wagonToSend); wagonToSend = newWiw(); freeWomim(p_womim); #ifdef INSERTION_TEST gettimeofday(&firstNewCircuitDate, NULL); timersub(&firstNewCircuitDate, &discoPredDate, &recoveryNewCircuitDuration); floatRecoveryNewCircuitDuration = ((double) recoveryNewCircuitDuration.tv_sec) * 1000 + ((double) recoveryNewCircuitDuration.tv_usec) / 1000; printf("I am alone !\n" "%.3lfms since the DISCONNECT_PRED message\n", floatRecoveryNewCircuitDuration); #endif /* INSERTION_TEST */ nextState(ALONE_INSERT_WAIT); MUTEX_UNLOCK(stateMachineMutex); MUTEX_UNLOCK(mutexWagonToSend); pthread_cond_signal(&condWagonToSend); break; case DISCONNECT_SUCC: succ = 0; freeWomim(p_womim); break; default: ERROR_AT_LINE_WITHOUT_ERRNUM(EXIT_FAILURE, __FILE__, __LINE__, "unexpected case : received message %s in state %s", msgTypeToStr(p_womim->msg.type), stateToStr(automatonState)); break; } break; default: ERROR_AT_LINE_WITHOUT_ERRNUM(EXIT_FAILURE, __FILE__, __LINE__, "Unknown state : %d", automatonState); freeWomim(p_womim); break; } MUTEX_UNLOCK(stateMachineMutex); }
void trainHandling(womim *p_womim) { int id = p_womim->msg.body.train.stamp.id; int round = p_womim->msg.body.train.stamp.round; wagon *p_wag; counters.recent_trains_received++; counters.recent_trains_bytes_received += p_womim->msg.len; //printf("TRAIN id=%d\n", id); if (round == lts[id].stamp.round) { round = (round + 1) % nbRounds; } if (requiredOrder != CAUSAL_ORDER) { // Thus (requiredOrder == TOTAL_ORDER) || (requiredOrder == UNIFORM_TOTAL_ORDER)) bqueueExtend(wagonsToDeliver, unstableWagons[id][(round + 1) % nbRounds]); cleanList(unstableWagons[id][(round + 1) % nbRounds]); } if (id == 0) { lts[0].circuit = addrUpdateCircuit(p_womim->msg.body.train.circuit, myAddress, cameProc, goneProc); cameProc = 0; signalDepartures(goneProc, lts[0].circuit, false); goneProc = 0; } else { lts[id].circuit = lts[0].circuit; } releaseWiw(&(lts[id].w.w_w)); lts[id].w.len = 0; freeWiw(lts[id].p_wtosend); lts[id].p_wtosend = NULL; for (p_wag = firstWagon(&(p_womim->msg)); p_wag != NULL ; p_wag = nextWagon(p_womim, p_wag)) { if (addrIsMember(p_wag->header.sender, lts[id].circuit) && !(addrIsMember(p_wag->header.sender, goneProc)) && !(addrIsMine(p_wag->header.sender))) { // We add a wiw (corresponding to this p_wag) to unstableWagons[id][round] // (in case of TOTAL_ORDER or UNIFORM_TOTAL_ORDER) or directly to // wagonsToDeliver (in case of CAUSAL_ORDER) wiw *wi = malloc(sizeof(wiw)); assert(wi != NULL); wi->p_wagon = p_wag; wi->p_womim = p_womim; MUTEX_LOCK(p_womim->pfx.mutex); p_womim->pfx.counter++; MUTEX_UNLOCK(p_womim->pfx.mutex); if (requiredOrder != CAUSAL_ORDER) { // Thus (requiredOrder == TOTAL_ORDER) || (requiredOrder == UNIFORM_TOTAL_ORDER)) listAppend(unstableWagons[id][round], wi); } else { bqueueEnqueue(wagonsToDeliver, wi); } // Shall this wagon be sent to our successor if (!addrIsEqual(succ,p_wag->header.sender)) { // Yes, it must sent if (lts[id].w.w_w.p_wagon == NULL ) { // lts must be updated to point on the first wagon to be sent lts[id].w.w_w.p_wagon = p_wag; lts[id].w.w_w.p_womim = p_womim; MUTEX_LOCK(lts[id].w.w_w.p_womim->pfx.mutex); lts[id].w.w_w.p_womim->pfx.counter++; MUTEX_UNLOCK(lts[id].w.w_w.p_womim->pfx.mutex); } // We adapt len lts[id].w.len += p_wag->header.len; } } } lts[id].stamp.round = (char) round; MUTEX_LOCK(mutexWagonToSend); if (firstMsg(wagonToSend->p_wagon) != NULL ) { wagonToSend->p_wagon->header.round = round; // We add a wiw (corresponding to this p_wag) to wagonToSend wiw *wi = malloc(sizeof(wiw)); assert(wi != NULL); *wi = *wagonToSend; // We do not need to lock wagonToSend->p_wagon->pfx.mutex // as we are for the moment alone to access to // wagonToSend->p_wagon->pfx.counter wagonToSend->p_womim->pfx.counter++; if (requiredOrder != CAUSAL_ORDER) { // Thus (requiredOrder == TOTAL_ORDER) || (requiredOrder == UNIFORM_TOTAL_ORDER)) listAppend(unstableWagons[id][round], wi); } else { bqueueEnqueue(wagonsToDeliver, wi); } lts[id].p_wtosend = wagonToSend; wagonToSend = newWiw(); } MUTEX_UNLOCK(mutexWagonToSend); pthread_cond_signal(&condWagonToSend); lts[id].stamp.lc = p_womim->msg.body.train.stamp.lc + 1; }