Index: /trunk/src/emx/src/lib/sys/__ftime.c
===================================================================
--- /trunk/src/emx/src/lib/sys/__ftime.c	(revision 1337)
+++ /trunk/src/emx/src/lib/sys/__ftime.c	(revision 1338)
@@ -1,5 +1,23 @@
-/* sys/ftime.c (emx+gcc) -- Copyright (c) 1992-1996 by Eberhard Mattes */
+/* $Id: $ */
+/** @file
+ *
+ * LIBC SYS Backend - ftime.
+ *
+ * InnoTek Systemberatung GmbH confidential
+ *
+ * Copyright (c) 2004 InnoTek Systemberatung GmbH
+ * Author: knut st. osmundsen <bird-srcspam@anduin.net>
+ *
+ * All Rights Reserved
+ *
+ */
 
+
+/*******************************************************************************
+*   Header Files                                                               *
+*******************************************************************************/
 #include "libc-alias.h"
+#define INCL_BASE
+#define INCL_DOSINFOSEG
 #define INCL_FSMACROS
 #include <os2emx.h>
@@ -11,27 +29,107 @@
 #include "syscalls.h"
 
-/* Return time in local format */
-void __ftime (struct timeb *ptr)
+/**
+ * Calcs the uDiff in formula timeb.millitm = (msecs + uDiff) % 1000.
+ */
+static unsigned calcdiff(void)
 {
-  DATETIME now;
-  struct tm tm;
-  FS_VAR();
+    /*
+     * We make a little effort to lower the chances of preempting
+     * while reading the msecs and hundredths members of GIS.
+     */
+    #pragma pack(1)
+    union combined2
+    {
+        volatile unsigned long long ull;
+        struct s
+        {
+            ULONG   msecs;
+            UCHAR   hour;
+            UCHAR   minutes;
+            UCHAR   seconds;
+            UCHAR   hundredths;
+        } s;
+    };
+    #pragma pack()
+    unsigned            uDiff;
+    PGINFOSEG           pGIS = GETGINFOSEG();
+    union combined2    *pCombined = (union combined2 *)&pGIS->msecs;
+    union combined2     Combined;
 
-  FS_SAVE_LOAD();
-  DosGetDateTime (&now);
-  FS_RESTORE();
-  tm.tm_sec = now.seconds;
-  tm.tm_min = now.minutes;
-  tm.tm_hour = now.hours;
-  tm.tm_mday = now.day;
-  tm.tm_mon = now.month - 1;
-  tm.tm_year = now.year - 1900;
+    /*
+     * Get a usable data set.
+     *
+     * We try to skip any msecs which end with 0. The two PCs I've got
+     * here indicates that this is a good idea for consistency in the result.
+     */
+    Combined.ull = pCombined->ull;
+    if (!(Combined.s.msecs % 10))
+    {
+        int i = 0;
+        FS_VAR();
+        FS_SAVE_LOAD();
+        do
+        {
+            DosSleep(1);
+            Combined.ull = pCombined->ull;
+        } while (!(Combined.s.msecs % 10) && ++i < 2);
+        FS_RESTORE();
+    }
 
-  ptr->time = (time_t)_mktime (&tm);
-  /* Apply timezone correction to get UTC time since we don't know what
-     timezone DosGetDateTime uses and whether it honors the TZ variable.
-     Then apply application's own timezone to get local time back. */
-  if (now.timezone != -1)
-    ptr->time = ptr->time - (long)now.timezone * 60 + _tzi.tz;
-  ptr->millitm = now.hundredths * 10;
+    /*
+     * Calc the diff value.
+     */
+    uDiff = Combined.s.hundredths * 10 - (Combined.s.msecs % 1000);
+    if ((int)uDiff < 0)
+        uDiff += 1000;                  /* must be positive for the rounding. */
+    /* round up to closes 10. */
+    uDiff += 9;
+    uDiff /= 10;
+    uDiff *= 10;
+    return uDiff;
 }
+
+
+/**
+ * Get the current local time.
+ * @param   ptr     Where to store the result.
+ *                  Note that only the members time and millitm are filled in,
+ *                  the caller is expected to fill the remaining fields.
+ */
+void __ftime(struct timeb *ptr)
+{
+    union combined
+    {
+        volatile unsigned long long ull;
+        struct
+        {
+            ULONG       time;
+            ULONG       msecs;
+        } s;
+    };
+    static union
+    {
+        PGINFOSEG       pGIS;
+        union combined *pCombined;
+    } uGIS;
+    static unsigned     uDiff;
+    union combined      Combined;
+
+    /*
+     * Init.
+     */
+    if (!uGIS.pGIS)
+    {
+        uDiff = calcdiff();
+        uGIS.pGIS = GETGINFOSEG();
+    }
+
+    /*
+     * Get the value and convert it to the return format.
+     */
+    Combined = *uGIS.pCombined;
+    ptr->time       = Combined.s.time;
+    ptr->millitm    = (Combined.s.msecs + uDiff) % 1000;
+    ptr->timezone   = 0;
+    ptr->dstflag    = 0;
+}
