OSDN Git Service

Provide more POSIX conforming sleep() functions.
authorKeith Marshall <keithmarshall@users.sourceforge.net>
Tue, 23 Dec 2014 20:59:37 +0000 (20:59 +0000)
committerKeith Marshall <keithmarshall@users.sourceforge.net>
Tue, 23 Dec 2014 20:59:37 +0000 (20:59 +0000)
mingwrt/ChangeLog
mingwrt/Makefile.in
mingwrt/include/parts/time.h [new file with mode: 0644]
mingwrt/include/sys/types.h
mingwrt/include/unistd.h
mingwrt/mingwex/nsleep.c [new file with mode: 0644]
mingwrt/mingwex/usleep.c [deleted file]

index 1be4574..8666b9f 100644 (file)
@@ -1,3 +1,38 @@
+2014-12-23  Keith Marshall  <keithmarshall@users.sourceforge.net>
+
+       Provide more POSIX conforming sleep() functions.
+
+       * include/sys/types.h (useconds_t): Make it explicitly long; int may
+       be okay, but doesn't guarantee enough bits; mark as deprecated, since
+       POSIX has declared it "obsolete", and no longer specifies it.
+
+       * mingwex/usleep.c: Delete file; it provided an implementation of...
+       (usleep): ...this now obsolete function, claiming POSIX.1 issue 6, but
+       its error handling was hopelessly broken; replace it with...
+       * mingwex/nsleep.c: ...this new file; it implements...
+       (__mingw_sleep): ...this generic helper function; it supports sleep
+       capability with interval specification to nanosecond precision.
+
+       * include/unistd.h (__mingw_sleep): Declare prototype; use it as the
+       basis for providing __LIBIMPL__ __CRT_INLINE implementations of...
+       (sleep, nanosleep): ...these current POSIX functions, and also...
+       (usleep): ...this obsolete one; mark it as deprecated.
+
+       * include/parts: New directory; it is intended to host partial header
+       implementations, for content which must be shared among arbitrary sets
+       of multiple standard header files.
+
+       * include/parts/time.h: New file; nominally declaring time.h content.
+       (struct timespec): Declare it; it is currently used within unistd.h,
+       to facilitate the __CRT_INLINE implementation of nanosleep().
+
+       * Makefile.in (libmingwex.a): Remove reference to...
+       (usleep.$OBJEXT): ...this; replace it with a reference to...
+       (nsleep.$OBJEXT): ...this alternative.
+       (mingwrt-includedirs): Add prerequisite to create...
+       ($includedir/parts): ...this new directory; it is populated by...
+       (install-mingwrt-headers): ...this rule; add requisite command.
+
 2014-12-13  Keith Marshall  <keithmarshall@users.sourceforge.net>
 
        Delete an unnecessary Unicode wrapper file.
index 87c4d1b..3decb35 100644 (file)
@@ -443,7 +443,7 @@ $(addsuffix fmt.$(OBJEXT),varo crto geto seto crtn getn setn): %.$(OBJEXT): ofmt
 #
 #libmingwex.a: $(addsuffix .$(OBJEXT), glob membarrier)
 libmingwex.a: $(addsuffix .$(OBJEXT), mingw-aligned-malloc mingw-fseek)
-libmingwex.a: $(addsuffix .$(OBJEXT), glob getopt basename dirname usleep)
+libmingwex.a: $(addsuffix .$(OBJEXT), glob getopt basename dirname nsleep)
 libmingwex.a: $(addsuffix .$(OBJEXT), mkstemp mkdtemp cryptnam)
 
 libmingwex.a: $(addsuffix .$(OBJEXT), tdelete tfind tsearch twalk)
@@ -673,13 +673,14 @@ install-mingwrt-license install-w32api-license: install-%: docdir %-files
 includedirs: mingwrt-includedirs
 install-headers install-mingwrt: install-mingwrt-headers
 
