Better implementation for usleep()

John Tytgat John.Tytgat at aaug.net
Tue Mar 26 16:51:27 PST 2002


This patch mainly is a better implementation for usleep() which now
works at a resolution of 1/100th of a second instead of 1 second.

Two comments:
  - Return type of usleep() got changed to 'int'.  Cfr. mail GCC mailing
    list msg-id <bc5b61084b.Jo at hobbes.riscos.be>
  - I also added a small fix in features.h which greatly reduces
    the warning list for Norcroft users.  Cfr mail GCC mailing list msg-id
    <082058084b.Jo at hobbes.riscos.be>.

John.
-- 
John Tytgat, in his comfy chair at home                                 BASS
John.Tytgat at aaug.net                             ARM powered, RISC OS driven
-------------- next part --------------
John Tytgat <John.Tytgat at aaug.net>

	* clib/unistd.h (ualarm): Declare.
	(usleep): return type is now 'int'.
	* clib/unixlib/features.h: Clean up Norcroft compiler warnings.
	* signal/sleep.c: Added GNU LGPL. (sleep_int): Created, this gets
	used by sleep() and usleep().  usleep() works now with a 1/100th
	sec resolution instead of 1 sec.
	* sys/alarm.c: Added GNU LGPL. (alarm): Synced implementation with
	GNU C Lib. (ualarm): Added.
	* time/setitmr.c (setitimer): Changed invalid parameter test
-------------- next part --------------
Index: source/clib/unistd.h
===================================================================
RCS file: /usr/local/cvsroot/gccsdk/unixlib/source/clib/unistd.h,v
retrieving revision 1.2.2.5
diff -c -u -r1.2.2.5 unistd.h
cvs server: conflicting specifications of output style
--- source/clib/unistd.h        2002/01/31 16:19:53     1.2.2.5
+++ source/clib/unistd.h        2002/03/27 00:32:21
@@ -192,10 +192,16 @@
    signal afterwards is undefined.  There is no return value to indicate
    error, but if `sleep' returns '__seconds', it probably didn't work.  */
 extern unsigned int sleep (unsigned int __seconds);
- 
+
+/* Set an alarm to go off (generating a SIGALRM signal) in VALUE
+   microseconds.  If INTERVAL is nonzero, when the alarm goes off, the
+   timer is reset to go off every INTERVAL microseconds thereafter.
+   Returns the number of microseconds remaining before the alarm.  */
+extern __useconds_t ualarm(__useconds_t __useconds, __useconds_t __interval);
+
 /* Make the process sleep for '__usec' microseconds, or until a signal
    arrives that is not blocked or ignored.  */
-extern unsigned int usleep (unsigned int __usec);
+extern int usleep (__useconds_t __usec);
 
 /* Suspend the process until a signal arrives.  */
 extern int pause (void);
Index: source/clib/unixlib/features.h
===================================================================
RCS file: /usr/local/cvsroot/gccsdk/unixlib/source/clib/unixlib/features.h,v
retrieving revision 1.2.2.2
diff -c -u -r1.2.2.2 features.h
cvs server: conflicting specifications of output style
--- source/clib/unixlib/features.h      2001/09/21 10:21:15     1.2.2.2
+++ source/clib/unixlib/features.h      2002/03/27 00:32:21
@@ -24,7 +24,7 @@
    modify it under the terms of the GNU Library General Public License as
    published by the Free Software Foundation; either version 2 of the
    License, or (at your option) any later version.
-   
+
    The GNU C Library 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
@@ -123,6 +123,19 @@
 #undef  __FAVOR_BSD
 #undef  __KERNEL_STRICT_NAMES
 
+/* This will reduce the number of Norcroft compiler warnings "Undefined macro
+   'xxx' in #if - treated as 0".  */
+#ifdef __CC_NORCROFT
+#ifndef __STDC_VERSION__
+# define __STDC_VERSION__      199409L
+#endif
+#ifndef _XOPEN_SOURCE
+# define _XOPEN_SOURCE         500
+#endif
+#ifndef _FILE_OFFSET_BITS
+# define _FILE_OFFSET_BITS     32
+#endif
+#endif
 
 /* If _BSD_SOURCE was defined by the user, favor BSD over POSIX.  */
 #if defined _BSD_SOURCE && \
@@ -294,7 +307,7 @@
 /* GCC has various useful declarations that can be made with the
    `__attribute__' syntax.  All of the ways we use this do fine if
    they are omitted for compilers that don't understand it. */
