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 <james.warner@comcast.net>
This commit is contained in:
Jim Warner 2021-09-28 00:00:00 -05:00 committed by Craig Small
parent 23cfb71366
commit ca30741a30
2 changed files with 22 additions and 19 deletions

View File

@ -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);

View File

@ -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");