We are running a survey to help us improve the experience for all of our members. If you see the survey appear, please take the time to tell us about your experience if you can.
I am using RTX 4.70 for a project on Cortex M-3. I have added some osXXX calls to the core RTX api.
I am finding that if I have 2 threads (in addition to main plus any timer thread or idle thread) and one is blocked on say an osDelay(), the other thread bombs when it enters kernel mode via a svc trap. I am seeing some form of stack smashing. If I increase OS_TSKCNT from 3 to 4, the problem goes away, but I fear I am postponing a later stack corruption, and that the extra TSK_CNT memory block is buying me some time.
Looking through the RTX4 sources, I am not quite sure whether each thread gets both its own thread mode stack, i.e. tracking PSP, AND its own handler mode stack, tracking MSP, or if there is a single kernel stack and ALL threads 'share it'. Surely for each thread to enter handler mode and exit from it, a dedicated handler mode stack space is needed.
I cannot quite fathom from RTX_Conf_CM.c which #define, if any, is supposed to let me 'increase my handler mode stack space'.
ANY help appreciated. I am using GCC toolchain on Linux, so I don't have an RTX-aware debugger alas. i think at this point that would be very useful.
Stu
1) The Handler Mode stack is the same as the original stack allocated at startup (vector entry 0). There is only 1 Handler Mode stack and there is no reason / need / not helpful to have more than 1. Adjusting this would either be in your startup file or in your scatter file and not part of RTX_Conf_CM.c / h. I could see where you might find it more logical to put the size of the Handler Stack in the RTX_Conf_CM.h when using and you COULD do this, but I think once you figure out how to change it in the startup / scatter file, you will just leave it alone.
2) Each Thread needs its own thread level stack. (Idle, Timer, main, your stuff)
3) You are entirely responsible for making sure these stacks are of adequate size.
4) Thread Stack sizes are "defined" by the user in RTX_CM_lib.h
4) OS_STKSIZE is used as the default thread stack size In words
5) OS_MAINSTKSIZE is use for the "main" thread stack size
6) OS_TIMERSTKSZ is used for the "timer" thread stack size
7) OS_TASKCNT is the number of threads the user may create.
8) OS_PRIVCNT is the number of threads the user may create with a non-default stack size.
9) OS_PRIVSTKSIZE is a single value that as the space to allocate for non-default stacks to allocate from. IF you use this, make sure the value is large enough to hold the sum or all the non default stack sizes you plan to use.
10) Main thread has its stack allocated from the Private stack (it also has its size MAINSTKSIZE added to OS_PRIVSTKSIZE for allocation so you do not need to worry about this)
11) Idle thread gets a default stack size.
12) Timer Thread is private stack (OS_TIMERSTKSZ - added to private stack allocation)
Thanks very much for your reply. One point I am still unsure of. Does OS_TSKCNT include the main thread, or not? I don't see it as a 'user' thread since, under RTX 4.70 at least, it's created by boilerplate code before osKernelStart(). So does OS_TSKCNT equate to the number of application-level calls to osThreadCreate, or that plus 1?
I do understand your point re MSP stack area. My gcc ld script defines __STACKTOP and my startup C code stuffs that value in vector[0]. I see that RTX never references that value, how could it, it's toolchain-derived. So then I guess the stack as defined by my ld script is ONLY used for MSP and handler mode stacking, and RTX is ignorant of this. RTX just concentrates on managing thread stacks only.
Possibly related q. Is it OK for main() to just end, or should it block, on say a Thread.join() of one of the threads spawned by main itself??
Thanks again for your help and comments, MUCH appreciated.
OS_TSKCNT needs to include the main thread also. If you make an app with nothing but a main thread you need an OS_TSKCNT needs to be at least 1. Timer Thread and Idle thread do not need to be included in this count.
It is "OK" for main() to return safely and terminate, but that has not always been the case. Not so many years ago main() returning would cause the whole system to crash. I would prefer to see an explicit ThreadTerminate(), an osDelay(osWaitForever) or just never terminate. Just stating my preference, not a right way / wrong way of doing it.
Yes, I can see now that OS_TSKCNT should include main.
As with so many scenarios of this type of debugging, I was on the wrong path for quite a while. I wasn't stack smashing at all, but now I am more aware of stack requirements, so this has been a good exercise.
For anyone interested in a 'don't do it like this':
1 An ISR calls os_signalSet( T, S); on a thread T but that thread had already exited (called osThreadExit())
2 ISR sets PendSV and exits
3 PendSV tries to decide who to run and sees a corruption in the RTX data structs, since the os_signalSet did some nasty updates (I haven't quite worked out what)
4 PendSV encounters a Hard Fault.
Curiously, and again I am not fully aware of why, if I bumped OS_TSKCNT to one more that the thread count I actually needed, I would 'get away with' the error condition, but of course not sure for how long.
The problem was in my application code, as is usual ;)