/* * 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-clt.c,v 1.13 2005/01/05 18:16:01 ca Exp $") #include "sm/assert.h" #include "sm/ctype.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 "sm/check.h" #include #define NSOCKET "./sockevthr1" #define WHAT_TERM 0 #define WHAT_CONT 1 #define IOBUFSIZE 64 int Verbose = 0; 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 */ 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 %lx '", (long) tsk); prtbuf(stderr, str, strlen(str)); fprintf(stderr, "', fd=%d, status=%d, ev=%x\n", fd, l, evthr_rqevents(tsk)); } r = fctx->what; if (r > 1) sleep(r - 1); if (fctx->called > 256) 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='", r); if (r > 0) prtbuf(stderr, fctx->buf, r); fprintf(stderr, "'\n"); } if (r > 0) { fctx->buflen = r; for (l = 0; l < r; l++) { if (fctx->buf[l] == 'Q') return EVTHR_TERM|EVTHR_DEL; if (fctx->buf[l] != '\0') fctx->buf[l]++; } return EVTHR_WAITQ|evthr_r_yes(EVTHR_EV_WR)| evthr_r_no(EVTHR_EV_RD); } else return EVTHR_TERM|EVTHR_DEL; } if (evthr_got_wr(tsk)) { if (fctx->buflen == 0) { fctx->buf[0] = fctx->called + ' '; fctx->buflen = 1; } 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_yes(EVTHR_EV_RD)| evthr_r_no(EVTHR_EV_WR); } } } 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; } static void testev(char *sockname, int what, int loops, int reps) { int fd; sm_ret_T ret; sm_evthr_ctx_P evthr_ctx; sm_evthr_task_P task3; t_ctx_T tctx3; char 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); fd = -1; strlcpy(dat3, "EvThr Client Q\n", sizeof(dat3)); tctx3.called = 0; if (sockname != NULL) { (void) unix_client_connect(sockname, &fd); SM_TEST(fd >= 0); if (fd >= 0) { size_t i; tctx3.ctx = evthr_ctx; tctx3.str = dat3; tctx3.fd = fd; tctx3.what = what; tctx3.status = loops; for (i = 0; i < sizeof(tctx3.buf); i++) tctx3.buf[i] = ' ' + (i % 4); tctx3.buf[sizeof(tctx3.buf) - 1] = '\0'; tctx3.buflen = sizeof(tctx3.buf) - 1; ret = sm_fd_nonblock(fd, true); SM_TEST(sm_is_success(ret)); ret = evthr_task_new(evthr_ctx, &task3, EVTHR_EV_WR, fd, &sleept, fct1, (void *) &tctx3); SM_TEST(sm_is_success(ret)); SM_TEST(task3 != NULL); } else fprintf(stderr, "unix_server_connect()=%d, errno=%d\n", fd, errno); } 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 (fd >= 0) close(fd); SM_TEST(tctx3.called > 0); if (reps > 0) SM_TEST(tctx3.called == reps); if (Verbose > 0) { fprintf(stderr, "fcts=%d\n", 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)); } static void usage(const char *prg) { fprintf(stderr, "usage: %s [options] socket\n", prg); exit(0); } int main(int argc, char *argv[]) { int c, what, loops, reps; char *sockname, *prg; sockname = NULL; what = 1; loops = 16; reps = -1; prg = argv[0]; 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"); argc -= optind; argv += optind; if (argc <= 0) usage(prg); sockname = argv[0]; testev(sockname, what, loops, reps); return sm_test_end(); }