windows simulation exiting/terminating application

dukb wrote on Tuesday, April 09, 2019:

I use windows simulation built with MinGW. Recently we updated freertos from 9.0.0 to 10.1.1.
I faced issue that our application never ends. I checked port.c and found out that in vPortEndScheduler there was TerminateProcess( GetCurrentProcess(), 0 ); which is now exchanged with exit(0).
TerminateProcess (Windows API function) unconditionally terminate current task (thread in this case) and all other tasks (threads) in same process. It doesn’t call any local destructors so in C++ application it should be called manually. exit (stdlib function) call destructors of locals in current thread (task) but do NOT finish other threads somehow (on linux it seems to work).
In the application there are even tasks created in the task which call vPortEndScheduler() so local destructor call vTaskDelete so task is closed but thread is not terminated because vPortCloseRunningThread is called only when if( pxTCB == pxCurrentTCB ) is fulfilled (looks like when task to delete is same as current running task .)
When all actions connected with exit ends application simply do other threads so to finish it taskkill needs to be used.

How freertos task in case of Windows simulator should be finished/closed/deleted?
Did anyone tries the behavior of exit with MSVC compiler?

davidefer wrote on Tuesday, April 09, 2019:

This is missing in the port. We had to implement it ourselves.

static xThreadState createdThreadsList[configMAX_PROCESSES];
static uint16_t createdThreadsNum = 0U;

In pxPortInitialiseStack add:
createdThreadsList[createdThreadsNum].pvThread = pxThreadState->pvThread;
createdThreadsNum++;

You have to let prvProcessSimulatedInterrupts return when you want to stop the application (we have done it with a dedicated simulated interrupt).

Then you can terminate all the threads:
for (int i=0; i< createdThreadsNum; i++)
{
ulErrorCode = TerminateThread(createdThreadsList[i].pvThread, 0);
configASSERT(ulErrorCode);
}

rtel wrote on Tuesday, April 09, 2019:

Thanks for the above - please let us know what if any changes are
required to shut down cleanly.

davidefer wrote on Wednesday, April 10, 2019:

see https://sourceforge.net/p/freertos/discussion/382005/thread/d8a09bc895/#f70d

dukb wrote on Wednesday, April 10, 2019:

Generally our application has one “main” task which create others tasks. “Main” task is inside C++ “main” class. So I noticed that changing TerminateProcess to exit(0) is good because destructors will be called. But as I mentioned application didn’t finished itself.
So my first solution was that I call TerminateProcess when “main” task is deleted (deletion of the task I have in destructor of my “main” class) inside* vPortCloseRunningThread* instead of ExitThread . But there is disadvantage of this solution that when task wants to be finished by itself during standard operation TerminateProcess is executed and application finished.

After davidefer replied to my post then I tried the proposition. I removed exit(0) in vPortEndScheduler and signaled scheduler to finish endless loop (and enabled interrupt so scheduler could be called). Then my application can reach return statement in main function in main thread and destructors also will be called (even for objects outside of my “main” task). So this solutions sound even better.

Unfortunately there are still some threads which are not finished and application still exist. Strange thing is when application reach main there are 4 threads already. I’m not sure if it has anything in common in affinity (which is set to 1 core further).

Next I took @davidefer port.c from
https://sourceforge.net/p/freertos/discussion/382005/thread/d8a09bc895/#f70d
and result is still the same.
So I still call TerminateProcess in vPortCloseRunningThread which is executed because pxCurrentTCB was not changed and it keeps “main” task (the task trigger process termination). The whole thing is called in “main” class destructor which is called at the end of my application. I know the solution is not elegant but it works :slight_smile:

@davidefer -> one remark to termination of threads at the end of schedule. I think in
for (int i=0; i< createdThreadsNum; i++)
{
ulErrorCode = TerminateThread(createdThreadsList[i].pvThread, 0);
configASSERT(ulErrorCode);
}
configASSERT should be removed since tasks can be finished dynamically during operation and TerminateThread can return 0. I think the best it to ignore it and try with next one.

Thanks for support, I'm still open for updates, suggestions, tips.

rtel wrote on Wednesday, April 10, 2019:

Will review these threads back in the office.