What could FreeRTOS do next? Share your Ideas

At least one reason the task entry point (“task function”) needs to have C language linkage, not C++ linkage. It’s the same problem with callbacks that expect C; by default, C++ class member functions don’t have the right linkage.

I do not recall if you can simply define a member of the class with “extern "C"” or if you have to have to have a non-member function declared “extern "C"” and have the task parameter be a pointer to the instance of the class, and then have that function call the task function of the object (after the parameter was cast to the correct pointer type). I have done the latter, I don’t recall if I’ve done the former.

What could FreeRTOS do next?

Ada bindings and the ability to use Ada procedure as task entry-points/functions.

For a mysterious (well, not to me, but I’m not permitted to say why) reason, a project I’m working on needs this, and though someone on my team (not me, I don’t know Ada well enough) can put something together, we can’t share it and it won’t be anything like portable.

A set of Ada bindings for things like FreeRTOS tasks, semaphores, mutexes, timers, events, etc., would make it easier for projects like mine to justify using FreeRTOS to our program managers.

As it stands, only the GCC Ada compiler (“Gnat”) is needed, but if there are other Ada compilers out there, it would be good if the bindings can work for them as well.

1 Like

Quick sketch:

  1. the main task is a call to a setup routine. That’s a C++ routine that creates tasks.
  2. while C++ classes own the task variables, the task itself is a C structure declared outside the class. It is not a part the class.
  3. A pointer to the class owning the task is passed as the argument to the task (this)
  4. to access the class variables, a copy of the task object is created in the task

I have added detail to my response. The problem is that the scheduler has to be the one to call the task entry, and the scheduler always uses a C linkage, so this will not be set, and the function will not be able to access the instance member variables.

What I have done in other instances is to create a function in the class implementation file, but not a member function of the class, with C language linkage. The function return type is void and it takes a single void* parameter. Assuming a C++ class named “FooClass” with the task main method “main”, the task wrapper function would be:

extern "C" void FooClassTaskEntry(void* param)
{
    FooClass* instance = (FooClass*)param;
    instance->main();
}

In the class’s “setup” method, you create the FreeRTOS Task instance providing the this pointer as the task parameter and the wrapper function “FooClassTaskEntry” as the entry point. It uses one extra stack frame, but otherwise it works pretty well.

It should not be necessary to copy the FreeRTOS task object; I simply have a pointer to the FreeRTOS task object as a member variable of my class. (Actually, I have a FreeRTOS task object as a member variable and use the static initialization API instead of the dynamic creation API; FreeRTOS doesn’t know if it’s static allocation or in some C++ class, it just knows the address you passed to it.)

I’ve been doing this across many projects over the past 10 years and it’s never been a problem, and it’s a technique I have been using since I first started with C++ in the 1990s, since pretty much all of the callbacks for interfaces I was using at the time were expecting C linkage, though that wasn’t on FreeRTOS.

1 Like

This works, too.


				xTaskCreate(
						(TaskFunction_t) &LED_TASK,
						name,
						LED_STACK_SIZE,
						(void*) this,
						2,
						&task_handle);

