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