mirror of
https://bitbucket.org/librepilot/librepilot.git
synced 2025-01-18 03:52:11 +01:00
OP-942 reliable and fast free stack test algorithm - will always 'see' overflows
This commit is contained in:
parent
ebe320b435
commit
6566a29054
@ -205,6 +205,7 @@ static void systemTask(__attribute__((unused)) void *parameters)
|
|||||||
|
|
||||||
#ifdef DIAG_TASKS
|
#ifdef DIAG_TASKS
|
||||||
TaskInfoData taskInfoData;
|
TaskInfoData taskInfoData;
|
||||||
|
CallbackInfoData callbackInfoData;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// Main system loop
|
// Main system loop
|
||||||
@ -224,6 +225,9 @@ static void systemTask(__attribute__((unused)) void *parameters)
|
|||||||
// Update the task status object
|
// Update the task status object
|
||||||
PIOS_TASK_MONITOR_ForEachTask(taskMonitorForEachCallback, &taskInfoData);
|
PIOS_TASK_MONITOR_ForEachTask(taskMonitorForEachCallback, &taskInfoData);
|
||||||
TaskInfoSet(&taskInfoData);
|
TaskInfoSet(&taskInfoData);
|
||||||
|
// Update the callback status object
|
||||||
|
PIOS_CALLBACKSCHEDULER_CallbackInfo(&callbackInfoData);
|
||||||
|
CallbackInfoSet(&callbackInfoData);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// Flash the heartbeat LED
|
// Flash the heartbeat LED
|
||||||
|
@ -34,8 +34,9 @@
|
|||||||
#include <callbackinfo.h>
|
#include <callbackinfo.h>
|
||||||
|
|
||||||
// Private constants
|
// Private constants
|
||||||
#define STACK_SIZE 384
|
#define STACK_SAFETYCOUNT 16
|
||||||
#define STACK_GRANULARITY 4
|
#define STACK_SIZE (384 + STACK_SAFETYSIZE)
|
||||||
|
#define STACK_SAFETYSIZE 8
|
||||||
#define MAX_SLEEP 1000
|
#define MAX_SLEEP 1000
|
||||||
|
|
||||||
// Private types
|
// Private types
|
||||||
@ -62,8 +63,10 @@ struct DelayedCallbackInfoStruct {
|
|||||||
bool volatile waiting;
|
bool volatile waiting;
|
||||||
uint32_t volatile scheduletime;
|
uint32_t volatile scheduletime;
|
||||||
uint32_t stackSize;
|
uint32_t stackSize;
|
||||||
int32_t stackWatermark;
|
|
||||||
int32_t stackFree;
|
int32_t stackFree;
|
||||||
|
int32_t stackNotFree;
|
||||||
|
uint16_t stackSafetyCount;
|
||||||
|
uint16_t currentSafetyCount;
|
||||||
uint32_t runCount;
|
uint32_t runCount;
|
||||||
struct DelayedCallbackTaskStruct *task;
|
struct DelayedCallbackTaskStruct *task;
|
||||||
struct DelayedCallbackInfoStruct *next;
|
struct DelayedCallbackInfoStruct *next;
|
||||||
@ -74,7 +77,6 @@ struct DelayedCallbackInfoStruct {
|
|||||||
static struct DelayedCallbackTaskStruct *schedulerTasks;
|
static struct DelayedCallbackTaskStruct *schedulerTasks;
|
||||||
static xSemaphoreHandle mutex;
|
static xSemaphoreHandle mutex;
|
||||||
static bool schedulerStarted;
|
static bool schedulerStarted;
|
||||||
static CallbackInfoData callbackInfo;
|
|
||||||
|
|
||||||
// Private functions
|
// Private functions
|
||||||
static void CallbackSchedulerTask(void *task);
|
static void CallbackSchedulerTask(void *task);
|
||||||
@ -118,11 +120,6 @@ int32_t PIOS_CALLBACKSCHEDULER_Start()
|
|||||||
// only call once
|
// only call once
|
||||||
PIOS_Assert(schedulerStarted == false);
|
PIOS_Assert(schedulerStarted == false);
|
||||||
|
|
||||||
#ifdef DIAG_TASKS
|
|
||||||
CallbackInfoInitialize();
|
|
||||||
CallbackInfoGet(&callbackInfo);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// start tasks
|
// start tasks
|
||||||
struct DelayedCallbackTaskStruct *cursor = NULL;
|
struct DelayedCallbackTaskStruct *cursor = NULL;
|
||||||
int t = 0;
|
int t = 0;
|
||||||
@ -339,17 +336,18 @@ DelayedCallbackInfo *PIOS_CALLBACKSCHEDULER_Create(
|
|||||||
xSemaphoreGiveRecursive(mutex);
|
xSemaphoreGiveRecursive(mutex);
|
||||||
return NULL; // error - not enough memory
|
return NULL; // error - not enough memory
|
||||||
}
|
}
|
||||||
info->next = NULL;
|
info->next = NULL;
|
||||||
info->waiting = false;
|
info->waiting = false;
|
||||||
info->scheduletime = 0;
|
info->scheduletime = 0;
|
||||||
info->task = task;
|
info->task = task;
|
||||||
info->cb = cb;
|
info->cb = cb;
|
||||||
info->callbackID = callbackID;
|
info->callbackID = callbackID;
|
||||||
info->runCount = 0;
|
info->runCount = 0;
|
||||||
// info->stackSize = stacksize - STACK_SIZE;
|
info->stackNotFree = stacksize - STACK_SIZE;
|
||||||
info->stackFree = stacksize - STACK_SIZE;
|
info->stackSize = info->stackNotFree;
|
||||||
info->stackSize = info->stackFree;
|
info->stackFree = 0;
|
||||||
info->stackWatermark = 0;
|
info->stackSafetyCount = STACK_SAFETYCOUNT;
|
||||||
|
info->currentSafetyCount = 0;
|
||||||
|
|
||||||
// add to scheduling queue
|
// add to scheduling queue
|
||||||
LL_APPEND(task->callbackQueue[priority], info);
|
LL_APPEND(task->callbackQueue[priority], info);
|
||||||
@ -359,48 +357,109 @@ DelayedCallbackInfo *PIOS_CALLBACKSCHEDULER_Create(
|
|||||||
return info;
|
return info;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
#ifdef DIAG_TASKS
|
|
||||||
/**
|
/**
|
||||||
* Stack magic, check presence of unique value
|
* Retrieve callback specific runtime information
|
||||||
|
* \param[out] *callbackInfoData pointer to CallbackInfoData structure
|
||||||
|
* \return Success (-1), failure (0)
|
||||||
*/
|
*/
|
||||||
static int8_t markStack(DelayedCallbackInfo *current)
|
int32_t PIOS_CALLBACKSCHEDULER_CallbackInfo(void *callbackInfoData)
|
||||||
{
|
{
|
||||||
volatile unsigned char *marker;
|
if (!callbackInfoData) {
|
||||||
marker = (unsigned char*)(((size_t)&marker) - (size_t)current->stackSize);
|
return 0;
|
||||||
// end of stack watermark
|
}
|
||||||
*(marker) = '#';
|
|
||||||
// shifted watermarks
|
CallbackInfoData *info = (CallbackInfoData *)callbackInfoData;
|
||||||
marker += 16 + (size_t)current->stackWatermark;
|
|
||||||
*(marker-15) = '#';
|
|
||||||
*(marker-14) = '#';
|
struct DelayedCallbackTaskStruct *task = NULL;
|
||||||
*(marker-13) = '#';
|
LL_FOREACH(schedulerTasks, task) {
|
||||||
*(marker-12) = '#';
|
int prio;
|
||||||
*(marker-3) = '#';
|
|
||||||
*(marker-2) = '#';
|
for (prio = 0; prio < (CALLBACK_PRIORITY_LOW + 1); prio++) {
|
||||||
*(marker-1) = '#';
|
struct DelayedCallbackInfoStruct *cbinfo;
|
||||||
*(marker) = '#';
|
LL_FOREACH(task->callbackQueue[prio], cbinfo) {
|
||||||
return 0;
|
if (cbinfo->callbackID >= 0 && cbinfo->callbackID < CALLBACKINFO_RUNNING_NUMELEM) {
|
||||||
|
xSemaphoreTakeRecursive(mutex, portMAX_DELAY);
|
||||||
|
((uint8_t *)&info->Running)[cbinfo->callbackID] = true;
|
||||||
|
((uint32_t *)&info->RunningTime)[cbinfo->callbackID] = cbinfo->runCount;
|
||||||
|
((int16_t *)&info->StackRemaining)[cbinfo->callbackID] = (int16_t)cbinfo->stackNotFree;
|
||||||
|
xSemaphoreGiveRecursive(mutex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
}
|
}
|
||||||
static int8_t checkStack(DelayedCallbackInfo *current)
|
|
||||||
|
/**
|
||||||
|
* Stack magic, find how much stack is being used without affecting performance
|
||||||
|
*/
|
||||||
|
static void markStack(DelayedCallbackInfo *current)
|
||||||
{
|
{
|
||||||
volatile unsigned char *marker;
|
register int8_t t;
|
||||||
marker = (unsigned char*)(((size_t)&marker) - (size_t)current->stackSize);
|
register int32_t halfWayMark;
|
||||||
// end of stack watermark
|
volatile unsigned char *marker;
|
||||||
if (*marker != '#') return -1;
|
|
||||||
// shifted watermarks
|
if (current->stackFree < 0) {
|
||||||
marker += 16 + (size_t)current->stackWatermark;
|
return;
|
||||||
if (*(marker-15) != '#') return -2;
|
}
|
||||||
if (*(marker-14) != '#') return -2;
|
|
||||||
if (*(marker-13) != '#') return -2;
|
// end of stack watermark
|
||||||
if (*(marker-12) != '#') return -2;
|
marker = (unsigned char *)(((size_t)&marker) - (size_t)current->stackSize);
|
||||||
if (*(marker-3) != '#') return -2;
|
for (t = -STACK_SAFETYSIZE; t < 0; t++) {
|
||||||
if (*(marker-2) != '#') return 3;
|
*(marker + t) = '#';
|
||||||
if (*(marker-1) != '#') return 2;
|
}
|
||||||
if (*(marker) != '#') return 1;
|
// shifted watermarks
|
||||||
return 0;
|
halfWayMark = current->stackFree + (current->stackNotFree - current->stackFree) / 2;
|
||||||
|
marker = (unsigned char *)((size_t)marker + halfWayMark);
|
||||||
|
for (t = -STACK_SAFETYSIZE; t < 0; t++) {
|
||||||
|
*(marker + t) = '#';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
static void checkStack(DelayedCallbackInfo *current)
|
||||||
|
{
|
||||||
|
register int8_t t;
|
||||||
|
register int32_t halfWayMark;
|
||||||
|
volatile unsigned char *marker;
|
||||||
|
|
||||||
|
if (current->stackFree < 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// end of stack watermark
|
||||||
|
marker = (unsigned char *)(((size_t)&marker) - (size_t)current->stackSize);
|
||||||
|
for (t = -STACK_SAFETYSIZE; t < 0; t++) {
|
||||||
|
if (*(marker + t) != '#') {
|
||||||
|
current->stackFree = -1; // stack overflow, disable all further checks
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// shifted watermarks
|
||||||
|
halfWayMark = current->stackFree + (current->stackNotFree - current->stackFree) / 2;
|
||||||
|
marker = (unsigned char *)((size_t)marker + halfWayMark);
|
||||||
|
for (t = -STACK_SAFETYSIZE; t < 0; t++) {
|
||||||
|
if (*(marker + t) != '#') {
|
||||||
|
current->stackNotFree = halfWayMark; // tainted mark, this place is definitely used stack
|
||||||
|
current->currentSafetyCount = 0;
|
||||||
|
if (current->stackNotFree <= current->stackFree) {
|
||||||
|
current->stackFree = 0; // if it was supposed to be free, restart search between here and bottom of stack
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (current->currentSafetyCount < 0xffff) {
|
||||||
|
current->currentSafetyCount++; // mark has not been tainted, increase safety counter
|
||||||
|
}
|
||||||
|
if (current->currentSafetyCount >= current->stackSafetyCount) { // if the safety counter is above the limit, then
|
||||||
|
if (halfWayMark == current->stackFree) { // check if search already converged, if so increase the limit to find very rare stack usage incidents
|
||||||
|
current->stackSafetyCount = current->currentSafetyCount;
|
||||||
|
} else {
|
||||||
|
current->stackFree = halfWayMark; // otherwise just mark this position as free stack to narrow search
|
||||||
|
current->currentSafetyCount = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
#endif /* ifdef DIAG_TASKS */
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Scheduler subtask
|
* Scheduler subtask
|
||||||
@ -455,45 +514,14 @@ static int32_t runNextCallback(struct DelayedCallbackTaskStruct *task, DelayedCa
|
|||||||
current->waiting = false; // the flag is reset just before execution.
|
current->waiting = false; // the flag is reset just before execution.
|
||||||
xSemaphoreGiveRecursive(mutex);
|
xSemaphoreGiveRecursive(mutex);
|
||||||
|
|
||||||
#ifdef DIAG_TASKS
|
|
||||||
/* callback gets invoked here - check stack sizes */
|
/* callback gets invoked here - check stack sizes */
|
||||||
diff = markStack(current);
|
markStack(current);
|
||||||
#endif
|
|
||||||
|
|
||||||
current->cb(); // call the callback
|
current->cb(); // call the callback
|
||||||
|
|
||||||
#ifdef DIAG_TASKS
|
checkStack(current);
|
||||||
diff = checkStack(current);
|
|
||||||
switch (diff) {
|
|
||||||
case -2:
|
|
||||||
current->stackWatermark = -1;
|
|
||||||
break;
|
|
||||||
case -1:
|
|
||||||
current->stackFree = -1;
|
|
||||||
current->stackWatermark = -1;
|
|
||||||
break;
|
|
||||||
case 0:
|
|
||||||
current->stackWatermark++;
|
|
||||||
if (current->stackWatermark>current->stackFree) {
|
|
||||||
current->stackWatermark = current->stackFree;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
current->stackWatermark -= diff;
|
|
||||||
current->stackFree = current->stackWatermark;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
current->runCount++;
|
current->runCount++;
|
||||||
if (current->callbackID >= 0 && current->callbackID < CALLBACKINFO_RUNNING_NUMELEM) {
|
|
||||||
xSemaphoreTakeRecursive(mutex, portMAX_DELAY); // access to uavobject
|
|
||||||
((uint8_t *)&callbackInfo.Running)[current->callbackID] = true;
|
|
||||||
((uint32_t *)&callbackInfo.RunningTime)[current->callbackID] = current->runCount;
|
|
||||||
((int16_t *)&callbackInfo.StackRemaining)[current->callbackID] = (int16_t)current->stackWatermark;
|
|
||||||
CallbackInfoSet(&callbackInfo);
|
|
||||||
xSemaphoreGiveRecursive(mutex);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -186,4 +186,12 @@ int32_t PIOS_CALLBACKSCHEDULER_Dispatch(DelayedCallbackInfo *cbinfo);
|
|||||||
*/
|
*/
|
||||||
int32_t PIOS_CALLBACKSCHEDULER_DispatchFromISR(DelayedCallbackInfo *cbinfo, long *pxHigherPriorityTaskWoken);
|
int32_t PIOS_CALLBACKSCHEDULER_DispatchFromISR(DelayedCallbackInfo *cbinfo, long *pxHigherPriorityTaskWoken);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieve callback specific runtime information
|
||||||
|
* \param[out] *callbackInfoData pointer to CallbackInfoData structure
|
||||||
|
* \return Success (-1), failure (0)
|
||||||
|
*/
|
||||||
|
int32_t PIOS_CALLBACKSCHEDULER_CallbackInfo(void *callbackInfoData);
|
||||||
|
|
||||||
|
|
||||||
#endif // PIOS_CALLBACKSCHEDULER_H
|
#endif // PIOS_CALLBACKSCHEDULER_H
|
||||||
|
Loading…
x
Reference in New Issue
Block a user