-${includedir}/sys: includedir
-mingwrt-includedirs: ${includedir}/sys
+${includedir}/sys ${includedir}/parts: includedir
+mingwrt-includedirs: ${includedir}/sys ${includedir}/parts
        $(mkinstalldirs) $^
 
 install-mingwrt-headers: mingwrt-includedirs
        $(INSTALL_DATA) ${mingwrt_srcdir}/include/*.h ${includedir}
        $(INSTALL_DATA) ${mingwrt_srcdir}/include/sys/*.h ${includedir}/sys
+       $(INSTALL_DATA) ${mingwrt_srcdir}/include/parts/*.h ${includedir}/parts
        $(INSTALL_DATA) ${mingwrt_srcdir}/profile/*.h ${includedir}
 
 # Install libraries, and supporting free standing object files.
diff --git a/mingwrt/include/parts/time.h b/mingwrt/include/parts/time.h
new file mode 100644 (file)
index 0000000..9e19be3
--- /dev/null
@@ -0,0 +1,76 @@
+/*
+ * parts/time.h
+ *
+ * Internal header file, declaring types and structures which nominally
+ * originate from time.h, but which POSIX requires to be made visible on
+ * inclusion of certain other headers, without including time.h itself.
+ *
+ * $Id$
+ *
+ * Written by Keith Marshall  <keithmarshall@users.sourceforge.net>
+ * Copyright (C) 2014, MinGW.org Project.
+ *
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice, this permission notice, and the following
+ * disclaimer shall be included in all copies or substantial portions of
+ * the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OF OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *
+ */
+#if _FAKE_TIME_H_SOURCED
+/*
+ * Since we expect this part-header to be sourced exclusively by other
+ * system headers, (nominally time.h), we don't apply any conventional
+ * multiple inclusion guard; rather, we rely on the guard within time.h
+ * itself, but allow other headers to fake it for one-shot inclusion
+ * only...
+ */
+# undef _FAKE_TIME_H_SOURCED
+
+#elif ! defined _TIME_H
+/*
+ * ...otherwise, we fail if the time.h guard is not in place.
+ */
+# error "Never include <parts/time.h> directly; use <time.h> instead"
+#endif
+
+#if defined __need_struct_timespec && ! __struct_timespec_defined
+/*
+ * Structure timespec is mandated by POSIX, for specification of
+ * intervals with the greatest precision supported by the OS kernel.
+ * Although this allows for specification to nanosecond precision, do
+ * not be deluded into any false expectation that such short intervals
+ * can be realized on Windows; on Win9x derivatives, the metronome used
+ * by the process scheduler has a period of ~55 milliseconds, while for
+ * WinNT derivatives, the corresponding period is ~15 milliseconds; thus,
+ * the shortest intervals which can be realistically timed will range
+ * from 0..55 milliseconds on Win9x hosts, and from 0..15 ms on WinNT,
+ * with period values normally distributed around means of ~27.5 ms
+ * and ~7.5 ms, for the two system types respectively.
+ */
+struct timespec
+{
+  /* Period is sum of tv_sec + tv_nsec; use fundamental integer types
+   * to avoid 32-bit vs. 64-bit time_t ambiguity.
+   */
+  long long    tv_sec;         /* seconds */
+  long         tv_nsec;        /* nanoseconds */
+};
+# define __struct_timespec_defined  1
+#endif
+
+/* $RCSfile$: end of file */
index 976a3fe..45da5e6 100644 (file)
@@ -129,9 +129,9 @@ typedef long long fpos64_t;
 typedef long long off64_t;
 #endif
 
-#if !defined __NO_ISOCEXT
-typedef unsigned int useconds_t;
-#endif  /* Not __NO_ISOCEXT */
+#if _POSIX_C_SOURCE
+typedef unsigned long useconds_t __MINGW_ATTRIB_DEPRECATED;
+#endif
 
 #endif /* Not RC_INVOKED */
 
