2 * Copyright (c) 2006 Sendmail, Inc. and its suppliers.
5 * By using this file, you agree to the terms and conditions set
6 * forth in the LICENSE file which can be found at the top level of
7 * the sendmail distribution.
12 SM_RCSID("@(#)$Id: monitor.c,v 8.7 2007/04/23 16:26:28 ca Exp $")
13 #include "libmilter.h"
15 #if _FFR_THREAD_MONITOR
19 ** Todo: more error checking (return code from function calls)
23 bool Monitor
= false; /* use monitoring? */
24 static unsigned int Mon_exec_time
= 0;
26 /* mutex protects Mon_cur_ctx, Mon_ctx_head, and ctx_start */
27 static smutex_t Mon_mutex
;
28 static scond_t Mon_cv
;
31 ** Current ctx to monitor.
33 ** Mon_cur_ctx == NULL || Mon_cur_ctx is thread which was started the longest
36 ** Basically the entries in the list are ordered by time because new
37 ** entries are appended at the end. However, due to the concurrent
38 ** execution (multi-threaded) and no guaranteed order of wakeups
39 ** after a mutex_lock() attempt, the order might not be strict,
40 ** i.e., if the list contains e1 and e2 (in that order) then
41 ** the the start time of e2 can be (slightly) smaller than that of e1.
42 ** However, this slight inaccurracy should not matter for the proper
43 ** working of this algorithm.
46 static SMFICTX_PTR Mon_cur_ctx
= NULL
;
47 static smfi_hd_T Mon_ctx_head
; /* head of the linked list of active contexts */
50 ** SMFI_SET_MAX_EXEC_TIME -- set maximum execution time for a thread
53 ** tm -- maximum execution time for a thread
60 smfi_set_max_exec_time(tm
)
68 ** MI_MONITOR_THREAD -- monitoring thread
71 ** arg -- ignored (required by pthread_create())
74 ** NULL on termination.
78 mi_monitor_thread(arg
)
86 SM_ASSERT(Mon_exec_time
> 0);
87 tid
= (sthread_t
) sthread_get_id();
88 if (pthread_detach(tid
) != 0)
95 ** NOTE: this is "flow through" code,
96 ** do NOT use do { } while ("break" is used here!)
99 #define MON_CHK_STOP \
101 end = Mon_cur_ctx->ctx_start + Mon_exec_time; \
104 smi_log(SMI_LOG_ERR, \
105 "WARNING: monitor timeout triggered, now=%ld, end=%ld, tid=%ld, state=0x%x",\
106 (long) now, (long) end, \
107 (long) Mon_cur_ctx->ctx_id, Mon_cur_ctx->ctx_state);\
108 mi_stop_milters(MILTER_STOP); \
112 (void) smutex_lock(&Mon_mutex
);
113 while (mi_stop() == MILTER_CONT
)
115 if (Mon_cur_ctx
!= NULL
&& Mon_cur_ctx
->ctx_start
> 0)
117 struct timespec abstime
;
120 abstime
.tv_sec
= end
;
122 r
= pthread_cond_timedwait(&Mon_cv
, &Mon_mutex
,
126 r
= pthread_cond_wait(&Mon_cv
, &Mon_mutex
);
127 if (mi_stop() != MILTER_CONT
)
129 if (Mon_cur_ctx
!= NULL
&& Mon_cur_ctx
->ctx_start
> 0)
134 (void) smutex_unlock(&Mon_mutex
);
140 ** MI_MONITOR_INIT -- initialize monitoring thread
145 ** MI_SUCCESS/MI_FAILURE
155 if (Mon_exec_time
<= 0)
158 if (!smutex_init(&Mon_mutex
))
160 if (scond_init(&Mon_cv
) != 0)
162 SM_TAILQ_INIT(&Mon_ctx_head
);
164 r
= thread_create(&tid
, mi_monitor_thread
, (void *)NULL
);
171 ** MI_MONITOR_WORK_BEGIN -- record start of thread execution
174 ** ctx -- session context
175 ** cmd -- milter command char
182 mi_monitor_work_begin(ctx
, cmd
)
186 (void) smutex_lock(&Mon_mutex
);
187 if (NULL
== Mon_cur_ctx
)
190 (void) scond_signal(&Mon_cv
);
192 ctx
->ctx_start
= time(NULL
);
193 SM_TAILQ_INSERT_TAIL(&Mon_ctx_head
, ctx
, ctx_mon_link
);
194 (void) smutex_unlock(&Mon_mutex
);
199 ** MI_MONITOR_WORK_END -- record end of thread execution
202 ** ctx -- session context
203 ** cmd -- milter command char
210 mi_monitor_work_end(ctx
, cmd
)
214 (void) smutex_lock(&Mon_mutex
);
216 SM_TAILQ_REMOVE(&Mon_ctx_head
, ctx
, ctx_mon_link
);
217 if (Mon_cur_ctx
== ctx
)
219 if (SM_TAILQ_EMPTY(&Mon_ctx_head
))
222 Mon_cur_ctx
= SM_TAILQ_FIRST(&Mon_ctx_head
);
224 (void) smutex_unlock(&Mon_mutex
);
227 #endif /* _FFR_THREAD_MONITOR */