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.26 2006/08/15 23:24:58 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__ 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 */ 232