Re: linux-kernel-digest V1 #3387

Ville Herva (vherva@niksula.hut.fi)
Tue, 23 Feb 1999 01:56:53 +0200


On Thu, Feb 18, 1999 at 04:00:04PM -0500, you wrote:
> From: hans@grumbeer.inka.de (Hans-Joachim Baader)
> Date: Thu, 18 Feb 99 07:41 MET
> Subject: Re: 2.0.34: clock() returns -1 after 248.5 days uptime
>
> Your program is incorrect. clock() returns clock_t, not int. clock_t

I'm sorry, I just quickly wrote that to test what clock() returns since it
seemed return something bizarre. Then I just went on pasting that in thhe
linux-kernel posting without properly checking the types.

> is long in glibc 2.1, so on a 32 bit architecture this would help
> nothing...

That I did check before posting.

> Certainly a result of -1 is less than useful. But perhaps it conforms
> to some standard ;-|

I did crawl through some source, but I did not check the standards on this
issue.

>From what I can conclude from the sources, it's just one typical
unsigned->signed issue ending disgracefully into a "if (value < 0) return
-1;" check.

The glibc-2.0.7 (and glibc-2.0.108-0.981221 - the version numbers are
from RedHat packages, but I doubt the function below varies all that much
across versions) seems to define clock() in
sysdeps/unix/sysv/linux/clock.c as follows:

#include <sys/times.h>
#include <time.h>
#include <unistd.h>

/* Return the time used by the program so far (user time + system time).
*/
clock_t
clock (void)
{
struct tms buf;
long clk_tck = __sysconf (_SC_CLK_TCK);

if (__times (&buf) < 0)
return (clock_t) -1;

return
(clk_tck <= CLOCKS_PER_SEC)
? ((unsigned long) buf.tms_utime + buf.tms_stime) * (CLOCKS_PER_SEC
/ clk_tck)
: ((unsigned long) buf.tms_utime + buf.tms_stime) / (clk_tck
/
CLOCKS_PER_SEC);
}

A closer inspection revealed that Linux seems return a signed long
as the return value of sys_times:

linux-2.0.3[46]/kernel/sys.c:
asmlinkage long sys_times(struct tms * tbuf)
{
if (tbuf) {
int error = verify_area(VERIFY_WRITE,tbuf,sizeof *tbuf);
if (error)
return error;
put_user(current->utime,&tbuf->tms_utime);
put_user(current->stime,&tbuf->tms_stime);
put_user(current->cutime,&tbuf->tms_cutime);
put_user(current->cstime,&tbuf->tms_cstime);
}
return jiffies;
}

linux-2.2.1/kernel/sys.c:
asmlinkage long sys_times(struct tms * tbuf)
{
/*
* In the SMP world we might just be unlucky and have one of
* the times increment as we use it. Since the value is an
* atomically safe type this is just fine. Conceptually its
* as if the syscall took an instant longer to occur.
*/
if (tbuf)
if (copy_to_user(tbuf, &current->times, sizeof(struct
tms)))
return -EFAULT;
return jiffies;
}

However, jiffies is a unsigned variable:

linux-2.2.1/kernel/sched.c: unsigned long volatile jiffies=0;
linux-2.0.3[46]/kernel/sched.c: unsigned long volatile jiffies=0;

Now, glibc seems to treat this value as signed:

glibc-2.0.6:
posix/sys/times.h:extern clock_t __times __P ((struct tms *__buffer));

glibc-2.0.108-0.981221:
include/sys/times.h:extern clock_t __times __P ((struct tms *__buffer));

which makes clock() to return -1 after 248.5 days due to the
(__times() < 0) return -1; -line.

(Hopefully I did not miss anything crucial in that...)

Although the real problem lies in the fact that 32 bit is not enough
for these counters, it would make more sense to me to return something
else that a consistent -1.

Hopefully, this problem will go away as our server reaches 500 day
uptime... But only for another 248 days.

> Since clock() is a libc function you should ask the
> libc maintainers about it.

I did that. Waiting for results...

There are propably other points of code in glibc that get broken after
248.5 days, since zsh's terminal handling begun working improperly after
248.5 days of uptime.

-- v --

v@iki.fi

-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@vger.rutgers.edu
Please read the FAQ at http://www.tux.org/lkml/