MJL 16/3/07 Added transitional statuses, removed blocking code, improved performance under error conditions.

r1664 | mle | 2007-03-16 16:57:36 +1100 (Fri, 16 Mar 2007) | 2 lines
This commit is contained in:
Mark Lesha
2007-03-16 16:57:36 +11:00
committed by Douglas Clowes
parent f62af28efb
commit 4da6d932fb

View File

@@ -21,7 +21,7 @@
#include <ghttp.h>
#include <stptok.h>
#include <countdriv.h>
#include <zlib.h>
#include <nserver.h>
extern char *trim(char *);
/*===================================================================
@@ -38,19 +38,17 @@ static char preset[] = {"/admin/presethm.egi"};
/*====================================================================
error codes
======================================================================*/
#define BADURL -701
#define HTTPERROR -702
#define NOBODY -703
#define BODYSHORT -704
#define BADURL -701
#define HTTPERROR -702
#define NOBODY -703
#define BODYSHORT -704
#define NOTIMPLEMENTED -705
#define SERVERERROR -706
#define BADSTATUS -707
#define BADAUTH -708
#define IMMEDFAIL -709
#define SERVERERROR -706
#define BADSTATUS -707
#define BADAUTH -708
/*=====================================================================
our driver private data structure
======================================================================*/
#define MAXSTRLEN 512
typedef struct {
ghttp_request *syncRequest;
char hmAddress[512];
@@ -343,13 +341,26 @@ static int readStatus(pHistDriver pDriv){
// This allows the status to be checked from all the start, stop, pause
// and continue callbacks, so we can wait for the server to actually
// change to the correct operating state before continuing.
static int AnstoHttpStatus(pHistDriver self,SConnection *pCon){ // pCon=NULL allowed
//
// Define codes for more detailed status info
// (returned via pextrastatus instead of retcode which is just HWBusy or HWIdle).
// These are needed so we can tell when a start/stop/pause operation actually completes.
#define ANSTO_HS_STATUS_INVALID 0 // e.g. couldn't retrieve a status because server is down
#define ANSTO_HS_STATUS_STARTED 1
#define ANSTO_HS_STATUS_PAUSED 2
#define ANSTO_HS_STATUS_STOPPED 3
#define ANSTO_HS_STATUS_STARTING 4
#define ANSTO_HS_STATUS_PAUSING 5
#define ANSTO_HS_STATUS_STOPPING 6
//
static int AnstoHttpStatus_Base(pHistDriver self,SConnection *pCon,int *pextrastatus){ // pCon=NULL allowed
pAnstoHttp pPriv = NULL;
ghttp_status httpStatus;
char daqStatus[20];
int status, len;
char *pPtr = NULL;
static int last_known_status=HWIdle; // assume idle initially
pPriv = (pAnstoHttp)self->pPriv;
assert(pPriv != NULL);
@@ -365,6 +376,7 @@ static int AnstoHttpStatus(pHistDriver self,SConnection *pCon){ // pCon=NULL all
ghttp_set_sync(pPriv->syncRequest,ghttp_async);
ghttp_prepare(pPriv->syncRequest);
if(status != 1){
if (pextrastatus) *pextrastatus=ANSTO_HS_STATUS_INVALID;
return HWFault;
}
pPriv->asyncRunning = 1;
@@ -379,8 +391,9 @@ static int AnstoHttpStatus(pHistDriver self,SConnection *pCon){ // pCon=NULL all
if(httpStatus != ghttp_done){
strncpy(pPriv->hmError,"Reconnect", 511);
pPriv->errorCode = SERVERERROR;
if (pextrastatus) *pextrastatus=ANSTO_HS_STATUS_INVALID;
pPriv->asyncRunning = 0; // MJL bug fix 9/03/07
return HWFault;
pPriv->asyncRunning = 0;
}
break;
case ghttp_not_done:
@@ -392,6 +405,7 @@ static int AnstoHttpStatus(pHistDriver self,SConnection *pCon){ // pCon=NULL all
pPriv->asyncRunning = 0;
status = anstoHttpCheckResponse(pPriv);
if(status != 1){
if (pextrastatus) *pextrastatus=ANSTO_HS_STATUS_INVALID;
return HWFault;
}
break;
@@ -400,22 +414,53 @@ static int AnstoHttpStatus(pHistDriver self,SConnection *pCon){ // pCon=NULL all
status = readStatus(self);
if(status != 1){
if (pextrastatus) *pextrastatus=ANSTO_HS_STATUS_INVALID;
return HWFault;
}
if(StringDictGet(self->pOption,"daq",daqStatus,20) != 1){
pPriv->errorCode = BADSTATUS;
strncpy(pPriv->hmError,"ERROR: status does not contain DAQ field",511);
if (pextrastatus) *pextrastatus=ANSTO_HS_STATUS_INVALID;
return HWFault;
}
///if (pCon) SCWrite(pCon,daqStatus,eError); // MJL DEBUG
//
// Basically we just diagnose whether the DAQ is running or not,
// but also return more detailed status via pextrastatus if supplied.
if(strstr(daqStatus,"Started") != NULL){
return HWBusy;
if (pextrastatus) *pextrastatus=ANSTO_HS_STATUS_STARTED;
return last_known_status=HWBusy;
} else if(strstr(daqStatus,"Paused") != NULL){
return HWIdle;
if (pextrastatus) *pextrastatus=ANSTO_HS_STATUS_PAUSED;
return last_known_status=HWIdle;
} else if(strstr(daqStatus,"Stopped") != NULL){
return HWIdle;
if (pextrastatus) *pextrastatus=ANSTO_HS_STATUS_STOPPED;
return last_known_status=HWIdle;
//
// The following are extra statuses which may
// (in the next histogram server version) be reported
// by the server, when the DAQ state is changing.
// As some DAE types are slow to start up, this
// is a valuable feature.
//
// Try to distinguish the HWBusy and HWIdle states
// based on the last known status. For example,
// when Stopping from Paused state it should report
// HWBusy if it was in Started state to begin with,
// otherwise HWIdle if it was in Paused or Stopped states.
} else if(strstr(daqStatus,"Starting") != NULL){
if (pextrastatus) *pextrastatus=ANSTO_HS_STATUS_STARTING;
return last_known_status; // if started already, is already HWBusy
} else if(strstr(daqStatus,"Stopping") != NULL){
if (pextrastatus) *pextrastatus=ANSTO_HS_STATUS_PAUSING;
return last_known_status; // return HWBusy only if it was started before
} else if(strstr(daqStatus,"Pausing") != NULL){
if (pextrastatus) *pextrastatus=ANSTO_HS_STATUS_STOPPING;
return last_known_status; // return HWBusy if it was started before
// bad or missing status??
} else {
if (pextrastatus) *pextrastatus=ANSTO_HS_STATUS_INVALID;
pPriv->errorCode = BADSTATUS;
snprintf(pPriv->hmError,511,"ERROR: invalid DAQ status %s",daqStatus);
return HWFault;
@@ -423,19 +468,53 @@ static int AnstoHttpStatus(pHistDriver self,SConnection *pCon){ // pCon=NULL all
return HWFault; // shouldn't get here
}
//
static int AnstoHttpStatus(pHistDriver self,SConnection *pCon){ // pCon=NULL allowed
return AnstoHttpStatus_Base(self,pCon,NULL); // pCon=NULL allowed
}
#define MAX_STATUS_READ_RETRIES 150
#define STATUS_READ_DELAY_US 200000
#define STATUS_READ_DELAY_USEC 200000 // re-check once per 0.2 second if possible
#define MAX_STATUS_READ_RETRIES 150 // wait up to 30 secs for status to change to desired state
#define MAX_BAD_STATUS_REQUESTS 3 // don't wait too long if too many bad status requests (probably server is down)
//
long long get_localtime_us()
// Get the time in us not in the US ;)
{
struct timeval tv;
gettimeofday(&tv,NULL);
return ((long long)tv.tv_sec)*1000000+tv.tv_usec;
}
//
static int AnstoHttpStatusWithRetries(pHistDriver self, int requiredstate,SConnection *pCon) // pCon=NULL allowed
{
int retries,retcode,initialentry=1;
for(retries=0;retries<MAX_STATUS_READ_RETRIES&&(initialentry||retcode!=requiredstate);retries++)
int retries=0,initialentry=1,bad_status_requests=0;
int retcode,runloop;
do
{
retcode=AnstoHttpStatus(self,pCon);
usleep(STATUS_READ_DELAY_US);
int extrastatus;
// Request current status from the histogram server.
// The server usually responds within milliseconds.
retcode=AnstoHttpStatus_Base(self,pCon,&extrastatus);
retries++;
bad_status_requests+=(extrastatus==ANSTO_HS_STATUS_INVALID);
runloop=(retries<MAX_STATUS_READ_RETRIES)&&(initialentry||extrastatus!=requiredstate)
&&(bad_status_requests<MAX_BAD_STATUS_REQUESTS);
// Retry after a delay if status hasn't changed yet
// (DAE takes time to start up / shut down)
if (runloop) // Only wait if we're going to loop, otherwise drop out immediately
{
long long start_time_us=get_localtime_us();
do // make sure the yield in this loop gets called at least once
{
// Service other SICS tasks while we wait.
pTaskMan pTasker = GetTasker();
if (pTasker)
TaskYield(pTasker);
} while(get_localtime_us()<(start_time_us+STATUS_READ_DELAY_USEC));
}
initialentry=0;
}
} while(runloop);
return retcode;
}
@@ -452,7 +531,7 @@ static int AnstoHttpStart(pHistDriver self, SConnection *pCon){
if(status != 1){
return HWFault;
}
AnstoHttpStatusWithRetries(self,HWBusy,pCon);
AnstoHttpStatusWithRetries(self,ANSTO_HS_STATUS_STARTED,pCon);
return OKOK;
}
/*---------------------------------------------------------------------*/
@@ -468,7 +547,7 @@ static int AnstoHttpHalt(pHistDriver self){ // hmm, why isn't there a pCon like
return HWFault;
}
AnstoHttpStatusWithRetries(self,HWIdle,NULL); // no pCon available :(
AnstoHttpStatusWithRetries(self,ANSTO_HS_STATUS_STOPPED,NULL); // no pCon available :(
return OKOK;
}
@@ -486,7 +565,7 @@ static int AnstoHttpPause(pHistDriver self,SConnection *pCon){
}
pPriv->pause = 1;
AnstoHttpStatusWithRetries(self,HWIdle,pCon);
AnstoHttpStatusWithRetries(self,ANSTO_HS_STATUS_PAUSED,pCon);
return OKOK;
}
@@ -498,12 +577,12 @@ static int AnstoHttpContinue(pHistDriver self, SConnection *pCon){
pPriv = (pAnstoHttp)self->pPriv;
assert(pPriv != NULL);
status = anstoHttpGet(pPriv,continuedaq);
status = anstoHttpGet(pPriv,continuedaq); // which is the same as restarting
if(status != 1){
return HWFault;
}
pPriv->pause = 0;
AnstoHttpStatusWithRetries(self,HWBusy,pCon);
AnstoHttpStatusWithRetries(self,ANSTO_HS_STATUS_STARTED,pCon);
return OKOK;
}
/*---------------------------------------------------------------------*/
@@ -517,7 +596,7 @@ static int AnstoHttpError(pHistDriver self, int *code,
strncpy(error,pPriv->hmError, errLen);
*code = pPriv->errorCode;
return OKOK;
return OKOK;
}
/*--------------------------------------------------------------------*/
static int AnstoHttpFixIt(pHistDriver self, int code){
@@ -550,60 +629,7 @@ static int AnstoHttpGetData(pHistDriver self,SConnection *pCon){
return OKOK;
}
/*-------------------------------------------------------------------*/
/** \brief Reads histogram data from a zipped file produced by the
* histogram memory server
*
* \param self (r) provides access to the histogram data structure
* \param bank number n maps to a HDS_Pn file.
*/
static int GetHMfromFile(pHistDriver self, SConnection *pCon,
int bank, int start, int end, HistInt *data){
HistInt *hmdata;
pAnstoHttp pPriv = NULL;
int status, len, i, size;
int errMsgLen;
FILE *fp;
char command[256];
char hmDataPath[MAXSTRLEN];
char DAQdir[MAXSTRLEN];
char DSfilepath[MAXSTRLEN];
char scanpoint[32];
memset(command, 0, sizeof(command));
memset(hmDataPath, 0, sizeof(hmDataPath));
memset(DAQdir, 0, sizeof(DAQdir));
memset(DSfilepath, 0, sizeof(DSfilepath));
memset(scanpoint, 0, sizeof(scanpoint));
pPriv = (pAnstoHttp)self->pPriv;
assert(pPriv != NULL);
errMsgLen = sizeof(pPriv->hmError);
if (bank < 0) {
snprintf(pPriv->hmError,errMsgLen,"Negative bank numbers are not supported when reading from the filesystem");
pPriv->errorCode = IMMEDFAIL;
return HWFault;
}
StringDictGet(self->pOption, "daq_dirname",DAQdir, sizeof(DAQdir)-1);
StringDictGet(self->pOption, "hmdatapath",hmDataPath, sizeof(hmDataPath)-1);
StringDictGet(self->pOption, "scanpoint",scanpoint, sizeof(scanpoint)-1);
snprintf(DSfilepath,sizeof(DSfilepath),"%s/%s/DATASET_%s/HDS_P%d",hmDataPath,DAQdir,scanpoint,bank);
if ((fp=gzopen(DSfilepath, "rb")) == NULL) {
snprintf(pPriv->hmError,errMsgLen,"Failed to open %s", DSfilepath);
pPriv->errorCode = IMMEDFAIL;
return HWFault;
}
size = end - start;
gzread(fp, data, size*sizeof(HistInt));
data+=size;
start+=size;
gzclose(fp);
return OKOK;
}
/**\brief Gets histogram data directly from the histogram memory http server.
*/
static int GetHMfromSocket(pHistDriver self, SConnection *pCon,
static int AnstoHttpGetHistogram(pHistDriver self, SConnection *pCon,
int bank, int start, int end, HistInt *data){
char command[256];
HistInt *hmdata;
@@ -683,17 +709,6 @@ static int GetHMfromSocket(pHistDriver self, SConnection *pCon,
}
return OKOK;
}
static int AnstoHttpGetHistogram(pHistDriver self, SConnection *pCon,
int bank, int start, int end, HistInt *data){
char direct[2];
StringDictGet(self->pOption, "direct",direct, 2);
if (strcmp(direct,"1") == 0)
return GetHMfromSocket(self, pCon, bank, start, end, data);
else
return GetHMfromFile(self, pCon, bank, start, end, data);
}
/*--------------------------------------------------------------------*/
static int AnstoHttpSetHistogram(pHistDriver self, SConnection *pCon,
int bank, int start, int end, HistInt *data){
@@ -758,8 +773,8 @@ pHistDriver CreateAnstoHttpDriver(pStringDict pOption){
}
/* add our options */
StringDictAddPair(pOption,"hmaddress","http://unknown.psi.ch:9090");
StringDictAddPair(pOption,"hmconfigurescript","hmconfigure");
StringDictAddPair(pOption,"hmaddress","http://localhost:8080");
StringDictAddPair(pOption,"hmconfigurescript","anstohm_full.xml");
/* initialise our private data structure */
pInternal = (pAnstoHttp)malloc(sizeof(anstoHttp));
@@ -770,17 +785,11 @@ pHistDriver CreateAnstoHttpDriver(pStringDict pOption){
memset(pInternal,0,sizeof(anstoHttp));
pNew->pPriv = pInternal;
pInternal->syncRequest = ghttp_request_new();
memset(pInternal->hmError,0,sizeof(pInternal->hmError));
if(pInternal->syncRequest == NULL){
free(pNew);
free(pInternal);
return NULL;
}
/* direct = 0 Get HM from data files
* direct = 1 Get HM from http server */
StringDictAddPair(pOption, "direct", "1");
StringDictAddPair(pOption, "hmdatapath", "../HMData");
StringDictAddPair(pOption, "scanpoint", "0");
/* configure all those functions */