]> granicus.if.org Git - check/commitdiff
Allow unit test timeouts to be specified using nanosecond precision
authorbrarcher <brarcher@64e312b2-a51f-0410-8e61-82d0ca0eb02a>
Wed, 21 Nov 2012 04:01:43 +0000 (04:01 +0000)
committerbrarcher <brarcher@64e312b2-a51f-0410-8e61-82d0ca0eb02a>
Wed, 21 Nov 2012 04:01:43 +0000 (04:01 +0000)
Previously, test timeouts were limited to second precision. The reason
was the call used to determine test timeouts, alarm, only supported
second precision. With this change, three more functions from librt
are used set a timer to fire with nanosecond precision. For systems
without librt, an implementation of these functions is in libcompat
which fall back on using alarm.

git-svn-id: svn+ssh://svn.code.sf.net/p/check/code/trunk@679 64e312b2-a51f-0410-8e61-82d0ca0eb02a

NEWS
configure.ac
doc/check.texi
lib/libcompat.h
src/check.c
src/check.h.in
src/check_impl.h
src/check_run.c
tests/check_check_master.c
tests/check_check_sub.c

diff --git a/NEWS b/NEWS
index 49c7b6e4fda27df63da0b17c0129bf449232dc35..d04dfdb6d3a0673d6bf2f96eccfe78e8285e765d 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -21,6 +21,10 @@ In development:
 * Improvements to the new Check API: new comparison functions for pointers:
   ck_assert_ptr_(eq|ne).
 
+* Test timeouts can now be in nanosecond precision. The tcase_set_timeout
+  call, and CK_DEFAULT_TIMEOUT and CK_TIMEOUT_MULTIPLIER environment
+  variables now can accept floating point arguments.
+
 Mon, Oct 22, 2012: Released Check 0.9.9
   based on r637 (2012-10-22 13:54:14 +0200)
 
index 396abb5687733c2c9bdbd7d8bbe32b6eb9867159..fd77551ac36f41dfb9a7505b2279df72d6ba5b5f 100644 (file)
@@ -124,11 +124,17 @@ if test "$TEX" = "false"; then
     AC_MSG_WARN(tex not installed: cannot rebuild HTML documentation.)
 fi
 
-# Checks for libraries.
+# Add math library
+LIBS=-lm
+AC_SUBST(LIBS)
 
-# Check if clock_gettime is available in lib rt, and if so,
+# Check if clock_gettime, timer_create, timer_settime, and timer_delete are available in lib rt, and if so,
 # add -lrt to LIBS
