29 #include <oc_stdlib.h> 30 #include <oc_system_cfg.h> 45 #define _________________________________________LOCAL_FUNCTIONS_SECTION____________________________________________________________________ 47 static void MemoryEventHandler(
void * Address , MemoryEventFlags_t Event ,
const char * Function, uint32_t LineNumber );
49 static void CountCpuLoad(
void );
50 static void SysTickHandler(
void);
52 #undef _________________________________________LOCAL_FUNCTIONS_SECTION____________________________________________________________________ 60 #define _________________________________________VARIABLES_SECTION__________________________________________________________________________ 62 static void * SavedThreadsListAddress =
NULL;
64 static oC_Time_t InIdleTime = 0;
65 static oC_Time_t CurrentInIdleTime = 0;
66 static double CpuLoad = 0;
67 static double CurrentCpuLoad = 0;
68 static double CpuLoadPanicMargin = CFG_PERCENT_CPU_LOAD_PANIC_MARGIN;
69 static oC_Time_t CpuLoadPanicTimeLimit = CFG_TIME_CPU_LOAD_PANIC_TIME;
70 static oC_Time_t CpuLoadPanicTimeout = 0;
71 static oC_Time_t CpuLoadMeasureTimeout = oC_Frequency_ToTime(CFG_FREQUENCY_CPU_LOAD_MEASUREMENT_FREQUENCY);
72 static oC_Time_t CpuLoadMeasureTime = 0;
75 static oC_MemorySize_t RedZoneSize = CFG_BYTES_DEFAULT_RED_ZONE_SIZE;
76 static oC_Frequency_t SystemFrequency = CFG_FREQUENCY_DEFAULT_SYSTEM_TIMER_FREQUENCY;
77 static oC_AutoStackMethod_t AutoStackMethod = CFG_BOOL_RERUN_THREAD_WHEN_STACK_IS_OVER ? oC_AutoStackMethod_RerunThread : oC_AutoStackMethod_Disabled;
78 static oC_MemorySize_t StackIncreaseStep = CFG_BYTES_STACK_INCREASE_STEP;
79 static oC_Time_t LastSwitchTime = 0;
80 uint64_t oC_ThreadManTickCounter = 0;
81 static oC_Time_t ForceChangeThreadTimeout= 0;
83 static oC_MemorySize_t DefaultStackSize = CFG_BYTES_DEFAULT_THREAD_STACK_SIZE;
86 .
Name =
"thread manager" ,
88 .EventFlags = MemoryEventFlags_BufferOverflow |
89 MemoryEventFlags_DataSectionOverflow |
90 MemoryEventFlags_PossibleMemoryLeak |
91 MemoryEventFlags_ModuleTurningOff |
92 MemoryEventFlags_PanicMemoryExhausted
95 .Name =
"Thread Manager" ,
96 .Module = oC_Module_ThreadMan ,
97 .TurnOnFunction = oC_ThreadMan_TurnOn ,
98 .TurnOffFunction = oC_ThreadMan_TurnOff ,
99 .RequiredModules = { 0 }
102 #undef _________________________________________VARIABLES_SECTION__________________________________________________________________________ 110 #define _________________________________________INTERFACE_FUNCTIONS_SECTION________________________________________________________________ 114 oC_ErrorCode_t oC_ThreadMan_TurnOn(
void )
116 oC_ErrorCode_t errorCode = oC_ErrorCode_ImplementError;
122 if(errorCode == oC_ErrorCode_ModuleIsTurnedOn || errorCode == oC_ErrorCode_None)
124 CurrentThread =
NULL;
125 ThreadToRemove =
NULL;
126 SystemFrequency = CFG_FREQUENCY_DEFAULT_SYSTEM_TIMER_FREQUENCY;
127 ThreadList = oC_List_New(&
Allocator,AllocationFlags_NoWait);
129 oC_ThreadManTickCounter = 0;
130 ForceChangeThreadTimeout= 0;
134 SavedThreadsListAddress = ThreadList;
139 errorCode = oC_ErrorCode_None;
144 errorCode = oC_ErrorCode_AllocationError;
154 oC_ErrorCode_t oC_ThreadMan_TurnOff(
void )
156 oC_ErrorCode_t errorCode = oC_ErrorCode_ImplementError;
163 oC_List_Delete(ThreadList,AllocationFlags_CanWaitForever);
165 if(errorCode == oC_ErrorCode_ModuleNotStartedYet || errorCode == oC_ErrorCode_None)
167 errorCode = oC_ErrorCode_None;
176 oC_ErrorCode_t oC_ThreadMan_SetSystemTimerFrequency(
oC_Frequency_t Frequency )
178 oC_ErrorCode_t errorCode = oC_ErrorCode_ImplementError;
192 return SystemFrequency;
197 oC_ErrorCode_t oC_ThreadMan_AddThread(
oC_Thread_t Thread )
199 oC_ErrorCode_t errorCode = oC_ErrorCode_ImplementError;
203 oC_AssignErrorCodeIfFalse(&errorCode , oC_Thread_IsCorrect(Thread) , oC_ErrorCode_ObjectNotCorrect )
208 oC_IntMan_EnterCriticalSection();
209 added = oC_List_PushBack(ThreadList,Thread,&
Allocator);
210 oC_IntMan_ExitCriticalSection();
214 oC_ThreadMan_SwitchThread();
215 errorCode = oC_ErrorCode_None;
219 errorCode = oC_ErrorCode_CannotAddObjectToList;
228 oC_ErrorCode_t oC_ThreadMan_RemoveThread(
oC_Thread_t Thread )
230 oC_ErrorCode_t errorCode = oC_ErrorCode_ImplementError;
234 oC_AssignErrorCodeIfFalse(&errorCode , oC_Thread_IsCorrect(Thread) , oC_ErrorCode_ObjectNotCorrect )
237 oC_IntMan_EnterCriticalSection();
238 bool objectFound = oC_List_Contains(ThreadList,Thread);
240 oC_List_Take(ThreadList,Thread,takenThread);
241 oC_IntMan_ExitCriticalSection();
243 if(takenThread == Thread)
245 oC_IntMan_EnterCriticalSection();
246 if(CurrentThread == Thread)
248 ThreadToRemove = Thread;
249 errorCode = oC_ErrorCode_None;
253 if(oC_Thread_Delete(&Thread))
255 oC_ThreadMan_SwitchThread();
256 errorCode = oC_ErrorCode_None;
260 errorCode = oC_ErrorCode_CannotDeleteObject;
263 oC_IntMan_ExitCriticalSection();
265 else if(objectFound ==
false)
267 errorCode = oC_ErrorCode_None;
271 errorCode = oC_ErrorCode_CannotRemoveObjectFromList;
281 bool oC_ThreadMan_ContainsThread(
oC_Thread_t Thread )
283 bool contains =
false;
285 if(oC_SaveIfFalse(
"Module is not enabled",
oC_Module_IsTurnedOn(oC_Module_ThreadMan), oC_ErrorCode_ModuleNotStartedYet ))
287 contains = oC_List_Contains(ThreadList,Thread);
302 void oC_ThreadMan_UnblockAllBlockedBy( uint32_t * BlockingFlag ,
bool OnlyIfUnblocked )
306 oC_List_Foreach(ThreadList,thread)
308 if(oC_Thread_IsBlockedBy(thread,BlockingFlag))
310 oC_IntMan_EnterCriticalSection();
311 if(!OnlyIfUnblocked || !oC_Thread_IsBlocked(thread))
313 oC_Thread_SetUnblocked(thread);
315 oC_IntMan_ExitCriticalSection();
319 oC_ThreadMan_SwitchThread();
325 void oC_ThreadMan_SwitchThread(
void )
327 static bool repairInProgress =
false;
329 char tempString[100] = {0};
330 bool foundOverflow =
false;
336 oC_List_Foreach(ThreadList,thread)
338 if(oC_Thread_IsCorrect(thread) ==
false)
340 kdebuglog(oC_LogType_Error ,
"switch-thread: Thread [%p] '%s' is not correct!\n", thread , oC_Thread_GetName(thread));
342 if(oC_List_Verify(ThreadList) ==
false )
348 sprintf(tempString,
"Overflowed buffer: [%p] with size: %d Allocated at: %s:%d", allStat.Address, allStat.Size, allStat.Function,allStat.LineNumber);
352 sprintf(tempString,
"(Damaged thread: %p - %s)", thread, oC_Thread_GetName(thread));
355 if(repairInProgress ==
false)
357 repairInProgress =
true;
359 if(List_Repair((
oC_List_t)ThreadList,SavedThreadsListAddress,CFG_UINT32_MAXIMUM_NUMBER_OF_THREADS))
361 oC_ThreadMan_SwitchThread();
362 repairInProgress =
false;
363 oC_ExcHan_LogEvent(
"Restored stable state after fatal exception. Threads list was damaged. There is a possibility of memory leakage.", tempString,
NULL, CurrentThread, oC_ExcHan_ExceptionType_KernelPanic);
370 oC_ExcHan_LogEvent(
"Cannot restore stable state after fatal exception. Threads list is damaged.", tempString,
NULL, CurrentThread, oC_ExcHan_ExceptionType_KernelPanic | oC_ExcHan_ExceptionType_RequiredReboot);
376 oC_Boot_Restart( oC_Boot_Reason_SystemException, oC_UserMan_GetRootUser() );
384 oC_ExcHan_LogEvent(
"Cannot restore stable state after fatal exception. Threads list is damaged.", tempString,
NULL, CurrentThread, oC_ExcHan_ExceptionType_KernelPanic | oC_ExcHan_ExceptionType_RequiredReboot);
390 oC_Boot_Restart( oC_Boot_Reason_SystemException, oC_UserMan_GetRootUser() );
396 oC_List_RemoveCurrentElement(ThreadList,thread);
399 else if(oC_Thread_IsBlocked(thread) ==
false)
401 oC_Thread_Priority_t nextPriority = oC_Thread_GetPriority(NextThread);
402 oC_Thread_Priority_t priority = oC_Thread_GetPriority(thread);
404 (NextThread ==
NULL) ||
405 (priority > nextPriority) ||
406 (priority == nextPriority && oC_Thread_GetLastExecutionTick(thread) < oC_Thread_GetLastExecutionTick(NextThread))
425 oC_Thread_t oC_ThreadMan_GetThread(
const char * Name )
431 oC_List_Foreach(ThreadList,thread)
433 if(strcmp(oC_Thread_GetName(thread),Name) == 0)
435 threadToReturn = thread;
440 return threadToReturn;
445 oC_MemorySize_t oC_ThreadMan_GetDefaultStackSize(
void )
447 return DefaultStackSize;
452 oC_ErrorCode_t oC_ThreadMan_SetDefaultStackSize( oC_MemorySize_t Size )
454 oC_ErrorCode_t errorCode = oC_ErrorCode_ImplementError;
458 && ErrorCondition(Size > 0 , oC_ErrorCode_SizeNotCorrect )
462 errorCode = oC_ErrorCode_None;
470 oC_ErrorCode_t oC_ThreadMan_SetAutoStackMethod( oC_AutoStackMethod_t Method )
472 oC_ErrorCode_t errorCode = oC_ErrorCode_ImplementError;
476 && ErrorCondition( Method >= 0 && Method <= oC_AutoStackMethod_RerunThread , oC_ErrorCode_AutoStackMethodNotCorrect )
479 AutoStackMethod = Method;
480 errorCode = oC_ErrorCode_None;
488 oC_AutoStackMethod_t oC_ThreadMan_GetAutoStackMethod(
void )
490 return AutoStackMethod;
495 oC_ErrorCode_t oC_ThreadMan_SetRedZoneSize( oC_MemorySize_t Size )
497 oC_ErrorCode_t errorCode = oC_ErrorCode_ImplementError;
501 && ErrorCondition(Size > 0 , oC_ErrorCode_SizeNotCorrect )
505 errorCode = oC_ErrorCode_None;
513 oC_MemorySize_t oC_ThreadMan_GetRedZoneSize(
void )
520 oC_ErrorCode_t oC_ThreadMan_SetStackIncreaseStep( oC_MemorySize_t Size )
522 oC_ErrorCode_t errorCode = oC_ErrorCode_ImplementError;
526 && ErrorCondition(Size > 0 , oC_ErrorCode_SizeNotCorrect )
530 errorCode = oC_ErrorCode_None;
538 oC_MemorySize_t oC_ThreadMan_GetStackIncreaseStep(
void )
540 return StackIncreaseStep;
545 double oC_ThreadMan_GetCpuLoad(
void )
552 double oC_ThreadMan_GetCurrentCpuLoad(
void )
554 return CurrentCpuLoad;
559 oC_Thread_t oC_ThreadMan_GetThreadOfContext(
void * Context )
563 foreach(ThreadList, thread)
565 bool inRedZone =
false;
569 foundThread = thread;
576 #undef _________________________________________INTERFACE_FUNCTIONS_SECTION________________________________________________________________ 583 #define _________________________________________LOCAL_FUNCTIONS_SECTION____________________________________________________________________ 593 CurrentThread =
NULL;
598 static void CountCpuLoad(
void )
600 oC_Timestamp_t currentTimestamp = oC_KTime_GetTimestamp();
601 oC_Time_t timeFromLastSwitch = currentTimestamp - LastSwitchTime;
602 CpuLoadMeasureTime += timeFromLastSwitch;
606 InIdleTime += timeFromLastSwitch;
607 CurrentInIdleTime += timeFromLastSwitch;
609 CpuLoad = (100.0 - (InIdleTime / currentTimestamp) * 100);
611 if(CpuLoadMeasureTime >= CpuLoadMeasureTimeout || (CurrentCpuLoad == 0 && CpuLoadMeasureTime > 0))
613 CurrentCpuLoad = (100.0 - (CurrentInIdleTime / CpuLoadMeasureTime) * 100);
614 CpuLoadMeasureTime = 0;
615 CurrentInIdleTime = 0;
618 if(CurrentCpuLoad > CpuLoadPanicMargin)
620 if(CpuLoadPanicTimeout > 0)
622 if(CpuLoadPanicTimeout < currentTimestamp)
626 sprintf_s(
string,
sizeof(
string),
"margin = %f, thread name = %s", CurrentCpuLoad, oC_Thread_GetName(CurrentThread));
628 CpuLoadPanicTimeout = 0;
629 ForceChangeThreadTimeout = currentTimestamp;
630 oC_Thread_Delete(&CurrentThread);
635 CpuLoadPanicTimeout = currentTimestamp + CpuLoadPanicTimeLimit;
640 CpuLoadPanicTimeout = 0;
646 static void SysTickHandler(
void)
650 oC_IntMan_EnterCriticalSection();
651 oC_Time_t currentTime = oC_KTime_GetTimestamp();
659 if(currentContext != threadContext)
661 kdebuglog(oC_LogType_Error ,
"systick: current context is not current thread!");
662 kdebuglog(oC_LogType_Error ,
"systick: Searching new thread...");
664 oC_ThreadMan_SwitchThread();
670 if(ThreadToRemove == CurrentThread)
672 CurrentThread =
NULL;
674 oC_Thread_Delete(&ThreadToRemove);
675 ThreadToRemove =
NULL;
678 if(oC_Thread_IsBlocked(CurrentThread) || currentTime >= ForceChangeThreadTimeout)
683 oC_Thread_AddToExecutionTime(CurrentThread, currentTime - LastSwitchTime);
684 oC_Thread_SetLastExecutionTick(CurrentThread,oC_ThreadManTickCounter);
687 LastSwitchTime = currentTime;
689 if(NextThread ==
NULL || oC_Thread_IsBlocked(NextThread))
691 oC_ThreadMan_SwitchThread();
694 if(NextThread != CurrentThread)
696 if(NextThread ==
NULL && currentTime >= ForceChangeThreadTimeout && CurrentThread !=
NULL && oC_Thread_IsBlocked(CurrentThread) ==
false)
700 if(errorCode != oC_ErrorCode_None)
702 oC_Int_t freeStackSize = oC_Thread_GetFreeStackSize(CurrentThread,
true);
703 if(freeStackSize <= 0)
705 kdebuglog(oC_LogType_Error,
"systick: Stack of the thread %s is too small! Closing..." , oC_Thread_GetName(CurrentThread));
706 kdebuglog(oC_LogType_Error,
"%s: lack of %d stack bytes..." , oC_Thread_GetName(CurrentThread) , freeStackSize);
710 sprintf(
string,
"Stack of the thread %s is too small! Lack of %d bytes", oC_Thread_GetName(CurrentThread), freeStackSize);
712 oC_ExcHan_LogEvent(
"Stack of the thread is too small!\n",
string,
NULL, CurrentThread, oC_ExcHan_ExceptionType_ProcessDamaged);
714 oC_SaveError(
"ThreadMan : SysTickHandler - cannot set next context (after timeout): " , errorCode );
715 oC_ThreadMan_RemoveThread(CurrentThread);
719 else if(NextThread !=
NULL)
721 ForceChangeThreadTimeout = oC_Frequency_ToTime(CFG_FREQUENCY_DEFAULT_FORCE_CHANGE_THREAD) + currentTime;
725 if(errorCode == oC_ErrorCode_None)
727 CurrentThread = NextThread;
732 oC_Int_t freeStackSize = oC_Thread_GetFreeStackSize(NextThread,
true);
735 if(freeStackSize <= 0)
737 kdebuglog(oC_LogType_Error,
"systick: Stack of the thread %s is too small! Closing..." , oC_Thread_GetName(oldThread));
738 kdebuglog(oC_LogType_Error,
"%s: lack of %d stack bytes..." , oC_Thread_GetName(oldThread) , freeStackSize);
741 sprintf(
string,
"Stack of the thread `%s` is too small! Lack of %d bytes", oC_Thread_GetName(oldThread), freeStackSize);
743 oC_ExcHan_LogEvent(
"Stack of the thread is too small!\n",
string,
NULL, oldThread, oC_ExcHan_ExceptionType_ProcessDamaged);
745 if(AutoStackMethod == oC_AutoStackMethod_RerunThread)
747 oC_MemorySize_t newStackSize = oC_Thread_GetStackSize(oldThread) + StackIncreaseStep;
748 oC_Thread_t newThread = oC_Thread_CloneWithNewStack(oldThread,newStackSize);
750 kdebuglog(oC_LogType_Error ,
"%s-rerun: new stack size: %uB" , oC_Thread_GetName(oldThread) , newStackSize);
752 errorCode = oC_ThreadMan_AddThread(newThread);
754 if(oC_ErrorOccur(errorCode))
756 kdebuglog(oC_LogType_Error ,
"systick: cannot rerun thread '%s'" , oC_Thread_GetName(oldThread));
757 kdebuglog(oC_LogType_Error ,
"systick: rerun error: %s" ,
oC_GetErrorString(errorCode));
761 oC_SaveError(
"ThreadMan : SysTickHandler - cannot set next context: " , errorCode );
762 oC_ThreadMan_RemoveThread(oldThread);
771 else if(CurrentThread ==
NULL)
776 oC_IntMan_ExitCriticalSection();
779 oC_ThreadManTickCounter++;
784 static void MemoryEventHandler(
void * Address , MemoryEventFlags_t Event ,
const char * Function, uint32_t LineNumber )
788 sprintf(
string,
"Event flags: 0x%X, Address = %p, %s:%d", Event, Address, Function, LineNumber);
793 #undef _________________________________________LOCAL_FUNCTIONS_SECTION____________________________________________________________________
oC_SYS_LLD_Context_t * oC_SYS_LLD_GetSystemContext(void)
returns pointer to the system context
double oC_Frequency_t
type to store frequency
identifier for allocations
oC_UInt_t oC_MemMan_AlignSizeTo(oC_UInt_t Size, oC_UInt_t Alignment)
returns size aligned to the given alignment
oC_SYS_LLD_Context_t * oC_SYS_LLD_GetCurrentContext(void)
returns pointer to the current context
The file with interface for process manager.
File with interface for user system manager.
oC_ErrorCode_t oC_SYS_LLD_TurnOnDriver(void)
initializes the driver to work
oC_ErrorCode_t oC_SYS_LLD_ReturnToSystemContext(void)
switches to the system context
oC_ErrorCode_t oC_SYS_LLD_ConfigureSystemTimer(oC_Frequency_t Frequency, oC_SYS_LLD_SysTickIncrementHandler_t Interrupt)
configures system timer
void oC_SYS_LLD_Context_t
type for storing context of the machine
oC_ErrorCode_t oC_SYS_LLD_TurnOffDriver(void)
release the driver
The file with interface for the module library.
static bool oC_Module_IsTurnedOn(oC_Module_t Module)
checks if the module is turned on
void oC_Boot_Restart(oC_Boot_Reason_t Reason, oC_User_t User)
restarts the system
bool oC_MemMan_FindOverflowedAllocation(Allocator_t Allocator, oC_MemMan_AllocationStats_t *outAllocationStat)
searches for a overflowed buffer
void oC_ExcHan_LogEvent(const char *Name, char *AdditionalInfo, void *Stack, oC_Thread_t Thread, oC_ExcHan_ExceptionType_t Type)
logs system event
The file with interface for interrupt manager.
oC_ErrorCode_t oC_SYS_LLD_SetNextContext(oC_SYS_LLD_Context_t *Context)
configures next machine context
static void MemoryEventHandler(void *Address, MemoryEventFlags_t Event, const char *Function, uint32_t LineNumber)
handler for memory manager events
oC_UInt_t oC_MemMan_AlignSize(oC_UInt_t Size)
returns size aligned to the machine alignment
static void oC_Module_TurnOn(oC_Module_t Module)
sets module as turned on
File with interface of Exception Handler.
static void SysTickReturnToIdle(void)
static bool oC_Module_TurnOffVerification(oC_ErrorCode_t *outErrorCode, oC_Module_t Module)
verify if module is turned off
static const oC_Allocator_t Allocator
static bool oC_Module_TurnOnVerification(oC_ErrorCode_t *outErrorCode, oC_Module_t Module)
verify if module is turned on
const char * oC_GetErrorString(oC_ErrorCode_t ErrorCode)
The file with LLD interface for the SYS driver.
bool oC_Thread_IsOwnedByStack(oC_Thread_t Thread, const void *Address, bool *outAddressInRedZone)
checks if the given address is owned by the thread stack
The file with interface for Thread Manager.
#define oC_MEM_LLD_STACK_ALIGNMENT
number of bytes in alignment of the stack
The file with interface of kernel time module.
#define NULL
pointer to a zero
static void oC_Module_TurnOff(oC_Module_t Module)
sets module as turned off