xref: /freebsd/contrib/sendmail/src/timers.c (revision 5ca8e32633c4ffbbcd6762e5888b6a4ba0708c6c)
1 /*
2  * Copyright (c) 1999-2001 Proofpoint, Inc. and its suppliers.
3  *	All rights reserved.
4  *
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.
8  *
9  * Contributed by Exactis.com, Inc.
10  *
11  */
12 
13 #include <sm/gen.h>
14 SM_RCSID("@(#)$Id: timers.c,v 8.27 2013-11-22 20:51:57 ca Exp $")
15 
16 #if _FFR_TIMERS
17 # include <sys/types.h>
18 # include <sm/time.h>
19 # include "sendmail.h"
20 # include <sys/resource.h>	/* Must be after sendmail.h for NCR MP-RAS */
21 
22 static TIMER	BaseTimer;		/* current baseline */
23 static int	NTimers;		/* current pointer into stack */
24 static TIMER	*TimerStack[MAXTIMERSTACK];
25 
26 static void
27 # ifdef __STDC__
28 warntimer(const char *msg, ...)
29 # else /* __STDC__ */
30 warntimer(msg, va_alist)
31 	const char *msg;
32 	va_dcl
33 # endif /* __STDC__ */
34 {
35 	char buf[MAXLINE];
36 	SM_VA_LOCAL_DECL
37 
38 # if 0
39 	if (!tTd(98, 30))
40 		return;
41 # endif
42 	SM_VA_START(ap, msg);
43 	(void) sm_vsnprintf(buf, sizeof(buf), msg, ap);
44 	SM_VA_END(ap);
45 	sm_syslog(LOG_NOTICE, CurEnv->e_id, "%s; e_timers=0x%lx",
46 		  buf, (unsigned long) &CurEnv->e_timers);
47 }
48 
49 static void
50 zerotimer(ptimer)
51 	TIMER *ptimer;
52 {
53 	memset(ptimer, '\0', sizeof(*ptimer));
54 }
55 
56 static void
57 addtimer(ta, tb)
58 	TIMER *ta;
59 	TIMER *tb;
60 {
61 	tb->ti_wall_sec += ta->ti_wall_sec;
62 	tb->ti_wall_usec += ta->ti_wall_usec;
63 	if (tb->ti_wall_usec > 1000000)
64 	{
65 		tb->ti_wall_sec++;
66 		tb->ti_wall_usec -= 1000000;
67 	}
68 	tb->ti_cpu_sec += ta->ti_cpu_sec;
69 	tb->ti_cpu_usec += ta->ti_cpu_usec;
70 	if (tb->ti_cpu_usec > 1000000)
71 	{
72 		tb->ti_cpu_sec++;
73 		tb->ti_cpu_usec -= 1000000;
74 	}
75 }
76 
77 static void
78 subtimer(ta, tb)
79 	TIMER *ta;
80 	TIMER *tb;
81 {
82 	tb->ti_wall_sec -= ta->ti_wall_sec;
83 	tb->ti_wall_usec -= ta->ti_wall_usec;
84 	if (tb->ti_wall_usec < 0)
85 	{
86 		tb->ti_wall_sec--;
87 		tb->ti_wall_usec += 1000000;
88 	}
89 	tb->ti_cpu_sec -= ta->ti_cpu_sec;
90 	tb->ti_cpu_usec -= ta->ti_cpu_usec;
91 	if (tb->ti_cpu_usec < 0)
92 	{
93 		tb->ti_cpu_sec--;
94 		tb->ti_cpu_usec += 1000000;
95 	}
96 }
97 
98 static int
99 getcurtimer(ptimer)
100 	TIMER *ptimer;
101 {
102 	struct rusage ru;
103 	struct timeval now;
104 
105 	if (getrusage(RUSAGE_SELF, &ru) < 0 || gettimeofday(&now, NULL) < 0)
106 		return -1;
107 	ptimer->ti_wall_sec = now.tv_sec;
108 	ptimer->ti_wall_usec = now.tv_usec;
109 	ptimer->ti_cpu_sec = ru.ru_utime.tv_sec + ru.ru_stime.tv_sec;
110 	ptimer->ti_cpu_usec = ru.ru_utime.tv_usec + ru.ru_stime.tv_usec;
111 	if (ptimer->ti_cpu_usec > 1000000)
112 	{
113 		ptimer->ti_cpu_sec++;
114 		ptimer->ti_cpu_usec -= 1000000;
115 	}
116 	return 0;
117 }
118 
119 static void
120 getinctimer(ptimer)
121 	TIMER *ptimer;
122 {
123 	TIMER cur;
124 
125 	if (getcurtimer(&cur) < 0)
126 	{
127 		zerotimer(ptimer);
128 		return;
129 	}
130 	if (BaseTimer.ti_wall_sec == 0)
131 	{
132 		/* first call */
133 		memset(ptimer, '\0', sizeof(*ptimer));
134 	}
135 	else
136 	{
137 		*ptimer = cur;
138 		subtimer(&BaseTimer, ptimer);
139 	}
140 	BaseTimer = cur;
141 }
142 
143 void
144 flushtimers()
145 {
146 	NTimers = 0;
147 	(void) getcurtimer(&BaseTimer);
148 }
149 
150 void
151 pushtimer(ptimer)
152 	TIMER *ptimer;
153 {
154 	int i;
155 	int save_errno = errno;
156 	TIMER incr;
157 
158 	/* find how much time has changed since last call */
159 	getinctimer(&incr);
160 
161 	/* add that into the old timers */
162 	i = NTimers;
163 	if (i > MAXTIMERSTACK)
164 		i = MAXTIMERSTACK;
165 	while (--i >= 0)
166 	{
167 		addtimer(&incr, TimerStack[i]);
168 		if (TimerStack[i] == ptimer)
169 		{
170 			warntimer("Timer@0x%lx already on stack, index=%d, NTimers=%d",
171 				  (unsigned long) ptimer, i, NTimers);
172 			errno = save_errno;
173 			return;
174 		}
175 	}
176 	errno = save_errno;
177 
178 	/* handle stack overflow */
179 	if (NTimers >= MAXTIMERSTACK)
180 		return;
181 
182 	/* now add the timer to the stack */
183 	TimerStack[NTimers++] = ptimer;
184 }
185 
186 void
187 poptimer(ptimer)
188 	TIMER *ptimer;
189 {
190 	int i;
191 	int save_errno = errno;
192 	TIMER incr;
193 
194 	/* find how much time has changed since last call */
195 	getinctimer(&incr);
196 
197 	/* add that into the old timers */
198 	i = NTimers;
199 	if (i > MAXTIMERSTACK)
200 		i = MAXTIMERSTACK;
201 	while (--i >= 0)
202 		addtimer(&incr, TimerStack[i]);
203 
204 	/* pop back to this timer */
205 	for (i = 0; i < NTimers; i++)
206 	{
207 		if (TimerStack[i] == ptimer)
208 			break;
209 	}
210 
211 	if (i != NTimers - 1)
212 		warntimer("poptimer: odd pop (timer=0x%lx, index=%d, NTimers=%d)",
213 			  (unsigned long) ptimer, i, NTimers);
214 	NTimers = i;
215 
216 	/* clean up and return */
217 	errno = save_errno;
218 }
219 
220 char *
221 strtimer(ptimer)
222 	TIMER *ptimer;
223 {
224 	static char buf[40];
225 
226 	(void) sm_snprintf(buf, sizeof(buf), "%ld.%06ldr/%ld.%06ldc",
227 		ptimer->ti_wall_sec, ptimer->ti_wall_usec,
228 		ptimer->ti_cpu_sec, ptimer->ti_cpu_usec);
229 	return buf;
230 }
231 #endif /* _FFR_TIMERS */
232