/* * Copyright (c) 2002, 2004-2006 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-s.c,v 1.21 2006/03/14 19:22:36 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 21 static uint Dbglvl = 0; static int Verbose = 0; timeval_T difft; struct t_ctx_S { char *str; int what; int status; 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); } } /* ** FCT1 -- deletes itself after first call */ static sm_ret_T fct1(sm_evthr_task_P tsk) { t_ctx_P fctx; SM_ASSERT(tsk != NULL); fctx = (t_ctx_P) tsk->evthr_t_actx; fctx->called++; chkt(fctx->nextt, "fct1", fctx->called); if (Verbose > 1) fprintf(stderr, "fct1: called %lx '%s'\n", (long) tsk, fctx->str); return EVTHR_DEL; } /* ** FCT2 -- deletes itself after first call */ static sm_ret_T fct2(sm_evthr_task_P tsk) { t_ctx_P fctx; SM_ASSERT(tsk != NULL); fctx = (t_ctx_P) tsk->evthr_t_actx; fctx->called++; chkt(fctx->nextt, "fct2", fctx->called); if (Verbose > 1) fprintf(stderr, "fct2: called %lx '%s'\n", (long) tsk, fctx->str); return EVTHR_DEL; } /* ** FCTS -- sleep 100000 usec up to REPS times. */ static sm_ret_T fcts(sm_evthr_task_P tsk) { int r; 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; fctx->called++; chkt(fctx->nextt, "fcts", fctx->called); if (Verbose > 1) fprintf(stderr, "fcts: called %lx '%s'\n", (long) tsk, fctx->str); if (fctx->called >= REPS) return EVTHR_TERM|EVTHR_DEL; r = gettimeofday(&sleept, NULL); SM_TEST(r == 0); delay.tv_sec = 0; delay.tv_usec = 100000; timeradd(&sleept, &delay, &tsk->evthr_t_sleep); fctx->nextt = tsk->evthr_t_sleep; return EVTHR_SLPQ; } static void testev(int sl1, int sl2, int what, int loops) { sm_ret_T ret; int r; sm_evthr_ctx_P evthr_ctx; sm_evthr_task_P task, task2, task3; t_ctx_T tctx, tctx2, tctx3; char data[16], dat2[16], dat3[16]; timeval_T sleept, nextt, delay; 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); evthr_set_dbglvl(evthr_ctx, Dbglvl); strlcpy(data, "Sleep1", sizeof(data)); strlcpy(dat2, "Sleep2", sizeof(dat2)); strlcpy(dat3, "Sleep3", sizeof(dat3)); if (sl1 >= 0) { r = gettimeofday(&sleept, NULL); SM_TEST(r == 0); sleept.tv_sec += sl1; tctx.str = data; tctx.what = what; tctx.status = loops; tctx.called = 0; tctx.nextt = sleept; ret = evthr_task_new(evthr_ctx, &task, EVTHR_EV_SL, -1, &sleept, fct1, (void *) &tctx); SM_TEST(sm_is_success(ret)); SM_TEST(task != NULL); } if (sl2 >= 0) { r = gettimeofday(&sleept, NULL); SM_TEST(r == 0); sleept.tv_sec += sl2; tctx2.str = dat2; tctx2.what = what; tctx2.status = loops; 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); } r = gettimeofday(&sleept, NULL); SM_TEST(r == 0); delay.tv_sec = 0; delay.tv_usec = 100000; timeradd(&sleept, &delay, &nextt); sleept = nextt; if (Verbose > 2) fprintf(stderr, "fcts: sleep=%ld.%06ld\n", sleept.tv_sec, sleept.tv_usec); /* */ tctx3.str = dat3; tctx3.what = what; tctx3.status = loops; tctx3.called = 0; tctx3.nextt = sleept; ret = evthr_task_new(evthr_ctx, &task3, EVTHR_EV_SL, -1, &sleept, fcts, (void *) &tctx3); SM_TEST(sm_is_success(ret)); SM_TEST(task3 != NULL); if (Verbose > 0) { gettimeofday(&sleept, NULL); ERRPRINTTV("before loop: ", sleept); } 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 0 ret = evthr_task_del(evthr_ctx, task, THR_LOCK_UNLOCK); SM_TEST(sm_is_success(ret)); if (!sm_is_success(ret)) fprintf(stderr, "evthr_task_del()=%x\n", ret); ret = evthr_task_del(evthr_ctx, task2, THR_LOCK_UNLOCK); SM_TEST(sm_is_success(ret)); if (!sm_is_success(ret)) fprintf(stderr, "evthr_task_del()=%x\n", ret); #endif /* 0 */ SM_TEST(tctx.called == 1); SM_TEST(tctx2.called == 1); SM_TEST(tctx3.called == REPS); if (Verbose > 0) { fprintf(stderr, "fct1=%d, fct2=%d, fcts=%d\n", tctx.called, tctx2.called, tctx3.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, sl1, sl2, what, loops; sl1 = 1; sl2 = 2; what = 1; loops = 16; difft.tv_sec = 0; difft.tv_usec = 50000; while ((c = getopt(argc, argv, "D:d:i:l:o:w:V")) != -1) { switch (c) { case 'D': Dbglvl = atoi(optarg); break; case 'd': difft.tv_usec = atoi(optarg); break; case 'l': loops = atoi(optarg); break; case 's': sl2 = atoi(optarg); break; case 'w': what = atoi(optarg); break; case 'V': Verbose++; break; #if 0 default: usage(argv[0]); return(1); #endif /* 0 */ } } sm_test_begin(argc, argv, "test evthr sleep"); testev(sl1, sl2, what, loops); return sm_test_end(); }