index 85a5cf5..b6bd05e 100644 (file)
@@ -1,12 +1,52 @@
 #ifndef _UNISTD_H
 /*
- * This file is part of the Mingw32 package.
+ * unistd.h
  *
- * unistd.h maps (roughly) to io.h
+ * Standard header file declaring MinGW's POSIX compatibility features.
+ *
+ * $Id$
+ *
+ * Written by Rob Savoye <rob@cygnus.com>
+ * Modified by Earnie Boyd <earnie@users.sourceforge.net>
+ *   Danny Smith <dannysmith@users.sourceforge.net>
+ *   Ramiro Polla <ramiro@lisha.ufsc.br>
+ *   Gregory McGarry  <gregorymcgarry@users.sourceforge.net>
+ *   Keith Marshall  <keithmarshall@users.sourceforge.net>
+ * Copyright (C) 1997, 1999, 2002-2004, 2007-2009, 2014, MinGW.org Project.
+ *
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice, this permission notice, and the following
+ * disclaimer shall be included in all copies or substantial portions of
+ * the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OF OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *
+ */
+#define _UNISTD_H  1
+#pragma GCC system_header
+
+/* All MinGW headers MUST include _mingw.h before anything else,
+ * to ensure proper initialization of feature test macros.
+ */
+#include <_mingw.h>
+
+/* unistd.h maps (roughly) to io.h
  * Other headers included by unistd.h may be selectively processed;
  * __UNISTD_H_SOURCED__ enables such selective processing.
  */
-#define _UNISTD_H
 #define __UNISTD_H_SOURCED__ 1
 
 #include <io.h>
 #define SEEK_END 2
 #endif
 
+#if _POSIX_C_SOURCE
+/*
+ * POSIX process/thread suspension functions; all are supported by a
+ * common MinGW API in libmingwex.a, providing for suspension periods
+ * ranging from mean values of ~7.5 milliseconds, (see comments below),
+ * extending up to a maximum of ~136 years.
+ *
+ * Note that, whereas POSIX supports early wake-up of any suspended
+ * process/thread, in response to a signal, this implementation makes
+ * no attempt to emulate this signalling behaviour, (since signals are
+ * not well supported by Windows); thus, unless impeded by an invalid
+ * argument, this implementation always returns an indication as if
+ * the sleeping period ran to completion.
+ */
+_EXTERN_C _cdecl __MINGW_NOTHROW
+int __mingw_sleep( unsigned long, unsigned long );
+
+/* Structure timespec is mandated by POSIX, for specification of
+ * intervals with the greatest precision supported by the OS kernel.
+ * Although this allows for specification to nanosecond precision, do
+ * not be deluded into any false expectation that such short intervals
+ * can be realized on Windows; on Win9x derivatives, the metronome used
+ * by the process scheduler has a period of ~55 milliseconds, while for
+ * WinNT derivatives, the corresponding period is ~15 milliseconds; thus,
+ * the shortest intervals which can be realistically timed will range
+ * from 0..55 milliseconds on Win9x hosts, and from 0..15 ms on WinNT,
+ * with period values normally distributed around means of ~27.5 ms
+ * and ~7.5 ms, for the two system types respectively.
+ */
+#define _FAKE_TIME_H_SOURCED   1
+#define __need_struct_timespec 1
+#include <parts/time.h>
+
 _BEGIN_C_DECLS
 
-#if !defined __NO_ISOCEXT
-#include <sys/types.h> /* For useconds_t. */
+/* The nanosleep() function provides the most general purpose API for
+ * process/thread suspension; it provides for specification of periods
+ * ranging from ~7.5 ms mean, (on WinNT derivatives; ~27.5 ms on Win9x),
+ * extending up to ~136 years, (effectively eternity).
+ */
+_cdecl __MINGW_NOTHROW
+int nanosleep( const struct timespec *, struct timespec * );
 
-int __cdecl __MINGW_NOTHROW usleep(useconds_t useconds);
-#endif  /* Not __NO_ISOCEXT */
+#ifndef __NO_INLINE__
+__CRT_INLINE __LIBIMPL__(( FUNCTION = nanosleep ))
+int nanosleep( const struct timespec *period, struct timespec *residual )
+{
+  if( residual != (void *)(0) )
+    residual->tv_sec = (long long)(residual->tv_nsec = 0);
+  return __mingw_sleep((unsigned)(period->tv_sec), (period->tv_sec < 0LL)
+    ? (unsigned)(-1) : (unsigned)(period->tv_nsec));
+}
+#endif
 
