Merge from vendor branch TEXINFO:
[dragonfly.git] / contrib / sendmail-8.13.4 / sendmail / timers.c
1 /*
2  * Copyright (c) 1999-2001 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 #include <sm/gen.h>
14 SM_RCSID("@(#)$Id: timers.c,v 8.24 2001/09/11 04:05:17 gshapiro Exp $")
15
16 #if _FFR_TIMERS
17 # include <sys/types.h>
18 # include <sys/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__
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 /* 0 */
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
50 zerotimer(ptimer)
51         TIMER *ptimer;
52 {
53         memset(ptimer, '\0', sizeof *ptimer);
54 }
55
56 static void
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
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
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
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
144 flushtimers()
145 {
146         NTimers = 0;
147         (void) getcurtimer(&BaseTimer);
148 }
149
150 void
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
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 *
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 */