timers.c revision 266692
1207753Smm/*
2207753Smm * Copyright (c) 1999-2001 Proofpoint, Inc. and its suppliers.
3207753Smm *	All rights reserved.
4207753Smm *
5207753Smm * By using this file, you agree to the terms and conditions set
6207753Smm * forth in the LICENSE file which can be found at the top level of
7207753Smm * the sendmail distribution.
8207753Smm *
9207753Smm * Contributed by Exactis.com, Inc.
10207753Smm *
11207753Smm */
12207753Smm
13207753Smm#include <sm/gen.h>
14207753SmmSM_RCSID("@(#)$Id: timers.c,v 8.27 2013-11-22 20:51:57 ca Exp $")
15207753Smm
16207753Smm#if _FFR_TIMERS
17207753Smm# include <sys/types.h>
18207753Smm# include <sm/time.h>
19312518Sdelphij# include "sendmail.h"
20207753Smm# include <sys/resource.h>	/* Must be after sendmail.h for NCR MP-RAS */
21207753Smm
22207753Smmstatic TIMER	BaseTimer;		/* current baseline */
23207753Smmstatic int	NTimers;		/* current pointer into stack */
24207753Smmstatic TIMER	*TimerStack[MAXTIMERSTACK];
25207753Smm
26207753Smmstatic void
27207753Smm# ifdef __STDC__
28207753Smmwarntimer(const char *msg, ...)
29207753Smm# else /* __STDC__ */
30207753Smmwarntimer(msg, va_alist)
31207753Smm	const char *msg;
32207753Smm	va_dcl
33207753Smm# endif /* __STDC__ */
34207753Smm{
35207753Smm	char buf[MAXLINE];
36207753Smm	SM_VA_LOCAL_DECL
37207753Smm
38207753Smm# if 0
39207753Smm	if (!tTd(98, 30))
40207753Smm		return;
41207753Smm# endif /* 0 */
42207753Smm	SM_VA_START(ap, msg);
43207753Smm	(void) sm_vsnprintf(buf, sizeof(buf), msg, ap);
44207753Smm	SM_VA_END(ap);
45207753Smm	sm_syslog(LOG_NOTICE, CurEnv->e_id, "%s; e_timers=0x%lx",
46207753Smm		  buf, (unsigned long) &CurEnv->e_timers);
47207753Smm}
48207753Smm
49207753Smmstatic void
50207753Smmzerotimer(ptimer)
51207753Smm	TIMER *ptimer;
52207753Smm{
53312518Sdelphij	memset(ptimer, '\0', sizeof(*ptimer));
54207753Smm}
55207753Smm
56207753Smmstatic void
57312518Sdelphijaddtimer(ta, tb)
58207753Smm	TIMER *ta;
59207753Smm	TIMER *tb;
60207753Smm{
61312518Sdelphij	tb->ti_wall_sec += ta->ti_wall_sec;
62312518Sdelphij	tb->ti_wall_usec += ta->ti_wall_usec;
63207753Smm	if (tb->ti_wall_usec > 1000000)
64207753Smm	{
65207753Smm		tb->ti_wall_sec++;
66207753Smm		tb->ti_wall_usec -= 1000000;
67207753Smm	}
68207753Smm	tb->ti_cpu_sec += ta->ti_cpu_sec;
69207753Smm	tb->ti_cpu_usec += ta->ti_cpu_usec;
70207753Smm	if (tb->ti_cpu_usec > 1000000)
71207753Smm	{
72223935Smm		tb->ti_cpu_sec++;
73223935Smm		tb->ti_cpu_usec -= 1000000;
74223935Smm	}
75223935Smm}
76207753Smm
77207753Smmstatic void
78207753Smmsubtimer(ta, tb)
79207753Smm	TIMER *ta;
80207753Smm	TIMER *tb;
81207753Smm{
82207753Smm	tb->ti_wall_sec -= ta->ti_wall_sec;
83207753Smm	tb->ti_wall_usec -= ta->ti_wall_usec;
84207753Smm	if (tb->ti_wall_usec < 0)
85207753Smm	{
86207753Smm		tb->ti_wall_sec--;
87207753Smm		tb->ti_wall_usec += 1000000;
88207753Smm	}
89207753Smm	tb->ti_cpu_sec -= ta->ti_cpu_sec;
90207753Smm	tb->ti_cpu_usec -= ta->ti_cpu_usec;
91207753Smm	if (tb->ti_cpu_usec < 0)
92207753Smm	{
93207753Smm		tb->ti_cpu_sec--;
94207753Smm		tb->ti_cpu_usec += 1000000;
95207753Smm	}
96207753Smm}
97207753Smm
98207753Smmstatic int
99207753Smmgetcurtimer(ptimer)
100207753Smm	TIMER *ptimer;
101207753Smm{
102207753Smm	struct rusage ru;
103207753Smm	struct timeval now;
104207753Smm
105207753Smm	if (getrusage(RUSAGE_SELF, &ru) < 0 || gettimeofday(&now, NULL) < 0)
106207753Smm		return -1;
107207753Smm	ptimer->ti_wall_sec = now.tv_sec;
108207753Smm	ptimer->ti_wall_usec = now.tv_usec;
109207753Smm	ptimer->ti_cpu_sec = ru.ru_utime.tv_sec + ru.ru_stime.tv_sec;
110207753Smm	ptimer->ti_cpu_usec = ru.ru_utime.tv_usec + ru.ru_stime.tv_usec;
111207753Smm	if (ptimer->ti_cpu_usec > 1000000)
112207753Smm	{
113207753Smm		ptimer->ti_cpu_sec++;
114207753Smm		ptimer->ti_cpu_usec -= 1000000;
115207753Smm	}
116207753Smm	return 0;
117207753Smm}
118207753Smm
119207753Smmstatic void
120207753Smmgetinctimer(ptimer)
121207753Smm	TIMER *ptimer;
122207753Smm{
123207753Smm	TIMER cur;
124207753Smm
125207753Smm	if (getcurtimer(&cur) < 0)
126207753Smm	{
127207753Smm		zerotimer(ptimer);
128207753Smm		return;
129207753Smm	}
130207753Smm	if (BaseTimer.ti_wall_sec == 0)
131207753Smm	{
132207753Smm		/* first call */
133207753Smm		memset(ptimer, '\0', sizeof(*ptimer));
134207753Smm	}
135207753Smm	else
136207753Smm	{
137207753Smm		*ptimer = cur;
138207753Smm		subtimer(&BaseTimer, ptimer);
139207753Smm	}
140207753Smm	BaseTimer = cur;
141207753Smm}
142207753Smm
143207753Smmvoid
144207753Smmflushtimers()
145207753Smm{
146207753Smm	NTimers = 0;
147207753Smm	(void) getcurtimer(&BaseTimer);
148207753Smm}
149207753Smm
150207753Smmvoid
151207753Smmpushtimer(ptimer)
152207753Smm	TIMER *ptimer;
153207753Smm{
154207753Smm	int i;
155207753Smm	int save_errno = errno;
156207753Smm	TIMER incr;
157207753Smm
158207753Smm	/* find how much time has changed since last call */
159207753Smm	getinctimer(&incr);
160207753Smm
161207753Smm	/* add that into the old timers */
162207753Smm	i = NTimers;
163207753Smm	if (i > MAXTIMERSTACK)
164207753Smm		i = MAXTIMERSTACK;
165207753Smm	while (--i >= 0)
166207753Smm	{
167207753Smm		addtimer(&incr, TimerStack[i]);
168207753Smm		if (TimerStack[i] == ptimer)
169207753Smm		{
170207753Smm			warntimer("Timer@0x%lx already on stack, index=%d, NTimers=%d",
171207753Smm				  (unsigned long) ptimer, i, NTimers);
172207753Smm			errno = save_errno;
173207753Smm			return;
174207753Smm		}
175207753Smm	}
176207753Smm	errno = save_errno;
177207753Smm
178207753Smm	/* handle stack overflow */
179207753Smm	if (NTimers >= MAXTIMERSTACK)
180207753Smm		return;
181207753Smm
182207753Smm	/* now add the timer to the stack */
183207753Smm	TimerStack[NTimers++] = ptimer;
184207753Smm}
185207753Smm
186207753Smmvoid
187207753Smmpoptimer(ptimer)
188207753Smm	TIMER *ptimer;
189207753Smm{
190207753Smm	int i;
191207753Smm	int save_errno = errno;
192207753Smm	TIMER incr;
193207753Smm
194207753Smm	/* find how much time has changed since last call */
195207753Smm	getinctimer(&incr);
196207753Smm
197207753Smm	/* add that into the old timers */
198207753Smm	i = NTimers;
199207753Smm	if (i > MAXTIMERSTACK)
200207753Smm		i = MAXTIMERSTACK;
201207753Smm	while (--i >= 0)
202207753Smm		addtimer(&incr, TimerStack[i]);
203207753Smm
204207753Smm	/* pop back to this timer */
205207753Smm	for (i = 0; i < NTimers; i++)
206207753Smm	{
207207753Smm		if (TimerStack[i] == ptimer)
208207753Smm			break;
209207753Smm	}
210207753Smm
211207753Smm	if (i != NTimers - 1)
212207753Smm		warntimer("poptimer: odd pop (timer=0x%lx, index=%d, NTimers=%d)",
213207753Smm			  (unsigned long) ptimer, i, NTimers);
214312518Sdelphij	NTimers = i;
215207753Smm
216312518Sdelphij	/* clean up and return */
217312518Sdelphij	errno = save_errno;
218207753Smm}
219207753Smm
220207753Smmchar *
221207753Smmstrtimer(ptimer)
222207753Smm	TIMER *ptimer;
223207753Smm{
224207753Smm	static char buf[40];
225207753Smm
226207753Smm	(void) sm_snprintf(buf, sizeof(buf), "%ld.%06ldr/%ld.%06ldc",
227207753Smm		ptimer->ti_wall_sec, ptimer->ti_wall_usec,
228292588Sdelphij		ptimer->ti_cpu_sec, ptimer->ti_cpu_usec);
229207753Smm	return buf;
230207753Smm}
231312518Sdelphij#endif /* _FFR_TIMERS */
232312518Sdelphij