timers.c revision 71345
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
14static 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
23static TIMER	BaseTimer;		/* current baseline */
24static int	NTimers;		/* current pointer into stack */
25static TIMER	*TimerStack[MAXTIMERSTACK];
26
27static void
28# ifdef __STDC__
29warntimer(const char *msg, ...)
30# else /* __STDC__ */
31warntimer(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
50static void
51zerotimer(ptimer)
52	TIMER *ptimer;
53{
54	memset(ptimer, '\0', sizeof *ptimer);
55}
56
57static void
58addtimer(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
78static void
79subtimer(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
99static int
100getcurtimer(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
120static void
121getinctimer(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
144void
145flushtimers()
146{
147	NTimers = 0;
148	(void) getcurtimer(&BaseTimer);
149}
150
151void
152pushtimer(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
187void
188poptimer(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
221char *
222strtimer(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