timers.c revision 98121
1214571Sdim/* 2214571Sdim * Copyright (c) 1999-2001 Sendmail, Inc. and its suppliers. 3214571Sdim * All rights reserved. 4214571Sdim * 5214571Sdim * By using this file, you agree to the terms and conditions set 6214571Sdim * forth in the LICENSE file which can be found at the top level of 7214571Sdim * the sendmail distribution. 8214571Sdim * 9214571Sdim * Contributed by Exactis.com, Inc. 10214571Sdim * 11214571Sdim */ 12214571Sdim 13214571Sdim#include <sm/gen.h> 14214571SdimSM_RCSID("@(#)$Id: timers.c,v 8.24 2001/09/11 04:05:17 gshapiro Exp $") 15214571Sdim 16214571Sdim#if _FFR_TIMERS 17214571Sdim# include <sys/types.h> 18214571Sdim# include <sys/time.h> 19214571Sdim# include "sendmail.h" 20214571Sdim# include <sys/resource.h> /* Must be after sendmail.h for NCR MP-RAS */ 21214571Sdim 22214571Sdimstatic TIMER BaseTimer; /* current baseline */ 23214571Sdimstatic int NTimers; /* current pointer into stack */ 24214571Sdimstatic TIMER *TimerStack[MAXTIMERSTACK]; 25214571Sdim 26214571Sdimstatic void 27214571Sdim# ifdef __STDC__ 28214571Sdimwarntimer(const char *msg, ...) 29214571Sdim# else /* __STDC__ */ 30214571Sdimwarntimer(msg, va_alist) 31214571Sdim const char *msg; 32214571Sdim va_dcl 33214571Sdim# endif /* __STDC__ */ 34214571Sdim{ 35214571Sdim char buf[MAXLINE]; 36214571Sdim SM_VA_LOCAL_DECL 37214571Sdim 38214571Sdim# if 0 39214571Sdim if (!tTd(98, 30)) 40214571Sdim return; 41214571Sdim# endif /* 0 */ 42214571Sdim SM_VA_START(ap, msg); 43214571Sdim (void) sm_vsnprintf(buf, sizeof buf, msg, ap); 44214571Sdim SM_VA_END(ap); 45214571Sdim sm_syslog(LOG_NOTICE, CurEnv->e_id, "%s; e_timers=0x%lx", 46214571Sdim buf, (unsigned long) &CurEnv->e_timers); 47214571Sdim} 48214571Sdim 49214571Sdimstatic void 50214571Sdimzerotimer(ptimer) 51214571Sdim TIMER *ptimer; 52214571Sdim{ 53214571Sdim memset(ptimer, '\0', sizeof *ptimer); 54} 55 56static void 57addtimer(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 77static void 78subtimer(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 98static int 99getcurtimer(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 119static void 120getinctimer(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 143void 144flushtimers() 145{ 146 NTimers = 0; 147 (void) getcurtimer(&BaseTimer); 148} 149 150void 151pushtimer(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 186void 187poptimer(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 220char * 221strtimer(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