Add API for accessing incremental GC time limit with nanosecond precision
authorIvan Maidanski <ivmai@mail.ru>
Fri, 4 Jan 2019 13:17:31 +0000 (16:17 +0300)
committerIvan Maidanski <ivmai@mail.ru>
Sat, 5 Jan 2019 09:04:24 +0000 (12:04 +0300)
Issue #258 (bdwgc).

This commit only adds the API (GC_set_time_limit_tv,
GC_get_time_limit_tv).

* alloc.c [!NO_CLOCK] (GC_time_lim_nsec): New STATIC variable.
* alloc.c [!NO_CLOCK] (TV_NSEC_LIMIT): New macro.
* alloc.c [!NO_CLOCK] (GC_set_time_limit_tv, GC_get_time_limit_tv):
New public function definition.
* include/gc.h (GC_time_limit, GC_set_time_limit): Update comment.
* include/gc.h (GC_timeval_s): New struct definition.
* include/gc.h (GC_set_time_limit_tv, GC_get_time_limit_tv): New public
function declaration.
* include/gc.h [GC_TIME_LIMIT && !CPPCHECK] (GC_INIT_CONF_TIME_LIMIT):
Refine comment.
* tests/test.c [!PCR && !GC_WIN32_THREADS && !GC_PTHREADS && CPPCHECK
&& !NO_CLOCK] (main): Add UNTESTED() for GC_get_time_limit_tv and
GC_set_time_limit_tv.

alloc.c
include/gc.h
tests/test.c

diff --git a/alloc.c b/alloc.c
index c2d859d..9c45d62 100644 (file)
--- a/alloc.c
+++ b/alloc.c
@@ -173,10 +173,36 @@ GC_INNER int GC_CALLBACK GC_never_stop_func(void)
 #endif
 
 #ifndef NO_CLOCK
+  STATIC unsigned long GC_time_lim_nsec = 0;
+                        /* The nanoseconds add-on to GC_time_limit      */
+                        /* value.  Not updated by GC_set_time_limit().  */
+                        /* Ignored if the value of GC_time_limit is     */
+                        /* GC_TIME_UNLIMITED; ignored on some platforms */
+                        /* (depending on GET_TIME implementation).      */
+
+# define TV_NSEC_LIMIT (1000UL * 1000) /* amount of nanoseconds in 1 ms */
+
+  GC_API void GC_CALL GC_set_time_limit_tv(struct GC_timeval_s tv)
+  {
+    GC_ASSERT(tv.tv_ms <= GC_TIME_UNLIMITED);
+    GC_ASSERT(tv.tv_nsec < TV_NSEC_LIMIT);
+    GC_time_limit = tv.tv_ms;
+    GC_time_lim_nsec = tv.tv_nsec;
+  }
+
+  GC_API struct GC_timeval_s GC_CALL GC_get_time_limit_tv(void)
+  {
+    struct GC_timeval_s tv;
+
+    tv.tv_ms = GC_time_limit;
+    tv.tv_nsec = GC_time_lim_nsec;
+    return tv;
+  }
+
   STATIC CLOCK_TYPE GC_start_time = CLOCK_TYPE_INITIALIZER;
                                 /* Time at which we stopped world.      */
                                 /* used only in GC_timeout_stop_func.   */
-#endif
+#endif /* !NO_CLOCK */
 
 STATIC int GC_n_attempts = 0;   /* Number of attempts at finishing      */
                                 /* collection within GC_time_limit.     */
index 1080dae..9eff116 100644 (file)
@@ -378,9 +378,12 @@ GC_API int GC_CALL GC_get_dont_precollect(void);
 
 GC_API GC_ATTR_DEPRECATED unsigned long GC_time_limit;
                                /* If incremental collection is enabled, */
-                               /* We try to terminate collections       */
-                               /* after this many milliseconds.  Not a  */
-                               /* hard time bound.  Setting this to     */
+                               /* we try to terminate collections       */
+                               /* after this many milliseconds (plus    */
+                               /* the amount of nanoseconds as given in */
+                               /* the latest GC_set_time_limit_tv call, */
+                               /* if any).  Not a hard time bound.      */
+                               /* Setting this variable to              */
                                /* GC_TIME_UNLIMITED will essentially    */
                                /* disable incremental collection while  */
                                /* leaving generational collection       */
@@ -393,11 +396,32 @@ GC_API GC_ATTR_DEPRECATED unsigned long GC_time_limit;
                         /* GC_call_with_alloc_lock() is required to     */
                         /* avoid data races (if the value is modified   */
                         /* after the GC is put to multi-threaded mode). */
+                        /* The setter does not update the value of the  */
+                        /* nanosecond part of the time limit (it is     */
+                        /* zero unless ever set by GC_set_time_limit_tv */
+                        /* call).                                       */
 GC_API void GC_CALL GC_set_time_limit(unsigned long);
 GC_API unsigned long GC_CALL GC_get_time_limit(void);
 
+/* A portable type definition of time with a nanosecond precision.      */
+struct GC_timeval_s {
+  unsigned long tv_ms;  /* time in milliseconds */
+  unsigned long tv_nsec;/* nanoseconds fraction (<1000000) */
+};
+
 /* Public procedures */
 
+/* Set/get the time limit of the incremental collections.  This is      */
+/* similar to GC_set_time_limit and GC_get_time_limit but the time is   */
+/* provided with the nanosecond precision.  The value of tv_nsec part   */
+/* should be less than a million.  If the value of tv_ms part is        */
+/* GC_TIME_UNLIMITED then tv_nsec is ignored.  Initially, the value of  */
+/* tv_nsec part of the time limit is zero.  The functions do not use    */
+/* any synchronization.  Defined only if the library has been compiled  */
+/* without NO_CLOCK.                                                    */
+GC_API void GC_CALL GC_set_time_limit_tv(struct GC_timeval_s);
+GC_API struct GC_timeval_s GC_CALL GC_get_time_limit_tv(void);
+
 /* Tell the collector to start various performance measurements.        */
 /* Only the total time taken by full collections is calculated, as      */
 /* of now.  And, currently, there is no way to stop the measurements.   */
@@ -1967,7 +1991,7 @@ GC_API int GC_CALL GC_get_force_unmap_on_gcollect(void);
 #endif
 
 #if defined(GC_TIME_LIMIT) && !defined(CPPCHECK)
-  /* Set GC_time_limit to the desired value at start-up */
+  /* Set GC_time_limit (in ms) to the desired value at start-up. */
 # define GC_INIT_CONF_TIME_LIMIT GC_set_time_limit(GC_TIME_LIMIT)
 #else
 # define GC_INIT_CONF_TIME_LIMIT /* empty */
index 321425f..e2f2256 100644 (file)
@@ -2001,6 +2001,10 @@ void GC_CALLBACK warn_proc(char *msg, GC_word p)
 #      ifdef GC_GCJ_SUPPORT
          UNTESTED(GC_gcj_malloc_ignore_off_page);
 #      endif
+#      ifndef NO_CLOCK
+         UNTESTED(GC_get_time_limit_tv);
+         UNTESTED(GC_set_time_limit_tv);
+#      endif
 #      ifndef NO_DEBUGGING
          UNTESTED(GC_dump);
          UNTESTED(GC_dump_regions);