From 64b212c4a0cede68d383279b5c78585f7614f3ec Mon Sep 17 00:00:00 2001 From: Ferdi Franceschini Date: Fri, 24 Apr 2015 13:36:59 +1000 Subject: [PATCH 1/4] Resolved a conflict that was missed during 'git merge' conflict resolution. --- drive.c | 33 +-------------------------------- 1 file changed, 1 insertion(+), 32 deletions(-) diff --git a/drive.c b/drive.c index f0554a96..4f6f5118 100644 --- a/drive.c +++ b/drive.c @@ -39,7 +39,6 @@ #include #include #include -#include #include "fortify.h" #include "sics.h" #include "drive.h" @@ -302,11 +301,7 @@ int DriveWrapper(SConnection * pCon, SicsInterp * pSics, void *pData, return 0; } -<<<<<<< HEAD - /* interpret arguments as pairs (name, value) and check */ -======= - /* interprete arguments as pairs name value and try to start */ ->>>>>>> master + /* interpret arguments as pairs (name, value) and try to start */ for (i = 1; i < argc; i += 2) { if (argv[i + 1] == NULL) { snprintf(pBueffel, 511, "ERROR: no value found for driving %s", argv[i]); @@ -316,25 +311,7 @@ int DriveWrapper(SConnection * pCon, SicsInterp * pSics, void *pData, iRet = Tcl_GetDouble(tcl_interp, argv[i + 1], &dTarget); if (iRet == TCL_ERROR) { SCWrite(pCon, Tcl_GetStringResult(tcl_interp), eError); -<<<<<<< HEAD - SetStatus(eOld); - return 0; - } else if (!isfinite(dTarget)) { - snprintf(pBueffel, 511, - "ERROR: target %s value for %s is not a finite number", - argv[i + 1], argv[i]); - SCWrite(pCon, pBueffel, eError); - return 0; - } - } - /* interpret arguments as pairs (name, value) and try to start */ - for (i = 1; i < argc; i += 2) { - iRet = Tcl_GetDouble(tcl_interp, argv[i + 1], &dTarget); - if (iRet == TCL_ERROR) { - SCWrite(pCon, Tcl_GetStringResult(tcl_interp), eError); -======= StopExe(GetExecutor(), "ALL"); ->>>>>>> master return 0; } iRet = Start2Run(pCon, pSics, argv[i], RUNDRIVE, dTarget); @@ -377,11 +354,7 @@ int DriveWrapper(SConnection * pCon, SicsInterp * pSics, void *pData, ClearExecutor(GetExecutor()); return 0; } -<<<<<<< HEAD SCWrite(pCon, "Driving finished successfully", eValue); -======= - SCWrite(pCon, "Driving finished sucessfully", eValue); ->>>>>>> master return 1; } @@ -418,11 +391,7 @@ int RunWrapper(SConnection * pCon, SicsInterp * pSics, void *pData, return 0; } -<<<<<<< HEAD /* interpret arguments as pairs name value and try to start */ -======= - /* interprete arguments as pairs name value and try to start */ ->>>>>>> master for (i = 1; i < argc; i += 2) { if (argv[i + 1] == NULL) { snprintf(pBueffel,511, "ERROR: no value found for driving %s", argv[i]); From 7ccbf7e0bd43cfd90b6acac80b0e661795992e82 Mon Sep 17 00:00:00 2001 From: Douglas Clowes Date: Wed, 29 Jul 2015 17:46:34 +1000 Subject: [PATCH 2/4] Change LLDstringDelete to LLDdeleteString --- SCinter.c | 2 +- lld_str.h | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/SCinter.c b/SCinter.c index 1d5cd1a4..87695dc8 100644 --- a/SCinter.c +++ b/SCinter.c @@ -1035,7 +1035,7 @@ static void printList(SConnection * pCon, int listID) static void freeList(int listID) { do { - LLDstringDelete(listID); + LLDdeleteString(listID); } while (0 != LLDnodePtr2First(listID)); LLDdelete(listID); } diff --git a/lld_str.h b/lld_str.h index 61280471..a3274759 100644 --- a/lld_str.h +++ b/lld_str.h @@ -21,6 +21,8 @@ #define LLDstringCreate() LLDblobCreate() +#define LLDdeleteString(l) LLDdeleteBlob(l) + #define LLDstringInsert(l,s) LLDblobInsert( l, s, strlen( s ) +1 ) #define LLDstringAdd(l,s) LLDblobAdd( l, s, strlen( s ) +1 ) From 0db57b9baecec5b04a07c4cc95de90f638b261d8 Mon Sep 17 00:00:00 2001 From: Douglas Clowes Date: Wed, 29 Jul 2015 17:47:15 +1000 Subject: [PATCH 3/4] Reference count async queue transactions so we can put them of task message queues --- asyncprotocol.h | 1 + asyncqueue.c | 53 +++++++++++++++++++++++++++++++++++-------------- asyncqueue.h | 10 ++++++++++ 3 files changed, 49 insertions(+), 15 deletions(-) diff --git a/asyncprotocol.h b/asyncprotocol.h index 5e79e968..24549ad3 100644 --- a/asyncprotocol.h +++ b/asyncprotocol.h @@ -33,6 +33,7 @@ typedef enum { #define AQU_POP_CMD -5 struct __async_txn { + int ref_counter; /**< reference counter (reference counted object) */ pAsyncUnit unit; /**< unit that transaction is associated with */ int txn_state; /**< protocol handler transaction parse state */ ATX_STATUS txn_status; /**< status of the transaction OK, Error, ... */ diff --git a/asyncqueue.c b/asyncqueue.c index e1a91337..fc075718 100644 --- a/asyncqueue.c +++ b/asyncqueue.c @@ -89,27 +89,36 @@ static const char *state_name(AsyncState the_state) return ""; } +/* + * Free the transaction and buffers + */ +static void free_transaction(pAsyncTxn myTxn) +{ + if (myTxn) { + if (--myTxn->ref_counter > 0) + return; + /* + * Allow kill_private to clean it all if it wants + */ + if (myTxn->kill_private) + myTxn->kill_private(myTxn); + if (myTxn->out_buf) + free(myTxn->out_buf); + if (myTxn->inp_buf) + free(myTxn->inp_buf); + if (myTxn->proto_private) + free(myTxn->proto_private); + free(myTxn); + } +} + /* * Free the command and transaction structures and their contents */ static void free_command(pAQ_Cmd myCmd) { if (myCmd) { - pAsyncTxn myTxn = myCmd->tran; - if (myTxn) { - /* - * Allow kill_private to clean it all if it wants - */ - if (myTxn->kill_private) - myTxn->kill_private(myTxn); - if (myTxn->out_buf) - free(myTxn->out_buf); - if (myTxn->inp_buf) - free(myTxn->inp_buf); - if (myTxn->proto_private) - free(myTxn->proto_private); - free(myTxn); - } + free_transaction(myCmd->tran); free(myCmd); } } @@ -735,9 +744,23 @@ pAsyncTxn AsyncUnitPrepareTxn(pAsyncUnit unit, myTxn->unit = unit; myTxn->handleResponse = callback; myTxn->cntx = context; + myTxn->ref_counter = 1; return myTxn; } +pAsyncTxn AsyncUnitHoldTxn(pAsyncTxn txn) +{ + if (txn) + txn->ref_counter++; + return txn; +} + +void AsyncUnitFreeTxn(pAsyncTxn txn) +{ + if (txn) + free_transaction(txn); +} + int AsyncUnitSendTxn(pAsyncUnit unit, const char *command, int cmd_len, AsyncTxnHandler callback, void *context, int rsp_len) diff --git a/asyncqueue.h b/asyncqueue.h index 669916c3..7ae70579 100644 --- a/asyncqueue.h +++ b/asyncqueue.h @@ -75,6 +75,16 @@ pAsyncTxn AsyncUnitPrepareTxn(pAsyncUnit unit, AsyncTxnHandler responseHandler, void *context, int rsp_len); +/** \brief clone a pointer to the transaction - must use AsyncUnitFreeTxn + * \param txn the transaction to clone + */ +pAsyncTxn AsyncUnitHoldTxn(pAsyncTxn txn); + +/** \brief free a cloned transaction + * \param txn the transaction to free (returned by AsyncUnitHoldTxn) + */ +void AsyncUnitFreeTxn(pAsyncTxn txn); + /** \brief prepare and queue a transaction * * \param unit AsyncUnit From eff54a5fd97dfb2016360b4d38f19818e90b6d47 Mon Sep 17 00:00:00 2001 From: Douglas Clowes Date: Wed, 29 Jul 2015 17:47:46 +1000 Subject: [PATCH 4/4] Implement task priorities and message queues --- background.c | 6 +- commandlog.c | 2 +- conman.c | 10 +- devexec.c | 3 +- devser.c | 2 +- diffscan.c | 2 +- interface.c | 4 +- nread.c | 16 +- nserver.c | 17 +- nxupdate.c | 2 +- oscillate.c | 2 +- remob.c | 2 +- scriptcontext.c | 4 +- serialwait.c | 2 +- sicscron.c | 2 +- sicsexit.c | 2 +- sicspoll.c | 2 +- sicspoll.tc | 2 +- status.c | 2 +- statusfile.c | 6 +- task.c | 1014 ++++++++++++++++++++++++++++++++++++++++------- task.h | 280 ++++++++++--- taskobj.c | 304 +++++++++++++- trace.c | 21 +- 24 files changed, 1440 insertions(+), 269 deletions(-) diff --git a/background.c b/background.c index 6adac099..70b142a4 100644 --- a/background.c +++ b/background.c @@ -28,6 +28,7 @@ static void KillBckTask(void *data) if (self->command) { free(self->command); } + free(self); } /*---------------------------------------------------------------------------*/ @@ -44,6 +45,7 @@ static int BackgroundTask(void *data) /*----------------------------------------------------------------------------*/ int BackgroundCommand(SConnection * pCon, char *command) { + long lID; pBckTask self = NULL; self = calloc(1, sizeof(BckTask)); @@ -58,7 +60,8 @@ int BackgroundCommand(SConnection * pCon, char *command) return 0; } - TaskRegisterN(pServ->pTasker, self->command, BackgroundTask, NULL, KillBckTask, self, 1); + lID = TaskRegisterN(pServ->pTasker, self->command, BackgroundTask, NULL, KillBckTask, self, TASK_PRIO_LOW); + SCPrintf(pCon, eValue, "bg = %ld", lID); return 1; } @@ -76,7 +79,6 @@ int BackgroundAction(SConnection * pCon, SicsInterp * pSics, SCWrite(pCon, "ERROR: out of memory starting task", eError); return 0; } - SCSendOK(pCon); return 1; } diff --git a/commandlog.c b/commandlog.c index 64b5c896..06d5bd54 100644 --- a/commandlog.c +++ b/commandlog.c @@ -491,7 +491,7 @@ int CommandLog(SConnection * pCon, SicsInterp * pSics, void *pData, SCWrite(pCon, "ERROR: autologging is already active", eError); return 0; } - TaskRegisterN(pServ->pTasker, "autologger", AutoTask, NULL, NULL, NULL, 1); + TaskRegisterN(pServ->pTasker, "autologger", AutoTask, NULL, NULL, NULL, TASK_PRIO_HIGH); SCSendOK(pCon); iAutoActive = 1; return 1; diff --git a/conman.c b/conman.c index 49fa8e03..e4a1234d 100644 --- a/conman.c +++ b/conman.c @@ -452,7 +452,10 @@ SConnection *SCCopyConnection(SConnection * pCon) result->iMacro = pCon->iMacro; result->iTelnet = pCon->iTelnet; result->iOutput = pCon->iOutput; - result->write = pCon->write; + if (pCon->oldWriteFunc != NULL) + result->write = pCon->oldWriteFunc; + else + result->write = pCon->write; result->listening = pCon->listening; result->eInterrupt = pCon->eInterrupt; result->inUse = pCon->inUse; @@ -467,7 +470,6 @@ SConnection *SCCopyConnection(SConnection * pCon) result->contextStack = -1; result->iList = -1; result->runLevel = pCon->runLevel; - result->data = pCon->data; return result; } @@ -2272,7 +2274,7 @@ int LogCapture(SConnection * pCon, SicsInterp * pSics, void *pData, if (code_bits & (1 << i)) { if (GetDynStringLength(buffer) > 0) DynStringConcatChar(buffer, ','); - DynStringConcat(buffer, OutCodeToTxt(i)); + DynStringConcat(buffer, (char *)OutCodeToTxt(i)); } } SCPrintf(pCon, eLog, "getlog %s", GetCharArray(buffer)); @@ -2291,7 +2293,7 @@ int LogCapture(SConnection * pCon, SicsInterp * pSics, void *pData, if (code_bits & (1 << i)) { if (GetDynStringLength(buffer) > 0) DynStringConcatChar(buffer, ','); - DynStringConcat(buffer, OutCodeToTxt(i)); + DynStringConcat(buffer, (char *)OutCodeToTxt(i)); } } SCPrintf(pCon, eLog, "getlog %s", GetCharArray(buffer)); diff --git a/devexec.c b/devexec.c index 0cc9268f..e1f3e7b5 100644 --- a/devexec.c +++ b/devexec.c @@ -250,7 +250,6 @@ int StartDevice(pExeList self, char *name, pObjectDescriptor pDes, char *overwriteOption; float oldVal; long taskID; - pTaskGroupData taskGroup = NULL; assert(self); assert(pDes); @@ -329,7 +328,7 @@ int StartDevice(pExeList self, char *name, pObjectDescriptor pDes, self->lTask = TaskRegisterN(self->pTask,"devexec", DevExecTask, DevExecSignal, - NULL, self,1); + NULL, self,TASK_PRIO_HIGH); } pCon->conStatus = HWBusy; return 1; diff --git a/devser.c b/devser.c index fc1f90b2..60908d6c 100644 --- a/devser.c +++ b/devser.c @@ -311,7 +311,7 @@ DevSer *DevMake(SConnection * con, int argc, char *argv[]) devser->status = AsconUnconnected; devser->startTime = -1; TaskRegisterN(pServ->pTasker, AsconHostport(ascon), - DevQueueTask, NULL, NULL, devser, 0); + DevQueueTask, NULL, NULL, devser, TASK_PRIO_HIGH); return devser; } diff --git a/diffscan.c b/diffscan.c index 87e1b616..a696b6ae 100644 --- a/diffscan.c +++ b/diffscan.c @@ -475,7 +475,7 @@ int RunDiffScan(pDiffScan self, pScanData pScan, InvokeCallBack(self->scanObject->pCall, SCANSTART, self->scanObject); - lID = TaskRegisterN(pServ->pTasker,"diffscan", DiffScanTask, NULL, NULL, self, 10); + lID = TaskRegisterN(pServ->pTasker,"diffscan", DiffScanTask, NULL, NULL, self, TASK_PRIO_HIGH); TaskWait(pServ->pTasker, lID); diff --git a/interface.c b/interface.c index d661b2c3..48807701 100644 --- a/interface.c +++ b/interface.c @@ -284,7 +284,7 @@ long StartDriveTask(void *obj, SConnection *pCon, char *name, float fTarget) DriveTaskFunc, DriveTaskSignal, KillDriveTaskData, - taskData,0); + taskData, TASK_PRIO_HIGH); } /*--------------------------------------------------------------------------*/ pICountable GetCountableInterface(void *pObject) @@ -430,7 +430,7 @@ long StartCountTask(void *obj, SConnection *pCon, char *name) CountTaskFunc, CountTaskSignal, KillCountTaskData, - taskData,0); + taskData, TASK_PRIO_HIGH); } /*--------------------------------------------------------------------------*/ diff --git a/nread.c b/nread.c index 3cb546e3..a492aecc 100644 --- a/nread.c +++ b/nread.c @@ -224,9 +224,9 @@ static int NetReadAccept(pNetRead self, mkChannel * pSock) } else { /* register the connection and create a task for it here */ NetReadRegister(self, pNew, command, pRes); - TaskRegister(self->pMain->pTasker, + TaskRegisterN(self->pMain->pTasker, "NetReadAccept", SCTaskFunction, - SCSignalFunction, SCDeleteConnection, pRes, 1); + SCSignalFunction, SCDeleteConnection, pRes, TASK_PRIO_LOW); SCSendOK(pRes); return 1; } @@ -377,8 +377,8 @@ static int TelnetAccept(pNetRead self, mkChannel * pSock) /* register connection and task */ pRes->iTelnet = 1; NetReadRegister(self, pNew, tcommand, pRes); - TaskRegister(self->pMain->pTasker, - TelnetTask, TelnetSignal, DeleteTelnet, pTel, 1); + TaskRegisterN(self->pMain->pTasker," TelnetAccept", + TelnetTask, TelnetSignal, DeleteTelnet, pTel, TASK_PRIO_LOW); return 1; } } else { @@ -896,8 +896,8 @@ int NetReadWait4Data(pNetRead self, int iSocket) pNew->pChan = pChan; pNew->iEnd = 0; pNew->pRead = self; - lID = TaskRegister(self->pMain->pTasker, - Wait4ReadTask, ReadWaitSignal, ReadWaitFree, pNew, 0); + lID = TaskRegisterN(self->pMain->pTasker, "NetReadWait4Data", + Wait4ReadTask, ReadWaitSignal, ReadWaitFree, pNew, TASK_PRIO_HIGH); /* wait for finish */ TaskWait(self->pMain->pTasker, lID); @@ -1127,7 +1127,7 @@ static int CommandAcceptCB(int handle, void *userData) TaskRegisterN(pServ->pTasker, buffer, SCTaskFunction, - SCSignalFunction, SCDeleteConnection, pCon, 1); + SCSignalFunction, SCDeleteConnection, pCon, TASK_PRIO_LOW); ANETsetReadCallback(handle, CommandDataCB, usData, killCommandCBData); SCSendOK(pCon); return 1; @@ -1343,7 +1343,7 @@ static int TelnetAcceptCB(int handle, void *userData) snprintf(buffer,sizeof(buffer),"con%ld", pCon->ident); TaskRegisterN(pServ->pTasker, buffer, - TelnetTask, TelnetSignal, DeleteTelnet, pTel, 1); + TelnetTask, TelnetSignal, DeleteTelnet, pTel, TASK_PRIO_LOW); ANETsetReadCallback(handle, ANETTelnetProcess, usData, killCommandCBData); SCSendOK(pCon); diff --git a/nserver.c b/nserver.c index e72917c6..5e2b0fcf 100644 --- a/nserver.c +++ b/nserver.c @@ -43,8 +43,6 @@ extern int openDevexecLog(); /* in devexec.c */ extern int NetWatchTask(void *pData); /* in nwatch.c */ -/* ========================= Less dreadful file statics =================== */ - /*------------------------------------------------------------------------*/ static void StopExit(void) { @@ -116,13 +114,14 @@ int InitServer(char *file, pServer * pServ) assert(self->pSics); /* initialise tasker */ - assert(TaskerInit(&self->pTasker)); + TaskerInit(&self->pTasker); + assert(self->pTasker != NULL); pSICSOptions = IFAddOption(pSICSOptions, "ConnectionCount", "0"); pSICSOptions = IFAddOption(pSICSOptions, "ConMask", "0"); /* initialize the network watcher */ - TaskRegister(self->pTasker, NetWatchTask, NULL, NULL, NULL, 1); + TaskRegisterN(self->pTasker, "nwatch", NetWatchTask, NULL, NULL, NULL, TASK_PRIO_HIGH); /* initialise the server from script */ SetWriteHistory(0); @@ -183,7 +182,7 @@ int InitServer(char *file, pServer * pServ) iCommandTimeOut)) != NULL); TaskRegisterN(self->pTasker, "Network Reader", NetReaderTask, NetReaderSignal, NULL, /* call DeleteNetReader later than TaskerDelete */ - pReader, 1); + pReader, TASK_PRIO_HIGH); self->pReader = pReader; /* the socket */ @@ -245,17 +244,17 @@ int InitServer(char *file, pServer * pServ) /* install environment monitor */ self->pMonitor = GetEnvMon(self->pSics); TaskRegisterN(self->pTasker,"EV Monitor", - EnvMonTask, EnvMonSignal, NULL, self->pMonitor, 1); + EnvMonTask, EnvMonSignal, NULL, self->pMonitor, TASK_PRIO_HIGH); /* install performance monitor */ pMon = CreatePerfMon(20); AddCommand(self->pSics, "Performance", PerfMonWrapper, DeletePerfMon, pMon); - TaskRegisterN(self->pTasker,"perfmon", PerfMonTask, PerfMonSignal, NULL, pMon, 1); + TaskRegisterN(self->pTasker,"perfmon", PerfMonTask, PerfMonSignal, NULL, pMon, TASK_PRIO_HIGH); /* Install a second one for higher granularity measurement */ pMon = CreatePerfMon(2); TaskRegisterN(self->pTasker,"perfmon2", - PerfMonTask, PerfMonSignal, DeletePerfMon, pMon, 1); + PerfMonTask, PerfMonSignal, DeletePerfMon, pMon, TASK_PRIO_HIGH); /* install telnet port */ @@ -467,7 +466,7 @@ int UserWait(SConnection * pCon, SicsInterp * pSics, void *pData, sWait.dFinish = DoubleTime() + (double)fVal; sWait.iEnd = 0; - lID = TaskRegisterN(pTask,"wait", WaitTask, WaitSignal, NULL, &sWait, 1); + lID = TaskRegisterN(pTask,"wait", WaitTask, WaitSignal, NULL, &sWait, TASK_PRIO_HIGH); TaskWait(pTask, lID); if (SCGetInterrupt(pCon) != eContinue) { return 0; } else { diff --git a/nxupdate.c b/nxupdate.c index cc7e6cb6..bdf39965 100644 --- a/nxupdate.c +++ b/nxupdate.c @@ -81,7 +81,7 @@ static int CountCallback(int iEvent, void *pEventData, void *pUser) self->nextUpdate = time(NULL) + self->updateIntervall; self->iEnd = 0; self->pCon = pCon; - TaskRegisterN(pServ->pTasker, "NXupdater", UpdateTask, NULL, NULL, self, 1); + TaskRegisterN(pServ->pTasker, "NXupdater", UpdateTask, NULL, NULL, self, TASK_PRIO_HIGH); return 1; } else if (iEvent == COUNTEND) { self->iEnd = 1; diff --git a/oscillate.c b/oscillate.c index 8a5228d0..19bc8e1d 100644 --- a/oscillate.c +++ b/oscillate.c @@ -165,7 +165,7 @@ static int StartOscillation(pOscillator self, SConnection * pCon) */ snprintf(pBueffel,sizeof(pBueffel),"Oscillate-%s", self->pMot->name); self->taskID = TaskRegisterN(pServ->pTasker,pBueffel, - OscillationTask, NULL, NULL, self, 10); + OscillationTask, NULL, NULL, self, TASK_PRIO_HIGH); if (self->taskID < 0) { SCWrite(pCon, "ERROR: failed to start oscillation task", eError); return 0; diff --git a/remob.c b/remob.c index 3aa384ea..ceae8026 100644 --- a/remob.c +++ b/remob.c @@ -954,7 +954,7 @@ static RemServer *RemServerInit(char *name, char *host, int port) remserver->interestActive = 0; remserver->forwardMessages = 1; TaskRegisterN(pServ->pTasker,name, RemServerTask, NULL, RemServerKill, - remserver, 1); + remserver, TASK_PRIO_HIGH); return remserver; } diff --git a/scriptcontext.c b/scriptcontext.c index f9a5d926..1add98d7 100644 --- a/scriptcontext.c +++ b/scriptcontext.c @@ -523,7 +523,7 @@ static char *SctActionHandler(void *actionData, char *lastReply, traceIO(data->controller->node->name, "ERROR: action {%s} in {%s} node %s:\nERROR: %s", data->name, origScript, path, result); } else { - traceIO("sctunknown", "reply:%s", "ERROR: action {%s} in {%s} node %s:\nERROR: %s", + traceIO("sctunknown", "ERROR: action {%s} in {%s} node %s:\nERROR: %s", data->name, origScript, path, result); } } @@ -1842,7 +1842,7 @@ static void SctKillController(void *c) if (pServ->pTasker) { TaskRegisterN(pServ->pTasker,"killsct", SctDeferredTask, NULL, SctDeferredFree, - controller, 0); + controller, TASK_PRIO_HIGH); } else { free(controller); } diff --git a/serialwait.c b/serialwait.c index bb73952f..fd21aa75 100644 --- a/serialwait.c +++ b/serialwait.c @@ -195,7 +195,7 @@ int SerialSicsExecute(void **pData, char *pCommand, /* start task */ lTask = TaskRegisterN(pServ->pTasker,"serialwait", - SWTask, SWSignal, NULL, &control, 1); + SWTask, SWSignal, NULL, &control, TASK_PRIO_LOW); /* wait for it to end */ TaskWait(pServ->pTasker, lTask); diff --git a/sicscron.c b/sicscron.c index da2ec5d3..0ad5ae63 100644 --- a/sicscron.c +++ b/sicscron.c @@ -237,7 +237,7 @@ int MakeCron(SConnection * pCon, SicsInterp * pSics, void *pData, } pNew->stat = StatisticsNew(cmd); - TaskRegisterN(pServ->pTasker, cmd, CronTask, CronSignal, KillCron, pNew, 1); + TaskRegisterN(pServ->pTasker, cmd, CronTask, CronSignal, KillCron, pNew, TASK_PRIO_LOW); SCSendOK(pCon); return 1; } diff --git a/sicsexit.c b/sicsexit.c index 130f5fb0..e6e56750 100644 --- a/sicsexit.c +++ b/sicsexit.c @@ -76,7 +76,7 @@ int SicsExit(SConnection * pCon, SicsInterp * pInterp, void *pData, if (SCMatchRights(pCon, usMugger)) { /* only Muggers are allowed to do it */ SetInterrupt(eEndServer); - lID = TaskRegisterN(pTask,"exittask", WaitTask, NULL, NULL, NULL, 1); + lID = TaskRegisterN(pTask,"exittask", WaitTask, NULL, NULL, NULL, TASK_PRIO_HIGH); TaskWait(pTask, lID); TaskStop(pTask); return 1; diff --git a/sicspoll.c b/sicspoll.c index 0601199a..33be09ff 100644 --- a/sicspoll.c +++ b/sicspoll.c @@ -379,7 +379,7 @@ int InstallSICSPoll(SConnection * pCon, SicsInterp * pSics, void *pData, pNew->pCon = defCon; pNew->nPoll = 3; - TaskRegisterN(pServ->pTasker,"sicspoll", PollTask, SicsPollSignal, NULL, pNew, 10); + TaskRegisterN(pServ->pTasker,"sicspoll", PollTask, SicsPollSignal, NULL, pNew, TASK_PRIO_HIGH); if (argc > 1) { AddCommand(pSics, argv[1], SICSPollWrapper, killSicsPoll, pNew); diff --git a/sicspoll.tc b/sicspoll.tc index ea2eb738..bbcf9f7d 100644 --- a/sicspoll.tc +++ b/sicspoll.tc @@ -292,7 +292,7 @@ static void printPollList(pSicsPoll self, SConnection *pCon){ pNew->pCon = defCon; pNew->nPoll = 3; - TaskRegister(pServ->pTasker,PollTask,SicsPollSignal,NULL,pNew, 10); + TaskRegister(pServ->pTasker,PollTask,SicsPollSignal,NULL,pNew, TASK_PRIO_HIGH); if(argc > 1){ AddCommand(pSics,argv[1],SICSPollWrapper, diff --git a/status.c b/status.c index c850e698..a8ec242e 100644 --- a/status.c +++ b/status.c @@ -504,5 +504,5 @@ static int StatusTask(void *data) void InitStatus(void) { BuildStatusChain(); - TaskRegisterN(pServ->pTasker,"statustask",StatusTask, NULL, NULL, NULL,1); + TaskRegisterN(pServ->pTasker,"statustask",StatusTask, NULL, NULL, NULL, TASK_PRIO_HIGH); } diff --git a/statusfile.c b/statusfile.c index 84eb343c..d1593d13 100644 --- a/statusfile.c +++ b/statusfile.c @@ -296,10 +296,10 @@ static int cleanRestoreErr(pRestoreObj self, SConnection * pCon, int hard) } if (errMsg) { SCWrite(pCon, errMsg, eError); - LLDstringDelete(newErrList); + LLDdeleteString(newErrList); } else { /* swap lists */ - LLDstringDelete(self->errList); + LLDdeleteString(self->errList); self->errList = newErrList; SCPrintf(pCon, eLog, "CleanErr: %d pairs in, %d pairs out", count_in, count_ex); } @@ -397,5 +397,5 @@ void StatusFileDirty(void) /*-----------------------------------------------------------------------*/ void StatusFileInit(void) { - TaskRegisterN(pServ->pTasker, "statusfile", StatusFileTask, NULL, NULL, NULL, 0); + TaskRegisterN(pServ->pTasker, "statusfile", StatusFileTask, NULL, NULL, NULL, TASK_PRIO_HIGH); } diff --git a/task.c b/task.c index 396f782d..20fb1380 100644 --- a/task.c +++ b/task.c @@ -1,47 +1,93 @@ /*------------------------------------------------------------------------ - T A S K E R - + T A S K E R + Implementation of a portable task switcher. - + Mark Koennecke, September 1997 - + copyleft, 1997. - + NO WARRANTIES OF ANY KIND WHATSOEVER TAKEN BY ME OR MY EMPLOYER. YOU ARE AT YOUR OWN! - Reworked to have a task name, stop by task name and better listing. + Reworked to have a task name, stop by task name and better listing. Mark Koennecke, December 2012 + + Reworked to implement priorities and message queues + + Douglas Clowes, July 2015 ----------------------------------------------------------------------------*/ #include +#include #include #include +#include #include #include "fortify.h" #include "task.h" #define READY 1 #define WAITING 2 #define YIELDING 3 +#define DERFUNCT 4 #define IDUNDEFINED 0L #define TASKMAGIC 777111999 + +typedef unsigned long long LoopCounter; +/*--------------------------------------------------------------------------*/ +struct __TaskTaskID { + long lID; +}; + +struct __TaskGroupID { + long lID; +}; + +typedef struct{ + pTaskMan tasker; + TaskGroupID groupID; +} TaskGroupData, *pTaskGroupData; + +TaskTaskID TaskUnknownTaskID = 0; +TaskGroupID TaskUnknownGroupID = 0; + +TaskTaskID TaskBadTaskID = -1; +TaskGroupID TaskBadGroupID = -1; /*--------------------------------------------------------------------------*/ typedef struct __TaskHead { long magic; - long lID; - long groupID; + TaskTaskID taskID; + TaskGroupID groupID; int iStatus; - long lWait; + int iPrioBase; + TaskTaskID waitTarget; char *name; time_t start_time; + double startRunTime; + double lastRunTime; + double nextRunTime; + double nextRunPeriod; TaskFunc pRun; + TaskMsgFunc pMsgRun; SignalFunc pSignal; void *pData; TaskKillFunc pKill; pTaskHead pNext; pTaskHead pPrevious; + pTaskQueue pQueue; + LoopCounter numRuns; + LoopCounter numWaits; + LoopCounter numYields; + double startWallTime; + double accumulatedWallTime; + double startYieldTime; + double accumulatedYieldTime; + double startProcessorTime; + double accumulatedProcessorTime; + int isActive; + int isLogged; } TaskHead; typedef struct __TaskMan { @@ -49,20 +95,93 @@ typedef struct __TaskMan { int iStop; pTaskHead pCurrent; /* Think trice before you interfere with this! */ pTaskHead pHead; + int stackPointer; + TaskTaskID stackStack[20]; } TaskMan; + +static TaskLogFunc TaskLogWrite = NULL; +static eTaskLogLevel TaskLogLevel = eTaskLogNone; + +static int LOGGING_AT(pTaskMan self, eTaskLogLevel level) { + if (TaskLogWrite == NULL) + return 0; + if (TaskLogLevel == eTaskLogNone) + return 0; + if (level < TaskLogLevel) + return 0; + return 1; +} + +static int TaskLogPrint(eTaskLogLevel lvl, const char *fmt, ...) +{ + va_list ap; + char buf[256]; + int l; + + if (TaskLogWrite == NULL || TaskLogLevel == eTaskLogNone || lvl < TaskLogLevel) { + return 0; + } + + va_start(ap, fmt); + l = vsnprintf(buf, sizeof buf, fmt, ap); + va_end(ap); + if (l <= 0) + return l; + if (l >= sizeof buf) { + char *dyn; + /* we have probably a C99 conforming snprintf and + need a larger buffer + */ + dyn = malloc(l + 1); + if (dyn != NULL) { + va_start(ap, fmt); + vsnprintf(dyn, l + 1, fmt, ap); + va_end(ap); + TaskLogWrite(lvl, dyn); + free(dyn); + return l; + } + } + TaskLogWrite(lvl, buf); + return l; +} + +void TaskLogStack(pTaskMan self, eTaskLogLevel typ); /*--------------------------------------------------------------------------- -The 7 below solves a subtle bug which occurs when a groupID in user code -has been initialized to 0 and starting fails. Then it seems as if this -group keeps running. As there will always be some task running at 0. +The 7 below solves a subtle bug which occurs when a groupID in user code +has been initialized to 0 and starting fails. Then it seems as if this +group keeps running. As there will always be some task running at 0. ----------------------------------------------------------------------------*/ static long lIDMama = 7L; #define TASKERID 123399 /*---------------------------------------------------------------------------*/ +static double DoubleTime(void) +{ + struct timeval now; + /* the resolution of this function is usec, if the machine supports this + and the mantissa of a double is 51 bits or more (31 for sec and 20 for mic$ + */ + gettimeofday(&now, NULL); + return now.tv_sec + now.tv_usec / 1e6; +} +/*-------------------------------------------------------------------------*/ +static double DoubleTimeCPU(void) +{ + struct timespec now; + /* the resolution of this function is usec, if the machine supports this + and the mantissa of a double is 51 bits or more (31 for sec and 20 for mic$ + */ + clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &now); + return now.tv_sec + now.tv_nsec / 1e9; +} + +/*---------------------------------------------------------------------------*/ static pTaskHead MakeTaskHead(char *name, TaskFunc pTask, SignalFunc pSignal, void *pData, TaskKillFunc pKill) { pTaskHead pNew = NULL; + TaskTaskID newID; pNew = (pTaskHead) malloc(sizeof(TaskHead)); if (!pNew) { @@ -73,18 +192,20 @@ static pTaskHead MakeTaskHead(char *name, TaskFunc pTask, SignalFunc pSignal, pNew->magic = TASKMAGIC; pNew->name = strdup(name); pNew->start_time = time(NULL); + pNew->startRunTime = DoubleTime(); pNew->pRun = pTask; pNew->pSignal = pSignal; pNew->pData = pData; pNew->pKill = pKill; lIDMama++; - pNew->lID = lIDMama; - pNew->iStatus = READY; - pNew->groupID = IDUNDEFINED; - - if(lIDMama < 0){ + if(lIDMama < 7){ lIDMama = 7; } + newID = lIDMama; + pNew->taskID = newID; + pNew->iStatus = READY; + pNew->groupID = TaskUnknownGroupID; + pNew->waitTarget = TaskUnknownTaskID; return pNew; } @@ -119,6 +240,74 @@ static int DummyTask(void *pData) return 1; } +/*--------------------------------------------------------------------------*/ +static double makeTaskActive(pTaskHead self) +{ + double now = DoubleTime(); + + self->isActive = 1; + self->startWallTime = now; + self->startProcessorTime = DoubleTimeCPU(); + return now; +} + +/*--------------------------------------------------------------------------*/ +static double makeTaskIdle(pTaskHead self) +{ + double now = DoubleTime(); + + self->accumulatedWallTime += now - self->startWallTime; + self->accumulatedProcessorTime += DoubleTimeCPU() - self->startProcessorTime; + self->isActive = 0; + return now; +} + +/*--------------------------------------------------------------------------*/ +static int makeTaskRun(pTaskMan self) +{ + int iRet; + LoopCounter numWaits; + LoopCounter numYields; + double start, elapsed; + pTaskHead pThis = self->pCurrent; + start = makeTaskActive(pThis); + numWaits = pThis->numWaits; + numYields = pThis->numYields; + if (pThis->pRun) + iRet = pThis->pRun(pThis->pData); + else if (pThis->pMsgRun) { + pTaskMessage pMsg = TaskQueueRecvMine(self); + if (pMsg) { + iRet = pThis->pMsgRun(pThis->pData, pMsg); + TaskMessageFree(pMsg); + } else { + /* TODO: should not happen */ + } + } else { + /* TODO: this should not happen */ + } + pThis->isLogged = 0; /* reset this after each run */ + pThis->lastRunTime = start; + pThis->numRuns++; + elapsed = makeTaskIdle(pThis) - start; + if (LOGGING_AT(self, eTaskLogDebug)) { + if (pThis->numWaits != numWaits) + TaskLogPrint(eTaskLogDebug, "TaskWaited: %s waited %lld times in %fS", + pThis->name, + pThis->numWaits - numWaits, + elapsed); + if (pThis->numYields != numYields) + TaskLogPrint(eTaskLogDebug, "TaskYielded: %s yielded %lld times in %fS", + pThis->name, + pThis->numYields - numYields, + elapsed); + if (pThis->numWaits != numWaits || pThis->numYields != numYields) + if (self->stackPointer > 0) + TaskLogStack(self, eTaskLogDebug); + } + return iRet; +} + /*--------------------------------------------------------------------------*/ int TaskerInit(pTaskMan * self) { @@ -170,26 +359,20 @@ int TaskerDelete(pTaskMan * pData) *pData = NULL; return 1; } -/*----------------------- temporary for backwards compatability -------------*/ -long TaskRegister(pTaskMan self,TaskFunc pTask, SignalFunc pSignal, - TaskKillFunc pKill, void *pData, int iPriority) -{ - return TaskRegisterN(self,"Unknown", pTask, pSignal, pKill, pData, iPriority); -} /*---------------------------------------------------------------------------*/ -long TaskRegisterN(pTaskMan self, char *name, TaskFunc pTask, SignalFunc pSignal, +static pTaskHead taskConstructor(pTaskMan self, char *name, TaskFunc pTask, SignalFunc pSignal, TaskKillFunc pKill, void *pData, int iPriority) { pTaskHead pNew = NULL; assert(self); assert(self->iID == TASKERID); - assert(pTask); pNew = MakeTaskHead(name, pTask, pSignal, pData, pKill); if (!pNew) { - return -1; + return NULL; } + pNew->iPrioBase = iPriority; /* link it in */ if (self->pCurrent->pNext) { @@ -199,7 +382,68 @@ long TaskRegisterN(pTaskMan self, char *name, TaskFunc pTask, SignalFunc pSignal pNew->pNext = self->pCurrent->pNext; self->pCurrent->pNext = pNew; - return pNew->lID; + if (LOGGING_AT(self, eTaskLogDebug)) { + TaskLogPrint(eTaskLogDebug, "TaskStart: %s (ID = %ld, Prio = %d)", + pNew->name, pNew->taskID, pNew->iPrioBase); + } + return pNew; +} +/*----------------------- temporary for backwards compatability -------------*/ +TaskTaskID TaskRegister(pTaskMan self,TaskFunc pTask, SignalFunc pSignal, + TaskKillFunc pKill, void *pData, int iPriority) +{ + pTaskHead pNew; + assert(pTask); + pNew = taskConstructor(self, "Unknown", pTask, pSignal, pKill, pData, iPriority); + return pNew ? pNew->taskID : TaskBadTaskID; +} +/*---------------------------------------------------------------------------*/ +TaskTaskID TaskRegisterN(pTaskMan self, char *name, TaskFunc pTask, SignalFunc pSignal, + TaskKillFunc pKill, void *pData, int iPriority) +{ + pTaskHead pNew; + assert(pTask); + pNew = taskConstructor(self, name, pTask, pSignal, pKill, pData, iPriority); + return pNew ? pNew->taskID : TaskBadTaskID; +} +/*---------------------------------------------------------------------------*/ +TaskTaskID TaskRegisterQ(pTaskMan self, char *name, TaskMsgFunc pTask, SignalFunc pSignal, + TaskKillFunc pKill, void *pData, int iPriority) +{ + pTaskHead pNew; + assert(pTask); + pNew = taskConstructor(self, name, NULL, pSignal, pKill, pData, iPriority); + if (pNew) { + pNew->pMsgRun = pTask; + pNew->pQueue = TaskQueueAlloc(); + } + return pNew ? pNew->taskID : TaskBadTaskID; +} +/*---------------------------------------------------------------------------*/ +TaskTaskID TaskRegisterD(pTaskMan self, char *name, TaskFunc pTask, SignalFunc pSignal, + TaskKillFunc pKill, void *pData, int iPriority, double delay) +{ + pTaskHead pNew; + assert(pTask); + pNew = taskConstructor(self, name, pTask, pSignal, pKill, pData, iPriority); + if (pNew) { + pNew->nextRunTime = DoubleTime() + delay; + } + return pNew ? pNew->taskID : TaskBadTaskID; +} +/*---------------------------------------------------------------------------*/ +TaskTaskID TaskRegisterP(pTaskMan self, char *name, TaskFunc pTask, SignalFunc pSignal, + TaskKillFunc pKill, void *pData, int iPriority, + double delay, double period) +{ + pTaskHead pNew; + assert(pTask); + pNew = taskConstructor(self, name, pTask, pSignal, pKill, pData, iPriority); + if (pNew) { + pNew->nextRunTime = DoubleTime() + delay; + pNew->nextRunPeriod = period; + } + return pNew ? pNew->taskID : TaskBadTaskID; } /*-------------------------------------------------------------------------*/ static void IncrTaskPointer(pTaskMan self) @@ -211,91 +455,110 @@ static void IncrTaskPointer(pTaskMan self) } /*-------------------------------------------------------------------------*/ -static int TaskExist(pTaskMan self, long lID) +static int TaskExist(pTaskMan self, TaskTaskID taskID) { - pTaskHead pCur = self->pHead; - while (pCur != NULL) { - if (pCur->lID == lID) { - return 1; + if (taskID == TaskBadTaskID || taskID == TaskUnknownTaskID) { + return 0; + } else { + pTaskHead pCur = self->pHead; + while (pCur != NULL) { + if (pCur->taskID == taskID) { + return 1; + } + pCur = pCur->pNext; } - pCur = pCur->pNext; + return 0; } - return 0; } +/*--------------------------------------------------------------------------*/ +static void TaskPush(pTaskMan self) +{ + makeTaskIdle(self->pCurrent); + self->stackStack[self->stackPointer] = self->pCurrent->taskID; + self->stackPointer++; +} +/*--------------------------------------------------------------------------*/ +static void TaskPop(pTaskMan self) +{ + makeTaskActive(self->pCurrent); + self->stackPointer--; +} +/*--------------------------------------------------------------------------*/ +static void TaskPrune(pTaskMan self) +{ + pTaskHead pThis; + pThis = self->pHead; /* start this at the dummy */ + while (pThis->pNext) { + if (pThis->pNext->iStatus == DERFUNCT) { + pTaskHead pThat = pThis->pNext; + if (LOGGING_AT(self, eTaskLogDebug)) + TaskLogPrint(eTaskLogDebug, + "TaskEnd: %s (ID=%ld,Loops=%lld,Waits=%lld,Yields=%lld,CPU=%f,Wall=%f,Yield=%f,Up=%f)", + pThat->name, + pThat->taskID, + pThat->numRuns, + pThat->numWaits, + pThat->numYields, + pThat->accumulatedProcessorTime, + pThat->accumulatedWallTime, + pThat->accumulatedYieldTime, + (double) (DoubleTime() - pThat->startRunTime) + ); + DeleteTaskHead(pThat); /* unlink and delete it */ + } + pThis = pThis->pNext; /* Note: not the same as pThat above */ + } +} +/*--------------------------------------------------------------------------*/ +static void TaskLoop(pTaskMan self) +{ + int iRet; + pTaskHead pThis; /* The current task on entry, or dummy */ + pTaskHead pThat; /* The task we are thinking of running next */ + pThis = self->pCurrent; + while (self->iStop == 0) { + pThat = self->pCurrent; + if (pThat->iStatus != READY) { + /* Not ready: do nothing */ + } else if (pThat->pQueue && TaskQueueCount(pThat->pQueue) == 0) { + /* Have Queue, but is empty: do nothing */ + } else if (pThat->nextRunTime > 0.0 && DoubleTime() < pThat->nextRunTime) { + /* Have due time but not there yet: do nothing */ + } else if (pThis->iPrioBase <= pThat->iPrioBase) { + if (pThat->nextRunTime > 0.0) { + /* Do this now so the task can override it during the run */ + if (pThat->nextRunPeriod > 0) { + double now = DoubleTime(); + pThat->nextRunTime += pThat->nextRunPeriod; + if (now > pThat->nextRunTime) + pThat->nextRunTime = now + pThat->nextRunPeriod; + } else { + pThat->nextRunTime = 0.0; + } + } + iRet = makeTaskRun(self); + if (iRet == 0) { + pThat->iStatus = DERFUNCT; + } + } + IncrTaskPointer(self); + if (self->pCurrent == pThis) + break; + } + TaskPrune(self); +} /*--------------------------------------------------------------------------*/ int TaskSchedule(pTaskMan self) { int iRet; - pTaskHead pTemp; assert(self); assert(self->iID == TASKERID); /* forever, until stop is called somehow */ - while (self->iStop == 0) { - if (self->pCurrent->iStatus == READY) { - iRet = self->pCurrent->pRun(self->pCurrent->pData); - if (iRet != 1) { - pTemp = self->pCurrent; - IncrTaskPointer(self); - DeleteTaskHead(pTemp); - } else { - IncrTaskPointer(self); - } - } else { - IncrTaskPointer(self); - } - } - return 1; -} - -/*-----------------------------------------------------------------*/ -int TaskWait(pTaskMan self, long lID) -{ - int iRet; - long lTest; - pTaskHead pTemp, pEnd; - - assert(self); - assert(self->iID == TASKERID); - - /* Cycle until lID is killed. Stop is obeyed as well */ - pEnd = self->pCurrent; - pEnd->iStatus = WAITING; - IncrTaskPointer(self); - while (self->iStop == 0) { - if ((self->pCurrent != pEnd) && (self->pCurrent->iStatus == READY) - && self->pCurrent != NULL) - /* omit ourselves! */ - { - iRet = self->pCurrent->pRun(self->pCurrent->pData); - if (iRet != 1) { - pTemp = self->pCurrent; - lTest = pTemp->lID; - IncrTaskPointer(self); - DeleteTaskHead(pTemp); - if (lTest == lID) { - goto ente; - } - } else { - IncrTaskPointer(self); - } - } else { - IncrTaskPointer(self); - } - if (self->pCurrent == self->pHead) { - if (!TaskExist(self, lID)) - goto ente; - } - } - -ente: - /* task ended, we need to continue to pEnd before we are done */ - while (self->pCurrent != pEnd) { - IncrTaskPointer(self); - } - pEnd->iStatus = READY; + while (self->iStop == 0) + TaskLoop(self); return 1; } @@ -303,34 +566,81 @@ ente: int TaskYield(pTaskMan self) { int iRet; - long lTest; - pTaskHead pTemp, pEnd; + double deltaTime; + pTaskHead pTemp, pThis; + extern void generate_stack_trace(int full, int dump); assert(self); assert(self->iID == TASKERID); /* Cycle until back at ourselves */ - pEnd = self->pCurrent; - pEnd->iStatus = WAITING; - IncrTaskPointer(self); - while ((self->iStop == 0) && (self->pCurrent != pEnd)) { - if ((self->pCurrent != pEnd) && (self->pCurrent->iStatus == READY)) - /* omit ourselves! */ - { - iRet = self->pCurrent->pRun(self->pCurrent->pData); - if (iRet != 1) { - pTemp = self->pCurrent; - lTest = pTemp->lID; - IncrTaskPointer(self); - DeleteTaskHead(pTemp); - } else { - IncrTaskPointer(self); + pThis = self->pCurrent; + pThis->iStatus = WAITING; + TaskPush(self); + self->pCurrent->numYields++; + if (LOGGING_AT(self, eTaskLogWarning)) { + if (pThis->iPrioBase > TASK_PRIO_LOW) { + if (!pThis->isLogged) { + pThis->isLogged = 1; + TaskLogPrint(eTaskLogWarning, "TaskYield: Unexpected Yield (not TASK_PRIO_LOW)"); + TaskLogStack(self, eTaskLogWarning); + generate_stack_trace(1, 0); } - } else { - IncrTaskPointer(self); } } - pEnd->iStatus = READY; + pThis->startYieldTime = DoubleTime(); + TaskLoop(self); + deltaTime = DoubleTime() - pThis->startYieldTime; + if (pThis->iPrioBase > TASK_PRIO_LOW && deltaTime > 0.250) { + if (LOGGING_AT(self, eTaskLogDebug)) { + TaskLogPrint(eTaskLogWarning, "TaskYield: Excessive Yield Time %fS in %s", + deltaTime, pThis->name); + } + } + pThis->accumulatedYieldTime += deltaTime; + pThis->iStatus = READY; + TaskPop(self); + return 1; +} + +/*-----------------------------------------------------------------*/ +int TaskWait(pTaskMan self, TaskTaskID taskID) +{ + int iRet; + pTaskHead pTemp, pThis; + extern void generate_stack_trace(int full, int dump); + + assert(self); + assert(self->iID == TASKERID); + + /* Cycle until taskID is killed. Stop is obeyed as well */ + pThis = self->pCurrent; + pThis->iStatus = WAITING; + pThis->waitTarget = taskID; + TaskPush(self); + self->pCurrent->numWaits++; + if (LOGGING_AT(self, eTaskLogWarning)) { + if (pThis->iPrioBase > TASK_PRIO_LOW) { + if (!pThis->isLogged) { + pThis->isLogged = 1; + TaskLogPrint(eTaskLogWarning, "TaskWait: Unexpected Wait (not TASK_PRIO_LOW)"); + TaskLogStack(self, eTaskLogWarning); + generate_stack_trace(1, 0); + } + } + } + pTemp = TaskIteratorByID(self, taskID); + if (pTemp && pTemp->iPrioBase < pThis->iPrioBase) { + /* Inverted priority */ + TaskLogPrint(eTaskLogError, "TaskWait: Bad Wait: Priority Inverted waiter(%s:%d) > target(%s:%d)", + pThis->name, pThis->iPrioBase, pTemp->name, pTemp->iPrioBase); + pTemp->iPrioBase = pThis->iPrioBase; + } + while (self->iStop == 0 && TaskExist(self, taskID)) + TaskLoop(self); + pThis->waitTarget = TaskUnknownTaskID; + pThis->iStatus = READY; + TaskPop(self); return 1; } @@ -397,8 +707,8 @@ void TaskRemove(pTaskMan self, TaskFunc pTaskRun, void *pData) pNext = pCurrent->pNext; if (pCurrent->pRun == pTaskRun && pCurrent->pData == pData) { if(pCurrent == self->pCurrent){ - /* cannot kill myself */ - return; + /* cannot kill myself */ + return; } /* unlink */ if (pCurrent->pPrevious != NULL) { @@ -408,7 +718,7 @@ void TaskRemove(pTaskMan self, TaskFunc pTaskRun, void *pData) pCurrent->pNext->pPrevious = pCurrent->pPrevious; } if(pCurrent->name != NULL){ - free(pCurrent->name); + free(pCurrent->name); } free(pCurrent); } @@ -430,10 +740,10 @@ int StopTask(pTaskMan self, char *name) pNext = pCurrent->pNext; if (strcmp(pCurrent->name,name) == 0) { if(self->pCurrent == pCurrent){ - /** - * cannot kill myself - */ - return 0; + /** + * cannot kill myself + */ + return 0; } /* unlink */ if (pCurrent->pPrevious != NULL) { @@ -443,7 +753,7 @@ int StopTask(pTaskMan self, char *name) pCurrent->pNext->pPrevious = pCurrent->pPrevious; } if(pCurrent->name != NULL){ - free(pCurrent->name); + free(pCurrent->name); } free(pCurrent); } @@ -470,7 +780,7 @@ int isTaskRunning(pTaskMan self, char *name) return 0; } /*-----------------------------------------------------------------------------*/ -int isTaskIDRunning(pTaskMan self, long lID) +int isTaskIDRunning(pTaskMan self, TaskTaskID taskID) { int iRet; pTaskHead pCurrent, pNext; @@ -482,7 +792,7 @@ int isTaskIDRunning(pTaskMan self, long lID) while (pNext != NULL) { pCurrent = pNext; pNext = pCurrent->pNext; - if (pCurrent->lID == lID) { + if (pCurrent->taskID == taskID) { return 1; } } @@ -501,10 +811,48 @@ pTaskHead TaskIteratorNext(pTaskHead it) { if(it != NULL && it->magic == TASKMAGIC){ return it->pNext; - } + } return NULL; } /*-----------------------------------------------------------------------------*/ +pTaskHead TaskIteratorCurrent(pTaskMan self) +{ + if (self == NULL) return NULL; + assert(self->iID == TASKERID); + + return self->pCurrent; +} +/*-----------------------------------------------------------------------------*/ +pTaskHead TaskIteratorByName(pTaskMan self, const char* name) +{ + pTaskHead it; + if (self == NULL) return NULL; + assert(self->iID == TASKERID); + + it = self->pHead->pNext; /* skip dummy task */ + while (it) { + if (strcasecmp(it->name, name) == 0) + break; + it = it->pNext; + } + return it; +} +/*-----------------------------------------------------------------------------*/ +pTaskHead TaskIteratorByID(pTaskMan self, TaskTaskID taskID) +{ + pTaskHead it; + if (self == NULL) return NULL; + assert(self->iID == TASKERID); + + it = self->pHead->pNext; /* skip dummy task */ + while (it) { + if (it->taskID == taskID) + break; + it = it->pNext; + } + return it; +} +/*-----------------------------------------------------------------------------*/ char *TaskDescription(pTaskHead it) { char *result; @@ -514,7 +862,7 @@ char *TaskDescription(pTaskHead it) if(it == NULL){ return NULL; } - + length = strlen(it->name) + 120; result = malloc(length*sizeof(char)); if(result == NULL){ @@ -526,22 +874,87 @@ char *TaskDescription(pTaskHead it) length = strlen(result); tm = localtime((const time_t *)&it->start_time); - strftime(result+length,100,"%F-%k-%m-%S",tm); + strftime(result+length,100,"%F-%H-%M-%S",tm); length = strlen(result); - snprintf(result+length,120-20,"|%ld", it->lID); + snprintf(result+length,120-20,"|%ld", it->taskID); length = strlen(result); snprintf(result+length,120-40,"|%.0ld ", it->groupID); return result; } -/*------------------------------------------------------------------------------*/ -long GetTaskID(pTaskHead it) +/*-----------------------------------------------------------------------------*/ +char *TaskDetail(pTaskHead it) { - return it->lID; + char *result; + int length; + const struct tm *tm; + + if(it == NULL){ + return NULL; + } + + length = strlen(it->name) + 120; + result = malloc(length*sizeof(char)); + if(result == NULL){ + return NULL; + } + memset(result,0,length*sizeof(char)); + strcpy(result,it->name); + + length = strlen(result); + snprintf(result+length,120-20,"|%lld", it->numRuns); + length = strlen(result); + snprintf(result+length,120-20,"|%lld", it->numWaits); + length = strlen(result); + snprintf(result+length,120-20,"|%lld", it->numYields); + length = strlen(result); + snprintf(result+length,120-20,"|%.6f", it->accumulatedProcessorTime); + length = strlen(result); + snprintf(result+length,120-40,"|%.6f", it->accumulatedWallTime); + length = strlen(result); + snprintf(result+length,120-40,"|%.6f", it->accumulatedYieldTime); + + return result; + } /*------------------------------------------------------------------------------*/ -long GetGroupID(pTaskHead it) +int TaskGetStack(pTaskMan self, pTaskHead it[]) +{ + if (it != NULL) { + int i; + for (i = 0; i < self->stackPointer; ++i) { + pTaskHead pTemp; + it[i] = NULL; + for (pTemp = self->pHead->pNext; pTemp; pTemp = pTemp->pNext) { + if (pTemp->taskID == self->stackStack[i]) { + it[i] = pTemp; + break; + } + } + } + } + return self->stackPointer; +} +/*------------------------------------------------------------------------------*/ +void TaskLogStack(pTaskMan self, eTaskLogLevel typ) +{ + if (LOGGING_AT(self, typ)) { + int i, count; + pTaskHead it[20]; + count = TaskGetStack(self, it); + for (i = 0; i < count; ++i) { + TaskLogPrint(typ, "TaskStack[%02d]: %s", i, it[count - 1 - i]->name); + } + } +} +/*------------------------------------------------------------------------------*/ +TaskTaskID GetTaskID(pTaskHead it) +{ + return it->taskID; +} +/*------------------------------------------------------------------------------*/ +TaskGroupID GetGroupID(pTaskHead it) { return it->groupID; } @@ -560,13 +973,18 @@ const void *GetTaskData(pTaskHead it) } } /*------------------------------------------------------------------------------*/ -long GetTaskGroupID(pTaskMan self) +TaskGroupID GetTaskGroupID(pTaskMan self) { + TaskGroupID newGroupID; lIDMama++; - return lIDMama; + if(lIDMama < 7){ + lIDMama = 7; + } + newGroupID = lIDMama; + return newGroupID; } /*-------------------------------------------------------------------------------*/ -void AddTaskToGroup(pTaskMan self, long taskID, long groupID) +void AddTaskToGroup(pTaskMan self, TaskTaskID taskID, TaskGroupID groupID) { pTaskHead pCurrent, pNext; @@ -577,7 +995,7 @@ void AddTaskToGroup(pTaskMan self, long taskID, long groupID) while (pNext != NULL) { pCurrent = pNext; pNext = pCurrent->pNext; - if (pCurrent->lID == taskID) { + if (pCurrent->taskID == taskID) { pCurrent->groupID = groupID; return; } @@ -587,12 +1005,13 @@ void AddTaskToGroup(pTaskMan self, long taskID, long groupID) This simply checks if there are any more tasks with the desired groupID in the list. If none, then all sub tasks have finished. -----------------------------------------------------------------------------------*/ -int isTaskGroupRunning(pTaskMan self, long groupID) +int isTaskGroupRunning(pTaskMan self, TaskGroupID groupID) { pTaskHead pCurrent, pNext; if (self == NULL) return 0; - if (groupID == IDUNDEFINED) return 0; + if (groupID == TaskUnknownGroupID || groupID == TaskBadGroupID) + return 0; assert(self->iID == TASKERID); @@ -600,7 +1019,7 @@ int isTaskGroupRunning(pTaskMan self, long groupID) while (pNext != NULL) { pCurrent = pNext; pNext = pCurrent->pNext; - if (pCurrent->groupID != IDUNDEFINED && pCurrent->groupID == groupID) { + if (pCurrent->groupID == groupID) { return 1; } } @@ -611,10 +1030,10 @@ int TaskGroupTask(void *data) { pTaskGroupData self = (pTaskGroupData)data; - return isTaskGroupRunning(self->tasker,self->groupID); + return isTaskGroupRunning(self->tasker,self->groupID); } /*-------------------------------------------------------------------------------*/ -int TaskSignalGroup(pTaskMan self, int iSignal, void *pSigData, long groupID) +int TaskSignalGroup(pTaskMan self, int iSignal, void *pSigData, TaskGroupID groupID) { pTaskHead pTemp, pEnd; @@ -633,3 +1052,308 @@ int TaskSignalGroup(pTaskMan self, int iSignal, void *pSigData, long groupID) return 1; } +/*-------------------------------------------------------------------------------*/ +void TaskSetLogFunc(TaskLogFunc logFunc) +{ + TaskLogWrite = logFunc; +} +/*-------------------------------------------------------------------------------*/ +TaskLogFunc TaskGetLogFunc(void) +{ + return TaskLogWrite; +} +/*-------------------------------------------------------------------------------*/ +eTaskLogLevel TaskSetLogLevel(eTaskLogLevel logLevel) +{ + eTaskLogLevel old = TaskLogLevel; + TaskLogLevel = logLevel; + return old; +} +/*-------------------------------------------------------------------------------*/ +eTaskLogLevel TaskGetLogLevel(void) +{ + return TaskLogLevel; +} +/*-------------------------------------------------------------------------------*/ +int TaskQueueSet(pTaskMan self, TaskTaskID taskID, pTaskQueue pQueue) +{ + pTaskHead pt = TaskIteratorByID(self, taskID); + if (pt) { + pt->pQueue = pQueue; + return 1; + } + return 0; +} + +/*-------------------------------------------------------------------------------*/ +int TaskQueueRem(pTaskMan self, TaskTaskID taskID) +{ + pTaskHead pt = TaskIteratorByID(self, taskID); + if (pt) { + pt->pQueue = NULL; + return 1; + } + return 0; +} +/*-------------------------------------------------------------------------------*/ +pTaskQueue TaskQueueGet(pTaskMan self, TaskTaskID taskID) +{ + pTaskHead pt = TaskIteratorByID(self, taskID); + if (pt) { + return pt->pQueue; + } + return NULL; +} + +/*-------------------------------------------------------------------------------*/ +pTaskQueue TaskQueueGetMine(pTaskMan self) +{ + pTaskHead pt = self->pCurrent; + if (pt) { + return pt->pQueue; + } + return NULL; +} + +#define MAGIC_Q 12334 +#define MAGIC_M 32441 + +typedef struct __TaskQueue { + int magic; + int count; + pTaskMessage head; + pTaskMessage tail; +} TaskQueue; + +typedef struct __TaskMessage { + int magic; + int mType; + pTaskMessage next; + pTaskMessage prev; + pTaskQueue owner; + TaskTaskID lSenderID; + void *pData; +} TaskMessage; + +/*-------------------------------------------------------------------------------*/ +static pTaskQueue taskQueueInit(pTaskQueue self) +{ + if (self) { + if (self->magic == MAGIC_Q) { + /* TODO */; + } + self->magic = MAGIC_Q; + self->count = 0; + self->head = NULL; + self->tail = NULL; + } + return self; +} + +/*-------------------------------------------------------------------------------*/ +void TaskRunMeAfter(pTaskMan self, double delay) +{ + pTaskHead pThis = self->pCurrent; + pThis->nextRunTime = DoubleTime() + delay; + pThis->nextRunPeriod = 0.0; +} +/*-------------------------------------------------------------------------------*/ +void TaskRunMeEvery(pTaskMan self, double delay) +{ + pTaskHead pThis = self->pCurrent; + pThis->nextRunTime = DoubleTime() + delay; + pThis->nextRunPeriod = delay; +} +/*-------------------------------------------------------------------------------*/ +double TaskRunMyPeriod(pTaskMan self) +{ + pTaskHead pThis = self->pCurrent; + return pThis->nextRunPeriod; +} +/*-------------------------------------------------------------------------------*/ +pTaskQueue TaskQueueAlloc(void) +{ + pTaskQueue self = (pTaskQueue) calloc(1, sizeof(TaskQueue)); + if (self) { + self = taskQueueInit(self); + } + return self; +} + +/*-------------------------------------------------------------------------------*/ +int TaskQueueFree(pTaskQueue self) +{ + if (self == NULL) { + /* TODO */ + return -1; + } + if (self->magic != MAGIC_Q) { + /* TODO */ + return -1; + } + if (self->count != 0 || self->head || self->tail) { + /* TODO */ + return -1; + } + self->magic = 0; + return 0; +} + +/*-------------------------------------------------------------------------------*/ +int TaskQueueCount(pTaskQueue self) { + if (self == NULL) { + /* TODO */ + return 0; + } + if (self->magic != MAGIC_Q) { + /* TODO */ + return 0; + } + return self->count; +} + +/*-------------------------------------------------------------------------------*/ +int TaskQueueSend(pTaskQueue the_q, pTaskMessage the_m) +{ + if (the_q == NULL || the_m == NULL) { + /* TODO */ + return 0; + } + if (the_q->magic != MAGIC_Q || the_m->magic != MAGIC_M) { + /* TODO */ + return 0; + } + if (the_q->head) { + the_m->prev = the_q->tail; + the_q->tail->next = the_m; + } else { + the_q->head = the_m; + the_m->prev = NULL; + } + the_q->tail = the_m; + the_m->next = NULL; + the_q->count++; + the_m->owner = the_q; + return the_q->count; +} + +/*-------------------------------------------------------------------------------*/ +int TaskQueueSendID(pTaskMan self, TaskTaskID taskID, pTaskMessage the_m) +{ + pTaskQueue the_q = TaskQueueGet(self, taskID); + + if (the_q == NULL) + return 0; + + return TaskQueueSend(the_q, the_m); +} + +/*-------------------------------------------------------------------------------*/ +pTaskMessage TaskQueueRecv(pTaskQueue self) +{ + pTaskMessage m; + if (self == NULL) { + /* TODO */ + return NULL; + } + if (self->magic != MAGIC_Q) { + /* TODO */ + return NULL; + } + if (self->count <= 0 || !self->head || !self->tail) { + /* TODO */ + return NULL; + } + self->count--; + m = self->head; + self->head = self->head->next; + if (self->head == NULL) { + self->tail = NULL; + if (self->count) { + /* TODO */ + self->count = 0; + } + } + m->next = m->prev = NULL; + return m; +} + +/*-------------------------------------------------------------------------------*/ +pTaskMessage TaskQueueRecvMine(pTaskMan self) +{ + return TaskQueueRecv(self->pCurrent->pQueue); +} +/*-------------------------------------------------------------------------------*/ +static pTaskMessage taskMessageInit(pTaskMessage self, int mType) +{ + if (self) { + if (self->magic == MAGIC_M) { + /* TODO */; + } + self->magic = MAGIC_M; + self->next = NULL; + self->prev = NULL; + self->owner = NULL; + self->mType = mType; + self->pData = NULL; + } + return self; +} + +/*-------------------------------------------------------------------------------*/ +pTaskMessage TaskMessageAlloc(size_t mSize, int mType) +{ + pTaskMessage self = (pTaskMessage) calloc(1, sizeof(TaskMessage) + mSize); + if (self) { + self = taskMessageInit(self, mType); + TaskMessageSetData(self, &self[1]); /* pointer to data beyond this structure */ + } + return self; +} + +/*-------------------------------------------------------------------------------*/ +int TaskMessageFree(pTaskMessage self) { + if (self == NULL) { + /* TODO */ + return -1; + } + if (self->magic != MAGIC_M) { + /* TODO */ + } + if (self->pData) { + /* TODO */ + } + self->magic = 0; + free(self); + return 0; +} + +/*-------------------------------------------------------------------------------*/ +int TaskMessageGetType(pTaskMessage self) +{ + if (self) + return self->mType; + return 0; +} + +/*-------------------------------------------------------------------------------*/ +void TaskMessageSetType(pTaskMessage self, int mType) +{ + if (self) + self->mType = mType; +} + +/*-------------------------------------------------------------------------------*/ +void * TaskMessageGetData(pTaskMessage self) +{ + if (self) + return self->pData; + return NULL; +} + +/*-------------------------------------------------------------------------------*/ +void TaskMessageSetData(pTaskMessage self, void *pData) +{ + if (self) + self->pData = pData; +} diff --git a/task.h b/task.h index 03d6636c..d95f5fd2 100644 --- a/task.h +++ b/task.h @@ -1,26 +1,57 @@ /*--------------------------------------------------------------------------- - T A S K - - This is a portable task switching module. Tasks are maintained in a + T A S K + + This is a portable task switching module. Tasks are maintained in a circular list and switched in between. Waiting for some task to end, a yield and a primitive form of inter task communication is implemented. - + Mark Koennecke, September 1997 - extended to suuport task groups + extended to support task groups Mark Koennecke, December 2012 - + copyright: see implementation file -----------------------------------------------------------------------------*/ #ifndef TASKOMAT #define TASKOMAT +typedef long TaskTaskID; +typedef long TaskGroupID; +extern TaskTaskID TaskUnknownTaskID, TaskBadTaskID; +extern TaskGroupID TaskUnknownGroupID, TaskBadGroupID; +/*---------------------------------------------------------------------------*/ +typedef enum eTaskLogLevel { + eTaskLogNone = 0, + eTaskLogDebug = 1, + eTaskLogInfo = 2, + eTaskLogWarning = 3, + eTaskLogError = 4, + eTaskLogFatal = 5 +} eTaskLogLevel; +typedef void (*TaskLogFunc) (eTaskLogLevel, const char *buf); +/* + A TaskLogFunc can be registered for logging activity within the task module. +*/ +/* + * Use these values for the Task Priority + */ +#define TASK_PRIO_LOW 10 +#define TASK_PRIO_MED 30 +#define TASK_PRIO_HIGH 50 +/*--------------------------------------------------------------------------*/ +typedef struct __TaskHead *pTaskHead; +typedef struct __TaskMan *pTaskMan; +typedef struct __TaskQueue *pTaskQueue; +typedef struct __TaskMessage *pTaskMessage; +/* + two data structure used internally and defined in task.c +*/ /*---------------------------------------------------------------------------*/ typedef int (*TaskFunc) (void *pData); -/* +/* a task function must be implemented by each task. This function will be - called when it is the tasks turn to execute. This function obtains a + called when it is the tasks turn to execute. This function obtains a pointer to a user defined data structure as parameter. If the task is going to end, it has to return 0. It's data structure will be removed by a KillFunction of the type defined below. If the task is @@ -28,9 +59,15 @@ typedef int (*TaskFunc) (void *pData); 1. */ /*--------------------------------------------------------------------------*/ +typedef int (*TaskMsgFunc) (void *pData, pTaskMessage pMsg); + +/* + * Like the TaskFunc but with a message extracted from the task queue + */ +/*--------------------------------------------------------------------------*/ typedef void (*TaskKillFunc) (void *pData); /* - Each task using private data structures must define this functions. It's + Each task using private data structures must define this functions. It's task is to clear the private data structure of the task and free all memory associated with it. This function will be called automatically by the Tasker when a task finishes or when the whole Tasker is shut down. @@ -41,23 +78,17 @@ typedef void (*SignalFunc) (void *pUser, int iSignal, void *pSigData); /* A SignalFunction can be implemented by each task. It is the means of inter task communication. The first parameter is a pointer to the - tasks private datastructure. Further parameters are an integer signal ID - and a pointer to a datastructure for this signal. The meaning of signal + tasks private datastructure. Further parameters are an integer signal ID + and a pointer to a datastructure for this signal. The meaning of signal ID's and signal data structures is up to the client of this code. */ -/*--------------------------------------------------------------------------*/ -typedef struct __TaskHead *pTaskHead; -typedef struct __TaskMan *pTaskMan; -/* - two data structure used internally and defined in task.c -*/ /*=========================================================================== ALL FUNTIONS RETURN 0 on FAILURE, 1 ON SUCCESS WHEN NOT MENTIONED OTHERWISE ============================================================================*/ int TaskerInit(pTaskMan * self); /* - Initalises a Task Manager. + Initalises a Task Manager. */ int TaskerDelete(pTaskMan * self); /* @@ -65,7 +96,7 @@ int TaskerDelete(pTaskMan * self); tasks and the TaskManager. */ /*--------------------------------------------------------------------------*/ -long TaskRegister(pTaskMan self, TaskFunc pTaskRun, +TaskTaskID TaskRegister(pTaskMan self, TaskFunc pTaskRun, SignalFunc pSignalFunc, TaskKillFunc pKillFunc, void *pData, int iPriority); /* @@ -75,16 +106,16 @@ long TaskRegister(pTaskMan self, TaskFunc pTaskRun, a SignalFunction [Optional, can be NULL] a KillFunction for task private data. [Optional, can be NULL] - a pointer to task private data + a pointer to task private data [Optional, can be NULL] - a priority for this task. This is currently unused. + a priority for this task. This is currently unused. On Success a positive value denoting the ID of the task is returned. On error a negative value is returned. */ /*--------------------------------------------------------------------------*/ -long TaskRegisterN(pTaskMan self, char *name, TaskFunc pTaskRun, - SignalFunc pSignalFunc, - TaskKillFunc pKillFunc, void *pData, int iPriority); +TaskTaskID TaskRegisterN(pTaskMan self, char *name, TaskFunc pTaskRun, + SignalFunc pSignalFunc, TaskKillFunc pKillFunc, + void *pData, int iPriority); /* This call enter a new task into the system. The caller has to specify: @@ -92,12 +123,37 @@ long TaskRegisterN(pTaskMan self, char *name, TaskFunc pTaskRun, a SignalFunction [Optional, can be NULL] a KillFunction for task private data. [Optional, can be NULL] - a pointer to task private data + a pointer to task private data [Optional, can be NULL] - a priority for this task. This is currently unused. + a priority for this task. This is currently unused. On Success a positive value denoting the ID of the task is returned. On error a negative value is returned. */ +/*--------------------------------------------------------------------------*/ +TaskTaskID TaskRegisterD(pTaskMan self, char *name, TaskFunc pTaskRun, + SignalFunc pSignalFunc, TaskKillFunc pKillFunc, + void *pData, int iPriority, double delay); + /* + This call enters a new task into the system. + The task will start running after the given delay in seconds. + */ +/*--------------------------------------------------------------------------*/ +TaskTaskID TaskRegisterP(pTaskMan self, char *name, TaskFunc pTaskRun, + SignalFunc pSignalFunc, TaskKillFunc pKillFunc, + void *pData, int iPriority, double delay, double period); + /* + This call enters a new task into the system. + The task will run after delay seconds and then every period seconds. + */ +/*--------------------------------------------------------------------------*/ +TaskTaskID TaskRegisterQ(pTaskMan self, char *name, TaskMsgFunc pTaskRun, + SignalFunc pSignalFunc, TaskKillFunc pKillFunc, + void *pData, int iPriority); + /* + This call enters a new task with queue into the system. + As for TaskRegisterN except the task function signature has + a message pointer. + */ /*-------------------------------------------------------------------------*/ int TaskSchedule(pTaskMan self); /* @@ -110,27 +166,27 @@ int TaskStop(pTaskMan self); */ /*------------------------------------------------------------------------*/ int TaskContinue(pTaskMan self); - /* + /* Continues an task switching session interrupted by TaskStop. After this the apopriate TaskYield, TaskSchedule or wahtever has to be called. */ /*-------------------------------------------------------------------------*/ -int TaskWait(pTaskMan self, long lID); +int TaskWait(pTaskMan self, TaskTaskID taskID); /* - Waits until the task specified by lID has finished. lID is obtained from - a call to TaskRegister. + Waits until the task specified by taskID has finished. taskID is obtained + from a call to TaskRegister. */ /*-------------------------------------------------------------------------*/ int TaskYield(pTaskMan self); /* does one cycle of the task loop and returns to the caller.This call allows - other tasks to execute while a task executes a lengthy calculation. + other tasks to execute while a task executes a lengthy calculation. */ /*--------------------------------------------------------------------------*/ int TaskSignal(pTaskMan self, int iSignal, void *pSigData); /* Invokes each Task's signal function with parameters iSignal and - pSigData. + pSigData. */ /*-------------------------------------------------------------------------*/ void TaskRemove(pTaskMan self, TaskFunc pTaskRun, void *pData); @@ -148,7 +204,7 @@ int TaskSignal(pTaskMan self, int iSignal, void *pSigData); returns 1 when task name is running, 0 else */ /*--------------------------------------------------------------------------*/ - int isTaskIDRunning(pTaskMan self, long lID); + int isTaskIDRunning(pTaskMan self, TaskTaskID taskID); /* returns 1 when task name is running, 0 else */ @@ -160,13 +216,13 @@ char *des; for(it = TaskIteratorStart(self); it != NULL; it = TaskIteratorNext(it)){ des = TaskDescription(it); -} +} There are two limitations of the implementation here: - Never, ever delete the Iterator it -- Do your iteration in one go or abandon it mid iteration. If another task - gets in between and registers new tasks or removes one, then the whole +- Do your iteration in one go or abandon it mid iteration. If another task + gets in between and registers new tasks or removes one, then the whole iterator may be messed up. =============================================================================*/ @@ -179,17 +235,30 @@ pTaskHead TaskIteratorNext(pTaskHead it); Steps to the next element in the task list. Returns NULL when node. Do NOT delete the returned pointer! */ +pTaskHead TaskIteratorCurrent(pTaskMan self); +pTaskHead TaskIteratorByName(pTaskMan self, const char* name); +pTaskHead TaskIteratorByID(pTaskMan self, TaskTaskID taskID); +/* + Gets the task iterator for either the current, named or numbered task + Do NOT delete the returned pointer! + */ char *TaskDescription(pTaskHead it); /* get a description of the task at the current iterator You are responsible for deleting the returned character array. */ -long GetTaskID(pTaskHead it); + +char *TaskDetail(pTaskHead it); +/* + get a detailed description of the task at the current iterator + You are responsible for deleting the returned character array. +*/ +TaskTaskID GetTaskID(pTaskHead it); /* get the ID of the current task */ -long GetGroupID(pTaskHead it); +TaskGroupID GetGroupID(pTaskHead it); /* get the group ID of the current task */ @@ -202,36 +271,147 @@ const void *GetTaskData(pTaskHead it); Get the user data for the current task. Do not free the returned pointer! */ /*============================================================================= - Task Groups. The implementation has the limit that any given task can + Task Groups. The implementation has the limit that any given task can only be member of one task group ===============================================================================*/ -long GetTaskGroupID(pTaskMan self); +TaskGroupID GetTaskGroupID(pTaskMan self); /* get the ID for a task group */ -void AddTaskToGroup(pTaskMan self, long taskID, long groupID); +void AddTaskToGroup(pTaskMan self, TaskTaskID taskID, TaskGroupID groupID); /* Add taskID to the task group groupID */ -int isTaskGroupRunning(pTaskMan self, long groupID); +int isTaskGroupRunning(pTaskMan self, TaskGroupID groupID); /* Returns 1 when the task group is still running, 0 else */ -typedef struct{ - pTaskMan tasker; - long groupID; -} TaskGroupData, *pTaskGroupData; - int TaskGroupTask(void *data); /* - This is a task function which implements the common task of waiting + This is a task function which implements the common task of waiting for a group of tasks to finish. It expects as data a TaskGroupData structure. */ /*--------------------------------------------------------------------------*/ -int TaskSignalGroup(pTaskMan self, int iSignal, void *pSigData, long groupID); +int TaskSignalGroup(pTaskMan self, int iSignal, void *pSigData, TaskGroupID groupID); /* signal only tasks in the group groupID -*/ +*/ +/*--------------------------------------------------------------------------*/ +void TaskSetLogFunc(TaskLogFunc); +TaskLogFunc TaskGetLogFunc(void); +eTaskLogLevel TaskSetLogLevel(eTaskLogLevel thresh); +eTaskLogLevel TaskGetLogLevel(void); + +/*--------------------------------------------------------------------------*/ +int TaskGetStack(pTaskMan self, pTaskHead it[]); +/* + * Returns the current stack depth of tasks and, if provided, fills the array + * of iterators. The iterators start at it[0] and can be used to get + * information about each task. + */ + +/*--------------------------------------------------------------------------*/ +void TaskRunMeAfter(pTaskMan self, double delay); +/* + * Run this task once in seconds + */ +/*--------------------------------------------------------------------------*/ +void TaskRunMeEvery(pTaskMan self, double delay); +/* + * Run this task every seconds from now on + */ +/*--------------------------------------------------------------------------*/ +double TaskRunMyPeriod(pTaskMan self); +/* + * Return this task run period in seconds + */ +/*--------------------------------------------------------------------------*/ +pTaskQueue TaskQueueAlloc(void); +/* + * Task Queue constructor + */ +/*--------------------------------------------------------------------------*/ +int TaskQueueFree(pTaskQueue); +/* + * Task Queue destructor + */ +/*--------------------------------------------------------------------------*/ +int TaskQueueCount(pTaskQueue); +/* + * Returns the message count on the Task Queue + */ +/*--------------------------------------------------------------------------*/ +int TaskQueueSend(pTaskQueue, pTaskMessage); +/* + * Pushes a Task Message onto the tail of the Task Queue + */ +/*--------------------------------------------------------------------------*/ +int TaskQueueSendID(pTaskMan self, TaskTaskID taskID, pTaskMessage); +/* + * Pushes a Task Message onto the tail of the Task Queue + */ +/*--------------------------------------------------------------------------*/ +pTaskMessage TaskQueueRecv(pTaskQueue); +/* + * Pops a Task Message off the head of the given Task Queue + */ +/*--------------------------------------------------------------------------*/ +pTaskMessage TaskQueueRecvMine(pTaskMan self); +/* + * Pops a Task Message off the head of the owner's Task Queue + */ +/*--------------------------------------------------------------------------*/ +int TaskQueueSet(pTaskMan self, TaskTaskID taskID, pTaskQueue); +/* + * Sets the Task Queue of the task + */ +/*--------------------------------------------------------------------------*/ +int TaskQueueRem(pTaskMan self, TaskTaskID taskID); +/* + * Clears the Task Queue of the task + */ +/*--------------------------------------------------------------------------*/ +pTaskQueue TaskQueueGet(pTaskMan self, TaskTaskID taskID); +/* + * Gets the Task Queue of the specified task + */ +/*--------------------------------------------------------------------------*/ +pTaskQueue TaskQueueGetMine(pTaskMan self); +/* + * Gets the Task Queue of the current task + */ +/*--------------------------------------------------------------------------*/ +pTaskMessage TaskMessageAlloc(size_t mSize, int mType); +/* + * Constructor for a Task Message of the requested size and type + */ +/*--------------------------------------------------------------------------*/ +int TaskMessageFree(pTaskMessage); +/* + * Destructor for the Task Message + * returne 0=success, -1=fail + */ +/*--------------------------------------------------------------------------*/ +int TaskMessageGetType(pTaskMessage self); +/* + * Get the type of the Task Message + */ +/*--------------------------------------------------------------------------*/ +void TaskMessageSetType(pTaskMessage self, int mType); +/* + * Set the type of the Task Message + */ +/*--------------------------------------------------------------------------*/ +void * TaskMessageGetData(pTaskMessage self); +/* + * Get the data pointer from the message + */ +/*--------------------------------------------------------------------------*/ +void TaskMessageSetData(pTaskMessage self, void *mData); +/* + * Set the data pointer in the message + */ +/*--------------------------------------------------------------------------*/ #endif diff --git a/taskobj.c b/taskobj.c index 3a3757b8..9f2cd2b8 100644 --- a/taskobj.c +++ b/taskobj.c @@ -2,7 +2,7 @@ * This is the SICS interface object to the tasker module * * copyright: GPL - * + * * Mark Koennecke, December 2012 */ #include @@ -15,6 +15,37 @@ typedef struct { char *scriptName; SConnection *con; } TclFunc, *pTclFunc; + +/*-------------------------------------------------------------------------*/ +void TaskObjLogFunc(eTaskLogLevel lvl, const char *buf) +{ + OutCode eOut; + + switch (lvl) { + case eTaskLogNone: + return; + case eTaskLogInfo: + eOut = eValue; + break; + case eTaskLogDebug: + eOut = eValue; + break; + case eTaskLogWarning: + eOut = eWarning; + break; + case eTaskLogError: + eOut = eError; + break; + case eTaskLogFatal: + eOut = eError; + break; + default: + eOut = eValue; + break; + } + SICSLogWrite(buf, eOut); + return; +} /*-------------------------------------------------------------------------*/ static int ListCmd(pSICSOBJ self, SConnection *pCon, pHdb commandNode, pHdb par[], int nPar) @@ -28,8 +59,8 @@ static int ListCmd(pSICSOBJ self, SConnection *pCon, pHdb commandNode, SCWrite(pCon,"ERROR: out of memory in ListCmd", eError); return 0; } - snprintf(buffer,sizeof(buffer),"%20s %20s %12s", - "Task", "Start_Time", "ID"); + 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)){ @@ -39,8 +70,8 @@ static int ListCmd(pSICSOBJ self, SConnection *pCon, pHdb commandNode, 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); + snprintf(buffer,sizeof(buffer),"%20s %20s %12s %10s", + name,time,id,gid); DynStringConcat(result,buffer); DynStringConcatChar(result,'\n'); free(pDes); @@ -51,6 +82,103 @@ static int ListCmd(pSICSOBJ self, SConnection *pCon, pHdb commandNode, 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) @@ -74,6 +202,126 @@ static int KillCmd(pSICSOBJ self, SConnection *pCon, pHdb commandNode, 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) { @@ -85,11 +333,11 @@ static int TclTaskFunction(void *pData) 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)); */ @@ -150,21 +398,21 @@ static int RunCmd(pSICSOBJ self, SConnection *pCon, pHdb commandNode, data->scriptName = strdup(par[0]->value.v.text); TaskRegisterN(pServ->pTasker, data->scriptName, - TclTaskFunction, - TclFuncSignal, - KillTclFunc, - data, 0); + 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 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; @@ -172,7 +420,9 @@ int TaskOBJFactory(SConnection *pCon, SicsInterp *pSics, void *pData, 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"); @@ -186,7 +436,7 @@ int TaskOBJFactory(SConnection *pCon, SicsInterp *pSics, void *pData, SetHdbProperty(cmd,"priv","spy"); node = MakeSICSHdbPar("script",usSpy,MakeHdbText("banana")); AddHipadabaChild(cmd,node,NULL); - + return 1; } @@ -195,7 +445,7 @@ void InitTaskOBJ() { pSICSOBJ pNew = NULL; pHdb cmd = NULL, node; - + pNew = MakeSICSOBJv("task", "TaskOBJ", HIPNONE, usInternal); if (pNew == NULL) { @@ -205,7 +455,25 @@ void InitTaskOBJ() 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"); @@ -222,5 +490,5 @@ void InitTaskOBJ() AddCommand(pServ->pSics, "task", InterInvokeSICSOBJ, KillSICSOBJ, pNew); - + } diff --git a/trace.c b/trace.c index db2dade1..aa1da596 100644 --- a/trace.c +++ b/trace.c @@ -191,15 +191,11 @@ static int strrepc(char *pszStr, char cFrom, char cTo) /*----------------------------------------------------------------*/ - while( 0 != ( ptr = strchr( pszStr, cFrom ) ) ) - - { /* WHILE cFrom occurs in pszStr */ - - pszStr[ (int) ptr - (int) pszStr ] = cTo ; - - /*- Replace next cFrom with cTo */ - - iReturn++ ; /*- count */ + for (ptr = pszStr; ptr && *ptr; ++ptr) { + if (*ptr == cFrom) { + *ptr = cTo; + ++iReturn; + } } return( iReturn ) ; @@ -286,12 +282,13 @@ void traceCommand(char *id, char *format, ...) va_end(argptr); if(len >= sizeof(buffer)){ buf = malloc(len+1); - memset(buf,0,len+1); if(buf != NULL){ + memset(buf,0,len+1); va_start(argptr,format); len = vsnprintf(buf, len+1,format,argptr); va_end(argptr); traceprint("com",id,buf); + free(buf); } } else { traceprint("com",id,buffer); @@ -471,7 +468,7 @@ static int TraceLog(pSICSOBJ ccmd, SConnection * con, } if(traceStamperID < 0){ traceStamperID = TaskRegisterN(pServ->pTasker,"tracestamper", - TraceLogTask, NULL, NULL, NULL, 1); + TraceLogTask, NULL, NULL, NULL, TASK_PRIO_HIGH); } } } @@ -514,7 +511,7 @@ static int TraceAppend(pSICSOBJ ccmd, SConnection * con, hdbInit = 1; } TaskRegisterN(pServ->pTasker,"tracestamper", - TraceLogTask, NULL, NULL, NULL, 1); + TraceLogTask, NULL, NULL, NULL, TASK_PRIO_HIGH); } return 1; }