_impure_ptr not setup when entering first task

beginend1 wrote on Friday, October 04, 2013:

Did I missed something or _impure_ptr only is initialized in vTaskSwitchContext(). This makes (on my SMT32f4 uC) that before first context switch _REENT points at global impute_data variable instead of first task reent variable.

Second: I think, that you should use _REENT macro instead of _impure_ptr directly.

FreeRTOS version 7.5.2

rtel wrote on Friday, October 04, 2013:

Did I missed something or _impure_ptr only is initialized in vTaskSwitchContext().

Hopefully you missed something, but like I say in the comments, I don’t use the newlib stuff myself so I am reliant on the people who requested its existence to let me know if anything is wrong.

prvInitialiseTCBVariables() (in tasks.c) is called to initialise the task control block of a task when the task is created - not when the task is first switched in. prvInitialiseTCBVariables() contains the following code which, I think, means each task has its own initialised impure_ptr.

#if ( configUSE_NEWLIB_REENTRANT == 1 )
{
    /* Initialise this task's Newlib reent structure. */
    _REENT_INIT_PTR( ( &( pxTCB->xNewLib_reent ) ) );
}
#endif /* configUSE_NEWLIB_REENTRANT */

Second: I think, that you should use _REENT macro instead of _impure_ptr directly

So the line:
_impure_ptr = &( pxCurrentTCB->xNewLib_reent );

should become?:
_REENT = &( pxCurrentTCB->xNewLib_reent );

Is that right? Will everything else still compile ok?

Regards.

beginend1 wrote on Friday, October 04, 2013:

I am no talking about allocation of _reent struct but initialization of _impure_ptr. Task switching properly changes _impure_ptr but first task doesn’t use the vTaskSwitchContext() but prvPortStartFirstTask() which is port specific, and this function does not touch _impure_ptr. I’ve looked at the code and there is no clean solution. The _impure_ptr can’t be initialized in prvPortStartFirstTask() becouse tskTCB is opaque there. The only solution came up is initialization of _impure_ptr just before call to prvPortStartFirstTask() and somehow in xTaskResumeAll() and/or in xTaskGenericCreate().

rtel wrote on Friday, October 04, 2013:

Ok, I understand now. So it is just the first execution of the first task that the pointer is not configured, not the first execution of every task.

When xPortStartScheduler() is called pxCurrentTCB already points to the task that will be started first, so I think the following code added before xPortStartScheduler() should do what you want.

#if ( configUSE_NEWLIB_REENTRANT == 1 )
{
	/* Switch Newlib's _impure_ptr variable to point to the _reent
	structure specific to the task that will run first. */
	_impure_ptr = &( pxCurrentTCB->xNewLib_reent );
}
#endif /* configUSE_NEWLIB_REENTRANT */

Do you agree?

Regards.

beginend1 wrote on Friday, October 04, 2013:

Yes, this code is needed but NOT BEFORE calling xPortStartScheduler(). Some code may want to do something before creating tasks and starting scheduler. If you switch _impure_ptr there you can mess up a lot of things (eg. stdin/out/err will be different, different errno variable, etc.). This must be done inside xPortStartScheduler(). I don’t know FreeRTOS source so good to tell you if xPortStartScheduler() is the only place where _REEN should be guarded. Generally speaking, all places where pxCurrentTCB is changed and task is switched should follow _REEN synchronization with new task. My doubts are also places where you create/delete tasks when scheduler is suspended, this is the reason why I pointed out xTaskResumeAll() and xTaskGenericCreate().

And at the end I think that
_REENT = &( pxCurrentTCB->xNewLib_reent );
will be ok :stuck_out_tongue:

rtel wrote on Friday, October 04, 2013:

I understand your point, but I’m not sure I understand the danger of where I have placed the code.

The sequence is as follows:

  1. Interrupts are disabled.
  2. The pointer is set to be correct for the first task.
  3. xPortStartScheduler() is called.
  4. The first task starts to run

Interrupt are not enabled until the point that the first task start to run - and all the code executed in between steps 1 and 4 is FreeRTOS code. There is no possibility of any application code running during this time, so no possibility of any inadvertent calls to newlib.

I would be grateful if you could elaborate using this scenario so I can get a better understanding.

Regards.

beginend1 wrote on Saturday, October 05, 2013:

Ok, looked again and you are right. I was thinking about vTaskStartScheduler() instead of xPortStartScheduler(). Your solution should work.