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