This is the mail archive of the libc-alpha@cygnus.com mailing list for the glibc project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]

[50 character or so descriptive subject here (for reference)]


>Submitter-Id:	net
>Originator:	
>Organization:
>
>Confidential:	no
>Synopsis:	
>Severity:	serious
>Priority:	medium
>Category:	libc
>Class:		sw-bug
>Release:	libc-2.0.7
>Environment:

Host type: i686-pc-linux-gnu
System: Linux turing.netspan.fi 2.0.34 #1 Sun May 17 18:45:16 EEST 1998 i686 unknown
Architecture: i686

Addons: crypt linuxthreads localedata
Build CFLAGS: -O2 -m486 -fno-strength-reduce -g -DNDEBUG=1
Build CC: gcc -B$(common-objpfx)
Build shared: yes
Build profile: yes
Build omitfp: no
Stdio: libio

>Description:

After ~249 day uptime on an linux-2.0.34 machine the glibc-2.0.7
clock() routine begun to return -1 consistently.

The glibc-2.0.7 (and glibc-2.0.108-0.981221 - the versions 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);
} 

Since CLK_TCK = 100 and clock_t is long (32 bit signed on linux-x86) and
2^31 / CLK_TCK / 60 / 60 / 24 is 248.551348148148 days, it seemed
clear that a counter had wrapped.

A closer inspection revealed that Linux seems return an unsigned 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;
}


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. 

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 248 days.

>How-To-Repeat:

Take a vanilla RedHat Linux 5.1 Box with vanilla linux-2.0.34 kernel
and glibc-2.0.7. Run this combination for more than 249 days non
stop. Then do

vherva@turing:/home/vherva>cat > c.c
#include <time.h>
#include <stdio.h>
        
int main(int argc, char* argv[])
{
   time_t i;
   time_t timer = clock();
   for (i = 1000000; i; i--);   
   printf("timer: %i\nclock(): %i\nCLK_TCK: %i\n"   
          "CLOCKS_PER_SEC: %i\n",
          timer, clock(), CLK_TCK, CLOCKS_PER_SEC);
        
   return 1;
}       
        
vherva@turing:/home/vherva>gcc c.c -o c
vherva@turing:/home/vherva>time c
timer: -1
clock(): -1
CLK_TCK: 100
CLOCKS_PER_SEC: 1000000
c  0.02s user 0.00s system 418% cpu 0.005 total

Notice the 418% CPU usage on a single CPU machine.

>Fix:

Up to you.



-- v --
  
--
Ville Herva   Ville.Herva@netspan.fi   +358-50-5164500
Netspan Oy    netspan@netspan.fi       PL 65  FIN-02151 Espoo    
              http://www.netspan.fi
For my PGP key, finger vherva@netspan.fi.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]