/* * 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.c,v 1.27 2006/03/13 19:13:19 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 static int Verbose = 0; struct t_ctx_S { char *str; int fd; int what; int status; int called; }; typedef struct t_ctx_S t_ctx_T, *t_ctx_P; /* ** FCT1 -- read from fd */ static sm_ret_T fct1(sm_evthr_task_P tsk) { t_ctx_P ctx; int fd, r, l; char buf[2]; SM_ASSERT(tsk != NULL); SM_ASSERT(evthr_got_rd(tsk)); ctx = (t_ctx_P) tsk->evthr_t_actx; fd = ctx->fd; l = ctx->status--; ctx->called++; if (Verbose > 1) fprintf(stderr, "fct1: called %lx '%s', fd=%d, status=%d\n", (long) tsk, ctx->str, fd, l); r = ctx->what; if (r > 1) sleep(r - 1); if (fd >= 0) { r = read(fd, buf, sizeof(buf)); if (Verbose > 2) fprintf(stderr, "fct1: got r=%d, buf=%d\n", r, (int) buf[0]); if (r > 0) return EVTHR_WAITQ; } if (l <= 0) return EVTHR_TERM|EVTHR_DEL; switch (ctx->what) { case WHAT_TERM: return EVTHR_TERM|EVTHR_DEL; case WHAT_CONT: default: return EVTHR_WAITQ; } /* NOTREACHED */ return EVTHR_TERM; } /* ** FCT2 -- write to fd */ static sm_ret_T fct2(sm_evthr_task_P tsk) { t_ctx_P ctx; int fd, r, l; char *str; SM_ASSERT(tsk != NULL); SM_ASSERT(evthr_got_wr(tsk)); ctx = (t_ctx_P) tsk->evthr_t_actx; ctx->called++; fd = ctx->fd; str = ctx->str; l = ctx->status--; if (Verbose > 2) fprintf(stderr, "fct2: called %lx '%s', fd=%d, status=%d\n", (long) tsk, ctx->str, fd, l); if (l <= 0) return EVTHR_DEL; if (fd >= 0) { r = write(fd, str, strlen(str)); if (Verbose > 2) fprintf(stderr, "fct2: wrote r=%d\n", r); if (r > 0) return EVTHR_WAITQ; } switch (ctx->what) { case WHAT_CONT: return EVTHR_WAITQ; case WHAT_TERM: return EVTHR_DEL; } return EVTHR_DEL; } /* ** FCTS -- deletes itself after first call */ static sm_ret_T fcts(sm_evthr_task_P tsk) { t_ctx_P ctx; SM_ASSERT(tsk != NULL); ctx = (t_ctx_P) tsk->evthr_t_actx; ctx->called++; if (Verbose > 1) fprintf(stderr, "fcts: called %lx '%s'\n", (long) tsk, ctx->str); return EVTHR_DEL; } static void testev(int fd, int fdo, 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]; struct timeval 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); strlcpy(data, "String", sizeof(data)); strlcpy(dat2, "Str2\n", sizeof(dat2)); strlcpy(dat3, "Sleep3\n", sizeof(dat3)); if (fd >= 0) { tctx.str = data; tctx.fd = fd; tctx.what = what; tctx.status = loops; tctx.called = 0; ret = evthr_task_new(evthr_ctx, &task, EVTHR_EV_RD, fd, &sleept, fct1, (void *) &tctx); SM_TEST(sm_is_success(ret)); SM_TEST(task != NULL); } if (fdo >= 0) { tctx2.str = dat2; tctx2.fd = fdo; tctx2.what = what; tctx2.status = loops; tctx2.called = 0; ret = evthr_task_new(evthr_ctx, &task2, EVTHR_EV_WR, fdo, &sleept, fct2, (void *) &tctx2); SM_TEST(sm_is_success(ret)); SM_TEST(task2 != NULL); } r = gettimeofday(&sleept, NULL); SM_TEST(r == 0); sleept.tv_usec += 1000; /* */ tctx3.str = dat3; tctx3.fd = fdo; tctx3.what = what; tctx3.status = loops; tctx3.called = 0; 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); 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 > 0); SM_TEST(tctx2.called > 0); SM_TEST(tctx3.called == 1); 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, fdin, fdout, what, loops; fdin = STDIN_FILENO; fdout = STDOUT_FILENO; what = 1; loops = 16; while ((c = getopt(argc, argv, "i:l:o:w:V")) != -1) { switch (c) { case 'i': fdin = atoi(optarg); break; case 'l': loops = atoi(optarg); break; case 'o': fdout = 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"); testev(fdin, fdout, what, loops); return sm_test_end(); }