/*
* 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-slp.c,v 1.8 2006/06/05 18:59:41 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 5
static int Verbose = 0;
static int short_idx = 2;
static int del1[] = { 1, 3, 3, 0 };
static int del2[] = { 2, 1, 1, 0 };
static int diff[] = { 1, 1, 2, 0 };
static timeval_T difft;
static timeval_T startt;
static sm_evthr_task_P task1, task2;
struct t_ctx_S
{
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);
}
}
static int
curt(timeval_P sleept, char *name)
{
timeval_T dt;
int r;
r = gettimeofday(sleept, NULL);
SM_TEST(r == 0);
timersub(sleept, &startt, &dt);
if (Verbose > 1)
fprintf(stderr, "%s: called %ld.%06ld\n"
,name
,dt.tv_sec
,dt.tv_usec
);
return (int) dt.tv_sec;
}
static void
chkdel(char *name, int d, int i, int sh, int del[])
{
int j, sum;
sum = 1;
for (j = 0; j < i; j++)
{
if (strcmp(name, "fct1") != 0 || j != short_idx - 1)
sum += del[j];
else
{
sum += sh;
if (Verbose > 2)
printf("%s: j=%d, added sh=%d instead of %d\n",
name, j, sh, del[j]);
}
}
if (Verbose > 0)
printf("%s: d=%d, del[%d]=%d\n", name, d, i - 1, sum);
SM_TEST(d == sum);
}
/*
** FCT1 -- sleep
*/
static sm_ret_T
fct1(sm_evthr_task_P tsk)
{
int i, d;
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;
i = fctx->called++;
chkt(fctx->nextt, "fct1", fctx->called);
d = curt(&sleept, "fct1");
if (i > 0)
chkdel("fct1", d, i,
diff[(short_idx < (int) (sizeof(diff)/sizeof(diff[0])))
? short_idx : 0],
del1);
if (fctx->called >= REPS)
return EVTHR_TERM|EVTHR_DEL;
delay.tv_sec = del1[i];
delay.tv_usec = 0;
if (del1[i] == 0)
return EVTHR_TERM|EVTHR_DEL;
timeradd(&sleept, &delay, &tsk->evthr_t_sleep);
fctx->nextt = tsk->evthr_t_sleep;
return EVTHR_SLPQ;
}
/*
** FCT2 -- sleep
*/
static sm_ret_T
fct2(sm_evthr_task_P tsk)
{
int i, d;
t_ctx_P fctx;
timeval_T sleept, delay;
sm_ret_T ret;
SM_ASSERT(tsk != NULL);
SM_ASSERT(evthr_got_slp(tsk));
fctx = (t_ctx_P) tsk->evthr_t_actx;
i = fctx->called++;
chkt(fctx->nextt, "fct2", fctx->called);
d = curt(&sleept, "fct2");
if (i > 0)
chkdel("fct2", d, i, 0, del2);
if (fctx->called >= REPS)
return EVTHR_TERM|EVTHR_DEL;
if (i == short_idx)
{
delay.tv_sec = 0;
delay.tv_usec = 200000;
timeradd(&sleept, &delay, &sleept);
ret = evthr_new_sl(task1, sleept, true);
curt(&sleept, "fct2: shorten task1");
SM_TEST(sm_is_success(ret));
}
delay.tv_sec = del2[i];
delay.tv_usec = 0;
if (del2[i] == 0)
return EVTHR_DEL;
timeradd(&sleept, &delay, &tsk->evthr_t_sleep);
fctx->nextt = tsk->evthr_t_sleep;
return EVTHR_SLPQ;
}
static void
testev(int sl1, int sl2)
{
sm_ret_T ret;
int r;
sm_evthr_ctx_P evthr_ctx;
t_ctx_T tctx1, tctx2;
timeval_T 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);
if (sl1 >= 0)
{
r = gettimeofday(&sleept, NULL);
SM_TEST(r == 0);
sleept.tv_sec += sl1;
tctx1.called = 0;
tctx1.nextt = sleept;
ret = evthr_task_new(evthr_ctx, &task1, EVTHR_EV_SL, -1,
&sleept, fct1, (void *) &tctx1);
SM_TEST(sm_is_success(ret));
SM_TEST(task1 != NULL);
}
if (sl2 >= 0)
{
r = gettimeofday(&sleept, NULL);
SM_TEST(r == 0);
sleept.tv_sec += sl2;
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);
}
gettimeofday(&startt, NULL);
if (Verbose > 0)
{
ERRPRINTTV("before loop: ", startt);
}
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 (Verbose > 0)
{
fprintf(stderr, "fct1=%d, fct2=%d\n",
tctx1.called, tctx2.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;
difft.tv_sec = 0;
difft.tv_usec = 60000;
while ((c = getopt(argc, argv, "d:sV")) != -1)
{
switch (c)
{
case 'd':
difft.tv_usec = atoi(optarg);
break;
case 's':
short_idx = 4;
break;
case 'V':
Verbose++;
break;
#if 0
default:
usage(argv[0]);
return(1);
#endif /* 0 */
}
}
sm_test_begin(argc, argv, "test evthr sleep");
short_idx = 2;
testev(1, 1);
short_idx = 5;
testev(1, 1);
return sm_test_end();
}
syntax highlighted by Code2HTML, v. 0.9.1