Fixing some problems related to timers and race conditions that were causing
[dyninst.git] / rtinst / src / RTaix.c
1 /*
2  * Copyright (c) 1993, 1994 Barton P. Miller, Jeff Hollingsworth,
3  *     Bruce Irvin, Jon Cargille, Krishna Kunchithapadam, Karen
4  *     Karavanic, Tia Newhall, Mark Callaghan.  All rights reserved.
5  * 
6  * This software is furnished under the condition that it may not be
7  * provided or otherwise made available to, or used by, any other
8  * person, except as provided for by the terms of applicable license
9  * agreements.  No title to or ownership of the software is hereby
10  * transferred.  The name of the principals may not be used in any
11  * advertising or publicity related to this software without specific,
12  * written prior authorization.  Any use of this software must include
13  * the above copyright notice.
14  *
15  */
16
17
18
19 /************************************************************************
20  * RTaix.c: clock access functions for aix.
21 ************************************************************************/
22
23 #include <sys/time.h>
24 #include <sys/resource.h>
25 #include <malloc.h>
26 #include <stdlib.h>
27 #include <stdio.h>
28 #include "rtinst/h/rtinst.h"
29
30
31 static const double NANO_PER_USEC = 1.0e3;
32 static const long int MILLION       = 1000000;
33
34 /************************************************************************
35  * void DYNINSTos_init(void)
36  *
37  * os initialization function---currently null.
38 ************************************************************************/
39
40 void
41 DYNINSTos_init(void) {
42 }
43
44
45 /************************************************************************
46  * time64 DYNINSTgetCPUtime(void)
47  *
48  * return value is in usec units.
49 ************************************************************************/
50
51 time64
52 DYNINSTgetCPUtime(void) {
53      time64 now;
54      static time64 previous=0;
55      struct rusage ru;
56
57 try_again:    
58     if (!getrusage(RUSAGE_SELF, &ru)) {
59       now = (time64)ru.ru_utime.tv_sec + (time64)ru.ru_stime.tv_sec;
60       now *= (time64)1000000;
61       now += (time64)ru.ru_utime.tv_usec + (time64)ru.ru_stime.tv_usec;
62       if (now<previous) {
63         goto try_again;
64       }
65       previous=now;
66       return(now);
67     }
68     else {
69       perror("getrusage");
70       abort();
71     }
72 }
73
74
75 \f
76
77
78 /************************************************************************
79  * time64 DYNINSTgetWalltime(void)
80  *
81  * get the total walltime used by the monitored process.
82  * return value is in usec units.
83 ************************************************************************/
84
85 time64 DYNINSTgetWalltime(void) {
86     time64 now;
87     register unsigned int timeSec asm("5");
88     register unsigned int timeNano asm("6");
89     register unsigned int timeSec2 asm("7");
90
91     /* Need to read the first value twice to make sure it doesn't role
92      *   over while we are reading it.
93      */
94 retry:
95     asm("mfspr   5,4");         /* read high into register 5 - timeSec */
96     asm("mfspr   6,5");         /* read low into register 6 - timeNano */
97     asm("mfspr   7,4");         /* read high into register 7 - timeSec2 */
98
99     if (timeSec != timeSec2) goto retry;
100     /* convert to correct form. */
101     now = (timer64)timeSec;
102     now *= (timer64)MILLION;
103     now += (timer64)timeNano/(timer64)1000;
104     return(now);
105 }
106
107
108 /*
109  * Code to trap execvp call and munge command (for SP-2).
110  *
111  */
112 void DYNINSTexecvp(char *argv[])
113 {
114      int i;
115      int ret;
116      char *ch;
117      char *cmd;
118      int iCount;
119      int acount;
120      char *pdArgs;
121      char **newArgs;
122      static int inExecvp;
123
124      if (inExecvp) return;
125      inExecvp = 1;
126
127      cmd = argv[0];
128
129      /* this only applies to poe on the SP-2 */
130      if (strcmp(cmd, "poe")) return;
131
132      for (iCount=0; argv[iCount]; iCount++);
133
134      pdArgs = (char *) getenv("PARADYN_MASTER_INFO");
135      if (!pdArgs) {
136          fprintf(stdout, "unable to get PARADYN_MASTER_INFO\n");
137          fflush(stdout);
138          return;
139      }
140
141      /* extras for first arg, command, -runme, and null  */
142      for (ch=pdArgs, acount=4; *ch; ch++) if (*ch == ' ') acount++;
143      newArgs = calloc(sizeof(char*), iCount+acount);
144
145      newArgs[0] = "poe";
146      newArgs[1] = "paradynd";
147
148      /* skip white spave at start */
149      while (*pdArgs && *pdArgs == ' ') pdArgs++;
150      newArgs[2] = pdArgs;
151      for (ch=pdArgs, acount=3; *ch; ch++) {
152          if (*ch == ' ') {
153              *ch = '\0';
154              /* skip over null argument -caused by spaces in environment var */
155              if (!strlen(newArgs[acount-1])) acount--;
156              newArgs[acount++] = ++ch;
157          }
158      }
159      /* skip over null argument -caused by space at end of environment var */
160      if (!strlen(newArgs[acount-1])) acount--;
161
162      newArgs[acount++] = "-runme";
163      for (i=1; i < iCount; i++) {
164          newArgs[acount++] = argv[i];
165      }
166
167      newArgs[acount] = "";
168
169      /* generate an exit record about the process to paradynd */
170      DYNINSTprintCost();
171
172      /* Now call execvp with the correct arguments */
173      ret = execvp(cmd, newArgs);
174
175      fprintf(stderr, "execvp failed\n");
176      perror("execvp");
177      fflush(stderr);
178
179      exit(-1);
180
181      inExecvp = 0;
182      return;
183 }
184
185
186 /*
187  * DYNINSTgetRusage(id) - Return the value of various OS stats.
188  *
189  *    The id is an integer, and when they are changed, any metric that uses
190  *        DYNINSTgetRusage will also need to be updated.
191  *
192  */
193 int DYNINSTgetRusage(int id)
194 {
195     int ret;
196     int value;
197     struct rusage rusage;
198     struct rusage *DYNINSTrusagePtr;
199
200     ret = getrusage(RUSAGE_SELF, &rusage);
201     if (ret) {
202         perror("getrusage");
203     }
204     DYNINSTrusagePtr = &rusage;
205     switch (id) {
206         case 0: /* page faults */
207             value = DYNINSTrusagePtr->ru_minflt+DYNINSTrusagePtr->ru_majflt;
208             break;
209         case 1: /* swaps */
210             value = DYNINSTrusagePtr->ru_nswap;
211             break;
212         case 2: /* signals received */
213             value = DYNINSTrusagePtr->ru_nsignals;
214             break;
215         case 3: /* max rss */
216             value = DYNINSTrusagePtr->ru_maxrss;
217             break;
218         case 4: /* context switches */
219             value = DYNINSTrusagePtr->ru_nvcsw + DYNINSTrusagePtr->ru_nivcsw;
220             break;
221         default:
222             value = 0;
223             break;
224     }
225     return value;
226 }