From c1d9354fef1e3bc06f5d20d1bab20250249b6085 Mon Sep 17 00:00:00 2001 From: Willy Tarreau Date: Thu, 7 Sep 2017 10:31:10 +0200 Subject: lcd: make lcdwrite conflict-resistant It can happen during services startup that some services display info on the LCD and that at the exact same time some async notifications are sent (eg: VRRP switchover). This causes a conflict, one of the senders gets an EBUSY response and aborts, leaving the previous message displayed. Here instead we loop around a usleep() for no more than 1 second cumulated to avoid this situation. Since LCD messages are short, it should not be an issue. --- lcd/lcdwrite.c | 60 ++++++++++++++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 56 insertions(+), 4 deletions(-) diff --git a/lcd/lcdwrite.c b/lcd/lcdwrite.c index 31db93d..d8c66f2 100644 --- a/lcd/lcdwrite.c +++ b/lcd/lcdwrite.c @@ -1,22 +1,73 @@ /* simply write all args to /dev/lcd, and don't complain if it doesn't work */ #ifndef NOLIBC #include +#include +#include +#include +#include #include +#include #endif +/* waits for ~10ms, keeping track of the cumulated wait time, and returns < 0 + * if the cumulated wait time reaches one second. 0 is returned otherwise. + */ +int wait_1smax() +{ + static unsigned int total_wait; + struct timeval tv; + + if (total_wait >= 1000) + return -1; + tv.tv_sec = 0; + tv.tv_usec = 10000; + select(0, NULL, NULL, NULL, &tv); + total_wait += 10; + return 0; +} + +int write_lcd(int fd, const char *buf, int len) +{ + int count = len; + int ret; + + while (len > 0) { + ret = write(fd, buf, len); + + if (ret < 0) { + if (errno != EBUSY && errno != EINTR) + return ret; + + /* conflict with another writer, wait a bit */ + if (wait_1smax() < 0) + return ret; + continue; + } + + buf += ret; + len -= ret; + } + return count; +} + int main(int argc, char **argv) { int fd; char buf[1024]; int len; - if ((fd = open("/dev/lcd", O_WRONLY, 0)) == -1) - return 0; + while ((fd = open("/dev/lcd", O_WRONLY, 0)) == -1) { + if (errno != EBUSY) + return 0; + if (wait_1smax() < 0) + return 0; + } if (--argc == 0) { while ((len = read(0, buf, sizeof(buf))) > 0) - write(fd, buf, len); + if (write_lcd(fd, buf, len) < 0) + return 0; } else { argv++; @@ -27,7 +78,8 @@ int main(int argc, char **argv) { argv[0][len++]=' '; /* add a delimitor */ else argv[0][len++]='\n'; /* end with a newline */ - write(fd, *argv, len); + if (write_lcd(fd, *argv, len) < 0) + return 0; argv++; } } -- 1.7.12.1