void LED_TASK(void const * argument)
{
	uint32_t				mask;
	LED*					me;


	me = (LED*)argument;


	// ************************ initialization **********************************************************************
	mask = 0x80000000;
	while (1)
	{

		if (me->blink_mask & mask)
		{

			me->SET(LED_ON, 100);

I’m using a static C++ entry point (the same one) for all tasks derived from my base task class. This calls a method on the task object, which is the main loop of the task. Task objects need to be explicitly started (a method called) to get them going, this method creates the task using FreeRTOS xTaskCreate and using the common entry point mentioned above with the object as the task parameter. So basically I create the task objects using constructors to pass parameters, and call start() on them. This seems to be working well.

I’m kind of perplexed by the difficulties everyone is describing, and wondering if I have some hidden issue because of lack of understanding. I don’t have any extern “C” linkage issues or declarations. My tasks can be created after the scheduler and can even be short lived and exit, although I don’t use that functionality much at all.

2 Likes

I’m using a very similar method since a long time and don’t have any problems with it.
There are more ways of suitable, pretty straight forward C++ bindings/wrappers.
Although I could imagine that a task create suspended could be useful in some use cases. Just my 2ct.

1 Like

The problem comes when the “Task” wrapper is a base class of the class the represents this specific task and creates the task as part of the constructor, then the FreeRTOS task comes into existence before the full class is constructed, and if the stub tries to use a virtual member function to access the task functionality.

Using a separate “start” or “run” member function in the task wrapper class gets around the problem, but means that until you do that the wrapper doesn’t have a task that it is wrapping.

If you use tasks that are created and destroyed a lot during the running, the start method can make sense, but if tasks will generally run “forever” the constructor method makes more sense, but leads to the issue for the unusual task created after the scheduler has started.

Better newlib support. Lots and lots and lots of users continue to be burned by MCU vendors providing improper integration - then they get memory corruption. Details https://nadler.com/embedded/newlibAndFreeRTOS.html
Thanks!

1 Like

Although it has been stated before, let me toss in another vote for an official set of modern (C++20 and beyond) C++ wrappers.

I’d also like to see a tickless mode to improve performance, not necessarily timer granularity, since this is easily made using a bit of architecture-specific code.

In general I’d like to see the diff of vendor-specifics fork against upstream vanish, but I realize that this is hardly your call.

What I do understand is that those ports reset the system stack after starting the OS so that they can use the full stack’s lenght for the ISRs chores, is my understanding correct? Isn’t that a flaw?

As @madyn pointed out: Is that behavior documented?

No :grin:

C++ bindings are a better option.

Not a flaw, just an engineering design decision weighing off contradicting requirements (in this case memory usage vs. serving fringe use cases). IMHO, the decision in those ports is perfectly ok as there is a straightforward and easy workaround (do not use local variables on the main stack for use after the OS has started, use globals instead).

As this is port specific behavior, there is no place in the “general documentation” for it. There probably should be a note in the porting guide if it isn’t yet. As for this forum, this behavior is pointed out in a perceived 1 out of 3 threads in the kernel section.

I don’t like the CubeIDE RTOS model. You might want to add FreeRTOS as independent module in your IDE project and just connect the timer that will drive the system tick. This is the way NXP used to include FreeRTOS in its also Eclipse-based IDE called MCUXpresso. Nowadays this IDE offers seamless integration with FreeRTOS and other OS, but including it under your control is sometimes the best option.

Just to update everybody, I have been talking with Sven regarding his heap library on the github page for the library. I have tried to communicate what the 5 heap_x.c is used for and why each has advantages and disavantages. I then downloaded Sven’s heap library and made an example (no example code is included atm) to evaluate the advantages and disavantages of this library as well: The problem with Sven’s heap is excessive memory usage - an overhead of 20 bytes per allocation is not ideal for embedded usage. For this reason alone, a general replacement of the 5 FreeRTOS heaps with this heap is out of the question and even as an additional option (like heap_6.c) it would most likely see limited use due to the memory usage.

3 Likes

Thanks for doing the tests, I considered that myself! Your results once more prove the engineer’s fact of life that very rarely there is a single best solution to any given problem - finding “the” best one is almost always a trade off between different, at times contradicting, pros and cons of each solution.

1 Like

We are working on a project that requires precise timing (timestamping ADC samples). Having a ready to roll PTP implementaion as an option in the FreeRTOS plus TCP stack would be very convenient, as is possible with ThreadX (see NetX Duo PTP Client) and Zephyr (see generic Precision Time Protocol (gPTP)). Or at least support for hardware timestamps (see ticket #928 in the FreeRTOS plus TCP repo) so that we can roll our own PTP implementation.

2 Likes

I am on a 64 bit architecture, so that is causing part of the difference. But it is 20 bytes - I will post the example on you github page.

OTA pal support in the OTA orchestrator example. The example just downloads a file from aws and marks the OTA as completed but OTA can’t be marked completed without signature verification of the downloaded file and without being in self-test mode and accepting/rejecting the file. You could just provide interface for

I would consider this example as incomplete because OTA job is not marked as succeeded: Refre mqtt-ota-agent-orchestrator example. (Cant paste the link here)