diff options
Diffstat (limited to 'vppinfra/vppinfra/timer.c')
-rw-r--r-- | vppinfra/vppinfra/timer.c | 322 |
1 files changed, 0 insertions, 322 deletions
diff --git a/vppinfra/vppinfra/timer.c b/vppinfra/vppinfra/timer.c deleted file mode 100644 index 0221cb749a1..00000000000 --- a/vppinfra/vppinfra/timer.c +++ /dev/null @@ -1,322 +0,0 @@ -/* - * Copyright (c) 2015 Cisco and/or its affiliates. - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at: - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -/* - Copyright (c) 2001, 2002, 2003 Eliot Dresselhaus - - 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 and this permission notice 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 OR OTHER DEALINGS IN THE SOFTWARE. -*/ - -#include <math.h> -#include <stdlib.h> -#include <string.h> -#include <sys/param.h> - -#include <vppinfra/vec.h> -#include <vppinfra/time.h> -#include <vppinfra/timer.h> -#include <vppinfra/error.h> - -typedef struct -{ - f64 time; - timer_func_t *func; - any arg; -} timer_callback_t; - -/* Vector of currently unexpired timers. */ -static timer_callback_t *timers; - -/* Convert time from 64bit floating format to struct timeval. */ -always_inline void -f64_to_tv (f64 t, struct timeval *tv) -{ - tv->tv_sec = t; - tv->tv_usec = 1e6 * (t - tv->tv_sec); - while (tv->tv_usec >= 1000000) - { - tv->tv_usec -= 1000000; - tv->tv_sec += 1; - } -} - -/* Sort timers so that timer soonest to expire is at end. */ -static int -timer_compare (const void *_a, const void *_b) -{ - const timer_callback_t *a = _a; - const timer_callback_t *b = _b; - f64 dt = b->time - a->time; - return dt < 0 ? -1 : (dt > 0 ? +1 : 0); -} - -static inline void -sort_timers (timer_callback_t * timers) -{ - qsort (timers, vec_len (timers), sizeof (timers[0]), timer_compare); -} - -#define TIMER_SIGNAL SIGALRM - -/* Don't bother set timer if time different is less than this value. */ -/* We would like to initialize this to 0.75 / (f64) HZ, - * but HZ may not be a compile-time constant on some systems, - * so instead we do the initialization before first use. - */ -static f64 time_resolution; - -/* Interrupt handler. Call functions for all expired timers. - Set time for next timer interrupt. */ -static void -timer_interrupt (int signum) -{ - f64 now = unix_time_now (); - f64 dt; - timer_callback_t *t; - - while (1) - { - if (vec_len (timers) <= 0) - return; - - /* Consider last (earliest) timer in reverse sorted - vector of pending timers. */ - t = vec_end (timers) - 1; - - ASSERT (now >= 0 && finite (now)); - - /* Time difference between when timer goes off and now. */ - dt = t->time - now; - - /* If timer is within threshold of going off - call user's callback. */ - if (dt <= time_resolution && finite (dt)) - { - _vec_len (timers) -= 1; - (*t->func) (t->arg, -dt); - } - else - { - /* Set timer for to go off in future. */ - struct itimerval itv; - memset (&itv, 0, sizeof (itv)); - f64_to_tv (dt, &itv.it_value); - if (setitimer (ITIMER_REAL, &itv, 0) < 0) - clib_unix_error ("sititmer"); - return; - } - } -} - -void -timer_block (sigset_t * save) -{ - sigset_t block_timer; - - memset (&block_timer, 0, sizeof (block_timer)); - sigaddset (&block_timer, TIMER_SIGNAL); - sigprocmask (SIG_BLOCK, &block_timer, save); -} - -void -timer_unblock (sigset_t * save) -{ - sigprocmask (SIG_SETMASK, save, 0); -} - -/* Arrange for function to be called some time, - roughly equal to dt seconds, in the future. */ -void -timer_call (timer_func_t * func, any arg, f64 dt) -{ - timer_callback_t *t; - sigset_t save; - - /* Install signal handler on first call. */ - static word signal_installed = 0; - - if (!signal_installed) - { - struct sigaction sa; - - /* Initialize time_resolution before first call to timer_interrupt */ - time_resolution = 0.75 / (f64) HZ; - - memset (&sa, 0, sizeof (sa)); - sa.sa_handler = timer_interrupt; - - if (sigaction (TIMER_SIGNAL, &sa, 0) < 0) - clib_panic ("sigaction"); - - signal_installed = 1; - } - - timer_block (&save); - - /* Add new timer. */ - vec_add2 (timers, t, 1); - - t->time = unix_time_now () + dt; - t->func = func; - t->arg = arg; - - { - word reset_timer = vec_len (timers) == 1; - - if (_vec_len (timers) > 1) - { - reset_timer += t->time < (t - 1)->time; - sort_timers (timers); - } - - if (reset_timer) - timer_interrupt (TIMER_SIGNAL); - } - - timer_unblock (&save); -} - -#ifdef TEST - -#include <vppinfra/random.h> - -/* Compute average delay of function calls to foo. - If this is a small number over a lot of iterations we know - the code is working. */ - -static f64 ave_delay = 0; -static word ave_delay_count = 0; - -always_inline -update (f64 delay) -{ - ave_delay += delay; - ave_delay_count += 1; -} - -typedef struct -{ - f64 time_requested, time_called; -} foo_t; - -static f64 foo_base_time = 0; -static foo_t *foos = 0; - -void -foo (any arg, f64 delay) -{ - foos[arg].time_called = unix_time_now () - foo_base_time; - update (delay); -} - -typedef struct -{ - word count; - word limit; -} bar_t; - -void -bar (any arg, f64 delay) -{ - bar_t *b = (bar_t *) arg; - - fformat (stdout, "bar %d delay %g\n", b->count++, delay); - - update (delay); - if (b->count < b->limit) - timer_call (bar, arg, random_f64 ()); -} - -int -main (int argc, char *argv[]) -{ - word i, n = atoi (argv[1]); - word run_foo = argc > 2; -bar_t b = { limit:10 }; - - if (run_foo) - { - f64 time_limit; - - time_limit = atof (argv[2]); - - vec_resize (foos, n); - for (i = 0; i < n; i++) - { - foos[i].time_requested = time_limit * random_f64 (); - foos[i].time_called = 1e100; - } - - foo_base_time = unix_time_now (); - for (i = 0; i < n; i++) - timer_call (foo, i, foos[i].time_requested); - } - else - timer_call (bar, (any) & b, random_f64 ()); - - while (vec_len (timers) > 0) - sched_yield (); - - if (vec_len (foos) > 0) - { - f64 min = 1e100, max = -min; - f64 ave = 0, rms = 0; - - for (i = 0; i < n; i++) - { - f64 dt = foos[i].time_requested - foos[i].time_called; - if (dt < min) - min = dt; - if (dt > max) - max = dt; - ave += dt; - rms += dt * dt; - } - ave /= n; - rms = sqrt (rms / n - ave * ave); - fformat (stdout, "error min %g max %g ave %g +- %g\n", min, max, ave, - rms); - } - - fformat (stdout, "%d function calls, ave. timer delay %g secs\n", - ave_delay_count, ave_delay / ave_delay_count); - - return 0; -} -#endif - -/* - * fd.io coding-style-patch-verification: ON - * - * Local Variables: - * eval: (c-set-style "gnu") - * End: - */ |