times(2) misbehaviour
Joakim Tjernlund
joakim.tjernlund at transmode.se
Sun Jan 31 21:26:35 UTC 2010
>
> Hello,
>
> after a big bug hunt we also found that the implementation of the
> "times" system call in uClibc 0.9.29/0.9.30 is problematic on some 32
> bits architectures (arm926 in our case); like it was reported 2 years
> ago by Will.
>
> The fact that uClibc considers some Linux sys_times() return values as
> errors makes some user space applications become crazy (Qt in our case):
> when Linux "times" syscall's return value is inside uClibc errors range
> (cf INTERNAL_SYSCALL_ERROR_P macro), uClibc forward a (-1) error code to
> caller. An application may freeze during many seconds (40 if system tick
> is 10ms), if it's event handling relies on times() accuracy. Problem
> occurs after 5 minutes of system's running, when Linux tick timer value
> reaches its limit on 32 bits systems.
Oh yes, been there done that :)
Most arch's has this bug in linux(ppc in recent 2.6 does not).
You can work around that in your app., but one should not have too:
errno = 0;
ret = times(NULL); /* Linux can handle NULL */
/* Workaround broken syscall impl.
* A bugfix exists for the kernel,
* 2.6.29 for ppc and possibly some more arch
*/
if (errno)
ret = (unsigned long) (-errno);
Not sure I like:
> + /* Return value (clock_t) -1 signals an error to userspace, but if there
> + wasn't any, return 0 instead. */
> + if (ret == (clock_t) -1)
> + return (clock_t) 0;
this will skip ahead a tick
Does the patch work for times(NULL) too? Perhaps EFAULT
can not be returned in this case?
>
> glibc has a special handling for "times" syscall.
> I have attached a patch that implements times in the same way as glibc.
>
> Could maintainers of uClibc get inspired from that patch and do a
> correction for this problem please ?
>
> Thanks !
> Regards,
> Julien
> > --
> >
> >
>
> Implements "times" syscall like on glibc: only EFAULT is considered as a valid
> error code from Linux kernel.
> To handle architectures that can't distinguish the error from a return value,
> make the application segfault in case of error (== bad struct tms parameter).
>
> Signed-off-by: Julien Boibessot <julien.boibessot at armadeus.com>
>
> Index: uClibc-0.9.29/libc/sysdeps/linux/common/times.c
> ===================================================================
> --- uClibc-0.9.29.orig/libc/sysdeps/linux/common/times.c 2010-01-27 10:15:
> 38.000000000 +0100
> +++ uClibc-0.9.29/libc/sysdeps/linux/common/times.c 2010-01-27 10:49:37.
> 000000000 +0100
> @@ -12,5 +12,39 @@
>
> libc_hidden_proto(times)
>
> -_syscall1(clock_t, times, struct tms *, buf);
> +clock_t times(struct tms *buf)
> +{
> + INTERNAL_SYSCALL_DECL (err);
> + clock_t ret = INTERNAL_SYSCALL (times, err, 1, buf);
> + if (INTERNAL_SYSCALL_ERROR_P (ret, err)
> + && __builtin_expect (INTERNAL_SYSCALL_ERRNO (ret, err) == EFAULT, 0))
> + {
> + /* This might be an error or not. For architectures which have
> + no separate return value and error indicators we cannot
> + distinguish a return value of -1 from an error. Do it the
> + hard way. We crash applications which pass in an invalid BUF
> + pointer. */
> +#define touch(v) \
> + do { \
> + clock_t temp = v; \
> + asm volatile ("" : "+r" (temp)); \
> + v = temp; \
> + } while (0)
> + touch (buf->tms_utime);
> + touch (buf->tms_stime);
> + touch (buf->tms_cutime);
> + touch (buf->tms_cstime);
> +
> + /* If we come here the tms struct is valid and the kernel did not
> + return an EFAULT error. Return the value given by the kernel. */
> + }
> +
> + /* Return value (clock_t) -1 signals an error to userspace, but if there
> + wasn't any, return 0 instead. */
> + if (ret == (clock_t) -1)
> + return (clock_t) 0;
> +
> + return ret;
> +}
> +
> libc_hidden_def(times)
> _______________________________________________
> uClibc mailing list
> uClibc at uclibc.org
> http://lists.busybox.net/mailman/listinfo/uclibc
More information about the uClibc
mailing list