diff --git a/winsup/cygwin/ChangeLog b/winsup/cygwin/ChangeLog
index 8224c9d9c..9275108d7 100644
--- a/winsup/cygwin/ChangeLog
+++ b/winsup/cygwin/ChangeLog
@@ -1,3 +1,10 @@
+2002-02-15  Christopher Faylor  <cgf@redhat.com>
+
+	* hires.h: New file.
+	* times.cc (gettimeofday): Use hires class for calculating current time.
+	(hires::prime): New method.
+	(hires::utime): Ditto.
+
 2002-02-14  Christopher Faylor  <cgf@redhat.com>
 
 	* include/sys/cygwin.h (cygwin_getinfo_types): New CW_STRACE_ACTIVE.
diff --git a/winsup/cygwin/hires.h b/winsup/cygwin/hires.h
new file mode 100644
index 000000000..06a00166d
--- /dev/null
+++ b/winsup/cygwin/hires.h
@@ -0,0 +1,24 @@
+/* hires.h: Definitions for hires clock calculations
+
+   Copyright 2002 Red Hat, Inc.
+
+This file is part of Cygwin.
+
+This software is a copyrighted work licensed under the terms of the
+Cygwin license.  Please consult the file "CYGWIN_LICENSE" for
+details. */
+
+#ifndef __HIRES_H__
+#define __HIRES_H__
+
+class hires
+{
+  int inited;
+  LARGE_INTEGER primed_ft;
+  LARGE_INTEGER primed_pc;
+  double freq;
+  void prime ();
+ public:
+  LONGLONG utime ();
+};
+#endif /*__HIRES_H__*/
diff --git a/winsup/cygwin/times.cc b/winsup/cygwin/times.cc
index 1993c5884..a30374a54 100644
--- a/winsup/cygwin/times.cc
+++ b/winsup/cygwin/times.cc
@@ -24,6 +24,7 @@ details. */
 #include "sync.h"
 #include "sigproc.h"
 #include "pinfo.h"
+#include "hires.h"
 
 #define FACTOR (0x19db1ded53e8000LL)
 #define NSPERSEC 10000000LL
@@ -149,34 +150,21 @@ totimeval (struct timeval *dst, FILETIME *src, int sub, int flag)
   dst->tv_sec = x / (long long) (1e6);
 }
 
-/* gettimeofday: BSD */
+/* FIXME: Make thread safe */
 extern "C" int
-gettimeofday (struct timeval *p, struct timezone *z)
+gettimeofday(struct timeval *tv, struct timezone *tz)
 {
-  int res = 0;
+  static hires gtod;
+  LONGLONG now = gtod.utime ();
+  if (now == (LONGLONG) -1)
+    return -1;
 
-  if (p != NULL)
-    {
-      FILETIME f;
-
-      GetSystemTimeAsFileTime (&f);
-      totimeval (p, &f, 0, 1);
-    }
-
-  if (z != NULL)
-    {
-      tzset();
-      z->tz_minuteswest = _timezone / 60;
-      z->tz_dsttime = _daylight;
-    }
-
-  syscall_printf ("%d = gettimeofday (%x, %x)", res, p, z);
-
-  return res;
+  tv->tv_sec = now / 1000000;
+  tv->tv_usec = now % 1000000;
+  return 0;
 }
 
-extern "C"
-int
+extern "C" int
 _gettimeofday (struct timeval *p, struct timezone *z)
 {
   return gettimeofday (p, z);
@@ -569,3 +557,57 @@ void
 cygwin_tzset ()
 {
 }
+
+void
+hires::prime ()
+{
+  LARGE_INTEGER ifreq;
+  if (!QueryPerformanceFrequency (&ifreq))
+    {
+      inited = -1;
+      return;
+    }
+
+  FILETIME f;
+  int priority = GetThreadPriority (GetCurrentThread ());
+  SetThreadPriority (GetCurrentThread (), THREAD_PRIORITY_TIME_CRITICAL);
+  if (!QueryPerformanceCounter (&primed_pc))
+    {
+      inited = -1;
+      return;
+    }
+
+  GetSystemTimeAsFileTime (&f);
+  SetThreadPriority (GetCurrentThread (), priority);
+
+  inited = 1;
+  primed_ft.HighPart = f.dwHighDateTime;
+  primed_ft.LowPart = f.dwLowDateTime;
+  primed_ft.QuadPart -= FACTOR;
+  primed_ft.QuadPart /= 10;
+  freq = (double) ((double) 1000000. / (double) ifreq.QuadPart);
+  return;
+}
+
+LONGLONG
+hires::utime ()
+{
+  if (!inited)
+    prime ();
+  if (inited < 0)
+    {
+      set_errno (ENOSYS);
+      return (long long) -1;
+    }
+
+  LARGE_INTEGER now;
+  if (!QueryPerformanceCounter (&now))
+    {
+      set_errno (ENOSYS);
+      return -1;
+    }
+
+  now.QuadPart -= primed_pc.QuadPart;
+  // FIXME: Use round() here?
+  return primed_ft.QuadPart + (LONGLONG) ((double) now.QuadPart * freq);
+}