8322 nl: misleading-indentation
[unleashed/tickless.git] / usr / src / cmd / sendmail / libmilter / monitor.c
blobb73a4b9ef235b7efdbf7d00d2dd4e23f5b2b9f93
1 /*
2 * Copyright (c) 2006 Sendmail, Inc. and its suppliers.
3 * All rights reserved.
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.
9 */
11 #pragma ident "%Z%%M% %I% %E% SMI"
13 #include <sm/gen.h>
14 SM_RCSID("@(#)$Id: monitor.c,v 8.7 2007/04/23 16:26:28 ca Exp $")
15 #include "libmilter.h"
17 #if _FFR_THREAD_MONITOR
20 ** Thread Monitoring
21 ** Todo: more error checking (return code from function calls)
22 ** add comments.
25 bool Monitor = false; /* use monitoring? */
26 static unsigned int Mon_exec_time = 0;
28 /* mutex protects Mon_cur_ctx, Mon_ctx_head, and ctx_start */
29 static smutex_t Mon_mutex;
30 static scond_t Mon_cv;
33 ** Current ctx to monitor.
34 ** Invariant:
35 ** Mon_cur_ctx == NULL || Mon_cur_ctx is thread which was started the longest
36 ** time ago.
38 ** Basically the entries in the list are ordered by time because new
39 ** entries are appended at the end. However, due to the concurrent
40 ** execution (multi-threaded) and no guaranteed order of wakeups
41 ** after a mutex_lock() attempt, the order might not be strict,
42 ** i.e., if the list contains e1 and e2 (in that order) then
43 ** the the start time of e2 can be (slightly) smaller than that of e1.
44 ** However, this slight inaccurracy should not matter for the proper
45 ** working of this algorithm.
48 static SMFICTX_PTR Mon_cur_ctx = NULL;
49 static smfi_hd_T Mon_ctx_head; /* head of the linked list of active contexts */
52 ** SMFI_SET_MAX_EXEC_TIME -- set maximum execution time for a thread
54 ** Parameters:
55 ** tm -- maximum execution time for a thread
57 ** Returns:
58 ** MI_SUCCESS
61 int
62 smfi_set_max_exec_time(tm)
63 unsigned int tm;
65 Mon_exec_time = tm;
66 return MI_SUCCESS;
70 ** MI_MONITOR_THREAD -- monitoring thread
72 ** Parameters:
73 ** arg -- ignored (required by pthread_create())
75 ** Returns:
76 ** NULL on termination.
79 static void *
80 mi_monitor_thread(arg)
81 void *arg;
83 sthread_t tid;
84 int r;
85 time_t now, end;
87 SM_ASSERT(Monitor);
88 SM_ASSERT(Mon_exec_time > 0);
89 tid = (sthread_t) sthread_get_id();
90 if (pthread_detach(tid) != 0)
92 /* log an error */
93 return (void *)1;
97 ** NOTE: this is "flow through" code,
98 ** do NOT use do { } while ("break" is used here!)
101 #define MON_CHK_STOP \
102 now = time(NULL); \
103 end = Mon_cur_ctx->ctx_start + Mon_exec_time; \
104 if (now > end) \
106 smi_log(SMI_LOG_ERR, \
107 "WARNING: monitor timeout triggered, now=%ld, end=%ld, tid=%ld, state=0x%x",\
108 (long) now, (long) end, \
109 (long) Mon_cur_ctx->ctx_id, Mon_cur_ctx->ctx_state);\
110 mi_stop_milters(MILTER_STOP); \
111 break; \
114 (void) smutex_lock(&Mon_mutex);
115 while (mi_stop() == MILTER_CONT)
117 if (Mon_cur_ctx != NULL && Mon_cur_ctx->ctx_start > 0)
119 struct timespec abstime;
121 MON_CHK_STOP;
122 abstime.tv_sec = end;
123 abstime.tv_nsec = 0;
124 r = pthread_cond_timedwait(&Mon_cv, &Mon_mutex,
125 &abstime);
127 else
128 r = pthread_cond_wait(&Mon_cv, &Mon_mutex);
129 if (mi_stop() != MILTER_CONT)
130 break;
131 if (Mon_cur_ctx != NULL && Mon_cur_ctx->ctx_start > 0)
133 MON_CHK_STOP;
136 (void) smutex_unlock(&Mon_mutex);
138 return NULL;
142 ** MI_MONITOR_INIT -- initialize monitoring thread
144 ** Parameters: none
146 ** Returns:
147 ** MI_SUCCESS/MI_FAILURE
151 mi_monitor_init()
153 int r;
154 sthread_t tid;
156 SM_ASSERT(!Monitor);
157 if (Mon_exec_time <= 0)
158 return MI_SUCCESS;
159 Monitor = true;
160 if (!smutex_init(&Mon_mutex))
161 return MI_FAILURE;
162 if (scond_init(&Mon_cv) != 0)
163 return MI_FAILURE;
164 SM_TAILQ_INIT(&Mon_ctx_head);
166 r = thread_create(&tid, mi_monitor_thread, (void *)NULL);
167 if (r != 0)
168 return r;
169 return MI_SUCCESS;
173 ** MI_MONITOR_WORK_BEGIN -- record start of thread execution
175 ** Parameters:
176 ** ctx -- session context
177 ** cmd -- milter command char
179 ** Returns:
180 ** 0
184 mi_monitor_work_begin(ctx, cmd)
185 SMFICTX_PTR ctx;
186 int cmd;
188 (void) smutex_lock(&Mon_mutex);
189 if (NULL == Mon_cur_ctx)
191 Mon_cur_ctx = ctx;
192 (void) scond_signal(&Mon_cv);
194 ctx->ctx_start = time(NULL);
195 SM_TAILQ_INSERT_TAIL(&Mon_ctx_head, ctx, ctx_mon_link);
196 (void) smutex_unlock(&Mon_mutex);
197 return 0;
201 ** MI_MONITOR_WORK_END -- record end of thread execution
203 ** Parameters:
204 ** ctx -- session context
205 ** cmd -- milter command char
207 ** Returns:
208 ** 0
212 mi_monitor_work_end(ctx, cmd)
213 SMFICTX_PTR ctx;
214 int cmd;
216 (void) smutex_lock(&Mon_mutex);
217 ctx->ctx_start = 0;
218 SM_TAILQ_REMOVE(&Mon_ctx_head, ctx, ctx_mon_link);
219 if (Mon_cur_ctx == ctx)
221 if (SM_TAILQ_EMPTY(&Mon_ctx_head))
222 Mon_cur_ctx = NULL;
223 else
224 Mon_cur_ctx = SM_TAILQ_FIRST(&Mon_ctx_head);
226 (void) smutex_unlock(&Mon_mutex);
227 return 0;
229 #endif /* _FFR_THREAD_MONITOR */