495 lines
15 KiB
C
495 lines
15 KiB
C
/**
|
|
* This is the SICS interface object to the tasker module
|
|
*
|
|
* copyright: GPL
|
|
*
|
|
* Mark Koennecke, December 2012
|
|
*/
|
|
#include <sics.h>
|
|
#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);
|
|
|
|
}
|