-#if !defined __GNUC__ || __GNUC__ < 2
+#if !defined __GNUC__ || __GNUC_PREREQ(2,0)
 # undef __attribute__
 # define __attribute__(xyz)     /* Ignore */
 #endif
Index: source/signal/sleep.c
===================================================================
RCS file: /usr/local/cvsroot/gccsdk/unixlib/source/signal/sleep.c,v
retrieving revision 1.2.2.3
diff -c -u -r1.2.2.3 sleep.c
cvs server: conflicting specifications of output style
--- source/signal/sleep.c       2001/09/11 13:40:57     1.2.2.3
+++ source/signal/sleep.c       2002/03/27 00:32:22
@@ -12,14 +12,33 @@
 static const char rcs_id[] = "$Id: sleep.c,v 1.2.2.3 2001/09/11 13:40:57 admin Exp $";
 #endif
 
-/* signal.c.sleep: Written by Nick Burrett, 6 October 1996.  */
+/* Copyright (C) 1991, 1992, 1993, 1996, 1997 Free Software Foundation, Inc.
 
+   The GNU C Library 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.1 of the License, or (at your option) any later version.
+
+   The GNU C Library 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 the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
 #include <signal.h>
 #include <time.h>
 #include <unistd.h>
 #include <errno.h>
 #include <unixlib/unix.h>
 
+#define USECS_PER_CLOCK (1000000 / CLOCKS_PER_SEC)
+
+/* #define DEBUG */
+
 /* SIGALRM signal handler for `sleep'.  This does nothing but return,
    but SIG_IGN isn't supposed to break `pause'.  */
 static void
@@ -29,19 +48,23 @@
   return;
 }
 
