From 12597da2a33fe196a785a656136cba7675a06e21 Mon Sep 17 00:00:00 2001 From: David Barksdale Date: Thu, 17 Nov 2016 23:24:43 -0600 Subject: [PATCH] Sometimes it's OK if multiplication overflows --- src/ats/plugin_ats_ril.c | 2 +- src/cadet/gnunet-service-cadet_channel.c | 8 +++---- src/cadet/gnunet-service-cadet_connection.c | 8 +++---- src/fragmentation/defragmentation.c | 4 ++-- src/fragmentation/fragmentation.c | 12 +++++----- src/fs/fs_api.c | 4 ++-- src/fs/fs_search.c | 4 ++-- src/fs/gnunet-auto-share.c | 12 +++++----- src/fs/gnunet-service-fs_pr.c | 2 +- src/include/gnunet_time_lib.h | 12 ++++++++++ src/regex/gnunet-regex-profiler.c | 2 +- src/rps/gnunet-service-rps.c | 4 ++-- src/util/bandwidth.c | 4 ++-- src/util/time.c | 26 +++++++++++++++++++++ src/vpn/vpn_api.c | 2 +- 15 files changed, 72 insertions(+), 34 deletions(-) diff --git a/src/ats/plugin_ats_ril.c b/src/ats/plugin_ats_ril.c index a3bdf200c..ea7920779 100644 --- a/src/ats/plugin_ats_ril.c +++ b/src/ats/plugin_ats_ril.c @@ -1835,7 +1835,7 @@ ril_step_schedule_next (struct GAS_RIL_Handle *solver) GNUNET_assert(y <= (double) solver->parameters.step_time_max.rel_value_us); GNUNET_assert(y >= (double) solver->parameters.step_time_min.rel_value_us); - time_next = GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_MICROSECONDS, (unsigned long long) y); + time_next = GNUNET_TIME_relative_saturating_multiply (GNUNET_TIME_UNIT_MICROSECONDS, (unsigned long long) y); // LOG (GNUNET_ERROR_TYPE_INFO, "ratio: %f, factor: %f, offset: %f, y: %f\n", // used_ratio, diff --git a/src/cadet/gnunet-service-cadet_channel.c b/src/cadet/gnunet-service-cadet_channel.c index 0e9b7a3af..22349aa80 100644 --- a/src/cadet/gnunet-service-cadet_channel.c +++ b/src/cadet/gnunet-service-cadet_channel.c @@ -819,8 +819,8 @@ ch_message_sent (void *cls, if (0 != rel->expected_delay.rel_value_us) { rel->retry_timer = - GNUNET_TIME_relative_multiply (rel->expected_delay, - CADET_RETRANSMIT_MARGIN); + GNUNET_TIME_relative_saturating_multiply (rel->expected_delay, + CADET_RETRANSMIT_MARGIN); } else { @@ -2110,8 +2110,8 @@ GCCH_handle_data_ack (struct CadetChannel *ch, struct GNUNET_TIME_Absolute new_target; struct GNUNET_TIME_Relative delay; - delay = GNUNET_TIME_relative_multiply (rel->retry_timer, - CADET_RETRANSMIT_MARGIN); + delay = GNUNET_TIME_relative_saturating_multiply (rel->retry_timer, + CADET_RETRANSMIT_MARGIN); new_target = GNUNET_TIME_absolute_add (rel->head_sent->timestamp, delay); delay = GNUNET_TIME_absolute_get_remaining (new_target); diff --git a/src/cadet/gnunet-service-cadet_connection.c b/src/cadet/gnunet-service-cadet_connection.c index face765e4..1c500f716 100644 --- a/src/cadet/gnunet-service-cadet_connection.c +++ b/src/cadet/gnunet-service-cadet_connection.c @@ -1318,8 +1318,8 @@ schedule_next_keepalive (struct CadetConnection *c, int fwd) { if (1 > c->create_retry) c->create_retry = 1; - delay = GNUNET_TIME_relative_multiply (create_connection_time, - c->create_retry); + delay = GNUNET_TIME_relative_saturating_multiply (create_connection_time, + c->create_retry); if (c->create_retry < 64) // TODO make configurable c->create_retry *= 2; } @@ -1548,7 +1548,7 @@ connection_reset_timeout (struct CadetConnection *c, int fwd) if (NULL != *ti) GNUNET_SCHEDULER_cancel (*ti); - delay = GNUNET_TIME_relative_multiply (refresh_connection_time, 4); + delay = GNUNET_TIME_relative_saturating_multiply (refresh_connection_time, 4); LOG (GNUNET_ERROR_TYPE_DEBUG, " timing out in %s\n", GNUNET_STRINGS_relative_time_to_string (delay, GNUNET_NO)); @@ -1681,7 +1681,7 @@ schedule_check_duplicates (struct CadetConnection *c) if (NULL != c->check_duplicates_task) return; - delay = GNUNET_TIME_relative_multiply (refresh_connection_time, 5); + delay = GNUNET_TIME_relative_saturating_multiply (refresh_connection_time, 5); c->check_duplicates_task = GNUNET_SCHEDULER_add_delayed (delay, &check_duplicates, c); diff --git a/src/fragmentation/defragmentation.c b/src/fragmentation/defragmentation.c index bc401435e..cc0f5a8c5 100644 --- a/src/fragmentation/defragmentation.c +++ b/src/fragmentation/defragmentation.c @@ -564,8 +564,8 @@ GNUNET_DEFRAGMENT_process_fragment (struct GNUNET_DEFRAGMENT_Context *dc, { dc->latency = estimate_latency (mc); } - delay = GNUNET_TIME_relative_multiply (dc->latency, - bc + 1); + delay = GNUNET_TIME_relative_saturating_multiply (dc->latency, + bc + 1); if ( (last + fid == num_fragments) || (0 == mc->bits) || (GNUNET_YES == duplicate) ) diff --git a/src/fragmentation/fragmentation.c b/src/fragmentation/fragmentation.c index eb0bad675..02444cf14 100644 --- a/src/fragmentation/fragmentation.c +++ b/src/fragmentation/fragmentation.c @@ -260,7 +260,7 @@ transmit_next (void *cls) delay = GNUNET_TIME_UNIT_ZERO; if (fc->num_rounds < 64) delay = GNUNET_TIME_relative_max (delay, - GNUNET_TIME_relative_multiply + GNUNET_TIME_relative_saturating_multiply (fc->msg_delay, (1ULL << fc->num_rounds))); else @@ -269,7 +269,7 @@ transmit_next (void *cls) { /* full round transmitted wait 2x delay for ACK before going again */ fc->num_rounds++; - delay = GNUNET_TIME_relative_multiply (fc->ack_delay, 2); + delay = GNUNET_TIME_relative_saturating_multiply (fc->ack_delay, 2); /* never use zero, need some time for ACK always */ delay = GNUNET_TIME_relative_max (MIN_ACK_DELAY, delay); fc->wack = GNUNET_YES; @@ -432,8 +432,8 @@ GNUNET_FRAGMENT_process_ack (struct GNUNET_FRAGMENT_Context *fc, if (0 == ack_cnt) { /* complete loss */ - fc->msg_delay = GNUNET_TIME_relative_multiply (fc->msg_delay, - snd_cnt); + fc->msg_delay = GNUNET_TIME_relative_saturating_multiply (fc->msg_delay, + snd_cnt); } else if (snd_cnt > ack_cnt) { @@ -515,8 +515,8 @@ GNUNET_FRAGMENT_context_destroy (struct GNUNET_FRAGMENT_Context *fc, if (NULL != ack_delay) *ack_delay = fc->ack_delay; if (NULL != msg_delay) - *msg_delay = GNUNET_TIME_relative_multiply (fc->msg_delay, - fc->num_rounds); + *msg_delay = GNUNET_TIME_relative_saturating_multiply (fc->msg_delay, + fc->num_rounds); GNUNET_free (fc); } diff --git a/src/fs/fs_api.c b/src/fs/fs_api.c index 1e8af23c5..7e769483b 100644 --- a/src/fs/fs_api.c +++ b/src/fs/fs_api.c @@ -178,8 +178,8 @@ process_job_queue (void *cls) break; case GNUNET_FS_QUEUE_PRIORITY_NORMAL: run_time = - GNUNET_TIME_relative_multiply (h->avg_block_latency, - qe->blocks * qe->start_times); + GNUNET_TIME_relative_saturating_multiply (h->avg_block_latency, + qe->blocks * qe->start_times); end_time = GNUNET_TIME_absolute_add (qe->start_time, run_time); rst = GNUNET_TIME_absolute_get_remaining (end_time); if (0 == rst.rel_value_us) diff --git a/src/fs/fs_search.c b/src/fs/fs_search.c index 7874bb6e0..198577b08 100644 --- a/src/fs/fs_search.c +++ b/src/fs/fs_search.c @@ -458,8 +458,8 @@ GNUNET_FS_search_start_probe_ (struct GNUNET_FS_SearchResult *sr) (unsigned long long) off, sr); sr->remaining_probe_time = - GNUNET_TIME_relative_multiply (sr->h->avg_block_latency, - 2 * (1 + sr->availability_trials)); + GNUNET_TIME_relative_saturating_multiply (sr->h->avg_block_latency, + 2 * (1 + sr->availability_trials)); sr->probe_ctx = GNUNET_FS_download_start (sr->h, sr->uri, sr->meta, NULL, NULL, off, len, sr->anonymity, diff --git a/src/fs/gnunet-auto-share.c b/src/fs/gnunet-auto-share.c index 96f86bf5d..cc0111111 100644 --- a/src/fs/gnunet-auto-share.c +++ b/src/fs/gnunet-auto-share.c @@ -29,9 +29,9 @@ #include "platform.h" #include "gnunet_util_lib.h" -#define MIN_FREQUENCY GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_HOURS, 4) +#define MAX_DELAY GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_HOURS, 4) -#define MAX_FREQUENCY GNUNET_TIME_UNIT_MINUTES +#define MIN_DELAY GNUNET_TIME_UNIT_MINUTES /** @@ -672,11 +672,11 @@ schedule_next_task () /* delay by at most 4h, at least 1s, and otherwise in between depending on how long it took to scan */ delay = GNUNET_TIME_absolute_get_duration (start_time); - delay = GNUNET_TIME_relative_min (MIN_FREQUENCY, - GNUNET_TIME_relative_multiply (delay, - 100)); + delay = GNUNET_TIME_relative_saturating_multiply (delay, 100); + delay = GNUNET_TIME_relative_min (delay, + MAX_DELAY); delay = GNUNET_TIME_relative_max (delay, - MAX_FREQUENCY); + MIN_DELAY); run_task = GNUNET_SCHEDULER_add_delayed (delay, &scan, NULL); diff --git a/src/fs/gnunet-service-fs_pr.c b/src/fs/gnunet-service-fs_pr.c index f8a7b61f0..63462f7dc 100644 --- a/src/fs/gnunet-service-fs_pr.c +++ b/src/fs/gnunet-service-fs_pr.c @@ -1036,7 +1036,7 @@ put_migration_continuation (void *cls, int success, ppd->migration_delay); mig_pause.rel_value_us = GNUNET_CRYPTO_random_u64 (GNUNET_CRYPTO_QUALITY_WEAK, ppd->migration_delay.rel_value_us); - ppd->migration_delay = GNUNET_TIME_relative_multiply (ppd->migration_delay, 2); + ppd->migration_delay = GNUNET_TIME_relative_saturating_multiply (ppd->migration_delay, 2); GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "Replicated content already exists locally, asking to stop migration for %s\n", GNUNET_STRINGS_relative_time_to_string (mig_pause, diff --git a/src/include/gnunet_time_lib.h b/src/include/gnunet_time_lib.h index 64c5769c6..224edc03e 100644 --- a/src/include/gnunet_time_lib.h +++ b/src/include/gnunet_time_lib.h @@ -420,6 +420,18 @@ GNUNET_TIME_relative_multiply (struct GNUNET_TIME_Relative rel, unsigned long long factor); +/** + * Saturating multiply relative time by a given factor. + * + * @param rel some duration + * @param factor integer to multiply with + * @return FOREVER if rel=FOREVER or on overflow; otherwise rel*factor + */ +struct GNUNET_TIME_Relative +GNUNET_TIME_relative_saturating_multiply (struct GNUNET_TIME_Relative rel, + unsigned long long factor); + + /** * Divide relative time by a given factor. * diff --git a/src/regex/gnunet-regex-profiler.c b/src/regex/gnunet-regex-profiler.c index c5ecf3b4d..dfbcd388a 100644 --- a/src/regex/gnunet-regex-profiler.c +++ b/src/regex/gnunet-regex-profiler.c @@ -950,7 +950,7 @@ daemon_started (void *cls, } peers[search_peer].search_str = search_strings[peer->id]; peers[search_peer].search_str_matched = GNUNET_NO; - GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_multiply( + GNUNET_SCHEDULER_add_delayed (GNUNET_TIME_relative_saturating_multiply( reannounce_period_max, 2), &find_string, diff --git a/src/rps/gnunet-service-rps.c b/src/rps/gnunet-service-rps.c index 90aab93fd..9de1f8d3a 100644 --- a/src/rps/gnunet-service-rps.c +++ b/src/rps/gnunet-service-rps.c @@ -1508,7 +1508,7 @@ compute_rand_delay (struct GNUNET_TIME_Relative mean, * via multiplying round_interval with a 'fraction' (0 to value)/value */ rand_delay = GNUNET_CRYPTO_random_u32 (GNUNET_CRYPTO_QUALITY_WEAK, max_rand_delay); - ret = GNUNET_TIME_relative_multiply (mean, rand_delay); + ret = GNUNET_TIME_relative_saturating_multiply (mean, rand_delay); ret = GNUNET_TIME_relative_divide (ret, max_rand_delay); ret = GNUNET_TIME_relative_add (ret, half_interval); @@ -2394,7 +2394,7 @@ run (void *cls, struct GNUNET_TIME_Relative half_round_interval; struct GNUNET_TIME_Relative max_round_interval; - half_round_interval = GNUNET_TIME_relative_multiply (round_interval, .5); + half_round_interval = GNUNET_TIME_relative_divide (round_interval, 2); max_round_interval = GNUNET_TIME_relative_add (round_interval, half_round_interval); prot_sampler = RPS_sampler_init (sampler_size_est_need, max_round_interval); diff --git a/src/util/bandwidth.c b/src/util/bandwidth.c index 980af764a..a059fc738 100644 --- a/src/util/bandwidth.c +++ b/src/util/bandwidth.c @@ -204,8 +204,8 @@ update_excess (struct GNUNET_BANDWIDTH_Tracker *av) else { double factor = 1.0 * left_bytes / (double) av->available_bytes_per_s__; - delay = GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, - (unsigned long long) factor); + delay = GNUNET_TIME_relative_saturating_multiply (GNUNET_TIME_UNIT_SECONDS, + (unsigned long long) factor); } GNUNET_log (GNUNET_ERROR_TYPE_DEBUG, "At %llu bps it will take us %s for %lld bytes to reach excess threshold\n", diff --git a/src/util/time.c b/src/util/time.c index eb168d531..89b0c2d44 100644 --- a/src/util/time.c +++ b/src/util/time.c @@ -445,6 +445,32 @@ GNUNET_TIME_relative_multiply (struct GNUNET_TIME_Relative rel, } +/** + * Saturating multiply relative time by a given factor. + * + * @param rel some duration + * @param factor integer to multiply with + * @return FOREVER if rel=FOREVER or on overflow; otherwise rel*factor + */ +struct GNUNET_TIME_Relative +GNUNET_TIME_relative_saturating_multiply (struct GNUNET_TIME_Relative rel, + unsigned long long factor) +{ + struct GNUNET_TIME_Relative ret; + + if (0 == factor) + return GNUNET_TIME_UNIT_ZERO; + if (rel.rel_value_us == GNUNET_TIME_UNIT_FOREVER_REL.rel_value_us) + return GNUNET_TIME_UNIT_FOREVER_REL; + ret.rel_value_us = rel.rel_value_us * factor; + if (ret.rel_value_us / factor != rel.rel_value_us) + { + return GNUNET_TIME_UNIT_FOREVER_REL; + } + return ret; +} + + /** * Divide relative time by a given factor. * diff --git a/src/vpn/vpn_api.c b/src/vpn/vpn_api.c index b22b805cd..4add41ce4 100644 --- a/src/vpn/vpn_api.c +++ b/src/vpn/vpn_api.c @@ -352,7 +352,7 @@ reconnect (struct GNUNET_VPN_Handle *vh) for (rr = vh->rr_head; NULL != rr; rr = rr->next) rr->request_id = 0; vh->backoff = GNUNET_TIME_relative_max (GNUNET_TIME_UNIT_MILLISECONDS, - GNUNET_TIME_relative_min (GNUNET_TIME_relative_multiply (vh->backoff, 2), + GNUNET_TIME_relative_min (GNUNET_TIME_relative_saturating_multiply (vh->backoff, 2), GNUNET_TIME_relative_multiply (GNUNET_TIME_UNIT_SECONDS, 30))); vh->rt = GNUNET_SCHEDULER_add_delayed (vh->backoff, &connect_task, -- 2.25.1