Possible bug in the way prvTimerTask() thread function is started in Win32 Port

It seems that in the windows Win32 kernel port of FreeRTOS, version of kernel 'FreeRTOS Kernel V10.5.1 version", per file header at the top, inside “timers.c”, there is a bug in a way prvTimerTask() thread function is started. The problem is that on my notebook, 8 × AMD Ryzen 5 CPU, Lenovo IdeaPad 3 15ADA05, it sometimes started BEFORE the main scheduler loop in the prvProcessSimulatedInterrupts() function. This causes assertion failure because “xPortRunning = pdTRUE;” line inside prvProcessSimulatedInterrupts() was not executed. Assertion failure is generated in the following stack trace state:

prvTimerTask()->prvProcessTimerOrBlockTask()->xTaskResumeAll()->taskEXIT_CRITICAL()->(portEXIT_CRITICAL)->vPortExitCritical()

	if( pvInterruptEventMutex != NULL )
	{
		if( lMutexNeedsReleasing == pdTRUE )
		{
			--> configASSERT( xPortRunning );
			ReleaseMutex( pvInterruptEventMutex );
		}
	}

since xPortRunning is still FALSE at this point.

I was able to fix this, presumably, bug by adding

        extern HANDLE hInitDone;
        WaitForSingleObject(hInitDone, INFINITE);

at the beginning of prvTimerTask() function, and also by adding
SetEvent(hInitDone); after “xPortRunning = pdTRUE;” line inside prvProcessSimulatedInterrupts().
hInitDone is initialized before as
HANDLE hInitDone = CreateEventA(NULL, TRUE, FALSE, NULL);

The problem appears only on this notebook, under Debian 12, kernel 6.1.0-18-amd64 (64-bit) + wine9.0 + mingw64-w32 gcc-12 posix (in both 32 and 64 bit output binary formats). On my more older work PC, with 2 CPU cores and Windows 7 OS, the same executable with FreeRTOS firmware working in emulation mode, do not exhibit this assertion failure (bug).

Thanks for taking the time to report this. I suspect this check-in is the root cause because it moves setting the flag to say the scheduler is running to a location too early in the initialisation. Could you try the version before this checkin - or alternatively manually undo this checkin, to see if that resolves your issue. Thanks.

Even before this check-in, as I understand, xPortRunning was set to pdTRUE, only after starting the first task via

ResumeThread( pxThreadState->pvThread )

As I understand, this behavior has relation with how Windows or Wine kernel treats thread priorities, especially when REALTIME_PRIORITY_CLASS was set for a given process. It seems that wine-9.0, at least on multi-core machines, does not guarantee that the only thread that will be in the running state among process threads with REALTIME_PRIORITY_CLASS set, would be the thread with highest priority.

The root cause, as I understand, is that

    pxThreadState = ( ThreadState_t * ) *( ( size_t * ) pxCurrentTCB );
    ResumeThread( pxThreadState->pvThread );

is called before xPortRunning is set to TRUE, inside xPortStartScheduler().

When I move the above two lines just after
xPortRunning = pdTRUE;
in the prvProcessSimulatedInterrupts() function, that assertion failure vanishes, without need for an extra Event hInitDone. Although I’m not sure that this movement does not break something else in the code.

Aside from this behavior, I experience strange failures (unexpected second-range delays) of xSemaphoreTakeRecursive() functions in the same program under the same wine platform. The problem maybe not in the FreeRTOS MSVC-MinGW port code, but in the lack of respect for real time priority class used by FreeRTOS source code to do its work, by this version of wine.

Your description of the difference in where xPortRunning is set to true is more accurate than mine.

I’ve never tried executing Wine. The code should still work even without the real time priority as long as the relative priorities are maintained - although without running real time you may get false positive failures (does that make sense?) in some of the tests the Win32 demo runs.

Are you able to use the POSIX/Linux simulator instead of the Windows one? That would avoid needing Wine.

From MSDN docs, Microsoft guarantees that if process has set REALTIME_PRIORITY_CLASS for itself, and possibly if priority boost for all thread in question is disabled, then OS scheduler will execute only thread with the highest priority value. FreeRTOS Windows port uses portSIMULATED_INTERRUPTS_THREAD_PRIORITY = THREAD_PRIORITY_TIME_CRITICAL for thread with prvProcessSimulatedInterrupts() function (former main thread, from which xPortStartScheduler() function is invoked), and portTASK_THREAD_PRIORITY = THREAD_PRIORITY_ABOVE_NORMAL for all Tasks (user threads), including Task for software timers. So per Microsoft docs, see SetPriorityClass function (processthreadsapi.h) - Win32 apps | Microsoft Learn, if the former thread is ready to run, the latter software timers thread should not be in runnable state. But the only logical explanation of why the above-mentioned assert got triggered, is that this is not the case on the desribed setup, and that sometimes (about 4 out of 5 runs), software timers thread functions was run either instead of prvProcessSimulatedInterrupts(), or in parallel. Yes, the problem, strictly speaking, is not in the REALTIME or not thread properties, but in the relative priorities of these threads. But I wrote about REALTIME attribute because it should imply, according to documentation, strict respect of relative priorities.

I tried to install winehq-staging packet, this changed version of wine to win-9.7 (staging), but behavior is the same. I also think that it would be more adequate to use POSIX FreeRTOS port and native Linux executable in this setup, but the idea was to use the same emulator firmware build under Windows and Linux. If I have time to play with it, I will write back to this forum thread.

1 Like

This change seems safe to me. Would you be willing to raise a PR for the same or would you like us to do it?

I re-read docs about REALTIME priority class, and it seems that I mistakenly blamed wine for not respecting its description. The problem here is that after first
ResumeThread( pxThreadState->pvThread ); call, we have at least two runnable thread: the former main, which is about to become scheduler thread, with endless loop in the prvProcessSimulatedInterrupts(), and our first FreeRTOS task with highest FreeRTOS task priority. They both have REALTIME class, and although thread with prvProcessSimulatedInterrupts() function has higher priority, on systems with two or more physical cores, it is absolutely legal to run both of them in parallel. So the reason that I did not experience this assertion failure on my work PC with Windows 7 OS, and experienced on my home PC with Linux+Wine, with the same program source code, is likely not in the differences between Windows and Wine schedulers, but in the fact that the home PC is faster, with 8 vs 2 cores, and so some race conditions have higher probability to manifest itself.

It would be nice if you would raise PR instead of me, because I’m, frankly speaking, still not quite accustomed to that community-adopted development process/system. This change not only will fix this bug with Simulated Software Timers thread, but also will eliminate possible similar situations in user threads code, when someone would potentially check for xPortRunning flag at the very beginning of the user thread code, in the thread function which will be selected to run first.

1 Like

This PR fixes the issue - Update xPortRunning before resuming first task by aggarg · Pull Request #1049 · FreeRTOS/FreeRTOS-Kernel · GitHub.

1 Like