-/* Make the process sleep for SECONDS seconds, or until a signal arrives
-   and is not ignored.  The function returns the number of seconds less
-   than SECONDS which it actually slept (zero if it slept the full time).  */
-unsigned int
-sleep (unsigned int seconds)
+/* Make the process sleep for CLOCKTICKS clock ticks, or until a signal
+   arrives and is not ignored.  The function returns the number of clock
+   ticks less than CLOCKTICKS which it actually slept (zero if it slept
+   the full time).
+   If a signal handler does a `longjmp' or modifies the handling of the
+   SIGALRM signal while inside `sleep' call, the handling of the SIGALRM
+   signal afterwards is undefined.  There is no return value to indicate
+   error, but if `sleep' returns SECONDS, it probably didn't work.  */
+static clock_t
+sleep_int (clock_t clockticks)
 {
-  unsigned int remaining, slept;
-  time_t before, after;
+  clock_t before, after, slept, remaining;
   sigset_t set, oset;
   struct sigaction act, oact;
   int save = errno;
 
-  if (seconds == 0)
+  if (clockticks == 0)
     return 0;
 
   /* alarm() does not work in a TaskWindow nor whilst running as a
@@ -49,46 +72,49 @@
      but not necessairy vice-versa so the test on __wimpprogram is enough. */
   if (__wimpprogram)
     {
-      before = time ((time_t *) NULL) + seconds;
-      while (time ((time_t *) NULL) < before)
+      before = clock () + clockticks;
+      while (clock () < before)
         ;
       return 0;
     }
 
   /* Block SIGALRM signals while frobbing the handler.  */
-  sigemptyset (&set);
-  if (sigaddset (&set, SIGALRM) || sigprocmask (SIG_BLOCK, &set, &oset))
-    return seconds;
+  if (sigemptyset (&set) < 0 ||
+      sigaddset (&set, SIGALRM) < 0 ||
+      sigprocmask (SIG_BLOCK, &set, &oset))
+    return clockticks;
 
   act.sa_handler = sleep_handler;
   act.sa_flags = 0;
-  sigemptyset (&act.sa_mask);
+  act.sa_mask = oset;  /* execute handler with original mask */
   if (sigaction (SIGALRM, &act, &oact))
-    return seconds;
+    return clockticks;
 
-  before = time ((time_t *) NULL);
-  remaining = alarm (seconds);
+  before = clock ();
+  remaining = ualarm ((useconds_t)clockticks * USECS_PER_CLOCK, 0) / USECS_PER_CLOCK;
 
 #ifdef DEBUG
-  __os_print ("sleep: Set up an alarm for "); __os_prdec (seconds);
-  __os_print (" seconds\r\n");
+  __os_print ("sleep: Set up an alarm for "); __os_prdec (clockticks);
+  __os_print (" clockticks\r\n  Remaining: "); __os_prdec(remaining);
+  __os_print (" clockticks\r\n");
 #endif
 
-  if (remaining > 0 && remaining < seconds)
+  if (remaining > 0 && remaining < clockticks)
     {
       /* The user's alarm will expire before our own would.
          Restore the user's signal action state and let his alarm happen.  */
       sigaction (SIGALRM, &oact, (struct sigaction *) NULL);
-      alarm (remaining);       /* Restore sooner alarm.  */
+      /* Restore sooner alarm.  */
+      ualarm ((useconds_t)clockticks * USECS_PER_CLOCK, 0);
 #ifdef DEBUG
       __os_print ("sleep: A user alarm existed. Wait ");
-      __os_prdec (remaining); __os_print (" secs for that instead\r\n");
+      __os_prdec (remaining); __os_print (" clockticks for that instead\r\n");
 #endif
       sigsuspend (&oset);      /* Wait for it to go off.  */
 #ifdef DEBUG
       __os_print ("sleep: Alarm has gone off. Continuing with execution\r\n");
 #endif
-      after = time ((time_t *) NULL);
+      after = clock ();
     }
   else
     {
@@ -102,32 +128,46 @@
 #ifdef DEBUG
       __os_print ("sleep: Alarm has gone off. Continuing with execution\r\n");
 #endif
-      after = time ((time_t *) NULL);
+      after = clock ();
 
       /* Restore the old signal action state.  */
       sigaction (SIGALRM, &oact, (struct sigaction *) NULL);
     }
 
   /* Notice how long we actually slept.  */
-  slept = (unsigned int) (after - before);
+  slept = after - before;
 
   /* Restore the user's alarm if we have not already past it.
      If we have, be sure to turn off the alarm in case a signal
      other than SIGALRM was what woke us up.  */
-  alarm (remaining > slept ? remaining - slept : 0);
+  (void) ualarm (remaining > slept ? (useconds_t)(remaining - slept) * USECS_PER_CLOCK : 0, 0);
 
   /* Restore the original signal mask.  */
-  sigprocmask (SIG_SETMASK, &oset, (sigset_t *) NULL);
+  (void) sigprocmask (SIG_SETMASK, &oset, (sigset_t *) NULL);
 
   /* Restore the `errno' value we started with.
      Some of the calls we made might have failed, but we don't care.  */
   (void) __set_errno (save);
 
-  return slept > seconds ? 0 : seconds - slept;
+  return slept > clockticks ? 0 : clockticks - slept;
 }
 
+/* Make the process sleep for SECONDS seconds, or until a signal arrives
+   and is not ignored.  The function returns the number of seconds less
+   than SECONDS which it actually slept (zero if it slept the full time).  */
 unsigned int
-usleep (unsigned int usec)
+sleep (unsigned int seconds)
 {
-  return sleep ((usec + 999) / 1000);
+  return (unsigned int) sleep_int ((clock_t)seconds * CLOCKS_PER_SEC) / CLOCKS_PER_SEC;
+}
+
+int
+usleep (useconds_t usec)
+{
+  /* An allowed & specified limitation. Otherwise our calculations might
+     overflow.  */
+  if (usec >= 1000000)
+    __set_errno (EINVAL);
+
+  return (int) sleep_int ((usec + USECS_PER_CLOCK-1) / USECS_PER_CLOCK) * USECS_PER_CLOCK;
 }
