058561cbaa119a6f2659bc27ef343e1b47266bb2jbeck/*
058561cbaa119a6f2659bc27ef343e1b47266bb2jbeck * Copyright (c) 2006 Sendmail, Inc. and its suppliers.
058561cbaa119a6f2659bc27ef343e1b47266bb2jbeck * All rights reserved.
058561cbaa119a6f2659bc27ef343e1b47266bb2jbeck *
058561cbaa119a6f2659bc27ef343e1b47266bb2jbeck * By using this file, you agree to the terms and conditions set
058561cbaa119a6f2659bc27ef343e1b47266bb2jbeck * forth in the LICENSE file which can be found at the top level of
058561cbaa119a6f2659bc27ef343e1b47266bb2jbeck * the sendmail distribution.
058561cbaa119a6f2659bc27ef343e1b47266bb2jbeck *
058561cbaa119a6f2659bc27ef343e1b47266bb2jbeck */
058561cbaa119a6f2659bc27ef343e1b47266bb2jbeck
058561cbaa119a6f2659bc27ef343e1b47266bb2jbeck#pragma ident "%Z%%M% %I% %E% SMI"
058561cbaa119a6f2659bc27ef343e1b47266bb2jbeck
7800901e60d340b6af88e94a2149805dcfcaaf56jbeck#include <sm/gen.h>
7800901e60d340b6af88e94a2149805dcfcaaf56jbeckSM_RCSID("@(#)$Id: monitor.c,v 8.7 2007/04/23 16:26:28 ca Exp $")
058561cbaa119a6f2659bc27ef343e1b47266bb2jbeck#include "libmilter.h"
058561cbaa119a6f2659bc27ef343e1b47266bb2jbeck
058561cbaa119a6f2659bc27ef343e1b47266bb2jbeck#if _FFR_THREAD_MONITOR
058561cbaa119a6f2659bc27ef343e1b47266bb2jbeck
058561cbaa119a6f2659bc27ef343e1b47266bb2jbeck/*
058561cbaa119a6f2659bc27ef343e1b47266bb2jbeck** Thread Monitoring
058561cbaa119a6f2659bc27ef343e1b47266bb2jbeck** Todo: more error checking (return code from function calls)
058561cbaa119a6f2659bc27ef343e1b47266bb2jbeck** add comments.
058561cbaa119a6f2659bc27ef343e1b47266bb2jbeck*/
058561cbaa119a6f2659bc27ef343e1b47266bb2jbeck
058561cbaa119a6f2659bc27ef343e1b47266bb2jbeckbool Monitor = false; /* use monitoring? */
058561cbaa119a6f2659bc27ef343e1b47266bb2jbeckstatic unsigned int Mon_exec_time = 0;
058561cbaa119a6f2659bc27ef343e1b47266bb2jbeck
058561cbaa119a6f2659bc27ef343e1b47266bb2jbeck/* mutex protects Mon_cur_ctx, Mon_ctx_head, and ctx_start */
058561cbaa119a6f2659bc27ef343e1b47266bb2jbeckstatic smutex_t Mon_mutex;
058561cbaa119a6f2659bc27ef343e1b47266bb2jbeckstatic scond_t Mon_cv;
058561cbaa119a6f2659bc27ef343e1b47266bb2jbeck
058561cbaa119a6f2659bc27ef343e1b47266bb2jbeck/*
058561cbaa119a6f2659bc27ef343e1b47266bb2jbeck** Current ctx to monitor.
058561cbaa119a6f2659bc27ef343e1b47266bb2jbeck** Invariant:
058561cbaa119a6f2659bc27ef343e1b47266bb2jbeck** Mon_cur_ctx == NULL || Mon_cur_ctx is thread which was started the longest
058561cbaa119a6f2659bc27ef343e1b47266bb2jbeck** time ago.
058561cbaa119a6f2659bc27ef343e1b47266bb2jbeck**
058561cbaa119a6f2659bc27ef343e1b47266bb2jbeck** Basically the entries in the list are ordered by time because new
058561cbaa119a6f2659bc27ef343e1b47266bb2jbeck** entries are appended at the end. However, due to the concurrent
058561cbaa119a6f2659bc27ef343e1b47266bb2jbeck** execution (multi-threaded) and no guaranteed order of wakeups
058561cbaa119a6f2659bc27ef343e1b47266bb2jbeck** after a mutex_lock() attempt, the order might not be strict,
058561cbaa119a6f2659bc27ef343e1b47266bb2jbeck** i.e., if the list contains e1 and e2 (in that order) then
058561cbaa119a6f2659bc27ef343e1b47266bb2jbeck** the the start time of e2 can be (slightly) smaller than that of e1.
058561cbaa119a6f2659bc27ef343e1b47266bb2jbeck** However, this slight inaccurracy should not matter for the proper
058561cbaa119a6f2659bc27ef343e1b47266bb2jbeck** working of this algorithm.
058561cbaa119a6f2659bc27ef343e1b47266bb2jbeck*/
058561cbaa119a6f2659bc27ef343e1b47266bb2jbeck
058561cbaa119a6f2659bc27ef343e1b47266bb2jbeckstatic SMFICTX_PTR Mon_cur_ctx = NULL;
058561cbaa119a6f2659bc27ef343e1b47266bb2jbeckstatic smfi_hd_T Mon_ctx_head; /* head of the linked list of active contexts */
058561cbaa119a6f2659bc27ef343e1b47266bb2jbeck
058561cbaa119a6f2659bc27ef343e1b47266bb2jbeck/*
058561cbaa119a6f2659bc27ef343e1b47266bb2jbeck** SMFI_SET_MAX_EXEC_TIME -- set maximum execution time for a thread
058561cbaa119a6f2659bc27ef343e1b47266bb2jbeck**
058561cbaa119a6f2659bc27ef343e1b47266bb2jbeck** Parameters:
058561cbaa119a6f2659bc27ef343e1b47266bb2jbeck** tm -- maximum execution time for a thread
058561cbaa119a6f2659bc27ef343e1b47266bb2jbeck**
058561cbaa119a6f2659bc27ef343e1b47266bb2jbeck** Returns:
058561cbaa119a6f2659bc27ef343e1b47266bb2jbeck** MI_SUCCESS
058561cbaa119a6f2659bc27ef343e1b47266bb2jbeck*/
058561cbaa119a6f2659bc27ef343e1b47266bb2jbeck
058561cbaa119a6f2659bc27ef343e1b47266bb2jbeckint
058561cbaa119a6f2659bc27ef343e1b47266bb2jbecksmfi_set_max_exec_time(tm)
058561cbaa119a6f2659bc27ef343e1b47266bb2jbeck unsigned int tm;
058561cbaa119a6f2659bc27ef343e1b47266bb2jbeck{
058561cbaa119a6f2659bc27ef343e1b47266bb2jbeck Mon_exec_time = tm;
058561cbaa119a6f2659bc27ef343e1b47266bb2jbeck return MI_SUCCESS;
058561cbaa119a6f2659bc27ef343e1b47266bb2jbeck}
058561cbaa119a6f2659bc27ef343e1b47266bb2jbeck
058561cbaa119a6f2659bc27ef343e1b47266bb2jbeck/*
058561cbaa119a6f2659bc27ef343e1b47266bb2jbeck** MI_MONITOR_THREAD -- monitoring thread
058561cbaa119a6f2659bc27ef343e1b47266bb2jbeck**
058561cbaa119a6f2659bc27ef343e1b47266bb2jbeck** Parameters:
058561cbaa119a6f2659bc27ef343e1b47266bb2jbeck** arg -- ignored (required by pthread_create())
058561cbaa119a6f2659bc27ef343e1b47266bb2jbeck**
058561cbaa119a6f2659bc27ef343e1b47266bb2jbeck** Returns:
058561cbaa119a6f2659bc27ef343e1b47266bb2jbeck** NULL on termination.
058561cbaa119a6f2659bc27ef343e1b47266bb2jbeck*/
058561cbaa119a6f2659bc27ef343e1b47266bb2jbeck
058561cbaa119a6f2659bc27ef343e1b47266bb2jbeckstatic void *
058561cbaa119a6f2659bc27ef343e1b47266bb2jbeckmi_monitor_thread(arg)
058561cbaa119a6f2659bc27ef343e1b47266bb2jbeck void *arg;
058561cbaa119a6f2659bc27ef343e1b47266bb2jbeck{
058561cbaa119a6f2659bc27ef343e1b47266bb2jbeck sthread_t tid;
058561cbaa119a6f2659bc27ef343e1b47266bb2jbeck int r;
058561cbaa119a6f2659bc27ef343e1b47266bb2jbeck time_t now, end;
058561cbaa119a6f2659bc27ef343e1b47266bb2jbeck
058561cbaa119a6f2659bc27ef343e1b47266bb2jbeck SM_ASSERT(Monitor);
058561cbaa119a6f2659bc27ef343e1b47266bb2jbeck SM_ASSERT(Mon_exec_time > 0);
058561cbaa119a6f2659bc27ef343e1b47266bb2jbeck tid = (sthread_t) sthread_get_id();
058561cbaa119a6f2659bc27ef343e1b47266bb2jbeck if (pthread_detach(tid) != 0)
058561cbaa119a6f2659bc27ef343e1b47266bb2jbeck {
058561cbaa119a6f2659bc27ef343e1b47266bb2jbeck /* log an error */
058561cbaa119a6f2659bc27ef343e1b47266bb2jbeck return (void *)1;
058561cbaa119a6f2659bc27ef343e1b47266bb2jbeck }
058561cbaa119a6f2659bc27ef343e1b47266bb2jbeck
058561cbaa119a6f2659bc27ef343e1b47266bb2jbeck/*
058561cbaa119a6f2659bc27ef343e1b47266bb2jbeck** NOTE: this is "flow through" code,
058561cbaa119a6f2659bc27ef343e1b47266bb2jbeck** do NOT use do { } while ("break" is used here!)
058561cbaa119a6f2659bc27ef343e1b47266bb2jbeck*/
058561cbaa119a6f2659bc27ef343e1b47266bb2jbeck
058561cbaa119a6f2659bc27ef343e1b47266bb2jbeck#define MON_CHK_STOP \
058561cbaa119a6f2659bc27ef343e1b47266bb2jbeck now = time(NULL); \
058561cbaa119a6f2659bc27ef343e1b47266bb2jbeck end = Mon_cur_ctx->ctx_start + Mon_exec_time; \
058561cbaa119a6f2659bc27ef343e1b47266bb2jbeck if (now > end) \
058561cbaa119a6f2659bc27ef343e1b47266bb2jbeck { \
058561cbaa119a6f2659bc27ef343e1b47266bb2jbeck smi_log(SMI_LOG_ERR, \
058561cbaa119a6f2659bc27ef343e1b47266bb2jbeck "WARNING: monitor timeout triggered, now=%ld, end=%ld, tid=%ld, state=0x%x",\
058561cbaa119a6f2659bc27ef343e1b47266bb2jbeck (long) now, (long) end, \
058561cbaa119a6f2659bc27ef343e1b47266bb2jbeck (long) Mon_cur_ctx->ctx_id, Mon_cur_ctx->ctx_state);\
058561cbaa119a6f2659bc27ef343e1b47266bb2jbeck mi_stop_milters(MILTER_STOP); \
058561cbaa119a6f2659bc27ef343e1b47266bb2jbeck break; \
058561cbaa119a6f2659bc27ef343e1b47266bb2jbeck }
058561cbaa119a6f2659bc27ef343e1b47266bb2jbeck
058561cbaa119a6f2659bc27ef343e1b47266bb2jbeck (void) smutex_lock(&Mon_mutex);
058561cbaa119a6f2659bc27ef343e1b47266bb2jbeck while (mi_stop() == MILTER_CONT)
058561cbaa119a6f2659bc27ef343e1b47266bb2jbeck {
058561cbaa119a6f2659bc27ef343e1b47266bb2jbeck if (Mon_cur_ctx != NULL && Mon_cur_ctx->ctx_start > 0)
058561cbaa119a6f2659bc27ef343e1b47266bb2jbeck {
058561cbaa119a6f2659bc27ef343e1b47266bb2jbeck struct timespec abstime;
058561cbaa119a6f2659bc27ef343e1b47266bb2jbeck
058561cbaa119a6f2659bc27ef343e1b47266bb2jbeck MON_CHK_STOP;
058561cbaa119a6f2659bc27ef343e1b47266bb2jbeck abstime.tv_sec = end;
058561cbaa119a6f2659bc27ef343e1b47266bb2jbeck abstime.tv_nsec = 0;
058561cbaa119a6f2659bc27ef343e1b47266bb2jbeck r = pthread_cond_timedwait(&Mon_cv, &Mon_mutex,
058561cbaa119a6f2659bc27ef343e1b47266bb2jbeck &abstime);
058561cbaa119a6f2659bc27ef343e1b47266bb2jbeck }
058561cbaa119a6f2659bc27ef343e1b47266bb2jbeck else
058561cbaa119a6f2659bc27ef343e1b47266bb2jbeck r = pthread_cond_wait(&Mon_cv, &Mon_mutex);
058561cbaa119a6f2659bc27ef343e1b47266bb2jbeck if (mi_stop() != MILTER_CONT)
058561cbaa119a6f2659bc27ef343e1b47266bb2jbeck break;
058561cbaa119a6f2659bc27ef343e1b47266bb2jbeck if (Mon_cur_ctx != NULL && Mon_cur_ctx->ctx_start > 0)
058561cbaa119a6f2659bc27ef343e1b47266bb2jbeck {
058561cbaa119a6f2659bc27ef343e1b47266bb2jbeck MON_CHK_STOP;
058561cbaa119a6f2659bc27ef343e1b47266bb2jbeck }
058561cbaa119a6f2659bc27ef343e1b47266bb2jbeck }
058561cbaa119a6f2659bc27ef343e1b47266bb2jbeck (void) smutex_unlock(&Mon_mutex);
058561cbaa119a6f2659bc27ef343e1b47266bb2jbeck
058561cbaa119a6f2659bc27ef343e1b47266bb2jbeck return NULL;
058561cbaa119a6f2659bc27ef343e1b47266bb2jbeck}
058561cbaa119a6f2659bc27ef343e1b47266bb2jbeck
058561cbaa119a6f2659bc27ef343e1b47266bb2jbeck/*
058561cbaa119a6f2659bc27ef343e1b47266bb2jbeck** MI_MONITOR_INIT -- initialize monitoring thread
058561cbaa119a6f2659bc27ef343e1b47266bb2jbeck**
058561cbaa119a6f2659bc27ef343e1b47266bb2jbeck** Parameters: none
058561cbaa119a6f2659bc27ef343e1b47266bb2jbeck**
058561cbaa119a6f2659bc27ef343e1b47266bb2jbeck** Returns:
058561cbaa119a6f2659bc27ef343e1b47266bb2jbeck** MI_SUCCESS/MI_FAILURE
058561cbaa119a6f2659bc27ef343e1b47266bb2jbeck*/
058561cbaa119a6f2659bc27ef343e1b47266bb2jbeck
058561cbaa119a6f2659bc27ef343e1b47266bb2jbeckint
058561cbaa119a6f2659bc27ef343e1b47266bb2jbeckmi_monitor_init()
058561cbaa119a6f2659bc27ef343e1b47266bb2jbeck{
058561cbaa119a6f2659bc27ef343e1b47266bb2jbeck int r;
058561cbaa119a6f2659bc27ef343e1b47266bb2jbeck sthread_t tid;
058561cbaa119a6f2659bc27ef343e1b47266bb2jbeck
058561cbaa119a6f2659bc27ef343e1b47266bb2jbeck SM_ASSERT(!Monitor);
058561cbaa119a6f2659bc27ef343e1b47266bb2jbeck if (Mon_exec_time <= 0)
058561cbaa119a6f2659bc27ef343e1b47266bb2jbeck return MI_SUCCESS;
058561cbaa119a6f2659bc27ef343e1b47266bb2jbeck Monitor = true;
058561cbaa119a6f2659bc27ef343e1b47266bb2jbeck if (!smutex_init(&Mon_mutex))
058561cbaa119a6f2659bc27ef343e1b47266bb2jbeck return MI_FAILURE;
058561cbaa119a6f2659bc27ef343e1b47266bb2jbeck if (scond_init(&Mon_cv) != 0)
058561cbaa119a6f2659bc27ef343e1b47266bb2jbeck return MI_FAILURE;
058561cbaa119a6f2659bc27ef343e1b47266bb2jbeck SM_TAILQ_INIT(&Mon_ctx_head);
058561cbaa119a6f2659bc27ef343e1b47266bb2jbeck
058561cbaa119a6f2659bc27ef343e1b47266bb2jbeck r = thread_create(&tid, mi_monitor_thread, (void *)NULL);
058561cbaa119a6f2659bc27ef343e1b47266bb2jbeck if (r != 0)
058561cbaa119a6f2659bc27ef343e1b47266bb2jbeck return r;
058561cbaa119a6f2659bc27ef343e1b47266bb2jbeck return MI_SUCCESS;
058561cbaa119a6f2659bc27ef343e1b47266bb2jbeck}
058561cbaa119a6f2659bc27ef343e1b47266bb2jbeck
058561cbaa119a6f2659bc27ef343e1b47266bb2jbeck/*
058561cbaa119a6f2659bc27ef343e1b47266bb2jbeck** MI_MONITOR_WORK_BEGIN -- record start of thread execution
058561cbaa119a6f2659bc27ef343e1b47266bb2jbeck**
058561cbaa119a6f2659bc27ef343e1b47266bb2jbeck** Parameters:
058561cbaa119a6f2659bc27ef343e1b47266bb2jbeck** ctx -- session context
058561cbaa119a6f2659bc27ef343e1b47266bb2jbeck** cmd -- milter command char
058561cbaa119a6f2659bc27ef343e1b47266bb2jbeck**
058561cbaa119a6f2659bc27ef343e1b47266bb2jbeck** Returns:
058561cbaa119a6f2659bc27ef343e1b47266bb2jbeck** 0
058561cbaa119a6f2659bc27ef343e1b47266bb2jbeck*/
058561cbaa119a6f2659bc27ef343e1b47266bb2jbeck
058561cbaa119a6f2659bc27ef343e1b47266bb2jbeckint
058561cbaa119a6f2659bc27ef343e1b47266bb2jbeckmi_monitor_work_begin(ctx, cmd)
058561cbaa119a6f2659bc27ef343e1b47266bb2jbeck SMFICTX_PTR ctx;
058561cbaa119a6f2659bc27ef343e1b47266bb2jbeck int cmd;
058561cbaa119a6f2659bc27ef343e1b47266bb2jbeck{
058561cbaa119a6f2659bc27ef343e1b47266bb2jbeck (void) smutex_lock(&Mon_mutex);
058561cbaa119a6f2659bc27ef343e1b47266bb2jbeck if (NULL == Mon_cur_ctx)
058561cbaa119a6f2659bc27ef343e1b47266bb2jbeck {
058561cbaa119a6f2659bc27ef343e1b47266bb2jbeck Mon_cur_ctx = ctx;
058561cbaa119a6f2659bc27ef343e1b47266bb2jbeck (void) scond_signal(&Mon_cv);
058561cbaa119a6f2659bc27ef343e1b47266bb2jbeck }
058561cbaa119a6f2659bc27ef343e1b47266bb2jbeck ctx->ctx_start = time(NULL);
058561cbaa119a6f2659bc27ef343e1b47266bb2jbeck SM_TAILQ_INSERT_TAIL(&Mon_ctx_head, ctx, ctx_mon_link);
058561cbaa119a6f2659bc27ef343e1b47266bb2jbeck (void) smutex_unlock(&Mon_mutex);
058561cbaa119a6f2659bc27ef343e1b47266bb2jbeck return 0;
058561cbaa119a6f2659bc27ef343e1b47266bb2jbeck}
058561cbaa119a6f2659bc27ef343e1b47266bb2jbeck
058561cbaa119a6f2659bc27ef343e1b47266bb2jbeck/*
058561cbaa119a6f2659bc27ef343e1b47266bb2jbeck** MI_MONITOR_WORK_END -- record end of thread execution
058561cbaa119a6f2659bc27ef343e1b47266bb2jbeck**
058561cbaa119a6f2659bc27ef343e1b47266bb2jbeck** Parameters:
058561cbaa119a6f2659bc27ef343e1b47266bb2jbeck** ctx -- session context
058561cbaa119a6f2659bc27ef343e1b47266bb2jbeck** cmd -- milter command char
058561cbaa119a6f2659bc27ef343e1b47266bb2jbeck**
058561cbaa119a6f2659bc27ef343e1b47266bb2jbeck** Returns:
058561cbaa119a6f2659bc27ef343e1b47266bb2jbeck** 0
058561cbaa119a6f2659bc27ef343e1b47266bb2jbeck*/
058561cbaa119a6f2659bc27ef343e1b47266bb2jbeck
058561cbaa119a6f2659bc27ef343e1b47266bb2jbeckint
058561cbaa119a6f2659bc27ef343e1b47266bb2jbeckmi_monitor_work_end(ctx, cmd)
058561cbaa119a6f2659bc27ef343e1b47266bb2jbeck SMFICTX_PTR ctx;
058561cbaa119a6f2659bc27ef343e1b47266bb2jbeck int cmd;
058561cbaa119a6f2659bc27ef343e1b47266bb2jbeck{
058561cbaa119a6f2659bc27ef343e1b47266bb2jbeck (void) smutex_lock(&Mon_mutex);
058561cbaa119a6f2659bc27ef343e1b47266bb2jbeck ctx->ctx_start = 0;
058561cbaa119a6f2659bc27ef343e1b47266bb2jbeck SM_TAILQ_REMOVE(&Mon_ctx_head, ctx, ctx_mon_link);
058561cbaa119a6f2659bc27ef343e1b47266bb2jbeck if (Mon_cur_ctx == ctx)
058561cbaa119a6f2659bc27ef343e1b47266bb2jbeck {
058561cbaa119a6f2659bc27ef343e1b47266bb2jbeck if (SM_TAILQ_EMPTY(&Mon_ctx_head))
058561cbaa119a6f2659bc27ef343e1b47266bb2jbeck Mon_cur_ctx = NULL;
058561cbaa119a6f2659bc27ef343e1b47266bb2jbeck else
058561cbaa119a6f2659bc27ef343e1b47266bb2jbeck Mon_cur_ctx = SM_TAILQ_FIRST(&Mon_ctx_head);
058561cbaa119a6f2659bc27ef343e1b47266bb2jbeck }
058561cbaa119a6f2659bc27ef343e1b47266bb2jbeck (void) smutex_unlock(&Mon_mutex);
058561cbaa119a6f2659bc27ef343e1b47266bb2jbeck return 0;
058561cbaa119a6f2659bc27ef343e1b47266bb2jbeck}
058561cbaa119a6f2659bc27ef343e1b47266bb2jbeck#endif /* _FFR_THREAD_MONITOR */