/*
* Copyright (c) 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.
*
*/
#pragma ident "%Z%%M% %I% %E% SMI"
#include "libmilter.h"
/*
** Thread Monitoring
** Todo: more error checking (return code from function calls)
** add comments.
*/
static unsigned int Mon_exec_time = 0;
/* mutex protects Mon_cur_ctx, Mon_ctx_head, and ctx_start */
/*
** Current ctx to monitor.
** Invariant:
** Mon_cur_ctx == NULL || Mon_cur_ctx is thread which was started the longest
** time ago.
**
** Basically the entries in the list are ordered by time because new
** entries are appended at the end. However, due to the concurrent
** execution (multi-threaded) and no guaranteed order of wakeups
** after a mutex_lock() attempt, the order might not be strict,
** i.e., if the list contains e1 and e2 (in that order) then
** the the start time of e2 can be (slightly) smaller than that of e1.
** However, this slight inaccurracy should not matter for the proper
** working of this algorithm.
*/
/*
** SMFI_SET_MAX_EXEC_TIME -- set maximum execution time for a thread
**
** Parameters:
** tm -- maximum execution time for a thread
**
** Returns:
** MI_SUCCESS
*/
int
unsigned int tm;
{
Mon_exec_time = tm;
return MI_SUCCESS;
}
/*
** MI_MONITOR_THREAD -- monitoring thread
**
** Parameters:
** arg -- ignored (required by pthread_create())
**
** Returns:
** NULL on termination.
*/
static void *
void *arg;
{
int r;
SM_ASSERT(Mon_exec_time > 0);
if (pthread_detach(tid) != 0)
{
/* log an error */
return (void *)1;
}
/*
** NOTE: this is "flow through" code,
** do NOT use do { } while ("break" is used here!)
*/
#define MON_CHK_STOP \
{ \
"WARNING: monitor timeout triggered, now=%ld, end=%ld, tid=%ld, state=0x%x",\
break; \
}
(void) smutex_lock(&Mon_mutex);
while (mi_stop() == MILTER_CONT)
{
{
&abstime);
}
else
if (mi_stop() != MILTER_CONT)
break;
{
}
}
(void) smutex_unlock(&Mon_mutex);
return NULL;
}
/*
** MI_MONITOR_INIT -- initialize monitoring thread
**
** Parameters: none
**
** Returns:
*/
int
{
int r;
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;
if (r != 0)
return r;
return MI_SUCCESS;
}
/*
** MI_MONITOR_WORK_BEGIN -- record start of thread execution
**
** Parameters:
** ctx -- session context
** cmd -- milter command char
**
** Returns:
** 0
*/
int
int cmd;
{
(void) smutex_lock(&Mon_mutex);
if (NULL == Mon_cur_ctx)
{
Mon_cur_ctx = ctx;
(void) scond_signal(&Mon_cv);
}
(void) smutex_unlock(&Mon_mutex);
return 0;
}
/*
** MI_MONITOR_WORK_END -- record end of thread execution
**
** Parameters:
** ctx -- session context
** cmd -- milter command char
**
** Returns:
** 0
*/
int
int cmd;
{
(void) smutex_lock(&Mon_mutex);
if (Mon_cur_ctx == ctx)
{
if (SM_TAILQ_EMPTY(&Mon_ctx_head))
Mon_cur_ctx = NULL;
else
}
(void) smutex_unlock(&Mon_mutex);
return 0;
}
#endif /* _FFR_THREAD_MONITOR */