/** * This is the SICS interface object to the tasker module * * copyright: GPL * * Mark Koennecke, December 2012 */ #include #include "sicsobj.h" #include "sicshipadaba.h" #include "stptok.h" #include "macro.h" typedef struct { char *scriptName; SConnection *con; } TclFunc, *pTclFunc; /*-------------------------------------------------------------------------*/ void TaskObjLogFunc(eTaskLogLevel lvl, const char *buf) { unsigned int severity; switch (lvl) { case eTaskLogNone: return; case eTaskLogInfo: severity = INFO; break; case eTaskLogDebug: severity = DEBUG; break; case eTaskLogWarning: severity = WARN; break; case eTaskLogError: severity = ERROR; break; case eTaskLogFatal: severity = FATAL; break; default: severity = DEBUG; break; } Log(severity, "task","%s",(char *)buf); return; } /*-------------------------------------------------------------------------*/ static int ListCmd(pSICSOBJ self, SConnection *pCon, pHdb commandNode, pHdb par[], int nPar) { pDynString result = NULL; char buffer[256], *pDes, *pPtr, name[80], time[80], id[80], gid[80]; pTaskHead it = NULL; result = CreateDynString(128,128); if(result == NULL){ SCWrite(pCon,"ERROR: out of memory in ListCmd", eError); return 0; } snprintf(buffer,sizeof(buffer),"%20s %20s %12s", "Task", "Start_Time", "ID"); DynStringConcat(result,buffer); DynStringConcatChar(result,'\n'); for(it = TaskIteratorStart(pServ->pTasker); it != NULL; it = TaskIteratorNext(it)){ pDes = TaskDescription(it); if(pDes != NULL){ pPtr = stptok(pDes,name,sizeof(name),"|"); pPtr = stptok(pPtr,time,sizeof(time),"|"); pPtr = stptok(pPtr,id,sizeof(id),"|"); pPtr = stptok(pPtr,gid,sizeof(gid),"|"); snprintf(buffer,sizeof(buffer),"%20s %20s %12s %10s", name,time,id,gid); DynStringConcat(result,buffer); DynStringConcatChar(result,'\n'); free(pDes); } } SCWrite(pCon,GetCharArray(result),eValue); DeleteDynString(result); return 1; } /*-------------------------------------------------------------------------*/ static int PerfCmd(pSICSOBJ self, SConnection *pCon, pHdb commandNode, pHdb par[], int nPar) { pDynString result = NULL; char buffer[256], *pDes, *pPtr, name[80]; char runs[80], waits[80], yields[80], cpu[80], wall[80], yield[80]; pTaskHead it = NULL; result = CreateDynString(128,128); if(result == NULL){ SCWrite(pCon,"ERROR: out of memory in PerfCmd", eError); return 0; } snprintf(buffer,sizeof(buffer),"%18s %16s %16s %16s %16s %16s %16s", "Task", "Runs", "Waits", "Yields", "Processor", "Elapsed", "Yield"); DynStringConcat(result,buffer); DynStringConcatChar(result,'\n'); for(it = TaskIteratorStart(pServ->pTasker); it != NULL; it = TaskIteratorNext(it)){ pDes = TaskDetail(it); if(pDes != NULL){ pPtr = stptok(pDes,name,sizeof(name),"|"); pPtr = stptok(pPtr,runs,sizeof(runs),"|"); pPtr = stptok(pPtr,waits,sizeof(waits),"|"); pPtr = stptok(pPtr,yields,sizeof(yields),"|"); pPtr = stptok(pPtr,cpu,sizeof(cpu),"|"); pPtr = stptok(pPtr,wall,sizeof(wall),"|"); pPtr = stptok(pPtr,yield,sizeof(yield),"|"); snprintf(buffer,sizeof(buffer),"%18s %16s %16s %16s %16s %16s %16s", name,runs,waits,yields,cpu,wall,yield); DynStringConcat(result,buffer); DynStringConcatChar(result,'\n'); free(pDes); } } SCWrite(pCon,GetCharArray(result),eValue); DeleteDynString(result); return 1; } /*----------------------------------------------------------------------*/ static int StackCmd(pSICSOBJ self, SConnection *pCon, pHdb commandNode, pHdb par[], int nPar) { pDynString result = NULL; char buffer[256], *pDes, *pPtr, name[80]; char runs[80], waits[80], yields[80], cpu[80], wall[80], yield[80]; pTaskHead it = NULL; pTaskHead *stack = NULL; int i, stackDepth; result = CreateDynString(128,128); if(result == NULL){ SCWrite(pCon,"ERROR: out of memory in StackCmd", eError); return 0; } snprintf(buffer,sizeof(buffer),"%18s %16s %16s %16s %16s %16s %16s", "Task", "Runs", "Waits", "Yields", "Processor", "Elapsed", "Yield"); DynStringConcat(result,buffer); DynStringConcatChar(result,'\n'); stackDepth = TaskGetStack(pServ->pTasker, NULL); if (stackDepth <= 0) { SCWrite(pCon,"No task stack", eValue); DeleteDynString(result); return 0; } stack = calloc(stackDepth, sizeof(pTaskHead)); if (stack == NULL) { SCWrite(pCon,"ERROR: out of memory in StackCmd", eError); DeleteDynString(result); return 0; } stackDepth = TaskGetStack(pServ->pTasker, stack); for (i = 0; i < stackDepth; ++i) { it = stack[i]; pDes = TaskDetail(it); if(pDes != NULL){ pPtr = stptok(pDes,name,sizeof(name),"|"); pPtr = stptok(pPtr,runs,sizeof(runs),"|"); pPtr = stptok(pPtr,waits,sizeof(waits),"|"); pPtr = stptok(pPtr,yields,sizeof(yields),"|"); pPtr = stptok(pPtr,cpu,sizeof(cpu),"|"); pPtr = stptok(pPtr,wall,sizeof(wall),"|"); pPtr = stptok(pPtr,yield,sizeof(yield),"|"); snprintf(buffer,sizeof(buffer),"%18s %16s %16s %16s %16s %16s %16s", name,runs,waits,yields,cpu,wall,yield); DynStringConcat(result,buffer); DynStringConcatChar(result,'\n'); free(pDes); } } SCWrite(pCon,GetCharArray(result),eValue); DeleteDynString(result); free(stack); return 1; } /*----------------------------------------------------------------------*/ static int KillCmd(pSICSOBJ self, SConnection *pCon, pHdb commandNode, pHdb par[], int nPar) { int status; if(nPar < 1){ SCWrite(pCon,"ERROR: need name of task to stop", eError); return 0; } if(!SCMatchRights(pCon,usMugger)){ return 0; } status = StopTask(pServ->pTasker,par[0]->value.v.text); if(status == 0) { SCWrite(pCon,"ERROR: cannot commit suicide!", eError); return 0; } SCSendOK(pCon); return 1; } /*----------------------------------------------------------------------*/ static int InfoCmd(pSICSOBJ self, SConnection *pCon, pHdb commandNode, pHdb par[], int nPar) { char buffer[256]; char *pArgs = NULL, *pPtr; char task_task[20], task_name[80], task_info[80]; pTaskHead it = NULL; if (nPar < 1) { SCWrite(pCon,"Info.args: NULL", eError); return 0; } if (!SCMatchRights(pCon,usMugger)) { return 0; } pArgs = par[0]->value.v.text; pPtr = pArgs; while (pPtr && *pPtr == '/') ++pPtr; pPtr = stptok(pPtr, task_task, sizeof(task_task), "/"); if (strcasecmp(task_task, "task") != 0) { SCPrintf(pCon, eError, "ERROR: task info must start with /task/, not %s in %s", task_task, pArgs); return 0; } while (pPtr && *pPtr == '/') ++pPtr; pPtr = stptok(pPtr, task_name, sizeof(task_name), "/"); while (pPtr && *pPtr == '/') ++pPtr; if (strcasecmp(task_name, "count") == 0) { int count = 0; for(it = TaskIteratorStart(pServ->pTasker); it != NULL; it = TaskIteratorNext(it)){ ++count; } SCPrintf(pCon, eValue, "Task.Count = %d", count); return 1; } else if (strcasecmp(task_name, "list") == 0) { int count = 0; pDynString result = CreateDynString(100, 100); char txt[80], *pDes; for(it = TaskIteratorStart(pServ->pTasker); it != NULL; it = TaskIteratorNext(it)) { pDes = TaskDescription(it); if (pDes != NULL) { char buffer[256], *pPtr, name[80], time[80], id[80], gid[80]; pPtr = stptok(pDes,name,sizeof(name),"|"); pPtr = stptok(pPtr,time,sizeof(time),"|"); pPtr = stptok(pPtr,id,sizeof(id),"|"); snprintf(buffer,sizeof(buffer),"%s", id); if (count++ > 0) DynStringConcatChar(result,' '); DynStringConcat(result, buffer); free(pDes); } } SCWrite(pCon,GetCharArray(result), eValue); DeleteDynString(result); return 1; } else if (strcasecmp(task_name, "current") == 0) { it = TaskIteratorCurrent(pServ->pTasker); } else if (strcasecmp(task_name, "by-id") == 0) { pPtr = stptok(pPtr, task_name, sizeof(task_name), "/"); while (*pPtr == '/') ++pPtr; it = TaskIteratorByID(pServ->pTasker, atol(task_name)); } else if (strcasecmp(task_name, "by-name") == 0) { pPtr = stptok(pPtr, task_name, sizeof(task_name), "/"); while (*pPtr == '/') ++pPtr; it = TaskIteratorByName(pServ->pTasker, task_name); } else { SCPrintf(pCon, eError, "ERROR: expected current, by-name or by-id in %s", pArgs); return 0; } if (it == NULL) { SCPrintf(pCon, eError, "ERROR: task not found in %s", pArgs); return 0; } pPtr = stptok(pPtr, task_info, sizeof(task_info), "/"); if (strcasecmp(task_info, "all") == 0) { char *pDet, *pDes; pDes = TaskDescription(it); pDet = TaskDetail(it); SCPrintf(pCon, eValue, "%s %s", pDes, pDet); free(pDes); free(pDet); } else { SCPrintf(pCon, eLog, "Info.args: %s", par[0]->value.v.text); } return 1; } /*----------------------------------------------------------------------*/ static int LogCmd(pSICSOBJ self, SConnection *pCon, pHdb commandNode, pHdb par[], int nPar) { if (nPar < 1) { SCWrite(pCon,"ERROR: need log level (none,debug,info,warning,error,fatal)", eError); return 0; } if (!SCMatchRights(pCon,usMugger)) { return 0; } if (strcasecmp("None", par[0]->value.v.text) == 0) { TaskSetLogLevel(eTaskLogNone); } else if (strcasecmp("Debug", par[0]->value.v.text) == 0) { TaskSetLogLevel(eTaskLogDebug); } else if (strcasecmp("Info", par[0]->value.v.text) == 0) { TaskSetLogLevel(eTaskLogInfo); } else if (strcasecmp("Warning", par[0]->value.v.text) == 0) { TaskSetLogLevel(eTaskLogWarning); } else if (strcasecmp("Error", par[0]->value.v.text) == 0) { TaskSetLogLevel(eTaskLogError); } else if (strcasecmp("Fatal", par[0]->value.v.text) == 0) { TaskSetLogLevel(eTaskLogFatal); } TaskSetLogFunc((TaskLogFunc) TaskObjLogFunc); SCSendOK(pCon); return 1; } /*--------------------------------------------------------------------*/ static int TclTaskFunction(void *pData) { int retVal, status ; Tcl_Interp *pTcl; pTclFunc self = (pTclFunc)pData; assert(self != NULL); pTcl = InterpGetTcl(pServ->pSics); assert(pTcl != NULL); MacroPush(self->con); status = Tcl_Eval(pTcl, self->scriptName); MacroPop(); /* traceSys("task","Executed %s with results %d and %s",self->scriptName, status, Tcl_GetStringResult(pTcl)); */ if(status == 0){ retVal = atoi(Tcl_GetStringResult(pTcl)); } else { return 1; } return retVal; } /*--------------------------------------------------------------------*/ static void KillTclFunc(void *pData) { pTclFunc self = (pTclFunc)pData; if(self == NULL){ return; } if(self->scriptName){ free(self->scriptName); } if(self->con) { SCDeleteConnection(self->con); } free(self); } /*------------------------------------------------------------------*/ static void TclFuncSignal(void *pData, int iSignal, void *pSigData) { int *iInt; pTclFunc self = NULL; self = (pTclFunc) pData; assert(self); if (iSignal == SICSINT) { iInt = (int *) pSigData; SCSetInterrupt(self->con,*iInt); } } /*----------------------------------------------------------------------*/ static int RunCmd(pSICSOBJ self, SConnection *pCon, pHdb commandNode, pHdb par[], int nPar) { pTclFunc data = NULL; if(nPar < 1) { SCWrite(pCon,"ERROR: need the name of a script to run",eError); return 0; } data = malloc(sizeof(TclFunc)); if(data == NULL){ SCWrite(pCon,"ERROR: out of memory in RunCmd",eError); return 0; } memset(data,0,sizeof(TclFunc)); data->con = SCCreateDummyConnection(pServ->pSics); data->scriptName = strdup(par[0]->value.v.text); TaskRegisterN(pServ->pTasker, data->scriptName, TclTaskFunction, TclFuncSignal, KillTclFunc, data, TASK_PRIO_HIGH); traceSys("task","Started task %s",data->scriptName); SCSendOK(pCon); return 1; } /*--------------------------------------------------------------------*/ int TaskOBJFactory(SConnection *pCon, SicsInterp *pSics, void *pData, int argc, char *argv[]) { pSICSOBJ pNew = NULL; pHdb cmd = NULL, node; pNew = SetupSICSOBJ(pCon,pSics,pData,argc,argv); if(pNew == NULL){ return 0; } cmd = AddSICSHdbPar(pNew->objectNode, "ps", usSpy, MakeSICSFunc(ListCmd)); cmd = AddSICSHdbPar(pNew->objectNode, "perf", usSpy, MakeSICSFunc(PerfCmd)); cmd = AddSICSHdbPar(pNew->objectNode, "kill", usSpy, MakeSICSFunc(KillCmd)); SetHdbProperty(cmd,"type","command"); SetHdbProperty(cmd,"priv","spy"); node = MakeSICSHdbPar("task",usSpy,MakeHdbText("banana")); AddHipadabaChild(cmd,node,NULL); cmd = AddSICSHdbPar(pNew->objectNode, "run", usSpy, MakeSICSFunc(RunCmd)); SetHdbProperty(cmd,"type","command"); SetHdbProperty(cmd,"priv","spy"); node = MakeSICSHdbPar("script",usSpy,MakeHdbText("banana")); AddHipadabaChild(cmd,node,NULL); return 1; } /*-------------------------------------------------------------------*/ void InitTaskOBJ() { pSICSOBJ pNew = NULL; pHdb cmd = NULL, node; pNew = MakeSICSOBJv("task", "TaskOBJ", HIPNONE, usInternal); if (pNew == NULL) { SCWrite(pServ->dummyCon, "ERROR: out of memory creating new SICS object", eError); return; } cmd = AddSICSHdbPar(pNew->objectNode, "ps", usSpy, MakeSICSFunc(ListCmd)); cmd = AddSICSHdbPar(pNew->objectNode, "perf", usSpy, MakeSICSFunc(PerfCmd)); cmd = AddSICSHdbPar(pNew->objectNode, "stack", usSpy, MakeSICSFunc(StackCmd)); cmd = AddSICSHdbPar(pNew->objectNode, "info", usSpy, MakeSICSFunc(InfoCmd)); SetHdbProperty(cmd,"type","command"); SetHdbProperty(cmd,"priv","spy"); node = MakeSICSHdbPar("args",usSpy,MakeHdbText("banana")); AddHipadabaChild(cmd,node,NULL); cmd = AddSICSHdbPar(pNew->objectNode, "log", usSpy, MakeSICSFunc(LogCmd)); SetHdbProperty(cmd,"type","command"); SetHdbProperty(cmd,"priv","spy"); node = MakeSICSHdbPar("level",usSpy,MakeHdbText("banana")); AddHipadabaChild(cmd,node,NULL); cmd = AddSICSHdbPar(pNew->objectNode, "kill", usSpy, MakeSICSFunc(KillCmd)); SetHdbProperty(cmd,"type","command"); SetHdbProperty(cmd,"priv","spy"); node = MakeSICSHdbPar("task",usSpy,MakeHdbText("banana")); AddHipadabaChild(cmd,node,NULL); cmd = AddSICSHdbPar(pNew->objectNode, "run", usSpy, MakeSICSFunc(RunCmd)); SetHdbProperty(cmd,"type","command"); SetHdbProperty(cmd,"priv","spy"); node = MakeSICSHdbPar("script",usSpy,MakeHdbText("banana")); AddHipadabaChild(cmd,node,NULL); AddCommand(pServ->pSics, "task", InterInvokeSICSOBJ, KillSICSOBJ, pNew); }