-/* This is defined both as a real library function, to allow autoconf
- * to verify its existence, and as a potentially inline implementation.
+/* The usleep() function, and its associated useconds_t type specifier
+ * were made obsolete in POSIX.1-2008; declared here, only for backward
+ * compatibility, its continued use is not recommended.  (It is limited
+ * to specification of suspension periods ranging from ~7.5 ms mean up
+ * to a maximum of 999,999 microseconds only).
  */
-int ftruncate(int, off_t);
+typedef unsigned long useconds_t __MINGW_ATTRIB_DEPRECATED;
+int _cdecl __MINGW_NOTHROW usleep( useconds_t )__MINGW_ATTRIB_DEPRECATED;
+
+#ifndef __NO_INLINE__
+__CRT_INLINE __LIBIMPL__(( FUNCTION = usleep ))
+int usleep( useconds_t period ){ return __mingw_sleep( 0, 1000 * period ); }
+#endif
+
+/* The sleep() function is, perhaps, the most commonly used of all the
+ * process/thread suspension APIs; it provides support for specification
+ * of suspension periods ranging from 1 second to ~136 years.  (However,
+ * POSIX recommends limiting the maximum period to 65535 seconds, to
+ * maintain portability to platforms with only 16-bit ints).
+ */
+unsigned _cdecl __MINGW_NOTHROW sleep( unsigned );
+
+#ifndef __NO_INLINE__
+__CRT_INLINE __LIBIMPL__(( FUNCTION = sleep ))
+unsigned sleep( unsigned period ){ return __mingw_sleep( period, 0 ); }
+#endif
+
+
+/* POSIX ftruncate() function.
+ *
+ * Microsoft's _chsize() function is incorrectly described, on MSDN,
+ * as a preferred replacement for the POSIX chsize() function.  There
+ * never was any such POSIX function; the actual POSIX equivalent is
+ * the ftruncate() function.
+ */
+int _cdecl ftruncate( int, off_t );
+
 #ifndef __NO_INLINE__
 __CRT_INLINE __JMPSTUB__(( FUNCTION = ftruncate, REMAPPED = _chsize ))
-int ftruncate(int __fd, off_t __length)
-{ return _chsize (__fd, __length); }
+int ftruncate( int __fd, off_t __length ){ return _chsize( __fd, __length ); }
 #endif
 
 _END_C_DECLS
 
+#endif /* _POSIX_C_SOURCE */
+
 #undef __UNISTD_H_SOURCED__
