#include <sm/gen.h>
SM_RCSID("@(#)$Id: monitor.c,v 8.7 2007/04/23 16:26:28 ca Exp $")
#include "libmilter.h"
#if _FFR_THREAD_MONITOR
bool Monitor = false;
static unsigned int Mon_exec_time = 0;
static smutex_t Mon_mutex;
static scond_t Mon_cv;
static SMFICTX_PTR Mon_cur_ctx = NULL;
static smfi_hd_T Mon_ctx_head;
int
smfi_set_max_exec_time(tm)
unsigned int tm;
{
Mon_exec_time = tm;
return MI_SUCCESS;
}
static void *
mi_monitor_thread(arg)
void *arg;
{
sthread_t tid;
int r;
time_t now, end;
SM_ASSERT(Monitor);
SM_ASSERT(Mon_exec_time > 0);
tid = (sthread_t) sthread_get_id();
if (pthread_detach(tid) != 0)
{
return (void *)1;
}
#define MON_CHK_STOP \
now = time(NULL); \
end = Mon_cur_ctx->ctx_start + Mon_exec_time; \
if (now > end) \
{ \
smi_log(SMI_LOG_ERR, \
"WARNING: monitor timeout triggered, now=%ld, end=%ld, tid=%ld, state=0x%x",\
(long) now, (long) end, \
(long) Mon_cur_ctx->ctx_id, Mon_cur_ctx->ctx_state);\
mi_stop_milters(MILTER_STOP); \
break; \
}
(void) smutex_lock(&Mon_mutex);
while (mi_stop() == MILTER_CONT)
{
if (Mon_cur_ctx != NULL && Mon_cur_ctx->ctx_start > 0)
{
struct timespec abstime;
MON_CHK_STOP;
abstime.tv_sec = end;
abstime.tv_nsec = 0;
r = pthread_cond_timedwait(&Mon_cv, &Mon_mutex,
&abstime);
}
else
r = pthread_cond_wait(&Mon_cv, &Mon_mutex);
if (mi_stop() != MILTER_CONT)
break;
if (Mon_cur_ctx != NULL && Mon_cur_ctx->ctx_start > 0)
{
MON_CHK_STOP;
}
}
(void) smutex_unlock(&Mon_mutex);
return NULL;
}
int
mi_monitor_init()
{
int r;
sthread_t tid;
SM_ASSERT(!Monitor);
if (Mon_exec_time <= 0)
return MI_SUCCESS;
Monitor = true;
if (!smutex_init(&Mon_mutex))
return MI_FAILURE;
if (scond_init(&Mon_cv) != 0)
return MI_FAILURE;
SM_TAILQ_INIT(&Mon_ctx_head);
r = thread_create(&tid, mi_monitor_thread, (void *)NULL);
if (r != 0)
return r;
return MI_SUCCESS;
}
int
mi_monitor_work_begin(ctx, cmd)
SMFICTX_PTR ctx;
int cmd;
{
(void) smutex_lock(&Mon_mutex);
if (NULL == Mon_cur_ctx)
{
Mon_cur_ctx = ctx;
(void) scond_signal(&Mon_cv);
}
ctx->ctx_start = time(NULL);
SM_TAILQ_INSERT_TAIL(&Mon_ctx_head, ctx, ctx_mon_link);
(void) smutex_unlock(&Mon_mutex);
return 0;
}
int
mi_monitor_work_end(ctx, cmd)
SMFICTX_PTR ctx;
int cmd;
{
(void) smutex_lock(&Mon_mutex);
ctx->ctx_start = 0;
SM_TAILQ_REMOVE(&Mon_ctx_head, ctx, ctx_mon_link);
if (Mon_cur_ctx == ctx)
{
if (SM_TAILQ_EMPTY(&Mon_ctx_head))
Mon_cur_ctx = NULL;
else
Mon_cur_ctx = SM_TAILQ_FIRST(&Mon_ctx_head);
}
(void) smutex_unlock(&Mon_mutex);
return 0;
}
#endif