timers.c revision 98121
1214571Sdim/*
2214571Sdim * Copyright (c) 1999-2001 Sendmail, Inc. and its suppliers.
3214571Sdim *	All rights reserved.
4214571Sdim *
5214571Sdim * By using this file, you agree to the terms and conditions set
6214571Sdim * forth in the LICENSE file which can be found at the top level of
7214571Sdim * the sendmail distribution.
8214571Sdim *
9214571Sdim * Contributed by Exactis.com, Inc.
10214571Sdim *
11214571Sdim */
12214571Sdim
13214571Sdim#include <sm/gen.h>
14214571SdimSM_RCSID("@(#)$Id: timers.c,v 8.24 2001/09/11 04:05:17 gshapiro Exp $")
15214571Sdim
16214571Sdim#if _FFR_TIMERS
17214571Sdim# include <sys/types.h>
18214571Sdim# include <sys/time.h>
19214571Sdim# include "sendmail.h"
20214571Sdim# include <sys/resource.h>	/* Must be after sendmail.h for NCR MP-RAS */
21214571Sdim
22214571Sdimstatic TIMER	BaseTimer;		/* current baseline */
23214571Sdimstatic int	NTimers;		/* current pointer into stack */
24214571Sdimstatic TIMER	*TimerStack[MAXTIMERSTACK];
25214571Sdim
26214571Sdimstatic void
27214571Sdim# ifdef __STDC__
28214571Sdimwarntimer(const char *msg, ...)
29214571Sdim# else /* __STDC__ */
30214571Sdimwarntimer(msg, va_alist)
31214571Sdim	const char *msg;
32214571Sdim	va_dcl
33214571Sdim# endif /* __STDC__ */
34214571Sdim{
35214571Sdim	char buf[MAXLINE];
36214571Sdim	SM_VA_LOCAL_DECL
37214571Sdim
38214571Sdim# if 0
39214571Sdim	if (!tTd(98, 30))
40214571Sdim		return;
41214571Sdim# endif /* 0 */
42214571Sdim	SM_VA_START(ap, msg);
43214571Sdim	(void) sm_vsnprintf(buf, sizeof buf, msg, ap);
44214571Sdim	SM_VA_END(ap);
45214571Sdim	sm_syslog(LOG_NOTICE, CurEnv->e_id, "%s; e_timers=0x%lx",
46214571Sdim		  buf, (unsigned long) &CurEnv->e_timers);
47214571Sdim}
48214571Sdim
49214571Sdimstatic void
50214571Sdimzerotimer(ptimer)
51214571Sdim	TIMER *ptimer;
52214571Sdim{
53214571Sdim	memset(ptimer, '\0', sizeof *ptimer);
54}
55
56static void
57addtimer(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
77static void
78subtimer(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
98static int
99getcurtimer(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
119static void
120getinctimer(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
143void
144flushtimers()
145{
146	NTimers = 0;
147	(void) getcurtimer(&BaseTimer);
148}
149
150void
151pushtimer(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
186void
187poptimer(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
220char *
221strtimer(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