From owner-freebsd-hackers Sun Oct 17 16:39:59 1999 Delivered-To: freebsd-hackers@freebsd.org Received: from outreach.wolfnet.org (CBL-jkfritcher1.hs.earthlink.net [207.217.155.123]) by hub.freebsd.org (Postfix) with ESMTP id 0D1A814C41 for ; Sun, 17 Oct 1999 16:39:53 -0700 (PDT) (envelope-from jkf@wolfnet.org) Received: from solaris.wolfnet.org ([10.0.0.3]) by outreach.wolfnet.org with esmtp (Exim 3.03 #1) id 11czu5-00057q-00 for freebsd-hackers@freebsd.org; Sun, 17 Oct 1999 16:39:53 -0700 Date: Sun, 17 Oct 1999 16:39:53 -0700 (PDT) From: "Jason K. Fritcher" To: freebsd-hackers@freebsd.org Subject: PR kern/14034: gettimeofday() returns negative value Message-ID: MIME-Version: 1.0 Content-Type: TEXT/PLAIN; charset=US-ASCII Sender: owner-freebsd-hackers@FreeBSD.ORG Precedence: bulk X-Loop: FreeBSD.ORG Hello. As a starting point to learn the FreeBSD kernel, and as a starting point for contributing back to the best free OS, I have decided to start trying to fix bugs in the bug database. The PR in the subject seemed like a subsystem that didn't seem too complex, so I made that my starting point. I been looking through source code, trying to understand it, and I think I do. What I would like to do is verify that my understanding of the code is correct. When gettimeofday() is called from a program, it enters the kernel at the gettimeofday() function in src/sys/kern/kern_time.c. If a timeval pointer has been given, it calls microtime() to get the time of day. Below is microtime(). void microtime(struct timeval *tv) { struct timecounter *tc; tc = (struct timecounter *)timecounter; tv->tv_sec = tc->tc_offset_sec; tv->tv_usec = tc->tc_offset_micro; tv->tv_usec += ((u_int64_t)tco_delta(tc) * tc->tc_scale_micro) >> 32; tv->tv_usec += boottime.tv_usec; tv->tv_sec += boottime.tv_sec; while (tv->tv_usec >= 1000000) { tv->tv_usec -= 1000000; tv->tv_sec++; } } In microtime(), it reads the seconds and microseconds since boot and puts them into the timeval struct. Next, tco_delta is called. The way I understand that code is it polls the counter so it knows how much time has elapsed since timecounter was updated by an interrupt. Since tco_delta is an inline function, that line gets expanded to this: tv->tv_usec += ((u_int64_t)((tc->tc_get_timecount(tc) - tc->tc_offset_count) & tc->tc_counter_mask) * tc->tc_scale_micro) >> 32; The way I am understanding this code, it reads the current value of the counter, which is going to be in ticks, then subtracts tc_offset_micro, which, unless I am mistaken, is in microseconds. This doesn't seem quite right to me. The remainder is then AND'ed with the counter's mask value to get a delta. With 64 bit, unsigned math, the delta is multiplied with the counter's scale value to translate the ticks into microseconds, leaves the result in the upper dword, and then shifts the result into the lower dword. The result is then added to the microsecond value in the timeval struct. Another thing that strikes me as odd about this line is the fact that the final math is done unsigned, but the result is put into a signed container. Next the boottime seconds and microseconds are added to the timeval struct, and finally if the microseconds in the timeval is larger than a second, it and the seconds value gets adjusted appropriately. gettimeofday then finishes and control is passed back to the user. The only concern I have about the code is if the final delta value that is computed is large enough to set the MSB in the lower dword, when it gets added into the timeval struct, the previously positive signed value becomes a negative signed value. It seems to me that this could possibly lead to what is being seen in the PR. I hope I am just misunderstanding the code, because this seems like it could be a real pain. Thanx. -- Jason K. Fritcher jkf@wolfnet.org To Unsubscribe: send mail to majordomo@FreeBSD.org with "unsubscribe freebsd-hackers" in the body of the message