We are using FreeRTOS with C++. Our main application is globally defined and so it's contructor gets called in the run init array. Afterwards main is called which finally calls vTaskStartScheduler.
Queues and mutexes are created in the constructors. Also some mutexes get locked and unlocked at that state. Even so this would not be necessary as nothing is running concurrently we do it anyway because we don't want to have duplicated code, one that locks the mutex and other that doesn't.
I now observed that all interrupts we disabled in this phase until the scheduler was started what caused for instance the USB not be ready until the scheduler was started. This caused to fail the enumeration process with some hosts.
I tracked the problem down to the vPortExitCritical which is called from xQueueGenericCreate -> pvPortMalloc -> xTaskResumeAll. As uxCriticalNesting is initialized to 0xaaaaaaaa the condition uxCriticalNesting == 0 is not true and thus portENABLE_INTERRUPTS() is not called and the interrupts remain disabled.
The same problem was already discussed here:
A proposed solution was to initialize uxCriticalNesting to 0. Is this safe? What are the drawbacks?
There are also threads related to the question what of the API can be used before the call of vTaskStartScheduler:
It would very helpful to know which API calls can be used before the call of vTaskStartScheduler.
In my opinion as many as API functions as possible should be usable before vTaskStartScheduler, even a e.g. xSemaphoreTake with a non-zero timeout because there is no other task that could have taken it. If so, an assertion should be triggered
Thanks a lot for any comment on this.
The initialisation of the critical nesting count to a non-zero value is,
as you have observed, quite deliberate and therefore not considered an
'issue'. It is done to ensure interrupts remain masked (up to a user
definable value) between FreeRTOS objects being created and the
scheduler being started - at which point they are unmasked.
Historically, going back many years, a very common source of support
requests originated from interrupts attempting to use kernel services
before the scheduler had been started - so this mechanism was introduced
to prevent that. You asked if changing the initialisation value to 0
would be dangerous - it would only be dangerous in the situation above -
where an RTOS object was created and something such as an interrupt
attempted to use it before the kernel was ready.
Copyright (C) Amazon Web Services, Inc. or its affiliates. All rights reserved.