From efcbf4dbe82db650d14fcf4b29b200c4e53f77a6 Mon Sep 17 00:00:00 2001 From: Ivan Maidanski Date: Fri, 4 Jan 2019 16:17:31 +0300 Subject: [PATCH] Add API for accessing incremental GC time limit with nanosecond precision 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 | 28 +++++++++++++++++++++++++++- include/gc.h | 32 ++++++++++++++++++++++++++++---- tests/test.c | 4 ++++ 3 files changed, 59 insertions(+), 5 deletions(-) diff --git a/alloc.c b/alloc.c index c2d859d5..9c45d625 100644 --- 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. */ diff --git a/include/gc.h b/include/gc.h index 1080dae3..9eff1166 100644 --- a/include/gc.h +++ b/include/gc.h @@ -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 */ diff --git a/tests/test.c b/tests/test.c index 321425f3..e2f22561 100644 --- a/tests/test.c +++ b/tests/test.c @@ -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); -- 2.50.1