-AC_CHECK_LIB([rt], [clock_gettime])
+AC_CHECK_LIB([rt], [clock_gettime, timer_create, timer_settime, timer_delete])
+
+# check that struct itimerspec is defined in time.h. If not, we need to
+# define it in libcompat.h
+AC_CHECK_MEMBERS([struct itimerspec.it_interval, struct itimerspec.it_value], [], [AC_DEFINE_UNQUOTED(STRUCT_ITIMERSPEC_DEFINITION_MISSING, 1, "Need to define the itimerspec structure")], [#include <time.h>])
 
 # Checks for header files.
 AC_HEADER_STDC
@@ -169,8 +175,8 @@ AC_CHECK_SIZEOF(long, 4)
 # Checks for library functions.
 AC_FUNC_MALLOC
 AC_FUNC_REALLOC
-AC_REPLACE_FUNCS([clock_gettime fileno localtime_r pipe putenv setenv sleep strdup strsignal unsetenv])
-AC_CHECK_DECLS([clock_gettime, fileno, localtime_r, pipe, putenv, setenv, sleep, strdup, strsignal, unsetenv])
+AC_REPLACE_FUNCS([clock_gettime timer_create timer_settime timer_delete fileno localtime_r pipe putenv setenv sleep strdup strsignal unsetenv])
+AC_CHECK_DECLS([clock_gettime, timer_create, timer_settime, timer_delete, fileno, localtime_r, pipe, putenv, setenv, sleep, strdup, strsignal, unsetenv])
 
 # Checks for pthread implementation.
 ACX_PTHREAD
index bdf11151b87dce2b69891fcfd78bbba61ac8024e..6720a104963c1665d3029b8ce1e75176c0a4aec3 100644 (file)
@@ -1243,7 +1243,8 @@ length is to use the @code{CK_TIMEOUT_MULTIPLIER} environment variable,
 which multiplies all timeouts, including those set with
 @code{tcase_set_timeout()}, with the supplied integer value. All timeout
 arguments are in seconds and a timeout of 0 seconds turns off the timeout
-functionality.
+functionality. On systems that support it, the timeout can be specified
+using a nanosecond precision. Otherwise, second precision is used.
 
 Test timeouts are only available in CK_FORK mode.
 
index 2afa389eb25aa651ad0478f089427cd841987f0f..62f6739d8e14b2ba01e2ad7ffd5072400a9f433c 100644 (file)
@@ -113,7 +113,29 @@ int unsetenv (const char *name);
 #ifndef CLOCK_MONOTONIC
 #define CLOCK_MONOTONIC 0
 #endif
+
+#ifdef STRUCT_ITIMERSPEC_DEFINITION_MISSING
+/* 
+ * The following structure is defined in POSIX.1b for timer start values and intervals.
+ * If it is not defined in time.h, then we need to define it here.
+ */
+struct itimerspec
+{
+    struct timespec it_interval;
+    struct timespec it_value;
+};
+#endif
+
+/* 
+ * As the functions which use timer_t are not defined on the system, 
+ * the timer_t type probably also is not defined.
+ */
+typedef int timer_t;
+
 int clock_gettime(int clk_id, struct timespec *ts);
+int timer_create(int clockid, struct sigevent *sevp, timer_t *timerid);
+int timer_settime(timer_t timerid, int flags, const struct itimerspec *new_value, struct itimerspec * old_value);
+int timer_delete(timer_t timerid);
 #endif /* HAVE_LIBRT */
 
 /* silence warnings about an empty library */
index 4afa41025b0001960cb9ab4cfb536c3379583a62..40fab636d6a71948e3404a33e42a834f63aa92ed 100644 (file)
@@ -24,6 +24,7 @@
 #include <stdio.h>
 #include <stdlib.h>
 #include <stdarg.h>
+#include <math.h>
 
 #include "check.h"
 #include "check_error.h"
@@ -35,6 +36,8 @@
 #define DEFAULT_TIMEOUT 4
 #endif
 
+#define NANOS_PER_SECONDS 1000000000
+
 int check_major_version = CHECK_MAJOR_VERSION;
 int check_minor_version = CHECK_MINOR_VERSION;
 int check_micro_version = CHECK_MICRO_VERSION;
@@ -93,7 +96,8 @@ static void suite_free (Suite *s)
 TCase *tcase_create (const char *name)
 {
   char *env;
-  int timeout = DEFAULT_TIMEOUT;
+  double timeout_sec = DEFAULT_TIMEOUT;
+  
   TCase *tc = emalloc (sizeof(TCase)); /*freed in tcase_free */
   if (name == NULL)
     tc->name = "";
@@ -102,21 +106,25 @@ TCase *tcase_create (const char *name)
 
   env = getenv("CK_DEFAULT_TIMEOUT");
   if (env != NULL) {
-    int tmp = atoi(env);
-    if (tmp >= 0) {
-      timeout = tmp;
+    char * endptr = NULL;
+    double tmp = strtod(env, &endptr);
+    if (tmp >= 0 && endptr != env && (*endptr) == '\0') {
+      timeout_sec = tmp;
     }
   }
 
   env = getenv("CK_TIMEOUT_MULTIPLIER");
   if (env != NULL) {
-    int tmp = atoi(env);
-    if (tmp >= 0) {
-      timeout = timeout * tmp;
+    char * endptr = NULL;
+    double tmp = strtod(env, &endptr);
+    if (tmp >= 0 && endptr != env && (*endptr) == '\0') {
+      timeout_sec = timeout_sec * tmp;
     }
   }  
 
-  tc->timeout = timeout;
+  tc->timeout.tv_sec   = floor(timeout_sec);
+  tc->timeout.tv_nsec  = ((timeout_sec-floor(timeout_sec)) * (double)NANOS_PER_SECONDS);
+  
   tc->tflst = check_list_create();
   tc->unch_sflst = check_list_create();
   tc->ch_sflst = check_list_create();
@@ -204,17 +212,20 @@ static void tcase_add_fixture (TCase *tc, SFun setup, SFun teardown,
   }
 }
 
-void tcase_set_timeout (TCase *tc, int timeout)
+void tcase_set_timeout (TCase *tc, double timeout)
 {
   if (timeout >= 0) {
     char *env = getenv("CK_TIMEOUT_MULTIPLIER");
     if (env != NULL) {
-      int tmp = atoi(env);
-      if (tmp >= 0) {
+      char * endptr = NULL;
+      double tmp = strtod(env, &endptr);
+      if (tmp >= 0 && endptr != env && (*endptr) == '\0') {
         timeout = timeout * tmp;
       }
     }
-    tc->timeout = timeout;
+    
+  tc->timeout.tv_sec   = floor(timeout);
+  tc->timeout.tv_nsec  = ((timeout-floor(timeout)) * (double)NANOS_PER_SECONDS);
   }
 }
 
index fe9465994409614ba3050fa5b1efd14b0bd045ee..429702a5d510bc0fb01add4a3a17c89c7a5a5f78 100644 (file)
@@ -223,7 +223,7 @@ void CK_EXPORT tcase_add_checked_fixture (TCase *tc, SFun setup, SFun teardown);
    The timeout can also be set globaly with the environment variable
    CK_DEFAULT_TIMEOUT, the specific setting always takes precedence.
 */
-void CK_EXPORT tcase_set_timeout (TCase *tc, int timeout);
+void CK_EXPORT tcase_set_timeout (TCase *tc, double timeout);
  
 /* Internal function to mark the start of a test function */
 void CK_EXPORT tcase_fn_start (const char *fname, const char *file, int line);
index 01f0f567103edb2ecb863bd171be6746d67281bc..f1f4664f7296bfa09cb579e141b8a147ec38a471 100644 (file)
 #ifndef CHECK_IMPL_H
 #define CHECK_IMPL_H
 
-
 /* This header should be included by any module that needs
    to know the implementation details of the check structures
-   Include stdio.h & list.h before this header
+   Include stdio.h, time.h, & list.h before this header
 */
 
 /** calculate the difference in useconds out of two "struct timespec"s */
@@ -54,7 +53,7 @@ typedef struct Fixture
 
 struct TCase {
   const char *name;
-  int timeout;
+  struct timespec timeout;
   List *tflst; /* list of test functions */
   List *unch_sflst;
   List *unch_tflst;
index d5d341f20c02a4be554ece98215b34bde2c4e50d..8b3f16c85adaa4ab7cd1fa49695a79739b68edd5 100644 (file)
@@ -378,8 +378,12 @@ static TestResult *tcase_run_tfun_fork (SRunner *sr, TCase *tc, TF *tfun, int i)
   pid_t pid;
   int status = 0;
   struct timespec ts_start, ts_end;
+
+  timer_t timerid;
+  struct itimerspec timer_spec; 
   TestResult * tr;
 
+
   pid = fork();
   if (pid == -1)
     eprintf("Error in call to fork:", __FILE__, __LINE__ - 2);
@@ -399,10 +403,33 @@ static TestResult *tcase_run_tfun_fork (SRunner *sr, TCase *tc, TF *tfun, int i)
   }
 
   alarm_received = 0;
-  alarm(tc->timeout);
-  do {
-    pid_w = waitpid(pid, &status, 0);
-  } while (pid_w == -1);
+  
+  if(timer_create(CLOCK_MONOTONIC, 
+               NULL /* fire SIGALRM if timer expires */,
+               &timerid) == 0)
+  {
+    /* Set the timer to fire once */
+    timer_spec.it_value            = tc->timeout;
+    timer_spec.it_interval.tv_sec  = 0;
+    timer_spec.it_interval.tv_nsec = 0;
+    if(timer_settime (timerid, 0, &timer_spec, NULL) == 0)
+    {
+      do {
+        pid_w = waitpid(pid, &status, 0);
+      } while (pid_w == -1);
+    }
+    else
+    {
+      eprintf("Error in call to timer_settime:", __FILE__, __LINE__);
+    }
+    
+      /* If the timer has not fired, disable it */
+      timer_delete(timerid);
+  }
+  else
+  {
+    eprintf("Error in call to timer_create:", __FILE__, __LINE__);
+  }
   
   killpg(pid, SIGKILL); /* Kill remaining processes. */
 
index b1ad268caf6be910838853eaed01c63f4e7ce73e..8e09fe515c7dbe32f75b10514b12b944377ee2e0 100644 (file)
@@ -72,37 +72,112 @@ static master_test_t master_tests[] = {
 
 #if TIMEOUT_TESTS_ENABLED
 #if HAVE_WORKING_SETENV
-  { "Environment Timeout Tests", CK_ERROR,  "Test timeout expired" },
-  { "Environment Timeout Tests", CK_PASS,   "Passed" },
-  { "Environment Timeout Tests", CK_PASS,   "Passed" },
-  { "Environment Timeout Tests", CK_ERROR,  "Test timeout expired" },
+  { "Environment Integer Timeout Tests", CK_ERROR,  "Test timeout expired" },
+  { "Environment Integer Timeout Tests", CK_PASS,   "Passed" },
+  { "Environment Integer Timeout Tests", CK_PASS,   "Passed" },
+  { "Environment Integer Timeout Tests", CK_ERROR,  "Test timeout expired" },
+  
+  { "Environment Double Timeout Tests", CK_ERROR,  "Test timeout expired" },
+#ifdef HAVE_LIBRT
+  { "Environment Double Timeout Tests", CK_PASS,  "Passed" },
+  { "Environment Double Timeout Tests", CK_ERROR,  "Test timeout expired" },
+#endif /* HAVE_LIBRT */
+  { "Environment Double Timeout Tests", CK_ERROR,  "Test timeout expired" },
+  { "Environment Double Timeout Tests", CK_ERROR,  "Test timeout expired" },
+  { "Environment Double Timeout Tests", CK_ERROR,  "Test timeout expired" },
 #endif
-  { "Timeout Tests", CK_ERROR,  "Test timeout expired" },
-  { "Timeout Tests", CK_PASS,   "Passed" },
-  { "Timeout Tests", CK_ERROR,  "Test timeout expired" },
-  { "Timeout Tests", CK_ERROR,  "Test timeout expired" },
-  { "User Timeout Tests", CK_ERROR,  "Test timeout expired" },
-  { "User Timeout Tests", CK_PASS,   "Passed" },
-  { "User Timeout Tests", CK_PASS,   "Passed" },
-  { "User Timeout Tests", CK_ERROR,  "Test timeout expired" },
-  /* Timeout tests are run twice , see check_check_sub.c:make_sub_suite() */
-  { "Timeout Tests", CK_ERROR,  "Test timeout expired" },
-  { "Timeout Tests", CK_PASS,   "Passed" },
-  { "Timeout Tests", CK_ERROR,  "Test timeout expired" },
-  { "Timeout Tests", CK_ERROR,  "Test timeout expired" },
+
+  { "Default Timeout Tests", CK_ERROR,  "Test timeout expired" },
+#ifdef HAVE_LIBRT
+  { "Default Timeout Tests", CK_PASS,   "Passed" },
+  { "Default Timeout Tests", CK_PASS,   "Passed" },
+#endif /* HAVE_LIBRT */
+  { "Default Timeout Tests", CK_PASS,   "Passed" },
+  { "Default Timeout Tests", CK_ERROR,  "Test timeout expired" },
+  { "Default Timeout Tests", CK_ERROR,  "Test timeout expired" },
+  
+  { "User Integer Timeout Tests", CK_ERROR,  "Test timeout expired" },
+  { "User Integer Timeout Tests", CK_PASS,   "Passed" },
+  { "User Integer Timeout Tests", CK_PASS,   "Passed" },
+  { "User Integer Timeout Tests", CK_ERROR,  "Test timeout expired" },
+
+  { "User Double Timeout Tests", CK_ERROR,  "Test timeout expired" },
+#ifdef HAVE_LIBRT
+  { "User Double Timeout Tests", CK_PASS,   "Passed" },
+  { "User Double Timeout Tests", CK_ERROR,  "Test timeout expired" },
+#endif /* HAVE_LIBRT */
+  { "User Double Timeout Tests", CK_ERROR,  "Test timeout expired" },
+  { "User Double Timeout Tests", CK_ERROR,  "Test timeout expired" },
+  { "User Double Timeout Tests", CK_ERROR,  "Test timeout expired" },
+  
+  /* Default Timeout tests are run twice , see check_check_sub.c:make_sub_suite() */
+  { "Default Timeout Tests", CK_ERROR,  "Test timeout expired" },
+#ifdef HAVE_LIBRT
+  { "Default Timeout Tests", CK_PASS,   "Passed" },
+  { "Default Timeout Tests", CK_PASS,   "Passed" },
+#endif /* HAVE_LIBRT */
+  { "Default Timeout Tests", CK_PASS,   "Passed" },
+  { "Default Timeout Tests", CK_ERROR,  "Test timeout expired" },
+  { "Default Timeout Tests", CK_ERROR,  "Test timeout expired" },
+  
 #if HAVE_WORKING_SETENV
-  { "Environment Timeout Scaling Tests", CK_ERROR,  "Test timeout expired" },
-  { "Environment Timeout Scaling Tests", CK_PASS,   "Passed" },
-  { "Environment Timeout Scaling Tests", CK_PASS,   "Passed" },
-  { "Environment Timeout Scaling Tests", CK_ERROR,  "Test timeout expired" },
-  { "Timeout Scaling Tests", CK_ERROR,  "Test timeout expired" },
-  { "Timeout Scaling Tests", CK_PASS,   "Passed" },
-  { "Timeout Scaling Tests", CK_PASS,   "Passed" },
-  { "Timeout Scaling Tests", CK_ERROR,  "Test timeout expired" },
-  { "User Timeout Scaling Tests", CK_ERROR,  "Test timeout expired" },
-  { "User Timeout Scaling Tests", CK_PASS,   "Passed" },
-  { "User Timeout Scaling Tests", CK_PASS,   "Passed" },
-  { "User Timeout Scaling Tests", CK_ERROR,  "Test timeout expired" },
+  { "Environment Integer Timeout Scaling Tests", CK_ERROR,  "Test timeout expired" },
+#ifdef HAVE_LIBRT
+  { "Environment Integer Timeout Scaling Tests", CK_PASS,   "Passed" },
+  { "Environment Integer Timeout Scaling Tests", CK_PASS,   "Passed" },
+#endif /* HAVE_LIBRT */
+  { "Environment Integer Timeout Scaling Tests", CK_PASS,   "Passed" },
+  { "Environment Integer Timeout Scaling Tests", CK_PASS,   "Passed" },
+  { "Environment Integer Timeout Scaling Tests", CK_PASS,   "Passed" },
+  { "Environment Integer Timeout Scaling Tests", CK_ERROR,  "Test timeout expired" },
+
+  { "Environment Double Timeout Scaling Tests", CK_ERROR,  "Test timeout expired" },
+#ifdef HAVE_LIBRT
+  { "Environment Double Timeout Scaling Tests", CK_PASS,   "Passed" },
+  { "Environment Double Timeout Scaling Tests", CK_ERROR,  "Test timeout expired" },
+#endif /* HAVE_LIBRT */
+  { "Environment Double Timeout Scaling Tests", CK_ERROR,  "Test timeout expired" },
+  { "Environment Double Timeout Scaling Tests", CK_ERROR,  "Test timeout expired" },
+  { "Environment Double Timeout Scaling Tests", CK_ERROR,  "Test timeout expired" },
+  { "Environment Double Timeout Scaling Tests", CK_ERROR,  "Test timeout expired" },
+  
+  { "Timeout Integer Scaling Tests", CK_ERROR,  "Test timeout expired" },
+#ifdef HAVE_LIBRT
+  { "Timeout Integer Scaling Tests", CK_PASS,   "Passed" },
+  { "Timeout Integer Scaling Tests", CK_PASS,   "Passed" },
+  { "Timeout Integer Scaling Tests", CK_PASS,   "Passed" },
+#endif /* HAVE_LIBRT */
+  { "Timeout Integer Scaling Tests", CK_PASS,   "Passed" },
+  { "Timeout Integer Scaling Tests", CK_ERROR,  "Test timeout expired" },
+  
+  { "Timeout Double Scaling Tests", CK_ERROR,  "Test timeout expired" },
+#ifdef HAVE_LIBRT
+  { "Timeout Double Scaling Tests", CK_PASS,   "Passed" },
+  { "Timeout Double Scaling Tests", CK_PASS,   "Passed" },
+#endif /* HAVE_LIBRT */
+  { "Timeout Double Scaling Tests", CK_ERROR,  "Test timeout expired" },
+  { "Timeout Double Scaling Tests", CK_ERROR,  "Test timeout expired" },
+  { "Timeout Double Scaling Tests", CK_ERROR,  "Test timeout expired" },
+  
+  { "User Integer Timeout Scaling Tests", CK_ERROR,  "Test timeout expired" },
+#ifdef HAVE_LIBRT
+  { "User Integer Timeout Scaling Tests", CK_PASS,   "Passed" },
+  { "User Integer Timeout Scaling Tests", CK_PASS,   "Passed" },
+#endif /* HAVE_LIBRT */
+  { "User Integer Timeout Scaling Tests", CK_PASS,   "Passed" },
+  { "User Integer Timeout Scaling Tests", CK_PASS,   "Passed" },
+  { "User Integer Timeout Scaling Tests", CK_PASS,   "Passed" },
+  { "User Integer Timeout Scaling Tests", CK_ERROR,  "Test timeout expired" },
+  
+  { "User Double Timeout Scaling Tests", CK_ERROR,  "Test timeout expired" },
+#ifdef HAVE_LIBRT
+  { "User Double Timeout Scaling Tests", CK_PASS,   "Passed" },
+  { "User Double Timeout Scaling Tests", CK_ERROR,  "Test timeout expired" },
+#endif /* HAVE_LIBRT */
+  { "User Double Timeout Scaling Tests", CK_ERROR,  "Test timeout expired" },
+  { "User Double Timeout Scaling Tests", CK_ERROR,  "Test timeout expired" },
+  { "User Double Timeout Scaling Tests", CK_ERROR,  "Test timeout expired" },
+  { "User Double Timeout Scaling Tests", CK_ERROR,  "Test timeout expired" },
 #endif
 #endif
 
index b28ffa605be7e5feed073803d8156d71346b81e3..26ba8bc8e631ffee8627a3a1d67022e86bd25a45 100644 (file)
@@ -363,7 +363,28 @@ START_TEST(test_eternal)
 }
 END_TEST
 
+/* 
+ * Only include sub-second timing tests on systems
+ * that support librt.
+ */
+#ifdef HAVE_LIBRT
+START_TEST(test_sleep0_025)
+  #define LINENO_sleep0_025 _STR(__LINE__)
+{
+  usleep(25*1000);
+}
+END_TEST
+
+START_TEST(test_sleep1)
+  #define LINENO_sleep1 _STR(__LINE__)
+{
+  sleep(1);
+}
+END_TEST
+#endif /* HAVE_LIBRT */
+
 START_TEST(test_sleep2)
+  #define LINENO_sleep2 _STR(__LINE__)
 {
   sleep(2);
 }
@@ -619,37 +640,113 @@ void init_master_tests_lineno(int num_master_tests) {
     "-1",
 
 #if TIMEOUT_TESTS_ENABLED
-/* Timeout Tests */
 #if HAVE_WORKING_SETENV
+/* Environment Integer Timeout Tests */
     LINENO_eternal,
     "-1",
     "-1",
     LINENO_sleep9,
+/* Environment Double Timeout Tests */
+    LINENO_eternal,
+#ifdef HAVE_LIBRT
+    "-1",
+    LINENO_sleep1,
+#endif /* HAVE_LIBRT */
+    LINENO_sleep2,
+    LINENO_sleep5,
+    LINENO_sleep9,
 #endif
+/* Default Timeout Tests */
     LINENO_eternal,
+#ifdef HAVE_LIBRT
+    "-1",
+    "-1",
+#endif /* HAVE_LIBRT */
     "-1",
     LINENO_sleep5,
     LINENO_sleep9,
+/* User Integer Timeout Tests */
     LINENO_eternal,
     "-1",
     "-1",
     LINENO_sleep9,
+/* User Double Timeout Tests */
     LINENO_eternal,
+#ifdef HAVE_LIBRT
+    "-1",
+    LINENO_sleep1,
+#endif /* HAVE_LIBRT */
+    LINENO_sleep2,
+    LINENO_sleep5,
+    LINENO_sleep9,
+    
+/* Default Timeout Tests (again)*/
+    LINENO_eternal,
+#ifdef HAVE_LIBRT
+    "-1",
+    "-1",
+#endif /* HAVE_LIBRT */
     "-1",
     LINENO_sleep5,
     LINENO_sleep9,
 #if HAVE_WORKING_SETENV
+/* Environment Integer Timeout Scaling Tests */
     LINENO_eternal,
+#ifdef HAVE_LIBRT
+    "-1",
+    "-1",
+#endif /* HAVE_LIBRT */
+    "-1",
     "-1",
     "-1",
     LINENO_sleep14,
+/* Environment Double Timeout Scaling Tests */
     LINENO_eternal,
+#ifdef HAVE_LIBRT
+    "-1",
+    LINENO_sleep1,
+#endif /* HAVE_LIBRT */
+    LINENO_sleep2,
+    LINENO_sleep5,
+    LINENO_sleep9,
+    LINENO_sleep14,
+/* Timeout Integer Scaling Tests */
+    LINENO_eternal,
+#ifdef HAVE_LIBRT
+    "-1",
     "-1",
     "-1",
+#endif /* HAVE_LIBRT */
+    "-1",
     LINENO_sleep9,
+/* Timeout Double Scaling Tests */
     LINENO_eternal,
+#ifdef HAVE_LIBRT
+    "-1",
+    "-1",
+#endif /* HAVE_LIBRT */
+    LINENO_sleep2,
+    LINENO_sleep5,
+    LINENO_sleep9,
+/* User Integer Timeout Scaling Tests */
+    LINENO_eternal,
+#ifdef HAVE_LIBRT
+    "-1",
     "-1",
+#endif /* HAVE_LIBRT */
     "-1",
+    "-1",
+    "-1",
+    LINENO_sleep14,
+/* User Integer Timeout Scaling Tests */
+    LINENO_eternal,
+#ifdef HAVE_LIBRT
+    "-1",
+    LINENO_sleep1,
+#endif /* HAVE_LIBRT */
+    LINENO_sleep2,
+    LINENO_sleep5,
+    LINENO_sleep9,
     LINENO_sleep14,
 #endif
 #endif
@@ -694,14 +791,19 @@ Suite *make_sub_suite(void)
   TCase *tc_signal;
 #if TIMEOUT_TESTS_ENABLED
 #if HAVE_WORKING_SETENV
-  TCase *tc_timeout_env;
+  TCase *tc_timeout_env_int;
+  TCase *tc_timeout_env_double;
 #endif /* HAVE_WORKING_SETENV */
-  TCase *tc_timeout;
-  TCase *tc_timeout_usr;
+  TCase *tc_timeout_default;
+  TCase *tc_timeout_usr_int;
+  TCase *tc_timeout_usr_double;
 #if HAVE_WORKING_SETENV
-  TCase *tc_timeout_env_scale;
-  TCase *tc_timeout_scale;
-  TCase *tc_timeout_usr_scale;
+  TCase *tc_timeout_env_scale_int;
+  TCase *tc_timeout_scale_int;
+  TCase *tc_timeout_usr_scale_int;
+  TCase *tc_timeout_env_scale_double;
+  TCase *tc_timeout_scale_double;
+  TCase *tc_timeout_usr_scale_double;
 #endif /* HAVE_WORKING_SETENV */
 #endif
   TCase *tc_limit;
@@ -714,21 +816,33 @@ Suite *make_sub_suite(void)
 #if TIMEOUT_TESTS_ENABLED
 #if HAVE_WORKING_SETENV
   setenv("CK_DEFAULT_TIMEOUT", "6", 1);
-  tc_timeout_env = tcase_create("Environment Timeout Tests");
+  tc_timeout_env_int = tcase_create("Environment Integer Timeout Tests");
+  unsetenv("CK_DEFAULT_TIMEOUT");
+  setenv("CK_DEFAULT_TIMEOUT", "0.5", 1);
+  tc_timeout_env_double = tcase_create("Environment Double Timeout Tests");
   unsetenv("CK_DEFAULT_TIMEOUT");
 #endif /* HAVE_WORKING_SETENV */
-  tc_timeout = tcase_create("Timeout Tests");
-  tc_timeout_usr = tcase_create("User Timeout Tests");
+  tc_timeout_default = tcase_create("Default Timeout Tests");
+  tc_timeout_usr_int = tcase_create("User Integer Timeout Tests");
+  tc_timeout_usr_double = tcase_create("User Double Timeout Tests");
 #if HAVE_WORKING_SETENV
   setenv("CK_TIMEOUT_MULTIPLIER", "2", 1);
-  tc_timeout_scale = tcase_create("Timeout Scaling Tests");
-  tc_timeout_usr_scale = tcase_create("User Timeout Scaling Tests");
+  tc_timeout_scale_int = tcase_create("Timeout Integer Scaling Tests");
+  tc_timeout_usr_scale_int = tcase_create("User Integer Timeout Scaling Tests");
   setenv("CK_DEFAULT_TIMEOUT", "6", 1);
-  tc_timeout_env_scale = tcase_create("Environment Timeout Scaling Tests");
+  tc_timeout_env_scale_int = tcase_create("Environment Integer Timeout Scaling Tests");
   unsetenv("CK_DEFAULT_TIMEOUT");
   unsetenv("CK_TIMEOUT_MULTIPLIER");
-#endif
-#endif
+  
+  setenv("CK_TIMEOUT_MULTIPLIER", "0.4", 1);
+  tc_timeout_scale_double = tcase_create("Timeout Double Scaling Tests");
+  tc_timeout_usr_scale_double = tcase_create("User Double Timeout Scaling Tests");
+  setenv("CK_DEFAULT_TIMEOUT", "0.9", 1);
+  tc_timeout_env_scale_double = tcase_create("Environment Double Timeout Scaling Tests");
+  unsetenv("CK_DEFAULT_TIMEOUT");
+  unsetenv("CK_TIMEOUT_MULTIPLIER");
+#endif /* HAVE_WORKING_SETENV */
+#endif /* TIMEOUT_TESTS_ENABLED */
   tc_limit = tcase_create("Limit Tests");
   tc_messaging_and_fork = tcase_create("Msg and fork Tests");
 
@@ -736,16 +850,22 @@ Suite *make_sub_suite(void)
   suite_add_tcase (s, tc_signal);
 #if TIMEOUT_TESTS_ENABLED
 #if HAVE_WORKING_SETENV
-  suite_add_tcase (s, tc_timeout_env);
+  suite_add_tcase (s, tc_timeout_env_int);
+  suite_add_tcase (s, tc_timeout_env_double);
 #endif /* HAVE_WORKING_SETENV */
-  suite_add_tcase (s, tc_timeout);
-  suite_add_tcase (s, tc_timeout_usr);
+  suite_add_tcase (s, tc_timeout_default);
+  suite_add_tcase (s, tc_timeout_usr_int);
+  suite_add_tcase (s, tc_timeout_usr_double);
+
   /* Add a second time to make sure tcase_set_timeout doesn't contaminate it. */
-  suite_add_tcase (s, tc_timeout);
+  suite_add_tcase (s, tc_timeout_default);
 #if HAVE_WORKING_SETENV
-  suite_add_tcase (s, tc_timeout_env_scale);
-  suite_add_tcase (s, tc_timeout_scale);
-  suite_add_tcase (s, tc_timeout_usr_scale);
+  suite_add_tcase (s, tc_timeout_env_scale_int);
+  suite_add_tcase (s, tc_timeout_env_scale_double);
+  suite_add_tcase (s, tc_timeout_scale_int);
+  suite_add_tcase (s, tc_timeout_scale_double);
+  suite_add_tcase (s, tc_timeout_usr_scale_int);
+  suite_add_tcase (s, tc_timeout_usr_scale_double);
 #endif
 #endif
   suite_add_tcase (s, tc_limit);
@@ -804,42 +924,109 @@ Suite *make_sub_suite(void)
 
 #if TIMEOUT_TESTS_ENABLED
 #if HAVE_WORKING_SETENV
-  tcase_add_test (tc_timeout_env, test_eternal);
-  tcase_add_test (tc_timeout_env, test_sleep2);
-  tcase_add_test (tc_timeout_env, test_sleep5);
-  tcase_add_test (tc_timeout_env, test_sleep9);
+  tcase_add_test (tc_timeout_env_int, test_eternal);
+  tcase_add_test (tc_timeout_env_int, test_sleep2);
+  tcase_add_test (tc_timeout_env_int, test_sleep5);
+  tcase_add_test (tc_timeout_env_int, test_sleep9);
+  tcase_add_test (tc_timeout_env_double, test_eternal);
+#ifdef HAVE_LIBRT
+  tcase_add_test (tc_timeout_env_double, test_sleep0_025);
+  tcase_add_test (tc_timeout_env_double, test_sleep1);
+#endif /* HAVE_LIBRT */
+  tcase_add_test (tc_timeout_env_double, test_sleep2);
+  tcase_add_test (tc_timeout_env_double, test_sleep5);
+  tcase_add_test (tc_timeout_env_double, test_sleep9);
 #endif /* HAVE_WORKING_SETENV */
 
-  tcase_add_test (tc_timeout, test_eternal);
-  tcase_add_test (tc_timeout, test_sleep2);
-  tcase_add_test (tc_timeout, test_sleep5);
-  tcase_add_test (tc_timeout, test_sleep9);
-
-  tcase_set_timeout (tc_timeout_usr, 6);
-  tcase_add_test (tc_timeout_usr, test_eternal);
-  tcase_add_test (tc_timeout_usr, test_sleep2);
-  tcase_add_test (tc_timeout_usr, test_sleep5);
-  tcase_add_test (tc_timeout_usr, test_sleep9);
+  tcase_add_test (tc_timeout_default, test_eternal);
+#ifdef HAVE_LIBRT
+  tcase_add_test (tc_timeout_default, test_sleep0_025);
+  tcase_add_test (tc_timeout_default, test_sleep1);
+#endif /* HAVE_LIBRT */
+  tcase_add_test (tc_timeout_default, test_sleep2);
+  tcase_add_test (tc_timeout_default, test_sleep5);
+  tcase_add_test (tc_timeout_default, test_sleep9);
+
+  tcase_set_timeout (tc_timeout_usr_int, 6);
+  tcase_add_test (tc_timeout_usr_int, test_eternal);
+  tcase_add_test (tc_timeout_usr_int, test_sleep2);
+  tcase_add_test (tc_timeout_usr_int, test_sleep5);
+  tcase_add_test (tc_timeout_usr_int, test_sleep9);
+
+  tcase_set_timeout (tc_timeout_usr_double, 0.5);
+  tcase_add_test (tc_timeout_usr_double, test_eternal);
+#ifdef HAVE_LIBRT
+  tcase_add_test (tc_timeout_usr_double, test_sleep0_025);
+  tcase_add_test (tc_timeout_usr_double, test_sleep1);
+#endif /* HAVE_LIBRT */
+  tcase_add_test (tc_timeout_usr_double, test_sleep2);
+  tcase_add_test (tc_timeout_usr_double, test_sleep5);
+  tcase_add_test (tc_timeout_usr_double, test_sleep9);
+  
 #if HAVE_WORKING_SETENV
-  tcase_add_test (tc_timeout_env_scale, test_eternal);
-  tcase_add_test (tc_timeout_env_scale, test_sleep5);
-  tcase_add_test (tc_timeout_env_scale, test_sleep9);
-  tcase_add_test (tc_timeout_env_scale, test_sleep14);
-  tcase_add_test (tc_timeout_scale, test_eternal);
-  tcase_add_test (tc_timeout_scale, test_sleep2);
-  tcase_add_test (tc_timeout_scale, test_sleep5);
-  tcase_add_test (tc_timeout_scale, test_sleep9);
+  tcase_add_test (tc_timeout_env_scale_int, test_eternal);
+#ifdef HAVE_LIBRT
+  tcase_add_test (tc_timeout_env_scale_int, test_sleep0_025);
+  tcase_add_test (tc_timeout_env_scale_int, test_sleep1);
+#endif /* HAVE_LIBRT */
+  tcase_add_test (tc_timeout_env_scale_int, test_sleep2);
+  tcase_add_test (tc_timeout_env_scale_int, test_sleep5);
+  tcase_add_test (tc_timeout_env_scale_int, test_sleep9);
+  tcase_add_test (tc_timeout_env_scale_int, test_sleep14);
+
+  tcase_add_test (tc_timeout_env_scale_double, test_eternal);
+#ifdef HAVE_LIBRT
+  tcase_add_test (tc_timeout_env_scale_double, test_sleep0_025);
+  tcase_add_test (tc_timeout_env_scale_double, test_sleep1);
+#endif /* HAVE_LIBRT */
+  tcase_add_test (tc_timeout_env_scale_double, test_sleep2);
+  tcase_add_test (tc_timeout_env_scale_double, test_sleep5);
+  tcase_add_test (tc_timeout_env_scale_double, test_sleep9);
+  tcase_add_test (tc_timeout_env_scale_double, test_sleep14);
+
+  tcase_add_test (tc_timeout_scale_int, test_eternal);
+#ifdef HAVE_LIBRT
+  tcase_add_test (tc_timeout_scale_int, test_sleep0_025);
+  tcase_add_test (tc_timeout_scale_int, test_sleep1);
+  tcase_add_test (tc_timeout_scale_int, test_sleep2);
+#endif /* HAVE_LIBRT */
+  tcase_add_test (tc_timeout_scale_int, test_sleep5);
+  tcase_add_test (tc_timeout_scale_int, test_sleep9);
+
+  tcase_add_test (tc_timeout_scale_double, test_eternal);
+#ifdef HAVE_LIBRT
+  tcase_add_test (tc_timeout_scale_double, test_sleep0_025);
+  tcase_add_test (tc_timeout_scale_double, test_sleep1);
+#endif /* HAVE_LIBRT */
+  tcase_add_test (tc_timeout_scale_double, test_sleep2);
+  tcase_add_test (tc_timeout_scale_double, test_sleep5);
+  tcase_add_test (tc_timeout_scale_double, test_sleep9);
+  
   setenv("CK_TIMEOUT_MULTIPLIER", "2", 1);
-  tcase_set_timeout (tc_timeout_usr_scale, 6);
+  tcase_set_timeout (tc_timeout_usr_scale_int, 6);
   unsetenv("CK_TIMEOUT_MULTIPLIER");
-  tcase_add_test (tc_timeout_usr_scale, test_eternal);
-  tcase_add_test (tc_timeout_usr_scale, test_sleep5);
-  tcase_add_test (tc_timeout_usr_scale, test_sleep9);
-  tcase_add_test (tc_timeout_usr_scale, test_sleep14);
-#endif
-#if 0
-  tcase_set_timeout (tc_timeout_kill, 2);
-  tcase_add_test (tc_timeout_kill, test_sleep);
+  tcase_add_test (tc_timeout_usr_scale_int, test_eternal);
+#ifdef HAVE_LIBRT
+  tcase_add_test (tc_timeout_usr_scale_int, test_sleep0_025);
+  tcase_add_test (tc_timeout_usr_scale_int, test_sleep1);
+#endif /* HAVE_LIBRT */
+  tcase_add_test (tc_timeout_usr_scale_int, test_sleep2);
+  tcase_add_test (tc_timeout_usr_scale_int, test_sleep5);
+  tcase_add_test (tc_timeout_usr_scale_int, test_sleep9);
+  tcase_add_test (tc_timeout_usr_scale_int, test_sleep14);
+  
+  setenv("CK_TIMEOUT_MULTIPLIER", "0.4", 1);
+  tcase_set_timeout (tc_timeout_usr_scale_double, 0.9);
+  unsetenv("CK_TIMEOUT_MULTIPLIER");
+  tcase_add_test (tc_timeout_usr_scale_double, test_eternal);
+#ifdef HAVE_LIBRT
+  tcase_add_test (tc_timeout_usr_scale_double, test_sleep0_025);
+  tcase_add_test (tc_timeout_usr_scale_double, test_sleep1);
+#endif /* HAVE_LIBRT */
+  tcase_add_test (tc_timeout_usr_scale_double, test_sleep2);
+  tcase_add_test (tc_timeout_usr_scale_double, test_sleep5);
+  tcase_add_test (tc_timeout_usr_scale_double, test_sleep9);
+  tcase_add_test (tc_timeout_usr_scale_double, test_sleep14);
 #endif
 #endif