From ca30741a30d2501b4d253e572d047e7d391be8a6 Mon Sep 17 00:00:00 2001 From: Jim Warner Date: Tue, 28 Sep 2021 00:00:00 -0500 Subject: [PATCH] library: ensure thread safety via function substitutes Even though we we had to abandon the master branch top multi-thread effort and even though the newlib version of a multi-threaded top provides no real benefit, that whole exercise was not wasted. Rather, it has revealed some deficiencies in our library which this addresses. If two or more threads in the same address space tried to use procps_loadavg or procps_uptime simultaneously, there's a chance they would experience problems due to thread-unsafe functions our library called internally. So, this patch switches them for thread-safe versions. [ along the way we will also make that procps_uptime ] [ initialization of his 'up' & 'idle' variables mean ] [ something by delaying the -ERANGE return a little. ] Reference(s): https://www.freelists.org/post/procps/a-few-more-patches,7 Signed-off-by: Jim Warner --- proc/sysinfo.c | 14 +++++++------- proc/uptime.c | 27 +++++++++++++++------------ 2 files changed, 22 insertions(+), 19 deletions(-) diff --git a/proc/sysinfo.c b/proc/sysinfo.c index 9dd0be03..ed052221 100644 --- a/proc/sysinfo.c +++ b/proc/sysinfo.c @@ -124,17 +124,17 @@ PROCPS_EXPORT int procps_loadavg( double *restrict av15) { double avg_1=0, avg_5=0, avg_15=0; - char savelocale[128]; + locale_t tmplocale; int retval=0; FILE_TO_BUF(LOADAVG_FILE,loadavg_fd); - snprintf(savelocale, sizeof(savelocale), "%s", setlocale(LC_NUMERIC, NULL)); - setlocale(LC_NUMERIC, "C"); - if (sscanf(buf, "%lf %lf %lf", &avg_1, &avg_5, &avg_15) < 3) { - setlocale(LC_NUMERIC, savelocale); + tmplocale = newlocale(LC_NUMERIC_MASK, "C", (locale_t)0); + uselocale(tmplocale); + if (sscanf(buf, "%lf %lf %lf", &avg_1, &avg_5, &avg_15) < 3) retval = -ERANGE; - } - setlocale(LC_NUMERIC, savelocale); + + uselocale(LC_GLOBAL_LOCALE); + freelocale(tmplocale); SET_IF_DESIRED(av1, avg_1); SET_IF_DESIRED(av5, avg_5); SET_IF_DESIRED(av15, avg_15); diff --git a/proc/uptime.c b/proc/uptime.c index e2cc225e..0f1fab24 100644 --- a/proc/uptime.c +++ b/proc/uptime.c @@ -69,25 +69,27 @@ PROCPS_EXPORT int procps_uptime( double *restrict idle_secs) { double up=0, idle=0; - char savelocale[128]; + locale_t tmplocale; FILE *fp; + int rc; if ((fp = fopen(UPTIME_FILE, "r")) == NULL) return -errno; - snprintf(savelocale, sizeof(savelocale), "%s", setlocale(LC_NUMERIC, NULL)); - setlocale(LC_NUMERIC, "C"); - if (fscanf(fp, "%lf %lf", &up, &idle) < 2) { - setlocale(LC_NUMERIC, savelocale); - fclose(fp); - return -ERANGE; - } + tmplocale = newlocale(LC_NUMERIC_MASK, "C", (locale_t)0); + uselocale(tmplocale); + rc = fscanf(fp, "%lf %lf", &up, &idle); fclose(fp); - setlocale(LC_NUMERIC, savelocale); + uselocale(LC_GLOBAL_LOCALE); + freelocale(tmplocale); + if (uptime_secs) *uptime_secs = up; if (idle_secs) *idle_secs = idle; + + if (rc < 2) + return -ERANGE; return 0; } @@ -103,14 +105,15 @@ PROCPS_EXPORT char *procps_uptime_sprint(void) int upminutes, uphours, updays, users; int pos; time_t realseconds; - struct tm *realtime; + struct tm realtime; double uptime_secs, idle_secs; double av1, av5, av15; upbuf[0] = '\0'; if (time(&realseconds) < 0) return upbuf; - realtime = localtime(&realseconds); + localtime_r(&realseconds, &realtime); + if (procps_uptime(&uptime_secs, &idle_secs) < 0) return upbuf; @@ -119,7 +122,7 @@ PROCPS_EXPORT char *procps_uptime_sprint(void) upminutes = ((int) uptime_secs / (60)) % 60; pos = sprintf(upbuf, " %02d:%02d:%02d up ", - realtime->tm_hour, realtime->tm_min, realtime->tm_sec); + realtime.tm_hour, realtime.tm_min, realtime.tm_sec); if (updays) pos += sprintf(upbuf + pos, "%d %s, ", updays, (updays > 1) ? "days" : "day");