Index: trunk/src/emx/src/lib/sys/usleep.c
===================================================================
--- trunk/src/emx/src/lib/sys/usleep.c	(revision 1270)
+++ trunk/src/emx/src/lib/sys/usleep.c	(revision 1270)
@@ -0,0 +1,144 @@
+/* $Id$ */
+/** @file
+ *
+ * usleep().
+ *
+ * Copyright (c) 2004 InnoTek Systemberatung GmbH
+ * Author: knut st. osmundsen <bird-srcspam@anduin.net>
+ *
+ *
+ * This file is part of Innotek LIBC.
+ *
+ * Innotek LIBC is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published
+ * by the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * Innotek LIBC is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with Innotek LIBC; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ *
+ */
+
+
+/*******************************************************************************
+*   Header Files                                                               *
+*******************************************************************************/
+#include "libc-alias.h"
+#include <unistd.h>
+#include <errno.h>
+#define INCL_BASE
+#define INCL_FSMACROS
+#include <os2.h>
+#include <emx/libclog.h>
+
+
+/**
+ * Suspend execution of the current thread for a given number of microseconds
+ * or till a signal is received.
+ *
+ * @returns 0 on success.
+ * @returns -1 if useconds is equal or larger than one million.
+ * @param   useconds    Number of microseconds to sleep.
+ *                      If 0 nothing is done.
+ *                      If equal or larger than one million errno is set to EINVAL and
+ *                      returning -1.
+ * @author  knut st. osmundsen <bird-srcspam@anduin.net>
+ * @remark  For relativly small sleeps this api temporarily changes the thread
+ *          priority to timecritical (that is, if it's in the normal or idle priority
+ *          classes) to increase precision. This means that if a signal or other
+ *          asyncronous event is executed, it will be executed at wrong priority.
+ *          It also means that if such code changes the priority it will be undone.
+ * @todo    Check out signal effects mentioned in the SUS function description.
+ */
+int _STD(usleep)(useconds_t useconds)
+{
+    LIBCLOG_ENTER("useconds=%d", useconds);
+    ULONG   msSleep;
+    FS_VAR();
+
+    /*
+     * Check input.
+     */
+    if (useconds >= 1000000)
+    {
+        errno = EINVAL;
+        LIBCLOG_RETURN_INT(-1);
+    }
+
+    /*
+     * If zero, nothing to do.
+     */
+    if (useconds == 0)
+        LIBCLOG_RETURN_INT(0);
+
+    /*
+     * Calc millisecond wait.
+     */
+    msSleep = (useconds + 999) / 1000;
+
+    FS_SAVE();
+
+    /*
+     * For small sleeps, precision might be important. OS/2 have a very bad
+     * precision on it's DosSleep api, the accuracy can easily be off by a
+     * timeslice. * It might be bad to return 32milliseconds late for small
+     * sleeps, thus we do a little hack for values of two timeslices or less.
+     * Timecritical threads are scheduled more precisely thank normal and idle
+     * threads, so we temporarily change the priority of the thread while
+     * waiting.
+     */
+    if (useconds < 65000)
+    {
+        PTIB    pTib;
+        PPIB    pPib;
+        ULONG   ulOldPri;
+
+        DosGetInfoBlocks(&pTib, &pPib);
+        ulOldPri = pTib->tib_ptib2->tib2_ulpri;
+
+        if (ulOldPri < (PRTYC_TIMECRITICAL << 8))
+        {
+            LIBCLOG_MSG("current priority %#05x temporarily boosting priority\n", ulOldPri);
+            DosSetPriority(PRTYS_THREAD, PRTYC_TIMECRITICAL, 0, 0);
+        }
+
+        /*
+         * For some reason we're frequently timing out too early the range
+         * 30-32ms. We're compensating here, just to make sure we're never
+         * too early without reason. (bird lives by that policy.)
+         */
+        if (msSleep >= 30 && msSleep < 33)
+            msSleep = 33;
+        LIBCLOG_MSG("DosSleep(%d)\n", msSleep);
+        DosSleep(msSleep);
+
+        if (ulOldPri < (PRTYC_TIMECRITICAL << 8))
+        {
+            APIRET rc = DosSetPriority(PRTYS_THREAD, ulOldPri >> 8, ulOldPri & 0xff, 0);
+            if (rc)
+            {
+                LIBCLOG_MSG("DosSetPriority(,%x,%x,0) failed with rc=%d\n",
+                            ulOldPri >> 8, ulOldPri & 0xff, rc);
+                //@todo add assertion.
+                DosSetPriority(PRTYS_PROCESS, PRTYC_REGULAR, 0, 0);
+            }
+        }
+    }
+    else
+    {
+        /*
+         * Simple DosSleep().
+         */
+        LIBCLOG_MSG("DosSleep(%d)\n", msSleep);
+        DosSleep(msSleep);
+    }
+
+    FS_RESTORE();
+    return 0;
+}
Index: trunk/src/emx/testcase/libc/miscinnotek/usleep.c
===================================================================
--- trunk/src/emx/testcase/libc/miscinnotek/usleep.c	(revision 1270)
+++ trunk/src/emx/testcase/libc/miscinnotek/usleep.c	(revision 1270)
@@ -0,0 +1,117 @@
+#include <unistd.h>
+#include <PrfTiming.h>
+#include <stdio.h>
+#include <errno.h>
+
+
+#ifdef __EMX__
+/* guesses, will fail on high system load */
+#define MAXDIFF_BIG     32000
+#define MAXDIFF_SMALL   10000
+#else
+#define MAXDIFF_BIG     20000
+#define MAXDIFF_SMALL    2000
+#endif
+
+
+
+
+int main()
+{
+    struct __test
+    {
+        /** Number of seconds to sleep. */
+        useconds_t      useconds;
+        /** Accepted number variation (higher, not lower). */
+        useconds_t      udiff;
+        /** expected return code. */
+        int             rc;
+        /** expected errno. */
+        int             err;
+    }   aTests[] =
+    {
+        { 10000000, MAXDIFF_BIG,  -1, EINVAL },
+        {        1, MAXDIFF_SMALL, 0, 0 },
+        {     2000, MAXDIFF_SMALL, 0, 0 },
+        {     4000, MAXDIFF_SMALL, 0, 0 },
+        {    10000, MAXDIFF_SMALL, 0, 0 },
+        {    20000, MAXDIFF_SMALL, 0, 0 },
+        {    25000, MAXDIFF_SMALL, 0, 0 },
+        {    30000, MAXDIFF_SMALL, 0, 0 },
+        {    33000, MAXDIFF_SMALL, 0, 0 },
+        {    32100, MAXDIFF_SMALL, 0, 0 },
+        {    32200, MAXDIFF_SMALL, 0, 0 },
+        {    32300, MAXDIFF_SMALL, 0, 0 },
+        {    33000, MAXDIFF_SMALL, 0, 0 },
+        {    32000, MAXDIFF_SMALL, 0, 0 },
+        {    29000, MAXDIFF_SMALL, 0, 0 },
+        {    29500, MAXDIFF_SMALL, 0, 0 },
+        {    30000, MAXDIFF_SMALL, 0, 0 },
+        {    30500, MAXDIFF_SMALL, 0, 0 },
+        {    31000, MAXDIFF_SMALL, 0, 0 },
+        {    31100, MAXDIFF_SMALL, 0, 0 },
+        {    31300, MAXDIFF_SMALL, 0, 0 },
+        {    31500, MAXDIFF_SMALL, 0, 0 },
+        {    31700, MAXDIFF_SMALL, 0, 0 },
+        {    31900, MAXDIFF_SMALL, 0, 0 },
+        {    33000, MAXDIFF_SMALL, 0, 0 },
+        {   200000, MAXDIFF_BIG,   0, 0 },
+    };
+    int         i;
+    int         rcRet = 0;
+
+    for (i = 0; i < sizeof(aTests)/sizeof(aTests[0]); i++)
+    {
+        int j;
+        for (j = 0; j < 10; j++)
+        {
+            long double lrdEnd, lrdStart, lrdDiff;
+            useconds_t  udiff;
+            int         err;
+            int         rc;
+
+            errno = 0;
+            lrdStart = gettime();
+            rc = usleep(aTests[i].useconds);
+            lrdEnd = gettime();
+            err = errno;
+
+            lrdDiff = lrdEnd - lrdStart;
+            udiff = lrdDiff * 1000000 / getHz();
+
+            /* check rc/errno */
+            if (    rc != aTests[i].rc
+                ||  err != aTests[i].err)
+            {
+                printf("usleep: %d: Invalid rc and/or errno. returned rc=%d expected %d, errno=%d, expected %d.\n",
+                       i, rc, aTests[i].rc, err, aTests[i].err);
+                rcRet++;
+            }
+            else if (!rc)
+            {   /* check time */
+                if (udiff < aTests[i].useconds)
+                {
+                    printf("usleep: %d: returned too early. sleept %d, requested %d\n",
+                           i, udiff, aTests[i].useconds);
+                    rcRet++;
+                    break;
+                }
+                else if (udiff > aTests[i].useconds + aTests[i].udiff)
+                {
+                    printf("usleep: %d: returned too late. sleept %d, requested %d. overslept %d max expected diff %d\n",
+                           i, udiff, aTests[i].useconds, udiff - aTests[i].useconds, aTests[i].udiff);
+                    rcRet++;
+                    break;
+                }
+            }
+        }
+    }
+
+    if (!rcRet)
+        printf("usleep: all tests succeeded.\n");
+    else
+        printf("usleep: %d failure%s\n", rcRet, rcRet > 1 ? "s" : "");
+
+    return rcRet;
+}
+
