timers.c revision 168515
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> 14SM_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 22static TIMER BaseTimer; /* current baseline */ 23static int NTimers; /* current pointer into stack */ 24static TIMER *TimerStack[MAXTIMERSTACK]; 25 26static void 27# ifdef __STDC__ 28warntimer(const char *msg, ...) 29# else /* __STDC__ */ 30warntimer(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 49static void 50zerotimer(ptimer) 51 TIMER *ptimer; 52{ 53 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