/* * Copyright (c) 2003-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-4.c,v 1.10 2006/03/13 19:01:27 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 "sm/io.h" #include "sm/unixsock.h" #include /* ** HACK ** Needs to be cleaned up. ** Just for testing whether a "non-sleep" task can be activated via ** evthr_new_sl(); */ #define WHAT_TERM 0 #define WHAT_CONT 1 #define IOBUFSIZE 32 #define REPS 5 static int Verbose = 0; static sm_evthr_task_P task, task2; struct t_ctx_S { sm_evthr_ctx_P ctx; char *str; int fd; int what; int status; int called; int buflen; char buf[IOBUFSIZE]; }; typedef struct t_ctx_S t_ctx_T, *t_ctx_P; /* ** FCT1 -- read/write/sleep */ static sm_ret_T fct1(sm_evthr_task_P tsk) { t_ctx_P fctx; int fd, r, l; char *str; SM_ASSERT(tsk != NULL); fctx = (t_ctx_P) tsk->evthr_t_actx; fd = fctx->fd; l = fctx->status--; str = (fctx->str == NULL) ? "" : fctx->str; fctx->called++; if (Verbose > 1) fprintf(stderr, "fct1: called %p '%s', fd=%d, status=%d, ev=%x\n", tsk, str, fd, l, evthr_rqevents(tsk)); r = fctx->what; if (r > 1) sleep(r - 1); if (evthr_got_slp(tsk)) { if (Verbose > 2) fprintf(stderr, "%ld: fct1: got sleep\n", (long) time(NULLT)); return EVTHR_TERM|EVTHR_DEL; } if (fd >= 0) { if (evthr_got_rd(tsk)) { sm_memzero(fctx->buf, sizeof(fctx->buf)); r = read(fd, fctx->buf, sizeof(fctx->buf)); fctx->buf[sizeof(fctx->buf) - 1] = '\0'; if (Verbose > 2) fprintf(stderr, "fct1: got r=%d, buf=%s\n", r, fctx->buf); if (r > 0) { fctx->buflen = r; for (l = 0; l < r - 1; l++) { if (fctx->buf[l] == 'Q') return EVTHR_TERM|EVTHR_DEL; fctx->buf[l]++; } return EVTHR_WAITQ|evthr_r_yes(EVTHR_EV_WR)|evthr_r_no(EVTHR_EV_RD); } } if (evthr_got_wr(tsk)) { r = write(fd, fctx->buf, fctx->buflen); if (Verbose > 2) fprintf(stderr, "fct1: wrote r=%d\n", r); if (r > 0) { return EVTHR_WAITQ|evthr_r_no(EVTHR_EV_WR)|evthr_r_yes(EVTHR_EV_RD); } } } if (l <= 0) return EVTHR_DEL; switch (fctx->what) { case WHAT_TERM: return EVTHR_TERM|EVTHR_DEL; case WHAT_CONT: default: return EVTHR_WAITQ; } /* NOTREACHED */ return EVTHR_TERM|EVTHR_DEL; } /* ** FCT2 -- sleep */ static sm_ret_T fct2(sm_evthr_task_P tsk) { sm_ret_T ret; int i; t_ctx_P fctx; timeval_T sleept, delay, wakeup; SM_ASSERT(tsk != NULL); SM_ASSERT(evthr_got_slp(tsk)); fctx = (t_ctx_P) tsk->evthr_t_actx; i = gettimeofday(&sleept, NULL); delay.tv_sec = 1; delay.tv_usec = 0; timeradd(&sleept, &delay, &wakeup); i = fctx->called++; if (i == 0) { if (Verbose > 2) fprintf(stderr, "%ld: fct2: wakeup tsk1\n", (long) time(NULLT)); ret = evthr_timeval(tsk->evthr_t_ctx, &wakeup); SM_TEST(sm_is_success(ret)); ret = evthr_new_sl(task, wakeup, false); SM_TEST(sm_is_success(ret)); } if (fctx->called >= REPS) return EVTHR_TERM|EVTHR_DEL; timeradd(&sleept, &delay, &tsk->evthr_t_sleep); return EVTHR_SLPQ; } static void testev(int what, int loops, int reps) { int lfd, r; sm_ret_T ret; sm_evthr_ctx_P evthr_ctx; t_ctx_T tctx, tctx2; timeval_T sleept; char dat[16]; char *sockname; 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); lfd = -1; strlcpy(dat, "Accept\n", sizeof(dat)); tctx.called = 0; sockname = "t-evthr-4.sock"; (void) unlink(sockname); lfd = unix_server_listen(sockname, 10); SM_TEST(lfd >= 0); if (lfd >= 0) { tctx.ctx = evthr_ctx; tctx.str = dat; tctx.fd = lfd; tctx.what = what; tctx.status = loops; ret = evthr_task_new(evthr_ctx, &task, EVTHR_EV_LI, lfd, &sleept, fct1, (void *) &tctx); SM_TEST(sm_is_success(ret)); SM_TEST(task != NULL); r = gettimeofday(&sleept, NULL); SM_TEST(r == 0); sleept.tv_sec += 1; tctx2.called = 0; 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); 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 (lfd >= 0) close(lfd); SM_TEST(tctx.called > 0); if (reps > 0) SM_TEST(tctx.called == reps); if (Verbose > 0) { fprintf(stderr, "fcts=%d\n", tctx.called); } (void) unlink(sockname); } else { fprintf(stderr, "unix_server_listen()=%d, errno=%d\n", lfd, errno); } 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, what, loops, reps; what = 1; loops = 16; reps = -1; while ((c = getopt(argc, argv, "l:r:w:V")) != -1) { switch (c) { case 'l': loops = atoi(optarg); break; case 'r': reps = 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(what, loops, reps); return sm_test_end(); }