monitor.c revision 168515
1168515Sgshapiro/* 2168515Sgshapiro * Copyright (c) 2006 Sendmail, Inc. and its suppliers. 3168515Sgshapiro * All rights reserved. 4168515Sgshapiro * 5168515Sgshapiro * By using this file, you agree to the terms and conditions set 6168515Sgshapiro * forth in the LICENSE file which can be found at the top level of 7168515Sgshapiro * the sendmail distribution. 8168515Sgshapiro * 9168515Sgshapiro */ 10168515Sgshapiro 11168515Sgshapiro#include "libmilter.h" 12168515Sgshapiro 13168515Sgshapiro#if _FFR_THREAD_MONITOR 14168515Sgshapiro 15168515Sgshapiro/* 16168515Sgshapiro** Thread Monitoring 17168515Sgshapiro** Todo: more error checking (return code from function calls) 18168515Sgshapiro** add comments. 19168515Sgshapiro*/ 20168515Sgshapiro 21168515Sgshapirobool Monitor = false; /* use monitoring? */ 22168515Sgshapirostatic unsigned int Mon_exec_time = 0; 23168515Sgshapiro 24168515Sgshapiro/* mutex protects Mon_cur_ctx, Mon_ctx_head, and ctx_start */ 25168515Sgshapirostatic smutex_t Mon_mutex; 26168515Sgshapirostatic scond_t Mon_cv; 27168515Sgshapiro 28168515Sgshapiro/* 29168515Sgshapiro** Current ctx to monitor. 30168515Sgshapiro** Invariant: 31168515Sgshapiro** Mon_cur_ctx == NULL || Mon_cur_ctx is thread which was started the longest 32168515Sgshapiro** time ago. 33168515Sgshapiro** 34168515Sgshapiro** Basically the entries in the list are ordered by time because new 35168515Sgshapiro** entries are appended at the end. However, due to the concurrent 36168515Sgshapiro** execution (multi-threaded) and no guaranteed order of wakeups 37168515Sgshapiro** after a mutex_lock() attempt, the order might not be strict, 38168515Sgshapiro** i.e., if the list contains e1 and e2 (in that order) then 39168515Sgshapiro** the the start time of e2 can be (slightly) smaller than that of e1. 40168515Sgshapiro** However, this slight inaccurracy should not matter for the proper 41168515Sgshapiro** working of this algorithm. 42168515Sgshapiro*/ 43168515Sgshapiro 44168515Sgshapirostatic SMFICTX_PTR Mon_cur_ctx = NULL; 45168515Sgshapirostatic smfi_hd_T Mon_ctx_head; /* head of the linked list of active contexts */ 46168515Sgshapiro 47168515Sgshapiro/* 48168515Sgshapiro** SMFI_SET_MAX_EXEC_TIME -- set maximum execution time for a thread 49168515Sgshapiro** 50168515Sgshapiro** Parameters: 51168515Sgshapiro** tm -- maximum execution time for a thread 52168515Sgshapiro** 53168515Sgshapiro** Returns: 54168515Sgshapiro** MI_SUCCESS 55168515Sgshapiro*/ 56168515Sgshapiro 57168515Sgshapiroint 58168515Sgshapirosmfi_set_max_exec_time(tm) 59168515Sgshapiro unsigned int tm; 60168515Sgshapiro{ 61168515Sgshapiro Mon_exec_time = tm; 62168515Sgshapiro return MI_SUCCESS; 63168515Sgshapiro} 64168515Sgshapiro 65168515Sgshapiro/* 66168515Sgshapiro** MI_MONITOR_THREAD -- monitoring thread 67168515Sgshapiro** 68168515Sgshapiro** Parameters: 69168515Sgshapiro** arg -- ignored (required by pthread_create()) 70168515Sgshapiro** 71168515Sgshapiro** Returns: 72168515Sgshapiro** NULL on termination. 73168515Sgshapiro*/ 74168515Sgshapiro 75168515Sgshapirostatic void * 76168515Sgshapiromi_monitor_thread(arg) 77168515Sgshapiro void *arg; 78168515Sgshapiro{ 79168515Sgshapiro sthread_t tid; 80168515Sgshapiro int r; 81168515Sgshapiro time_t now, end; 82168515Sgshapiro 83168515Sgshapiro SM_ASSERT(Monitor); 84168515Sgshapiro SM_ASSERT(Mon_exec_time > 0); 85168515Sgshapiro tid = (sthread_t) sthread_get_id(); 86168515Sgshapiro if (pthread_detach(tid) != 0) 87168515Sgshapiro { 88168515Sgshapiro /* log an error */ 89168515Sgshapiro return (void *)1; 90168515Sgshapiro } 91168515Sgshapiro 92168515Sgshapiro/* 93168515Sgshapiro** NOTE: this is "flow through" code, 94168515Sgshapiro** do NOT use do { } while ("break" is used here!) 95168515Sgshapiro*/ 96168515Sgshapiro 97168515Sgshapiro#define MON_CHK_STOP \ 98168515Sgshapiro now = time(NULL); \ 99168515Sgshapiro end = Mon_cur_ctx->ctx_start + Mon_exec_time; \ 100168515Sgshapiro if (now > end) \ 101168515Sgshapiro { \ 102168515Sgshapiro smi_log(SMI_LOG_ERR, \ 103168515Sgshapiro "WARNING: monitor timeout triggered, now=%ld, end=%ld, tid=%ld, state=0x%x",\ 104168515Sgshapiro (long) now, (long) end, \ 105168515Sgshapiro (long) Mon_cur_ctx->ctx_id, Mon_cur_ctx->ctx_state);\ 106168515Sgshapiro mi_stop_milters(MILTER_STOP); \ 107168515Sgshapiro break; \ 108168515Sgshapiro } 109168515Sgshapiro 110168515Sgshapiro (void) smutex_lock(&Mon_mutex); 111168515Sgshapiro while (mi_stop() == MILTER_CONT) 112168515Sgshapiro { 113168515Sgshapiro if (Mon_cur_ctx != NULL && Mon_cur_ctx->ctx_start > 0) 114168515Sgshapiro { 115168515Sgshapiro struct timespec abstime; 116168515Sgshapiro 117168515Sgshapiro MON_CHK_STOP; 118168515Sgshapiro abstime.tv_sec = end; 119168515Sgshapiro abstime.tv_nsec = 0; 120168515Sgshapiro r = pthread_cond_timedwait(&Mon_cv, &Mon_mutex, 121168515Sgshapiro &abstime); 122168515Sgshapiro } 123168515Sgshapiro else 124168515Sgshapiro r = pthread_cond_wait(&Mon_cv, &Mon_mutex); 125168515Sgshapiro if (mi_stop() != MILTER_CONT) 126168515Sgshapiro break; 127168515Sgshapiro if (Mon_cur_ctx != NULL && Mon_cur_ctx->ctx_start > 0) 128168515Sgshapiro { 129168515Sgshapiro MON_CHK_STOP; 130168515Sgshapiro } 131168515Sgshapiro } 132168515Sgshapiro (void) smutex_unlock(&Mon_mutex); 133168515Sgshapiro 134168515Sgshapiro return NULL; 135168515Sgshapiro} 136168515Sgshapiro 137168515Sgshapiro/* 138168515Sgshapiro** MI_MONITOR_INIT -- initialize monitoring thread 139168515Sgshapiro** 140168515Sgshapiro** Parameters: none 141168515Sgshapiro** 142168515Sgshapiro** Returns: 143168515Sgshapiro** MI_SUCCESS/MI_FAILURE 144168515Sgshapiro*/ 145168515Sgshapiro 146168515Sgshapiroint 147168515Sgshapiromi_monitor_init() 148168515Sgshapiro{ 149168515Sgshapiro int r; 150168515Sgshapiro sthread_t tid; 151168515Sgshapiro 152168515Sgshapiro SM_ASSERT(!Monitor); 153168515Sgshapiro if (Mon_exec_time <= 0) 154168515Sgshapiro return MI_SUCCESS; 155168515Sgshapiro Monitor = true; 156168515Sgshapiro if (!smutex_init(&Mon_mutex)) 157168515Sgshapiro return MI_FAILURE; 158168515Sgshapiro if (scond_init(&Mon_cv) != 0) 159168515Sgshapiro return MI_FAILURE; 160168515Sgshapiro SM_TAILQ_INIT(&Mon_ctx_head); 161168515Sgshapiro 162168515Sgshapiro r = thread_create(&tid, mi_monitor_thread, (void *)NULL); 163168515Sgshapiro if (r != 0) 164168515Sgshapiro return r; 165168515Sgshapiro return MI_SUCCESS; 166168515Sgshapiro} 167168515Sgshapiro 168168515Sgshapiro/* 169168515Sgshapiro** MI_MONITOR_WORK_BEGIN -- record start of thread execution 170168515Sgshapiro** 171168515Sgshapiro** Parameters: 172168515Sgshapiro** ctx -- session context 173168515Sgshapiro** cmd -- milter command char 174168515Sgshapiro** 175168515Sgshapiro** Returns: 176168515Sgshapiro** 0 177168515Sgshapiro*/ 178168515Sgshapiro 179168515Sgshapiroint 180168515Sgshapiromi_monitor_work_begin(ctx, cmd) 181168515Sgshapiro SMFICTX_PTR ctx; 182168515Sgshapiro int cmd; 183168515Sgshapiro{ 184168515Sgshapiro (void) smutex_lock(&Mon_mutex); 185168515Sgshapiro if (NULL == Mon_cur_ctx) 186168515Sgshapiro { 187168515Sgshapiro Mon_cur_ctx = ctx; 188168515Sgshapiro (void) scond_signal(&Mon_cv); 189168515Sgshapiro } 190168515Sgshapiro ctx->ctx_start = time(NULL); 191168515Sgshapiro SM_TAILQ_INSERT_TAIL(&Mon_ctx_head, ctx, ctx_mon_link); 192168515Sgshapiro (void) smutex_unlock(&Mon_mutex); 193168515Sgshapiro return 0; 194168515Sgshapiro} 195168515Sgshapiro 196168515Sgshapiro/* 197168515Sgshapiro** MI_MONITOR_WORK_END -- record end of thread execution 198168515Sgshapiro** 199168515Sgshapiro** Parameters: 200168515Sgshapiro** ctx -- session context 201168515Sgshapiro** cmd -- milter command char 202168515Sgshapiro** 203168515Sgshapiro** Returns: 204168515Sgshapiro** 0 205168515Sgshapiro*/ 206168515Sgshapiro 207168515Sgshapiroint 208168515Sgshapiromi_monitor_work_end(ctx, cmd) 209168515Sgshapiro SMFICTX_PTR ctx; 210168515Sgshapiro int cmd; 211168515Sgshapiro{ 212168515Sgshapiro (void) smutex_lock(&Mon_mutex); 213168515Sgshapiro ctx->ctx_start = 0; 214168515Sgshapiro SM_TAILQ_REMOVE(&Mon_ctx_head, ctx, ctx_mon_link); 215168515Sgshapiro if (Mon_cur_ctx == ctx) 216168515Sgshapiro { 217168515Sgshapiro if (SM_TAILQ_EMPTY(&Mon_ctx_head)) 218168515Sgshapiro Mon_cur_ctx = NULL; 219168515Sgshapiro else 220168515Sgshapiro Mon_cur_ctx = SM_TAILQ_FIRST(&Mon_ctx_head); 221168515Sgshapiro } 222168515Sgshapiro (void) smutex_unlock(&Mon_mutex); 223168515Sgshapiro return 0; 224168515Sgshapiro} 225168515Sgshapiro#endif /* _FFR_THREAD_MONITOR */ 226