/* * Copyright (c) 2002, 2004, 2005 Sendmail, Inc. and its suppliers. * All rights reserved. * * By using this file, you agree to the terms and conditions set * forth in the LICENSE file which can be found at the top level of * the sendmail distribution. */ #include "sm/generic.h" SM_RCSID("@(#)$Id: t-evthr-slp.c,v 1.8 2006/06/05 18:59:41 ca Exp $") #include "sm/assert.h" #include "sm/error.h" #include "sm/memops.h" #include "sm/heap.h" #include "sm/test.h" #include "sm/evthr.h" #include #define WHAT_TERM 0 #define WHAT_CONT 1 #define REPS 5 static int Verbose = 0; static int short_idx = 2; static int del1[] = { 1, 3, 3, 0 }; static int del2[] = { 2, 1, 1, 0 }; static int diff[] = { 1, 1, 2, 0 }; static timeval_T difft; static timeval_T startt; static sm_evthr_task_P task1, task2; struct t_ctx_S { int called; timeval_T nextt; }; typedef struct t_ctx_S t_ctx_T, *t_ctx_P; static void chkt(timeval_T exp, char *n, int c) { int r; timeval_T now, dt; bool ok; r = gettimeofday(&now, NULL); SM_TEST(r == 0); timersub(&now, &exp, &dt); ok = timercmp(&dt, &difft, <=); SM_TEST(ok); if (!ok) { fprintf(stderr, "%s[%d]: ", n, c); ERRPRINTTV("now=", now); ERRPRINTTV(" sleep=", exp); ERRPRINTTV(" diff=", dt); } } static int curt(timeval_P sleept, char *name) { timeval_T dt; int r; r = gettimeofday(sleept, NULL); SM_TEST(r == 0); timersub(sleept, &startt, &dt); if (Verbose > 1) fprintf(stderr, "%s: called %ld.%06ld\n" ,name ,dt.tv_sec ,dt.tv_usec ); return (int) dt.tv_sec; } static void chkdel(char *name, int d, int i, int sh, int del[]) { int j, sum; sum = 1; for (j = 0; j < i; j++) { if (strcmp(name, "fct1") != 0 || j != short_idx - 1) sum += del[j]; else { sum += sh; if (Verbose > 2) printf("%s: j=%d, added sh=%d instead of %d\n", name, j, sh, del[j]); } } if (Verbose > 0) printf("%s: d=%d, del[%d]=%d\n", name, d, i - 1, sum); SM_TEST(d == sum); } /* ** FCT1 -- sleep */ static sm_ret_T fct1(sm_evthr_task_P tsk) { int i, d; t_ctx_P fctx; timeval_T sleept, delay; SM_ASSERT(tsk != NULL); SM_ASSERT(evthr_got_slp(tsk)); fctx = (t_ctx_P) tsk->evthr_t_actx; i = fctx->called++; chkt(fctx->nextt, "fct1", fctx->called); d = curt(&sleept, "fct1"); if (i > 0) chkdel("fct1", d, i, diff[(short_idx < (int) (sizeof(diff)/sizeof(diff[0]))) ? short_idx : 0], del1); if (fctx->called >= REPS) return EVTHR_TERM|EVTHR_DEL; delay.tv_sec = del1[i]; delay.tv_usec = 0; if (del1[i] == 0) return EVTHR_TERM|EVTHR_DEL; timeradd(&sleept, &delay, &tsk->evthr_t_sleep); fctx->nextt = tsk->evthr_t_sleep; return EVTHR_SLPQ; } /* ** FCT2 -- sleep */ static sm_ret_T fct2(sm_evthr_task_P tsk) { int i, d; t_ctx_P fctx; timeval_T sleept, delay; sm_ret_T ret; SM_ASSERT(tsk != NULL); SM_ASSERT(evthr_got_slp(tsk)); fctx = (t_ctx_P) tsk->evthr_t_actx; i = fctx->called++; chkt(fctx->nextt, "fct2", fctx->called); d = curt(&sleept, "fct2"); if (i > 0) chkdel("fct2", d, i, 0, del2); if (fctx->called >= REPS) return EVTHR_TERM|EVTHR_DEL; if (i == short_idx) { delay.tv_sec = 0; delay.tv_usec = 200000; timeradd(&sleept, &delay, &sleept); ret = evthr_new_sl(task1, sleept, true); curt(&sleept, "fct2: shorten task1"); SM_TEST(sm_is_success(ret)); } delay.tv_sec = del2[i]; delay.tv_usec = 0; if (del2[i] == 0) return EVTHR_DEL; timeradd(&sleept, &delay, &tsk->evthr_t_sleep); fctx->nextt = tsk->evthr_t_sleep; return EVTHR_SLPQ; } static void testev(int sl1, int sl2) { sm_ret_T ret; int r; sm_evthr_ctx_P evthr_ctx; t_ctx_T tctx1, tctx2; timeval_T sleept; ret = thr_init(); SM_TEST(sm_is_success(ret)); sm_memzero(&sleept, sizeof(sleept)); ret = evthr_init(&evthr_ctx, 1, 6, 10); SM_TEST(sm_is_success(ret)); SM_TEST(evthr_ctx != NULL); if (sl1 >= 0) { r = gettimeofday(&sleept, NULL); SM_TEST(r == 0); sleept.tv_sec += sl1; tctx1.called = 0; tctx1.nextt = sleept; ret = evthr_task_new(evthr_ctx, &task1, EVTHR_EV_SL, -1, &sleept, fct1, (void *) &tctx1); SM_TEST(sm_is_success(ret)); SM_TEST(task1 != NULL); } if (sl2 >= 0) { r = gettimeofday(&sleept, NULL); SM_TEST(r == 0); sleept.tv_sec += sl2; tctx2.called = 0; tctx2.nextt = sleept; ret = evthr_task_new(evthr_ctx, &task2, EVTHR_EV_SL, -1, &sleept, fct2, (void *) &tctx2); SM_TEST(sm_is_success(ret)); SM_TEST(task2 != NULL); } gettimeofday(&startt, NULL); if (Verbose > 0) { ERRPRINTTV("before loop: ", startt); } ret = evthr_loop(evthr_ctx); SM_TEST(sm_is_success(ret)); if (!sm_is_success(ret)) fprintf(stderr, "evthr_loop()=%x\n", ret); /* ** we should "hold" the system before deleting tasks? ** deleting the tasks while they are still in use ** will break things. */ if (Verbose > 0) { fprintf(stderr, "fct1=%d, fct2=%d\n", tctx1.called, tctx2.called); } ret = evthr_stop(evthr_ctx); SM_TEST(sm_is_success(ret)); if (!sm_is_success(ret)) fprintf(stderr, "evthr_stop()=%x\n", ret); ret = thr_stop(); SM_TEST(sm_is_success(ret)); } int main(int argc, char *argv[]) { int c; difft.tv_sec = 0; difft.tv_usec = 60000; while ((c = getopt(argc, argv, "d:sV")) != -1) { switch (c) { case 'd': difft.tv_usec = atoi(optarg); break; case 's': short_idx = 4; break; case 'V': Verbose++; break; #if 0 default: usage(argv[0]); return(1); #endif /* 0 */ } } sm_test_begin(argc, argv, "test evthr sleep"); short_idx = 2; testev(1, 1); short_idx = 5; testev(1, 1); return sm_test_end(); }