/* * This file is part of the Sofia-SIP package * * Copyright (C) 2005 Nokia Corporation. * * Contact: Pekka Pessi * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public License * as published by the Free Software Foundation; either version 2.1 of * the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA * 02110-1301 USA * */ /**@ingroup su_root_ex * @CFILE torture_su_timer.c * * @brief Test program for su timers * * @author Pekka Pessi * * @internal * * @date Created: Fri Oct 19 08:53:55 2001 pessi */ #include "config.h" #include #include #include #include struct tester; #define SU_ROOT_MAGIC_T struct tester #define SU_INTERNAL_P su_root_t * #define SU_TIMER_ARG_T struct timing #include "sofia-sip/su.h" #include "sofia-sip/su_wait.h" #include "sofia-sip/su_log.h" struct timing { int t_run; int t_times; su_time_t t_prev; }; struct tester { su_root_t *root; su_timer_t *t, *t1; unsigned times; void *sentinel; }; void print_stamp(struct tester *x, su_timer_t *t, struct timing *ti) { su_time_t now = su_now(), prev = ti->t_prev; ti->t_prev = now; if (!ti->t_run) su_timer_set(t, print_stamp, ti); printf("timer interval %f\n", 1000 * su_time_diff(now, prev)); if (++ti->t_times >= 10) su_timer_reset(t); } void print_X(struct tester *x, su_timer_t *t1, struct timing *ti) { su_timer_set(t1, print_X, ti); putchar('X'); fflush(stdout); } #if HAVE_SIGNAL #include su_msg_r intr_msg = SU_MSG_R_INIT; static RETSIGTYPE intr_handler(int signum) { su_msg_send(intr_msg); } static void test_break(struct tester *tester, su_msg_r msg, su_msg_arg_t *arg) { su_root_break(tester->root); } #endif void end_test(struct tester *tester, su_timer_t *t, struct timing *ti) { su_timer_destroy(t); su_timer_reset(tester->t); su_timer_reset(tester->t1); su_root_break(tester->root); } void increment(struct tester *tester, su_timer_t *t, struct timing *ti) { tester->times++; if ((void *)ti == (void*)tester->sentinel) su_root_break(tester->root); } void usage(char const *name) { fprintf(stderr, "usage: %s [-1r] [-Nnum] [interval]\n", name); exit(1); } /* * test su_timer functionality: * * Create a timer, executing print_stamp() in every 20 ms */ int main(int argc, char *argv[]) { su_root_t *root; su_timer_t *t, *t1, *t_end; su_timer_t **timers; su_duration_t interval = 60; char *argv0 = argv[0]; char *s; int use_t1 = 0; su_time_t now, started, inserted; unsigned i, N = 500; struct timing timing[1] = {{ 0 }}; struct tester tester[1] = {{ 0 }}; while (argv[1] && argv[1][0] == '-') { char *o = argv[1] + 1; while (*o) { if (*o == '1') o++, use_t1 = 1; else if (*o == 'r') o++, timing->t_run = 1; else if (*o == 'N') { if (o[1]) N = strtoul(o + 1, &o, 0); else if (argv[2]) N = strtoul(argv++[2], &o, 0); break; } else break; } if (*o) usage(argv0); argv++; } if (argv[1]) { interval = strtoul(argv[1], &s, 10); if (interval == 0 || s == argv[1]) usage(argv0); } su_init(); atexit(su_deinit); tester->root = root = su_root_create(tester); #if HAVE_SIGNAL su_msg_create(intr_msg, su_root_task(root), su_root_task(root), test_break, 0); signal(SIGINT, intr_handler); #if HAVE_SIGPIPE signal(SIGQUIT, intr_handler); signal(SIGHUP, intr_handler); #endif #endif t = su_timer_create(su_root_task(root), interval); t1 = su_timer_create(su_root_task(root), 1); t_end = su_timer_create(su_root_task(root), 20 * interval); if (t == NULL || t1 == NULL || t_end == NULL) su_perror("su_timer_create"), exit(1); tester->t = t, tester->t1 = t1; timing->t_prev = su_now(); if (timing->t_run) su_timer_run(t, print_stamp, timing); else su_timer_set(t, print_stamp, timing); if (use_t1) su_timer_set(t1, print_X, NULL); su_timer_set(t_end, end_test, NULL); su_root_run(root); #if HAVE_SIGNAL su_msg_destroy(intr_msg); #endif su_timer_destroy(t); su_timer_destroy(t1); if (timing->t_times != 10) { fprintf(stderr, "%s: t expired %d times (expecting 10)\n", argv0, timing->t_times); return 1; } /* Insert timers in order */ timers = calloc(N, sizeof *timers); if (!timers) { perror("calloc"); exit(1); } for (i = 0; i < N; i++) { t = su_timer_create(su_root_task(root), 1000); if (!t) { perror("su_timer_create"); exit(1); } timers[i] = t; } now = started = su_now(); for (i = 0; i < N; i++) { if (++now.tv_usec == 0) ++now.tv_sec; su_timer_set_at(timers[i], increment, (void *)(intptr_t)i, now); } tester->sentinel = (void*)(intptr_t)(i - 1); inserted = su_now(); su_root_run(root); now = su_now(); printf("Inserting %u timers took %f millisec\n", i, su_time_diff(inserted, started) * 1000); printf("Processing %u/%u timers took %f millisec (%f expected)\n", tester->times, i, su_time_diff(now, started) * 1000, (double)i / 1000); for (i = 0; i < N; i++) { su_timer_destroy(timers[i]); } su_root_destroy(root); su_deinit(); return 0; }