Page 1 of 1

Correct way to pass struct as an xTaskCreate parameter?

Posted: Tue May 16, 2017 10:00 pm
by smeedy
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

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

Posted: Tue May 16, 2017 10:25 pm
by WiFive
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.

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

Posted: Wed May 17, 2017 6:43 am
by smeedy
Ah yes. Missed that one completely. It's obvious now. Thanks for your help!

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

Posted: Sun Oct 06, 2019 10:27 pm
by g01d10x
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.

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

Posted: Mon Oct 07, 2019 2:48 am
by Aussie Susan
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

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

Posted: Mon Oct 07, 2019 6:02 am
by markkuk
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.