vprintf_like_t reentrancy

Leherenn
Posts: 6
Joined: Tue Mar 24, 2020 3:11 pm

vprintf_like_t reentrancy

Postby Leherenn » Tue Mar 24, 2020 3:28 pm

Hi!

I am using a custom "vprintf_like_t" function with "esp_log_set_vprintf" to log to SPIFFS, similar to this:
https://github.com/pantaluna/esp32-mjd- ... main.c#L40

I am however seeing a behaviour consistent with data races as I am logging from several tasks, and I was wondering whether the "vprintf_like_t" function needed to be reentrant.

Thank you.

ESP_igrr
Posts: 2067
Joined: Tue Dec 01, 2015 8:37 am

Re: vprintf_like_t reentrancy

Postby ESP_igrr » Wed Mar 25, 2020 6:13 am

This is correct — the assumptions are the same as for vprintf function. In IDF, vprintf is reentrant because the I/O streams have locks, so only one task can vprintf to a given stream at any point in time. Also keep in mind the situation when your custom vprintf implementation causes esp_log_write to be called. For example, this may happen if SPIFFS driver emits some warning or error message. So you also need to consider how to handle recursive entry into your custom vprintf function in a given thread.

Leherenn
Posts: 6
Joined: Tue Mar 24, 2020 3:11 pm

Re: vprintf_like_t reentrancy

Postby Leherenn » Wed Mar 25, 2020 7:25 am

Thank you.

May I suggest adding something in the documentation regarding this?
The example I linked above is not reentrant, and it may wrongly suggest there is some write serialisation happening somewhere before this.

willemmerson
Posts: 40
Joined: Mon Mar 18, 2019 12:34 pm

Re: vprintf_like_t reentrancy

Postby willemmerson » Wed Mar 25, 2020 12:01 pm

I have also got in a mess with this before. I found a simple solution was to do nothing in the vprintf_like_function except print the log and put the formatted string into a queue and do the meat of the work in another task:

Code: Select all

// all a bit simplified but you get the idea:
int my_vprintf(const char *format, va_list args) {
    char *log_buffer; 
    size_t len = vasprintf(&log_buffer, format, args);
    fputs(log_buffer, stdout);
    xQueueSend(mqtt_queue, &log_buffer, 0)
    return len;
}
You then end up with less problems to do with recursion and system processes running out of stack because of your my_vprintf, and an added benefit is you can store logs before you've initialised network/flash or whatever you're writing logs to.
I've also seen a my_vprintf function somewhere with a kind of TAG blacklist to make sure it's not inside my_vprintf itself or some system functions.
Disclaimer: I don't know what I'm doing.

Who is online

Users browsing this forum: Corand and 125 guests