Cleaned up ANSTO code to merge with sinqdev.sics
This is our new RELEASE-4_0 branch which was taken from ansto/93d9a7c Conflicts: .gitignore SICSmain.c asynnet.c confvirtualmot.c counter.c devexec.c drive.c event.h exebuf.c exeman.c histmem.c interface.h motor.c motorlist.c motorsec.c multicounter.c napi.c napi.h napi4.c network.c nwatch.c nxscript.c nxxml.c nxxml.h ofac.c reflist.c scan.c sicshipadaba.c sicsobj.c site_ansto/docs/Copyright.txt site_ansto/instrument/lyrebird/config/tasmad/sicscommon/nxsupport.tcl site_ansto/instrument/lyrebird/config/tasmad/taspub_sics/tasscript.tcl statusfile.c tasdrive.c tasub.c tasub.h tasublib.c tasublib.h
This commit is contained in:
517
sctcomtask.c
Normal file
517
sctcomtask.c
Normal file
@ -0,0 +1,517 @@
|
||||
/**
|
||||
* This is another approach at using the scriptcontext system. It introduces
|
||||
* the concept of a communication task which is executed against a device serializer,
|
||||
* accessed via a given ScriptContext. Clients can:
|
||||
* - Create CommTasks
|
||||
* - Figure out their state
|
||||
* - Retrieve reply data
|
||||
* - wait for a ComTask to finish.
|
||||
*
|
||||
* The purpose sctcomtask will keep a cache of pending and finished communications.
|
||||
* Old runs will be deleted periodically. Nevertheless the cache can be listed in order
|
||||
* to figure out what happened.
|
||||
*
|
||||
* The intended use is for C-code or scripts to interact in a serial manner with
|
||||
* the asynchronous communication system implemented in devser and ascon. As a
|
||||
* standalone implementation this would share tons of code with scriptcontext, thus
|
||||
* this has been implemented as an add on module to scriptcontext.
|
||||
*
|
||||
* copyright: see file COPYRIGHT
|
||||
*
|
||||
* Mark Koennecke, December 2012
|
||||
*/
|
||||
#include <string.h>
|
||||
#include "sctcomtask.h"
|
||||
#include "scriptcontext.h"
|
||||
#include "sicsobj.h"
|
||||
#include "sicsutil.h"
|
||||
#include "sicshipadaba.h"
|
||||
|
||||
static unsigned int mamaID = 0L;
|
||||
|
||||
extern char *ParText(Hdb * cmdNode, char *name,
|
||||
int nPar, char *defaultValue);
|
||||
|
||||
/*----------------------------------------------------------------*/
|
||||
typedef struct{
|
||||
char *sendData;
|
||||
char *replyData;
|
||||
int replyDataLength;
|
||||
int ID;
|
||||
double startTime;
|
||||
double endTime;
|
||||
ComTaskState state;
|
||||
}ComTask, *pComTask;
|
||||
|
||||
/*----------------------------------------------------------------*/
|
||||
struct ComTaskManager{
|
||||
DevSer *devser;
|
||||
unsigned int halfQueueLength;
|
||||
ComTask *TaskQueue;
|
||||
unsigned int iPtr;
|
||||
};
|
||||
/*-----------------------------------------------------------------*/
|
||||
static void KillComTaskData(ComTask *queue, int length)
|
||||
{
|
||||
int i;
|
||||
|
||||
for(i = 0; i < length; i++){
|
||||
if(queue[i].sendData != NULL){
|
||||
free(queue[i].sendData);
|
||||
queue[i].sendData = NULL;
|
||||
}
|
||||
if(queue[i].replyData != NULL){
|
||||
free(queue[i].replyData);
|
||||
queue[i].replyData = NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
/*-----------------------------------------------------------------*/
|
||||
static char *ComTaskHandler(void *data, char *replyData, int commError)
|
||||
{
|
||||
pComTask task = (pComTask)data;
|
||||
assert(task != NULL);
|
||||
|
||||
if(replyData == NULL){
|
||||
task->state = eRunning;
|
||||
return task->sendData;
|
||||
} else {
|
||||
if(task->replyData != NULL){
|
||||
free(task->replyData);
|
||||
}
|
||||
task->replyData = strdup(replyData);
|
||||
task->replyDataLength = strlen(replyData);
|
||||
task->endTime = DoubleTime();
|
||||
task->state = eFinished;
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
/*-----------------------------------------------------------------*/
|
||||
static int ComTaskMatch(void *data1, void *data2)
|
||||
{
|
||||
pComTask task1 = (pComTask)data1;
|
||||
pComTask task2 = (pComTask)data2;
|
||||
|
||||
assert(task1 && task2);
|
||||
|
||||
if(task1->ID == task2->ID){
|
||||
return 1;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
/*----------------------------------------------------------------*/
|
||||
static char *stateName[] = {
|
||||
"waiting",
|
||||
"running",
|
||||
"finished",
|
||||
"unknown"
|
||||
};
|
||||
|
||||
static char* StateToText(ComTaskState state)
|
||||
{
|
||||
return stateName[(int)state];
|
||||
}
|
||||
/*----------------------------------------------------------------*/
|
||||
static char* ComTaskInfo(void *data)
|
||||
{
|
||||
char *info = NULL;
|
||||
char buf[] = {"NA"};
|
||||
char *reply;
|
||||
int length = 256;
|
||||
|
||||
pComTask task = (pComTask)data;
|
||||
assert(data != NULL);
|
||||
|
||||
if(task->sendData != NULL){
|
||||
length += strlen(task->sendData);
|
||||
}
|
||||
if(task->replyData != NULL){
|
||||
length += strlen(task->replyData);
|
||||
}
|
||||
info = calloc(length,sizeof(char));
|
||||
if(info == NULL){
|
||||
return info;
|
||||
}
|
||||
if(task->replyData == NULL){
|
||||
reply = buf;
|
||||
} else {
|
||||
reply = task->replyData;
|
||||
}
|
||||
snprintf(info,length,"%s:%s:%lf:%s:%lf", StateToText(task->state),
|
||||
task->sendData,task->startTime, reply, task->endTime);
|
||||
return info;
|
||||
}
|
||||
/*----------------------------------------------------------------*/
|
||||
int StartComTask(ComTaskManager *manager, char *priority, char *sendData)
|
||||
{
|
||||
int ID, i;
|
||||
unsigned int ptr;
|
||||
DevPrio prio;
|
||||
|
||||
assert(manager != NULL && priority != NULL);
|
||||
|
||||
ID = mamaID;
|
||||
mamaID++;
|
||||
if(mamaID < 0){
|
||||
mamaID = 0;
|
||||
}
|
||||
|
||||
if(manager->iPtr >= 2*manager->halfQueueLength){
|
||||
KillComTaskData(manager->TaskQueue,manager->halfQueueLength);
|
||||
memmove(manager->TaskQueue,&manager->TaskQueue[manager->halfQueueLength],
|
||||
manager->halfQueueLength*sizeof(ComTask));
|
||||
/**
|
||||
* The pointers need to be cleared, not freed, in order to
|
||||
* prevent double freeing when reusing them.
|
||||
*/
|
||||
for(i = manager->halfQueueLength; i < 2*manager->halfQueueLength; i++){
|
||||
manager->TaskQueue[i].sendData = NULL;
|
||||
manager->TaskQueue[i].replyData = NULL;
|
||||
}
|
||||
manager->iPtr = manager->halfQueueLength;
|
||||
}
|
||||
ptr = manager->iPtr;
|
||||
manager->iPtr++;
|
||||
|
||||
manager->TaskQueue[ptr].ID = ID;
|
||||
manager->TaskQueue[ptr].startTime = DoubleTime();
|
||||
manager->TaskQueue[ptr].endTime = 0.;
|
||||
manager->TaskQueue[ptr].state = eWaiting;
|
||||
if(manager->TaskQueue[ptr].sendData != NULL){
|
||||
free(manager->TaskQueue[ptr].sendData);
|
||||
}
|
||||
manager->TaskQueue[ptr].sendData = strdup(sendData);
|
||||
if(manager->TaskQueue[ptr].replyData != NULL){
|
||||
free(manager->TaskQueue[ptr].replyData);
|
||||
}
|
||||
manager->TaskQueue[ptr].replyData = NULL;
|
||||
|
||||
prio = DevText2Prio(priority);
|
||||
DevQueue(manager->devser,
|
||||
&manager->TaskQueue[ptr],
|
||||
prio,
|
||||
ComTaskHandler,
|
||||
ComTaskMatch,
|
||||
NULL,
|
||||
ComTaskInfo);
|
||||
|
||||
return ID;
|
||||
}
|
||||
/*-----------------------------------------------------------------*/
|
||||
static int StartComTaskCmd(pSICSOBJ ccmd, SConnection * con,
|
||||
Hdb * cmdNode, Hdb * par[], int nPar)
|
||||
{
|
||||
char *priority, *sendData;
|
||||
int lID;
|
||||
ComTaskManager *manni = NULL;
|
||||
|
||||
if(nPar < 2) {
|
||||
SCWrite(con,"ERROR: need priorty and send data as parameters",eError);
|
||||
return 0;
|
||||
}
|
||||
|
||||
priority = ParText(cmdNode,"priority",nPar,"read");
|
||||
sendData = ParText(cmdNode,"send",nPar,"None");
|
||||
|
||||
manni = (ComTaskManager *)ccmd->pPrivate;
|
||||
lID = StartComTask(manni, priority, sendData);
|
||||
SCPrintf(con,eValue,"comtaskid = %ld", lID);
|
||||
return 1;
|
||||
|
||||
}
|
||||
/*-----------------------------------------------------------------*/
|
||||
static int ComTaskCompare(const void *data1, const void *data2)
|
||||
{
|
||||
pComTask task1 = (pComTask)data1;
|
||||
pComTask task2 = (pComTask)data2;
|
||||
|
||||
assert(task1 && task2);
|
||||
|
||||
if(task1->ID < task2->ID){
|
||||
return -1;
|
||||
} else if(task1->ID > task2->ID){
|
||||
return 1;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
/*------------------------------------------------------------------*/
|
||||
ComTaskState GetComTaskState(ComTaskManager *manager, int comTaskID)
|
||||
{
|
||||
ComTask key;
|
||||
ComTask *task = NULL;
|
||||
|
||||
key.ID = comTaskID;
|
||||
|
||||
task = bsearch(&key,manager->TaskQueue,manager->iPtr,
|
||||
sizeof(ComTask), ComTaskCompare);
|
||||
if(task == NULL){
|
||||
return eUnknown;
|
||||
} else {
|
||||
return task->state;
|
||||
}
|
||||
}
|
||||
/*-----------------------------------------------------------------*/
|
||||
static int GetComTaskStateCmd(pSICSOBJ ccmd, SConnection * con,
|
||||
Hdb * cmdNode, Hdb * par[], int nPar)
|
||||
{
|
||||
int lID;
|
||||
ComTaskManager *manni = NULL;
|
||||
ComTaskState state;
|
||||
|
||||
if(nPar < 1) {
|
||||
SCWrite(con,"ERROR: need task ID parameter",eError);
|
||||
return 0;
|
||||
}
|
||||
lID = par[0]->value.v.intValue;
|
||||
|
||||
manni = (ComTaskManager *)ccmd->pPrivate;
|
||||
state = GetComTaskState(manni,lID);
|
||||
SCPrintf(con,eValue,"%d = %s", lID, StateToText(state));
|
||||
|
||||
|
||||
return 1;
|
||||
}
|
||||
/*------------------------------------------------------------------*/
|
||||
const char *GetComTaskReply(ComTaskManager *manager,
|
||||
int comTaskID, int *length)
|
||||
{
|
||||
ComTask key;
|
||||
ComTask *task = NULL;
|
||||
|
||||
key.ID = comTaskID;
|
||||
|
||||
task = bsearch(&key,manager->TaskQueue,manager->iPtr,
|
||||
sizeof(ComTask), ComTaskCompare);
|
||||
if(task == NULL || task->state != eFinished){
|
||||
return NULL;
|
||||
} else {
|
||||
return (const char *)task->replyData;
|
||||
}
|
||||
}
|
||||
/*-----------------------------------------------------------------*/
|
||||
static int GetComTaskReplyCmd(pSICSOBJ ccmd, SConnection * con,
|
||||
Hdb * cmdNode, Hdb * par[], int nPar)
|
||||
{
|
||||
int lID;
|
||||
int length;
|
||||
ComTaskManager *manni = NULL;
|
||||
const char *reply;
|
||||
|
||||
if(nPar < 1) {
|
||||
SCWrite(con,"ERROR: need task ID parameter",eError);
|
||||
return 0;
|
||||
}
|
||||
lID = par[0]->value.v.intValue;
|
||||
|
||||
manni = (ComTaskManager *)ccmd->pPrivate;
|
||||
reply = GetComTaskReply(manni,lID,&length);
|
||||
if(reply == NULL){
|
||||
SCPrintf(con,eError,"No reply for %ld found", lID);
|
||||
return 0;
|
||||
} else {
|
||||
SCPrintf(con,eValue,"%d = %s", lID, reply);
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
/*------------------------------------------------------------*/
|
||||
void ComTaskWait(ComTaskManager *manager, int comTaskID)
|
||||
{
|
||||
|
||||
ComTask key;
|
||||
ComTask *task = NULL;
|
||||
|
||||
key.ID = comTaskID;
|
||||
|
||||
task = bsearch(&key,manager->TaskQueue,manager->iPtr,
|
||||
sizeof(ComTask), ComTaskCompare);
|
||||
if(task == NULL){
|
||||
return;
|
||||
}
|
||||
/**
|
||||
* Hmmmmhhhh. It might be better to start a SICS task here and
|
||||
* wait for it terminate. But this would essentially also call
|
||||
* TaskYield or, worse, Taskwait.
|
||||
*/
|
||||
while(task->state != eFinished){
|
||||
TaskYield(pServ->pTasker);
|
||||
}
|
||||
}
|
||||
/*-----------------------------------------------------------------*/
|
||||
static int ComTaskWaitCmd(pSICSOBJ ccmd, SConnection * con,
|
||||
Hdb * cmdNode, Hdb * par[], int nPar)
|
||||
{
|
||||
int lID;
|
||||
ComTaskManager *manni = NULL;
|
||||
|
||||
if(nPar < 1) {
|
||||
SCWrite(con,"ERROR: need task ID parameter",eError);
|
||||
return 0;
|
||||
}
|
||||
lID = par[0]->value.v.intValue;
|
||||
|
||||
manni = (ComTaskManager *)ccmd->pPrivate;
|
||||
ComTaskWait(manni,lID);
|
||||
SCWrite(con,"Done",eValue);
|
||||
|
||||
return 1;
|
||||
}
|
||||
/*-----------------------------------------------------------------*/
|
||||
static int ComTaskListAllCmd(pSICSOBJ ccmd, SConnection * con,
|
||||
Hdb * cmdNode, Hdb * par[], int nPar)
|
||||
{
|
||||
ComTaskManager *manni = NULL;
|
||||
pDynString list = NULL;
|
||||
int i;
|
||||
char *info;
|
||||
|
||||
manni = (ComTaskManager *)ccmd->pPrivate;
|
||||
list = CreateDynString(256,256);
|
||||
if(list == NULL){
|
||||
SCWrite(con,"ERROR: out of memory listing ComTasks", eError);
|
||||
return 0;
|
||||
}
|
||||
|
||||
for(i = 0; i < manni->iPtr; i++){
|
||||
info = ComTaskInfo((void *)&manni->TaskQueue[i]);
|
||||
DynStringConcat(list,info);
|
||||
DynStringConcatChar(list,'\n');
|
||||
free(info);
|
||||
}
|
||||
SCWrite(con,GetCharArray(list),eValue);
|
||||
DeleteDynString(list);
|
||||
|
||||
return 1;
|
||||
}
|
||||
/*--------------------------------------------------------------------*/
|
||||
static int ComTaskListPendingCmd(pSICSOBJ ccmd, SConnection * con,
|
||||
Hdb * cmdNode, Hdb * par[], int nPar)
|
||||
{
|
||||
ComTaskManager *manni = NULL;
|
||||
pDynString list = NULL;
|
||||
int i;
|
||||
char *info;
|
||||
|
||||
manni = (ComTaskManager *)ccmd->pPrivate;
|
||||
list = CreateDynString(256,256);
|
||||
if(list == NULL){
|
||||
SCWrite(con,"ERROR: out of memory listing ComTasks", eError);
|
||||
return 0;
|
||||
}
|
||||
|
||||
for(i = 0; i < manni->iPtr; i++){
|
||||
if(manni->TaskQueue[i].state != eFinished){
|
||||
info = ComTaskInfo((void *)&manni->TaskQueue[i]);
|
||||
DynStringConcat(list,info);
|
||||
DynStringConcatChar(list,'\n');
|
||||
free(info);
|
||||
}
|
||||
}
|
||||
SCWrite(con,GetCharArray(list),eValue);
|
||||
DeleteDynString(list);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
/*-----------------------------------------------------------------*/
|
||||
static ComTaskManager *MakeComTaskManager(int length)
|
||||
{
|
||||
ComTaskManager *manni = NULL;
|
||||
manni = calloc(1, sizeof(ComTaskManager));
|
||||
if(manni != NULL){
|
||||
manni->halfQueueLength=length;
|
||||
manni->TaskQueue = calloc(length*2,sizeof(ComTask));
|
||||
if(manni->TaskQueue == NULL){
|
||||
free(manni);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
return manni;
|
||||
}
|
||||
/*-----------------------------------------------------------------*/
|
||||
static void KillComTaskManager(void *data)
|
||||
{
|
||||
ComTaskManager *manni = (ComTaskManager *)data;
|
||||
|
||||
if(manni == NULL){
|
||||
return;
|
||||
}
|
||||
|
||||
if(manni->TaskQueue != NULL){
|
||||
free(manni->TaskQueue);
|
||||
}
|
||||
KillComTaskData(manni->TaskQueue,manni->halfQueueLength*2);
|
||||
free(manni);
|
||||
|
||||
}
|
||||
/*-----------------------------------------------------------------*/
|
||||
int SctMakeComTask(SConnection * con, SicsInterp * sics,
|
||||
void *object, int argc, char *argv[])
|
||||
{
|
||||
SICSOBJ *ccmd;
|
||||
pHdb cmd = NULL;
|
||||
ComTaskManager *manni = NULL;
|
||||
int length = 64;
|
||||
|
||||
if (argc < 3) {
|
||||
SCWrite(con,"ERROR: need at least comtaskmanager name and sctcontroller as arguments",
|
||||
eError);
|
||||
return 0;
|
||||
}
|
||||
|
||||
ccmd = (SICSOBJ *)FindCommandData(sics,argv[2],"SctController");
|
||||
if(ccmd == NULL){
|
||||
SCPrintf(con,eError,"ERROR: SctController %s not found",argv[2]);
|
||||
return 0;
|
||||
}
|
||||
|
||||
if(argc > 3) {
|
||||
length = atoi(argv[3]);
|
||||
}
|
||||
|
||||
manni = MakeComTaskManager(length);
|
||||
if(manni == NULL){
|
||||
SCWrite(con,"ERROR: out of memory allocating ComTaskmanager",eError);
|
||||
return 0;
|
||||
}
|
||||
manni->devser = SctGetDevser(ccmd);
|
||||
assert(manni->devser != NULL);
|
||||
|
||||
ccmd = MakeSICSOBJv(argv[1], "SctComTask", HIPNONE, usSpy);
|
||||
assert(ccmd);
|
||||
ccmd->pPrivate = manni;
|
||||
ccmd->KillPrivate = KillComTaskManager;
|
||||
|
||||
AddCommand(pServ->pSics, argv[1], InterInvokeSICSOBJ, KillSICSOBJ, ccmd);
|
||||
RegisterSICSOBJKillCmd(ccmd, argv[1]);
|
||||
SetDescriptorKey(ccmd->pDes, "creationCommand", "0");
|
||||
|
||||
cmd = AddSICSHdbPar(ccmd->objectNode,
|
||||
"start", usUser, MakeSICSFunc(StartComTaskCmd));
|
||||
AddSICSHdbPar(cmd, "priority", usUser, MakeHdbText(""));
|
||||
AddSICSHdbPar(cmd, "send", usUser, MakeHdbText("None"));
|
||||
|
||||
cmd = AddSICSHdbPar(ccmd->objectNode,
|
||||
"state", usUser, MakeSICSFunc(GetComTaskStateCmd));
|
||||
AddSICSHdbPar(cmd, "id", usUser, MakeHdbInt(0));
|
||||
|
||||
cmd = AddSICSHdbPar(ccmd->objectNode,
|
||||
"reply", usUser, MakeSICSFunc(GetComTaskReplyCmd));
|
||||
AddSICSHdbPar(cmd, "id", usUser, MakeHdbInt(0));
|
||||
|
||||
cmd = AddSICSHdbPar(ccmd->objectNode,
|
||||
"wait", usUser, MakeSICSFunc(ComTaskWaitCmd));
|
||||
AddSICSHdbPar(cmd, "id", usUser, MakeHdbInt(0));
|
||||
|
||||
cmd = AddSICSHdbPar(ccmd->objectNode,
|
||||
"listall", usSpy, MakeSICSFunc(ComTaskListAllCmd));
|
||||
|
||||
cmd = AddSICSHdbPar(ccmd->objectNode,
|
||||
"listpend", usSpy, MakeSICSFunc(ComTaskListPendingCmd));
|
||||
|
||||
|
||||
return 1;
|
||||
}
|
||||
/*-------------------------------------------------------------------------------*/
|
Reference in New Issue
Block a user