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__
warntimer(const char * msg,...)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
zerotimer(ptimer)50 zerotimer(ptimer)
51 TIMER *ptimer;
52 {
53 memset(ptimer, '\0', sizeof(*ptimer));
54 }
55
56 static void
addtimer(ta,tb)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
subtimer(ta,tb)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
getcurtimer(ptimer)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
getinctimer(ptimer)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
flushtimers()144 flushtimers()
145 {
146 NTimers = 0;
147 (void) getcurtimer(&BaseTimer);
148 }
149
150 void
pushtimer(ptimer)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
poptimer(ptimer)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 *
strtimer(ptimer)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