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