Correct way to pass struct as an xTaskCreate parameter?

smeedy
Posts: 15
Joined: Sun Jan 22, 2017 10:35 pm

Correct way to pass struct as an xTaskCreate parameter?

Postby smeedy » Tue May 16, 2017 10:00 pm

Hi all,

Perhaps a bit off-topic and perhaps a beginners error, but this one is biting me with all erratic behaviour on the ESP32. So please lend me your ears.

Within an app.h I hold the definitions for structs I use for different tasks. In this example I have a PixelTask which drives a Neopixel depending on bits on an app event group. I use the pvParameter to feed it the proper GPIO when I xTaskCreate it from main like so:

app.h:

Code: Select all

/** Structure to initialize Pixel task */
typedef struct {
	gpio_num_t dio_pin;
} pixel_config_t;
config.h:

Code: Select all

#define PIXEL_PIN_DIN GPIO_NUM_19
main.c:

Code: Select all

pixel_config_t config;
config.dio_pin = PIXEL_PIN_DIN;
xTaskCreate(&pixel_task, "pixel_task", 2048, &config, 5, NULL);
pixel_task.cpp:

Code: Select all

void pixel_task(void *data) {
  pixel_config_t pixel_config = *(pixel_config_t *) data;

  ESP_LOGI(TAG, "starting task");
  ESP_LOGI(TAG, "pixel_config.dio_pin %i", pixel_config.dio_pin);
The last LOGI will just give me some random piece of 4 bytes of memory it seems, which gives me just an insane number. Same with a wifi_sta task I've created for dealing with the client init and event handling. This is a C task, and the struct looks like

Code: Select all

/** Structure to initialize WiFi STA task */
typedef struct {
	const char *ssid;
	const char *password;
	const char *client_hostname;
} local_wifi_sta_config_t;
When creating it from main, even with a bigger stacksize, but along the same principle, the task gives me not a random values, but just the wrong values. I end up with the TAG from main for example.

So how does one pass parameters the proper way? I'm missing something here..

thanks for your time,
Martijn

WiFive
Posts: 3529
Joined: Tue Dec 01, 2015 7:35 am

Re: Correct way to pass struct as an xTaskCreate parameter?

Postby WiFive » Tue May 16, 2017 10:25 pm

http://www.freertos.org/a00125.html
If pvParameters is set to the address of a variable then the variable must still exist when the created task executes - so it is not valid to pass the address of a stack variable.

smeedy
Posts: 15
Joined: Sun Jan 22, 2017 10:35 pm

Re: Correct way to pass struct as an xTaskCreate parameter?

Postby smeedy » Wed May 17, 2017 6:43 am

Ah yes. Missed that one completely. It's obvious now. Thanks for your help!

g01d10x
Posts: 2
Joined: Sun Apr 01, 2018 8:19 pm

Re: Correct way to pass struct as an xTaskCreate parameter?

Postby g01d10x » Sun Oct 06, 2019 10:27 pm

This looks like you had the same idea that I did regarding how to start a task with a set of variables.

In reading the responses, I'm not sure what 'became obvious' to you though. Could you explain? Is it possible somehow to pass in a struct ? I'm trying with an int and a char array, but no luck.

Aussie Susan
Posts: 45
Joined: Thu Aug 22, 2019 3:48 am

Re: Correct way to pass struct as an xTaskCreate parameter?

Postby Aussie Susan » Mon Oct 07, 2019 2:48 am

The problem the OP had was that the structure that was passed in was created on the stack. When the function used to start the 'other' task exited then the structure was destroyed.
However the started task still had the pointer to where the structure used to be on the stack. In the mean time anything could have been written to the stack and so they picked up 'random' values.
The correct way to do this is to allocate the structure somewhere that will not be destroyed - typically this is as a global variable.
(Note that many embedded systems have an infinite loop in the 'main' function which is never left. However when you are dealing with an RTOS, it can be the case that the started tasks can keep the app alive after the 'main' has been exited.)
Susan

markkuk
Posts: 38
Joined: Wed Mar 27, 2019 11:50 am

Re: Correct way to pass struct as an xTaskCreate parameter?

Postby markkuk » Mon Oct 07, 2019 6:02 am

Smeedy's original code had a "use after free" bug caused by passing pointer to a local variable to a thread that continues executing after the function that created the thread has returned. The fix is to use either a static variable or heap allocated variable for the data you want to pass to a thread.

Who is online

Users browsing this forum: Bing [Bot] and 97 guests