changes to support changing the sampling rate: dynRPC::setSampleRate changes
[dyninst.git] / paradynd / src / perfStream.C
1 /*
2  *  Copyright 1993 Jeff Hollingsworth.  All rights reserved.
3  *
4  */
5
6 /*
7  * perfStream.C - Manage performance streams.
8  *
9  * $Log: perfStream.C,v $
10  * Revision 1.46  1995/11/03 00:06:10  newhall
11  * changes to support changing the sampling rate: dynRPC::setSampleRate changes
12  *     the value of DYNINSTsampleMultiple, implemented image::findInternalSymbol
13  * fix so that SIGKILL is not being forwarded to CM5 applications.
14  *
15  * Revision 1.45  1995/10/30  23:27:52  naim
16  * Fixing minor warning message - naim
17  *
18  * Revision 1.44  1995/10/30  23:09:01  naim
19  * Updating error message - naim
20  *
21  * Revision 1.43  1995/10/19  22:36:43  mjrg
22  * Added callback function for paradynd's to report change in status of application.
23  * Added Exited status for applications.
24  * Removed breakpoints from CM5 applications.
25  * Added search for executables in a given directory.
26  *
27  * Revision 1.42  1995/09/26  22:01:21  naim
28  * Minor comment added about function bzero.
29  *
30  * Revision 1.41  1995/09/26  20:28:49  naim
31  * Minor warning fixes and some other minor error messages fixes
32  *
33  * Revision 1.40  1995/08/24  15:04:26  hollings
34  * AIX/SP-2 port (including option for split instruction/data heaps)
35  * Tracing of rexec (correctly spawns a paradynd if needed)
36  * Added rtinst function to read getrusage stats (can now be used in metrics)
37  * Critical Path
38  * Improved Error reporting in MDL sematic checks
39  * Fixed MDL Function call statement
40  * Fixed bugs in TK usage (strings passed where UID expected)
41  *
42  * Revision 1.39  1995/05/18  10:40:37  markc
43  * Added code to read mdl calls to prevent starting a process before this
44  * data arrives.
45  *
46  * Revision 1.38  1995/02/16  08:53:54  markc
47  * Corrected error in comments -- I put a "star slash" in the comment.
48  *
49  * Revision 1.37  1995/02/16  08:34:21  markc
50  * Changed igen interfaces to use strings/vectors rather than char igen-arrays
51  * Changed igen interfaces to use bool, not Boolean.
52  * Cleaned up symbol table parsing - favor properly labeled symbol table objects
53  * Updated binary search for modules
54  * Moved machine dependnent ptrace code to architecture specific files.
55  * Moved machine dependent code out of class process.
56  * Removed almost all compiler warnings.
57  * Use "posix" like library to remove compiler warnings
58  *
59  * Revision 1.36  1994/11/12  17:28:59  rbi
60  * improved status reporting for applications pauses
61  *
62  * Revision 1.35  1994/11/11  10:44:06  markc
63  * Remove non-emergency prints
64  * Changed others to use statusLine
65  *
66  * Revision 1.34  1994/11/10  18:58:15  jcargill
67  * The "Don't Blame Me Either" commit
68  *
69  * Revision 1.33  1994/11/09  18:40:31  rbi
70  * the "Don't Blame Me" commit
71  *
72  * Revision 1.32  1994/11/06  18:29:56  rbi
73  * hid some debugging output.
74  *
75  * Revision 1.31  1994/11/02  11:14:21  markc
76  * Removed compiler warnings.
77  * Removed unused pvm code.
78  *
79  * Revision 1.30  1994/10/13  07:24:52  krisna
80  * solaris porting and updates
81  *
82  * Revision 1.29  1994/09/30  19:47:12  rbi
83  * Basic instrumentation for CMFortran
84  *
85  * Revision 1.28  1994/09/22  02:20:56  markc
86  * Added signatures for select, wait3
87  *
88  * Revision 1.27  1994/09/20  18:18:30  hollings
89  * added code to use actual clock speed for cost model numbers.
90  *
91  * Revision 1.26  1994/08/17  18:17:02  markc
92  * Call installDefaultInst when SIGTRAP is seen.
93  * Cleaned up error messages.
94  *
95  * Revision 1.25  1994/08/02  18:24:16  hollings
96  * added clock speed argument to printAppStats
97  *
98  * Revision 1.24  1994/07/26  20:01:14  hollings
99  * added CMMDhostless variable.
100  *
101  * Revision 1.23  1994/07/15  04:19:12  hollings
102  * moved dyninst stats to stats.C
103  *
104  * Revision 1.22  1994/07/14  23:30:30  hollings
105  * Hybrid cost model added.
106  *
107  * Revision 1.21  1994/07/14  14:35:37  jcargill
108  * Removed some dead code, added called to processArchDependentTraceStream
109  *
110  * Revision 1.20  1994/07/12  18:45:30  jcargill
111  * Got rid of old/unused trace-record types
112  *
113  * Revision 1.19  1994/07/05  03:26:17  hollings
114  * observed cost model
115  *
116  * Revision 1.18  1994/06/29  02:52:45  hollings
117  * Added metricDefs-common.{C,h}
118  * Added module level performance data
119  * cleanedup types of inferrior addresses instrumentation defintions
120  * added firewalls for large branch displacements due to text+data over 2meg.
121  * assorted bug fixes.
122  *
123  * Revision 1.17  1994/06/27  21:28:14  rbi
124  * Abstraction-specific resources and mapping info
125  *
126  * Revision 1.16  1994/06/27  18:57:04  hollings
127  * removed printfs.  Now use logLine so it works in the remote case.
128  * added internalMetric class.
129  * added extra paramter to metric info for aggregation.
130  *
131  * Revision 1.15  1994/06/22  01:43:17  markc
132  * Removed warnings.  Changed bcopy in inst-sparc.C to memcpy.  Changed process.C
133  * reference to proc->status to use proc->heap->status.
134  *
135  * Revision 1.14  1994/06/02  23:27:59  markc
136  * Replaced references to igen generated class to a new class derived from
137  * this class to implement error handling for igen code.
138  *
139  * Revision 1.13  1994/05/31  19:53:52  markc
140  * Fixed pause time bug which was causing negative values to be reported.  The
141  * fix involved adding an extra test in computePauseTimeMetric that did not
142  * begin reporting pause times until firstSampleReceived is TRUE.
143  *
144  * Revision 1.12  1994/05/31  18:00:46  markc
145  * Added pvm messages to copy printf messages.
146  *
147  * Revision 1.11  1994/05/18  00:52:29  hollings
148  * added ability to gather IO from application processes and forward it to
149  * the paradyn proces.
150  *
151  * Revision 1.10  1994/05/16  22:31:52  hollings
152  * added way to request unique resource name.
153  *
154  * Revision 1.9  1994/05/03  05:06:19  markc
155  * Passed exit status to pvm.
156  *
157  * Revision 1.8  1994/04/11  23:25:25  hollings
158  * Added pause_time metric.
159  *
160  * Revision 1.7  1994/04/09  18:34:55  hollings
161  * Changed {pause,continue}Application to {pause,continue}AllProceses, and
162  * made the RPC interfaces use these.  This makes the computation of pause
163  * Time correct.
164  *
165  * Revision 1.6  1994/03/31  02:03:21  markc
166  * paradyndPVM keeps a process at neonatal until the first breakpoint is
167  * reached.  Moved PDYN_reportSIGCHLD to correct location.
168  *
169  * Revision 1.5  1994/03/26  20:50:49  jcargill
170  * Changed the pause/continue code.  Now it really stops, instead of
171  * spin looping.
172  *
173  * Revision 1.4  1994/03/20  01:53:10  markc
174  * Added a buffer to each process structure to allow for multiple writers on the
175  * traceStream.  Replaced old inst-pvm.C.  Changed addProcess to return type
176  * int.
177  *
178  * Revision 1.3  1994/02/28  05:09:43  markc
179  * Added pvm hooks and ifdefs.
180  *
181  * Revision 1.2  1994/02/24  04:32:35  markc
182  * Changed header files to reflect igen changes.  main.C does not look at the number of command line arguments now.
183  *
184  * Revision 1.1  1994/01/27  20:31:35  hollings
185  * Iinital version of paradynd speaking dynRPC igend protocol.
186  *
187  * Revision 1.16  1994/01/20  17:47:41  hollings
188  * moved signal stuff into seperate functions.
189  *
190  * Revision 1.15  1993/12/14  17:57:24  jcargill
191  * Added alignment sanity checking and fixup
192  *
193  * Revision 1.14  1993/10/19  15:27:54  hollings
194  * AST based mini-tramp code generator.
195  *
196  * Revision 1.13  1993/10/04  21:38:22  hollings
197  * added createResource.
198  *
199  * Revision 1.12  1993/09/08  23:02:32  hollings
200  * added option to indicate if dumpCore should stop process.
201  *
202  * Revision 1.11  1993/08/30  18:25:40  hollings
203  * added better checking for unused trace link fields.
204  *
205  * Revision 1.10  1993/08/26  19:51:40  hollings
206  * make change for trace line >= 0 rather than non zero.
207  *
208  * Revision 1.9  1993/08/26  18:20:26  hollings
209  * added code to dump binary on illegal instruction faults.
210  *
211  * Revision 1.8  1993/08/25  20:00:37  jcargill
212  * Changes for new ptrace
213  *
214  * Revision 1.7  1993/08/11  01:57:26  hollings
215  * added code for UNIX fork.
216  *
217  * Revision 1.6  1993/07/13  18:29:16  hollings
218  * new include file syntax.
219  *
220  * Revision 1.5  1993/06/28  23:13:18  hollings
221  * fixed process stopping.
222  *
223  * Revision 1.4  1993/06/24  16:18:06  hollings
224  * global fixes.
225  *
226  * Revision 1.3  1993/06/22  19:00:01  hollings
227  * global inst state.
228  *
229  * Revision 1.2  1993/06/08  20:14:34  hollings
230  * state prior to bc net ptrace replacement.
231  *
232  * Revision 1.1  1993/03/19  22:45:45  hollings
233  * Initial revision
234  *
235  *
236  */
237
238
239 #ifdef PARADYND_PVM
240 extern "C" {
241 #include "pvm3.h"
242 }
243 #include "paradyndPVM/h/pvm_support.h"
244 #endif
245
246 #include "util/h/headers.h"
247 #include "rtinst/h/rtinst.h"
248 #include "rtinst/h/trace.h"
249 #include "symtab.h"
250 #include "process.h"
251 #include "inst.h"
252 #include "dyninstP.h"
253 #include "metric.h"
254 #include "primitives.h"
255 #include "util.h"
256 #include "comm.h"
257 #include "stats.h"
258 #include "debugger.h"
259 #include "main.h"
260 #include "association.h"
261 #include "init.h"
262 #include "context.h"
263 #include "perfStream.h"
264 #include "os.h"
265 #include "paradynd/src/mdld.h"
266 #include "showerror.h"
267 #include "main.h"
268
269 // TODO: this eliminates a warning but creates a conflict when compiling
270 // paradyndCM5.
271 //extern "C" void bzero(char *b, int length);
272
273 void createResource(traceHeader *header, struct _newresource *r);
274
275 bool CMMDhostless = false;
276 bool synchronousMode = false;
277 bool firstSampleReceived = false;
278
279 double cyclesPerSecond = 0;
280 time64 firstRecordTime = 0;
281
282 void processAppIO(process *curr)
283 {
284     int ret;
285     char lineBuf[256];
286
287     ret = read(curr->ioLink, lineBuf, sizeof(lineBuf)-1);
288     if (ret < 0) {
289         statusLine("read error");
290         showErrorCallback(23, "Read error");
291         exit(-2);
292     } else if (ret == 0) {
293         /* end of file */
294         curr->ioLink = -1;
295         return;
296     }
297
298     // null terminate it
299     lineBuf[ret] = '\0';
300
301     // forawrd the data to the paradyn process.
302     tp->applicationIO(curr->pid, ret, lineBuf);
303
304 }
305
306
307 char errorLine[1024];
308
309 void logLine(const char *line)
310 {
311     static char fullLine[1024];
312
313     strcat(fullLine, line);
314     if (fullLine[strlen(fullLine)-1] == '\n') {
315         tp->applicationIO(0, strlen(fullLine), fullLine);
316         fullLine[0] = '\0';
317     }
318 }
319
320 void statusLine(const char *line)
321 {
322   tp->reportStatus(line);
323 }
324
325 void processTraceStream(process *curr)
326 {
327     int ret;
328     traceStream sid;
329     char *recordData;
330     traceHeader header;
331     struct _association *a;
332     char buffer[100];
333
334     ret = read(curr->traceLink, &(curr->buffer[curr->bufEnd]), 
335                sizeof(curr->buffer)-curr->bufEnd);
336
337     if (ret < 0) {
338         statusLine("read error, exiting");
339         showErrorCallback(23, "Read error");
340         exit(-2);
341     } else if (ret == 0) {
342         /* end of file */
343         sprintf(buffer, "Process %d has exited", curr->pid);
344         statusLine(buffer);
345         showErrorCallback(11, buffer);
346         curr->traceLink = -1;
347         curr->Exited();
348         return;
349     }
350
351     curr->bufEnd += ret;
352     curr->bufStart = 0;
353
354     while (curr->bufStart < curr->bufEnd) {
355         if (curr->bufEnd - curr->bufStart < (sizeof(traceStream) + sizeof(header))) {
356             break;
357         }
358
359         if (curr->bufStart % WORDSIZE != 0)     /* Word alignment check */
360             break;                      /* this will re-align by shifting */
361
362         memcpy(&sid, &(curr->buffer[curr->bufStart]), sizeof(traceStream));
363         curr->bufStart += sizeof(traceStream);
364
365         memcpy(&header, &(curr->buffer[curr->bufStart]), sizeof(header));
366         curr->bufStart += sizeof(header);
367
368         curr->bufStart = ALIGN_TO_WORDSIZE(curr->bufStart);
369         if (header.length % WORDSIZE != 0) {
370             sprintf(errorLine, "Warning: non-aligned length (%d) received on traceStream.  Type=%d\n", header.length, header.type);
371             logLine(errorLine);
372             showErrorCallback(36,(const char *) errorLine);
373         }
374             
375         if (curr->bufEnd - curr->bufStart < header.length) {
376             /* the whole record isn't here yet */
377             curr->bufStart -= sizeof(traceStream) + sizeof(header);
378             break;
379         }
380
381         recordData = &(curr->buffer[curr->bufStart]);
382         curr->bufStart +=  header.length;
383
384         if (!firstRecordTime)
385             firstRecordTime = header.wall;
386
387         /*
388          * convert header to time based on first record.
389          *
390          */
391         if (!curr->getFirstRecordTime()) {
392             double st;
393
394             curr->setFirstRecordTime(header.wall);
395             st = curr->getFirstRecordTime() / 1000000.0;
396             /* sprintf(errorLine, "started at %f\n", st);*/
397             /* logLine(errorLine);*/
398             // report sample here
399             tp->firstSampleCallback(curr->getPid(), (double) (header.wall/1000000.0));
400         }
401         // header.wall -= curr->firstRecordTime();
402
403         switch (header.type) {
404             case TR_FORK:
405                 forkProcess(&header, (traceFork *) ((void*)recordData));
406                 break;
407
408             case TR_NEW_RESOURCE:
409                 createResource(&header, (struct _newresource *) ((void*)recordData));
410                 break;
411
412             case TR_NEW_ASSOCIATION:
413                 a = (struct _association *) ((void*)recordData);
414                 newAssoc(curr, a->abstraction, a->type, a->key, a->value);
415                 break;
416
417             case TR_MULTI_FORK:
418                 // logLine("got TR_MULTI_FORK record\n");
419                 CMMDhostless = true;
420                 forkNodeProcesses(curr, &header, (traceFork *) ((void*)recordData));
421                 statusLine("node daemon started");
422                 // the process stops itself after writing this trace record
423                 // and must wait until the daemon is ready.
424                 curr->waitingForNodeDaemon = true;
425                 curr->status_ = stopped;
426                 break;
427
428             case TR_SAMPLE:
429                 // sprintf(errorLine, "Got data from process %d\n", curr->pid);
430                 // logLine(errorLine);
431                 assert(curr->getFirstRecordTime());
432                 processSample(&header, (traceSample *) ((void*)recordData));
433                 firstSampleReceived = true;
434                 break;
435
436             case TR_EXIT:
437                 sprintf(errorLine, "process %d exited\n", curr->pid);
438                 logLine(errorLine);
439                 printAppStats((struct endStatsRec *) ((void*)recordData),
440                               cyclesPerSecond);
441                 printDyninstStats();
442                 curr->Exited();
443                 break;
444
445             case TR_COST_UPDATE:
446                 processCost(curr, &header, (costUpdate *) ((void*)recordData));
447                 break;
448
449             case TR_CP_SAMPLE:
450                 extern void processCP(process *, traceHeader *, cpSample *);
451                 processCP(curr, &header, (cpSample *) recordData);
452                 break;
453
454             default:
455                 sprintf(errorLine, "Got record type %d on sid %d\n", 
456                     header.type, sid);
457                 logLine(errorLine);
458                 showErrorCallback(37,(const char *) errorLine);
459         }
460     }
461
462     /* copy those bits we have to the base */
463     memcpy(curr->buffer, &(curr->buffer[curr->bufStart]), 
464         curr->bufEnd - curr->bufStart);
465     curr->bufEnd = curr->bufEnd - curr->bufStart;
466 }
467
468 // TODO -- make this a process method
469 int handleSigChild(int pid, int status)
470 {
471     int sig;
472     char buffer[100];
473
474     // ignore signals from unknown processes
475     process *curr = findProcess(pid);
476     if (!curr) return -1;
477
478     if (WIFSTOPPED(status)) {
479         sig = WSTOPSIG(status);
480         switch (sig) {
481
482             case SIGTSTP:
483                 sprintf(buffer, "process %d got SIGTSTP", pid);
484                 statusLine(errorLine);
485                 curr->Stopped();
486                 break;
487
488             case SIGTRAP:
489                 /* trap at the start of a ptraced process 
490                  *   continue past it.
491                  */
492
493                 // the process is stopped as a result of the initial SIGTRAP
494                 curr->status_ = stopped;
495
496                 // query default instrumentation here - not done yet
497                 // We must check that this is the first trap since on machines
498                 //   where we use ptrace detach, a TRAP is generated on a pause.
499                 //   - jkh 7/7/95
500                 if (!curr->reachedFirstBreak) {
501                     sprintf(buffer, "PID=%d, passed trap at start of program", pid);
502                     statusLine(buffer);
503                     installDefaultInst(curr, initialRequests);
504                     curr->reachedFirstBreak = 1;
505                     if (! curr->stopAtFirstBreak) {
506                       // don't stop here when processes are spawned by other processes
507                       if (!OS::osForwardSignal(pid,0)) {
508                         P_abort();
509                       }
510                       curr->status_ = running;
511                       statusLine("Application running");
512                     }
513                 }
514 #ifdef notdef
515                 if (!OS::osForwardSignal(pid, 0)) {
516                   logLine("error  in forwarding  signal\n");
517                   P_abort();
518                 }
519
520                 // If this is a CM-process, we don't want to label it as
521                 // running until the nodes get init'ed.  We need to test
522                 // based on magic number, I guess...   XXXXXX
523
524                 curr->status_ = running;
525 #endif
526                 break;
527
528             case SIGSTOP:
529             case SIGINT:
530                 if (curr->waitingForNodeDaemon) {
531                   // no need to update status here
532                   break;
533                 }
534
535                 curr->Stopped();
536                 curr->reachedFirstBreak = 1;
537
538                 // The Unix process should be stopped already, 
539                 // since it's blocked on ptrace and we didn't forward
540                 // received the SIGSTOP...
541                 // But we need to pause the rest of the application
542                 pauseAllProcesses(); 
543                 sprintf(buffer, "PID=%d received SIGSTOP/SIGINT. Application stopped.\n", pid);
544                 statusLine(buffer);
545                 break;
546
547             case SIGIOT:
548             case SIGBUS:
549             case SIGILL:
550                 curr->status_ = stopped;
551                 dumpProcessImage(curr, true);
552                 OS::osDumpCore(pid, "core.real");
553                 curr->Exited();
554                 // ???
555                 // should really log this to the error reporting system.
556                 // jkh - 6/25/96
557                 // now forward it to the process.
558                 OS::osForwardSignal(pid, WSTOPSIG(status));
559                 break;
560
561             case SIGCHLD:
562             case SIGUSR1:
563             case SIGUSR2:
564             case SIGALRM:
565             case SIGVTALRM:
566             case SIGCONT:
567             case SIGSEGV:       // treadmarks needs this signal
568                 // printf("caught signal, forwarding...  (sig=%d)\n", 
569                 //       WSTOPSIG(status));
570                 if (!OS::osForwardSignal(pid, WSTOPSIG(status))) {
571                      logLine("error  in forwarding  signal\n");
572                      showErrorCallback(38, "Error  in forwarding  signal");
573                      P_abort();
574                 }
575                 break;
576
577 #ifdef CM5_SIGXCPU_KLUDGE
578               // don't forward SIGXCPU so that applications may run for more
579               // than the max CPUtime limit
580               case SIGXCPU:
581               case SIGKILL:
582 //              sprintf(errorLine,"Process %d received signal SIGXCPU or SIGKILL. Not forwarded.\n",pid);
583 //              logLine(errorLine);
584                 OS::osForwardSignal(pid,0);
585                 break;
586 #endif
587
588 #ifdef notdef
589             // XXXX for debugging
590             case SIGSEGV:       // treadmarks needs this signal
591                 sprintf(errorLine, "DEBUG: forwarding signal (sig=%d, pid=%d)\n"
592                         , WSTOPSIG(status), pid);
593                 logLine(errorLine);
594 #endif
595             default:
596                 if (!OS::osForwardSignal(pid, WSTOPSIG(status))) {
597                      logLine("error  in forwarding  signal\n");
598                      P_abort();
599                 }
600                 break;
601
602         }
603     } else if (WIFEXITED(status)) {
604 #ifdef PARADYND_PVM
605                 PDYN_reportSIGCHLD (pid, WEXITSTATUS(status));
606 #endif
607         sprintf(errorLine, "process %d has terminated\n", curr->pid);
608         logLine(errorLine);
609
610         printDyninstStats();
611         curr->Exited();
612         sprintf(buffer,"Process %d has terminated\n", curr->pid);
613         statusLine(buffer);
614     } else if (WIFSIGNALED(status)) {
615         sprintf(errorLine, "process %d has terminated on signal %d\n", curr->pid,
616             WTERMSIG(status));
617         logLine(errorLine);
618         curr->Exited();
619         statusLine(errorLine);
620     } else {
621         sprintf(errorLine, "Unknown state %d from process %d\n", status, curr->pid);
622         logLine(errorLine);
623         showErrorCallback(39,(const char *) errorLine);
624     }
625     return(0);
626 }
627
628 void ioFunc()
629 {
630      printf("in SIG child func\n");
631      fflush(stdout);
632 }
633
634 /*
635  * Wait for a data from one of the inferriors or a request to come in.
636  *
637  */
638 void controllerMainLoop(bool check_buffer_first)
639 {
640     int ct;
641     int pid;
642     int width;
643     int status;
644     fd_set readSet;
645     fd_set errorSet;
646     struct timeval pollTime;
647
648     // TODO - i am the guilty party - this will go soon - mdc
649 #ifdef PARADYND_PVM
650     int fd_num, *fd_ptr;
651     if (pvm_mytid() < 0)
652       {
653         printf("pvm not working\n");
654         _exit(-1);
655       }
656     fd_num = pvm_getfds(&fd_ptr);
657     assert(fd_num == 1);
658 #endif
659
660     while (1) {
661         FD_ZERO(&readSet);
662         FD_ZERO(&errorSet);
663         width = 0;
664         unsigned p_size = processVec.size();
665         for (unsigned u=0; u<p_size; u++) {
666             if (processVec[u]->traceLink >= 0)
667               FD_SET(processVec[u]->traceLink, &readSet);
668             if (processVec[u]->traceLink > width)
669               width = processVec[u]->traceLink;
670             if (processVec[u]->ioLink >= 0)
671               FD_SET(processVec[u]->ioLink, &readSet);
672             if (processVec[u]->ioLink > width)
673               width = processVec[u]->ioLink;
674         }
675
676         // add connection to paradyn process.
677         FD_SET(tp->get_fd(), &readSet);
678         FD_SET(tp->get_fd(), &errorSet);
679         if (tp->get_fd() > width) width = tp->get_fd();
680
681 #ifdef PARADYND_PVM
682         fd_num = pvm_getfds(&fd_ptr);
683         assert(fd_num == 1);
684         FD_SET(fd_ptr[0], &readSet);
685         if (fd_ptr[0] > width)
686           width = fd_ptr[0];
687 #endif
688
689         // poll for IO
690         pollTime.tv_sec = 0;
691         pollTime.tv_usec = 50000;
692
693         // This fd may have been read from prior to entering this loop
694         // There may be some bytes lying around
695         if (check_buffer_first) {
696           bool no_stuff_there = P_xdrrec_eof(tp->net_obj());
697           while (!no_stuff_there) {
698             T_dyninstRPC::message_tags ret = tp->waitLoop();
699             if (ret == T_dyninstRPC::error) {
700               // assume the client has exited, and leave.
701               exit(-1);
702             }
703             no_stuff_there = P_xdrrec_eof(tp->net_obj());
704           }
705         }
706
707         // TODO - move this into an os dependent area
708         ct = P_select(width+1, &readSet, NULL, &errorSet, &pollTime);
709
710         if (ct > 0) {
711             unsigned p_size = processVec.size();
712             for (unsigned u=0; u<p_size; u++) {
713                 if ((processVec[u]->traceLink >= 0) && 
714                     FD_ISSET(processVec[u]->traceLink, &readSet)) {
715                     processTraceStream(processVec[u]);
716                     /* clear it in case another process is sharing it */
717                     if (processVec[u]->traceLink >= 0) 
718                         FD_CLR(processVec[u]->traceLink, &readSet);
719                 }
720
721                 if ((processVec[u]->ioLink >= 0) && 
722                     FD_ISSET(processVec[u]->ioLink, &readSet)) {
723                     processAppIO(processVec[u]);
724                 }
725             }
726             if (FD_ISSET(tp->get_fd(), &errorSet)) {
727                 // paradyn is gone so we got too.
728                 P_exit(-1);
729             }
730             if (FD_ISSET(tp->get_fd(), &readSet)) {
731               bool no_stuff_there = false;
732               while(!no_stuff_there) {
733                 T_dyninstRPC::message_tags ret = tp->waitLoop();
734                 if (ret == T_dyninstRPC::error) {
735                   // assume the client has exited, and leave.
736                   exit(-1);
737                 }
738                 no_stuff_there = P_xdrrec_eof(tp->net_obj());
739               }
740             }
741             while (tp->buffered_requests()) {
742               T_dyninstRPC::message_tags ret = tp->process_buffered();
743               if (ret == T_dyninstRPC::error)
744                 exit(-1);
745             }
746
747 #ifdef PARADYND_PVM
748             // message on pvmd channel
749             int res;
750             fd_num = pvm_getfds(&fd_ptr);
751             assert(fd_num == 1);
752             if (FD_ISSET(fd_ptr[0], &readSet)) {
753                 // res == -1 --> error
754                 res = PDYN_handle_pvmd_message();
755                 // handle pvm message
756             }
757 #endif
758         }
759
760         processArchDependentTraceStream();
761
762         /* generate internal metrics */
763         reportInternalMetrics();
764
765         /* check for status change on inferrior processes */
766         pid = P_waitpid(0, &status, WNOHANG);
767         if (pid > 0) {
768             handleSigChild(pid, status);
769         }
770     }
771 }
772
773
774 void createResource(traceHeader *header, struct _newresource *r)
775 {
776     char *tmp;
777     char *name;
778     resource *res;
779     resource *parent;
780
781     name = r->name;
782     parent = rootResource;
783     while (name) {
784         tmp = strchr(name, '/');
785         if (tmp) {
786             *tmp = '\0';
787             tmp++;
788         }
789         res = resource::newResource(parent, NULL, r->abstraction, name, 
790                                     header->wall, "");
791         parent = res;
792         name = tmp;
793     }
794 }
795