Index: source/sys/alarm.c
===================================================================
RCS file: /usr/local/cvsroot/gccsdk/unixlib/source/sys/alarm.c,v
retrieving revision 1.2
diff -c -u -r1.2 alarm.c
cvs server: conflicting specifications of output style
--- source/sys/alarm.c  2001/01/29 15:10:21     1.2
+++ source/sys/alarm.c  2002/03/27 00:32:22
@@ -12,6 +12,23 @@
 static const char rcs_id[] = "$Id: alarm.c,v 1.2 2001/01/29 15:10:21 admin Exp $";
 #endif
 
+/* Copyright (C) 1991, 1992, 1994, 1997 Free Software Foundation, Inc.
+
+   The GNU C Library 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.1 of the License, or (at your option) any later version.
+
+   The GNU C Library 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 the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
+   02111-1307 USA.  */
+
 #include <errno.h>
 #include <unistd.h>
 #include <sys/time.h>
@@ -21,12 +38,39 @@
 alarm (unsigned int seconds)
 {
 #if __FEATURE_ITIMERS
-  struct itimerval old, new_timer;
+  struct itimerval old_timer, new_timer;
+  unsigned int retval;
+
   new_timer.it_interval.tv_usec = 0;
   new_timer.it_interval.tv_sec = 0;
   new_timer.it_value.tv_usec = 0;
-  new_timer.it_value.tv_sec = (int) seconds;
-  return (setitimer (ITIMER_REAL, &new_timer, &old) < 0) ? 0 : old.it_value.tv_sec;
+  new_timer.it_value.tv_sec = (time_t) seconds;
+  if (setitimer (ITIMER_REAL, &new_timer, &old_timer) < 0)
+    return 0;
+
+  retval = old_timer.it_value.tv_sec;
+  if (old_timer.it_value.tv_usec)
+    ++retval;
+  return retval;
+#else
+  return __set_errno (ENOSYS);
+#endif
+}
+
+useconds_t
+ualarm (useconds_t useconds, useconds_t interval)
+{
+#if __FEATURE_ITIMERS
+  struct itimerval old_timer, new_timer;
+
+  new_timer.it_interval.tv_sec = (time_t)interval / 1000000;
+  new_timer.it_interval.tv_usec = (suseconds_t) interval - 1000000 * new_timer.it_interval.tv_sec;;
+  new_timer.it_value.tv_sec = (time_t)useconds / 1000000;
+  new_timer.it_value.tv_usec = (suseconds_t) useconds - 1000000 * new_timer.it_value.tv_sec;
+  if (setitimer (ITIMER_REAL, &new_timer, &old_timer) < 0)
+    return -1; /* errno is already set by setitimer() */
+
+  return old_timer.it_value.tv_usec + (useconds_t)new_timer.it_value.tv_sec * 1000000;
 #else
   return __set_errno (ENOSYS);
 #endif
Index: source/time/setitmr.c
===================================================================
RCS file: /usr/local/cvsroot/gccsdk/unixlib/source/time/setitmr.c,v
retrieving revision 1.2.2.5
diff -c -u -r1.2.2.5 setitmr.c
cvs server: conflicting specifications of output style
--- source/time/setitmr.c       2001/09/11 14:16:00     1.2.2.5
+++ source/time/setitmr.c       2002/03/27 00:32:22
@@ -112,7 +112,9 @@
   if (__wimpprogram)
     return __set_errno (ENOSYS);
 
-  if ((unsigned) which >= __MAX_ITIMERS)
+  if ((unsigned) which >= __MAX_ITIMERS
+      || new_timer->it_interval.tv_usec >= 1000000
+      || new_timer->it_value.tv_usec >= 1000000)
     return __set_errno (EINVAL);
 
   /* __u is current process <unixlib/unix.h>.  */
@@ -131,9 +133,11 @@
   *itimer = *new_timer;
 
   if (check_ticker (&new_timer->it_value) == 1)
+{
     return add_ticker (&new_timer->it_value,
                       timer_controls[which].callback,
                       &itimer->it_interval);
+}
 
   return 0;
 }


More information about the gcc mailing list