-#endif /* _UNISTD_H */
+#endif /* ! _UNISTD_H: $RCSfile$: end of file */
diff --git a/mingwrt/mingwex/nsleep.c b/mingwrt/mingwex/nsleep.c
new file mode 100644 (file)
index 0000000..646e4b5
--- /dev/null
@@ -0,0 +1,107 @@
+/*
+ * nsleep.c
+ *
+ * Core implementation of the __mingw_sleep() API, which facilitates the
+ * provision of (mostly) POSIX compliant sleep(), usleep(), and nanosleep()
+ * functions, (per inline implementations in unistd.h).
+ *
+ * $Id$
+ *
+ * Written by Keith Marshall <keithmarshall@users.sourceforge.net>
+ * Copyright (C) 2014, MinGW.org Project.
+ *
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice, this permission notice, and the following
+ * disclaimer shall be included in all copies or substantial portions of
+ * the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OF OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *
+ */
+#include <errno.h>
+#include <limits.h>
+#include <unistd.h>
+
+/* Including windows.h, just to declare Sleep(), seems like overkill; we
+ * prefer to declare it directly, to ensure we get the kernel DLL import,
+ * without the overhead of redirection through a libkernel.a trampoline.
+ */
+__declspec(dllimport) _stdcall void Sleep( unsigned long );
+
+int __mingw_sleep( unsigned long secs, unsigned long nsecs )
+{
+  /* Entry point for general purpose sleep() function API, supporting
+   * the __CRT_INLINE implementations of the three functions identified
+   * in the file description above.
+   */
+  if( (secs | nsecs) > 0UL )
+  {
+    /* At least one of the seconds or nanoseconds components must
+     * be non-zero, to require us to perform any action.
+     */
+    if( nsecs < 1000000000UL )
+    {
+      /* POSIX requires the nanoseconds component of the specified
+       * interval to be less than one full second (1,000,000,000 ns);
+       * we've satisfied that requirement, so we proceed to combine
+       * the seconds and nanoseconds components into a millisecond
+       * representation, as required by the kernel's Sleep() API,
+       * (using a 64-bit representation, to avoid overflow).
+       */
+      unsigned long long interval = (secs > 0UL)
+       ? secs * 1000ULL + ((nsecs > 0UL) ? nsecs / 1000000ULL : 0ULL)
+       : (nsecs + 999999ULL) / 1000000ULL;
+
+      /* It is unlikely that we should ever need this, (but it is
+       * possible, so we proceed defensively)...
+       */
+      while( interval > (unsigned long long)(LONG_MAX) )
+      {
+       /* ...breaking excessively long intervals into cycles of
+        * LONG_MAX milliseconds, (~25 days, and we may be asked
+        * to sleep through up to 2000 cycles, or ~136 years), so
+        * that we avoid any interval value with the high bit set
+        * (lest that be interpreted as "sleep forever").
+        */
+       Sleep( (unsigned long)(LONG_MAX) );
+       interval -= (unsigned long long)(LONG_MAX);
+      }
+      /* Since suspension requests of 25 days are unlikely, in
+       * the majority of cases we should simply skip over the
+       * preceding loop; we must still call Sleep(), either to
+       * satisfy the original request in its entirety, or the
+       * residual from the loop.
+       */
+      Sleep( (unsigned long)(interval) );
+    }
+    else
+    { /* We were given a nanoseconds component value, within the
+       * interval specification, which exceeds one full second; in
+       * this event, POSIX specifies the following failure:
+       */
+      errno = EINVAL;
+      return -1;
+    }
+  }
+  /* On success, or maybe having done nothing at all, we simply
+   * return zero; (note that Windows Sleep() isn't interruptible
+   * in the way that that POSIX sleep() is, so we do not provide
+   * any indication of an uncompleted interval).
+   */
+  return 0;
+}
+
+/* $RCSfile$: end of file */
diff --git a/mingwrt/mingwex/usleep.c b/mingwrt/mingwex/usleep.c
deleted file mode 100644 (file)
index c059c06..0000000
+++ /dev/null
@@ -1,40 +0,0 @@
-/*
- * usleep
- * Implementation according to:
- * The Open Group Base Specifications Issue 6
- * IEEE Std 1003.1, 2004 Edition
- */
-
-/*
- *  THIS SOFTWARE IS NOT COPYRIGHTED
- *
- *  This source code is offered for use in the public domain. You may
- *  use, modify or distribute it freely.
- *
- *  This code is distributed in the hope that it will be useful but
- *  WITHOUT ANY WARRANTY. ALL WARRANTIES, EXPRESS OR IMPLIED ARE HEREBY
- *  DISCLAIMED. This includes but is not limited to warranties of
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- *
- *  Contributed by:
- *  Ramiro Polla <ramiro@lisha.ufsc.br>
- */
-
-#include <sys/types.h>
-#include <errno.h>
-
-#define WIN32_LEAN_AND_MEAN
-#include <windows.h>
-
-int __cdecl usleep(useconds_t useconds)
-{
-    if(useconds == 0)
-        return 0;
-
-    if(useconds >= 1000000)
-        return EINVAL;
-
-    Sleep((useconds + 999) / 1000);
-
-    return 0;
-}