/*
* 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 <stdio.h>
#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();
}
syntax highlighted by Code2HTML, v. 0.9.1