blob: f52e928f3b12c33ddc7430c7a4338748cc7aee28 [file] [log] [blame]
#ifndef _PRAGMA_COPYRIGHT_
#define _PRAGMA_COPYRIGHT_
#pragma comment(copyright, "%Z% %I% %W% %D% %T%\0")
#endif /* _PRAGMA_COPYRIGHT_ */
/****************************************************************************
* Copyright (c) 2008, 2010 IBM Corporation.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0s
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
Classes: StateMachine
Description: SCI state Machine
Author: Nicole
History:
Date Who ID Description
-------- --- --- -----------
02/25/08 nieyy Initial code (D153875)
****************************************************************************/
#include "statemachine.hpp"
#include <assert.h>
#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include "sci.h"
#include "log.hpp"
#include "ctrlblock.hpp"
#include "routinglist.hpp"
const char * StateMsg[] = {
"uninitialized",
"starting",
"running",
"idling",
"exiting"
};
const char * EventMsg[] = {
"data structures were created",
"data structure were cleaned",
"a child was connected",
"a child was disconnected",
"connected to the parent",
"lost connection to the parent",
"received a quit signal from the front end",
"a fatal exception occured",
"connection to the parent is recovered",
"failed recover the connection to the parent"
};
StateMachine * StateMachine::instance = NULL;
StateMachine::StateMachine()
{
::pthread_mutex_init(&mtx, NULL);
reset();
}
StateMachine::~StateMachine()
{
::pthread_mutex_destroy(&mtx);
instance = NULL;
}
void StateMachine::parse(StateMachine::EVENT e)
{
lock();
history.push_back(e);
if (gCtrlBlock->getMyRole() == CtrlBlock::FRONT_END) {
parseFE(e);
if ((gCtrlBlock->getEndInfo()->fe_info.mode==SCI_POLLING) &&
(state==IDLING)) {
// if polling mode, need notify SCI_Poll in idling state
gCtrlBlock->notifyPollQueue();
}
} else if (gCtrlBlock->getMyRole() == CtrlBlock::AGENT) {
parseAgent(e);
} else if (gCtrlBlock->getMyRole() == CtrlBlock::BACK_END) {
parseBE(e);
if ((gCtrlBlock->getEndInfo()->be_info.mode==SCI_POLLING) &&
(state==EXITING)) {
// if polling mode, need notify SCI_Poll in exiting state
gCtrlBlock->notifyPollQueue();
}
}
log_debug("StateMachine: current state is %s", StateMsg[state]);
if (state == EXITING) {
gCtrlBlock->disable();
} else if (state != UNINITIALIZED) {
gCtrlBlock->enable();
}
unlock();
}
void StateMachine::reset()
{
lock();
state = UNINITIALIZED;
connected = 0;
disconnected = 0;
toQuit = false;
history.clear();
unlock();
}
StateMachine::STATE StateMachine::getState()
{
STATE s;
lock();
s = state;
unlock();
return s;
}
bool StateMachine::isToQuit(int handle)
{
bool ret;
lock();
if (toQuit) {
ret = true;
} else {
if (handle == gCtrlBlock->getMyHandle()) {
ret = false;
} else {
if (gRoutingList->isSuccessorExist(handle)) {
ret = false;
} else {
ret = true;
}
}
}
unlock();
return ret;
}
void StateMachine::dump()
{
char outFile[256];
int hndl = gCtrlBlock->getMyHandle();
if (gCtrlBlock->getMyRole() == CtrlBlock::FRONT_END) {
::sprintf(outFile, "fe.state");
} else if (gCtrlBlock->getMyRole() == CtrlBlock::AGENT) {
::sprintf(outFile, "scia.state.%d", hndl);
} else {
::sprintf(outFile, "be.state.%d", hndl);
}
FILE *fp = ::fopen(outFile, "w");
if (fp) {
int size = history.size();
for (int i=0; i<size; i++) {
::fprintf(fp, "Event %d: %s\n", i, EventMsg[history[i]]);
}
::fclose(fp);
}
}
void StateMachine::doAssert(bool expression)
{
if (!expression) {
dump();
assert(!"Should not be here");
}
}
void StateMachine::parseFE(StateMachine::EVENT e)
{
switch (e) {
case USER_QUIT:
log_debug("StateMachine: user called SCI_Terminate");
if (state == IDLING) {
state = EXITING;
}
toQuit = true;
break;
case FATAL_EXCEPTION:
log_debug("StateMachine: fatal exception");
if (state != EXITING) {
state = EXITING;
}
break;
case CLIENT_CONNECTED:
log_debug("StateMachine: a client is connected");
connected++;
if (state == STARTING) {
if (connected >= gRoutingList->numOfSuccessor(SCI_GROUP_ALL)) {
state = RUNNING;
}
} else if (state == IDLING) {
state = RUNNING;
}
break;
case CLIENT_BROKEN:
log_debug("StateMachine: a client is disconnected");
disconnected++;
if (state == RUNNING) {
int numSuccessors = gRoutingList->numOfSuccessor(SCI_GROUP_ALL);
int max = connected > numSuccessors ? connected : numSuccessors;
if (disconnected >= max) {
state = IDLING;
if (toQuit) {
state = EXITING;
}
}
}
break;
case DATASTRUC_CREATED:
log_debug("StateMachine: data structure created");
if (state == UNINITIALIZED) {
state = STARTING;
} else {
doAssert();
}
break;
case DATASTUCT_CLEANED:
log_debug("StateMachine: data structure cleaned");
if (state == EXITING) {
state = UNINITIALIZED;
} else {
doAssert();
}
break;
default:
log_error("StateMachine: unexpected event");
break;
}
}
void StateMachine::parseAgent(StateMachine::EVENT e)
{
switch (e) {
case PARENT_CONNECTED:
log_debug("StateMachine: connected to the parent");
if (state == UNINITIALIZED) {
state = STARTING;
} else {
doAssert();
}
break;
case USER_QUIT:
log_debug("StateMachine: got a quit command");
toQuit = true;
if (gRoutingList->numOfSuccessor(SCI_GROUP_ALL) == 0) {
state = EXITING;
}
break;
case FATAL_EXCEPTION:
log_debug("StateMachine: parent broken or fatal exception");
if (state != EXITING) {
state = EXITING;
}
break;
case CLIENT_CONNECTED:
log_debug("StateMachine: a client is connected");
connected++;
if (state == STARTING) {
if (connected >= gRoutingList->numOfSuccessor(SCI_GROUP_ALL)) {
state = RUNNING;
}
}
break;
case CLIENT_BROKEN:
log_debug("StateMachine: a client is disconnected");
disconnected++;
if (state == RUNNING) {
int numSuccessors = gRoutingList->numOfSuccessor(SCI_GROUP_ALL);
int max = connected > numSuccessors ? connected : numSuccessors;
if ((disconnected>=max) && toQuit) {
state = EXITING;
}
}
break;
case DATASTRUC_CREATED:
log_debug("StateMachine: data structure created");
doAssert(state == STARTING);
break;
case DATASTUCT_CLEANED:
log_debug("StateMachine: data structure cleaned");
if (state == EXITING) {
state = UNINITIALIZED;
} else {
doAssert();
}
break;
case PARENT_BROKEN:
log_debug("StateMachine: parent broken");
if (state == RUNNING) {
state = IDLING;
} else {
state = EXITING;
}
break;
case RECOVER_OK:
log_debug("StateMachine: recover okay");
if (state == IDLING) {
state = RUNNING;
} else {
doAssert();
}
break;
case RECOVER_FAILED:
log_debug("StateMachine: recover failed");
if (state == IDLING) {
state = EXITING;
} else if (state != EXITING) {
doAssert();
}
break;
default:
log_error("StateMachine: unexpected event");
break;
}
}
void StateMachine::parseBE(StateMachine::EVENT e)
{
switch (e) {
case PARENT_CONNECTED:
log_debug("StateMachine: connected to the parent");
if (state == UNINITIALIZED) {
state = STARTING;
} else {
doAssert();
}
break;
case USER_QUIT:
log_debug("StateMachine: got a quit command");
if (state == RUNNING) {
state = EXITING;
} else if (state != EXITING) {
doAssert();
}
break;
case FATAL_EXCEPTION:
log_debug("StateMachine: fatal exception");
if (state != EXITING) {
state = EXITING;
}
break;
case DATASTRUC_CREATED:
log_debug("StateMachine: data structure created");
if (state == STARTING) {
state = RUNNING;
} else {
doAssert();
}
break;
case DATASTUCT_CLEANED:
log_debug("StateMachine: data structure cleaned");
if (state == EXITING) {
state = UNINITIALIZED;
} else {
doAssert();
}
break;
case PARENT_BROKEN:
log_debug("StateMachine: parent broken");
if (state == RUNNING) {
state = IDLING;
} else {
state = EXITING;
}
break;
case RECOVER_OK:
log_debug("StateMachine: recover okay");
if (state == IDLING) {
state = RUNNING;
} else {
doAssert();
}
break;
case RECOVER_FAILED:
log_debug("StateMachine: recover failed");
if (state == IDLING) {
state = EXITING;
} else if (state != EXITING) {
doAssert();
}
break;
default:
log_error("StateMachine: unexpected event");
break;
}
}