2 * Copyright (c) 1996-1999 Barton P. Miller
4 * We provide the Paradyn Parallel Performance Tools (below
5 * described as Paradyn") on an AS IS basis, and do not warrant its
6 * validity or performance. We reserve the right to update, modify,
7 * or discontinue this software at any time. We shall have no
8 * obligation to supply such updates or modifications or any other
9 * form of support to you.
11 * This license is for research uses. For such uses, there is no
12 * charge. We define "research use" to mean you may freely use it
13 * inside your organization for whatever purposes you see fit. But you
14 * may not re-distribute Paradyn or parts of Paradyn, in any form
15 * source or binary (including derivatives), electronic or otherwise,
16 * to any other organization or entity without our permission.
18 * (for other uses, please contact us at paradyn@cs.wisc.edu)
20 * All warranties, including without limitation, any warranty of
21 * merchantability or fitness for a particular purpose, are hereby
24 * By your use of Paradyn, you understand and agree that we (or any
25 * other person or entity with proprietary rights in Paradyn) are
26 * under no obligation to provide either maintenance services,
27 * update services, notices of latent defects, or correction of
28 * defects for Paradyn.
30 * Even if advised of the possibility of such damages, under no
31 * circumstances shall we (or any other person or entity with
32 * proprietary rights in the software licensed hereunder) be liable
33 * to you or any third party for direct, indirect, or consequential
34 * damages of any character regardless of type of action, including,
35 * without limitation, loss of profits, loss of use, loss of good
36 * will, or computer failure or malfunction. You agree to indemnify
37 * us (and any other person or entity with proprietary rights in the
38 * software licensed hereunder) for any and all liability it may
39 * incur to third parties resulting from your use of Paradyn.
42 // $Id: main.C,v 1.91 2000/10/20 19:41:54 zandy Exp $
44 #include "common/h/headers.h"
45 #include "pdutil/h/makenan.h"
46 #include "common/h/Ident.h"
48 #if defined(MT_THREAD)
49 extern "C" const char V_paradyndMT[];
51 extern "C" const char V_paradynd[];
53 extern "C" const char V_libpdutil[];
55 #if defined(MT_THREAD)
56 Ident V_id(V_paradyndMT,"Paradyn");
58 Ident V_id(V_paradynd,"Paradyn");
60 Ident V_Uid(V_libpdutil,"Paradyn");
62 #include "rtinst/h/rtinst.h"
64 #include "dyninstAPI/src/symtab.h"
65 #include "dyninstAPI/src/process.h"
66 #include "dyninstAPI/src/inst.h"
67 #include "dyninstAPI/src/instP.h"
68 #include "dyninstAPI/src/ast.h"
69 #include "dyninstAPI/src/util.h"
70 #include "dyninstAPI/src/dyninstP.h"
71 #include "paradynd/src/metric.h"
72 #include "paradynd/src/comm.h"
73 #include "paradynd/src/internalMetrics.h"
74 #include "common/h/machineType.h"
75 #include "paradynd/src/init.h"
76 #include "paradynd/src/perfStream.h"
77 #include "paradynd/src/mdld.h"
82 #include "pvm_support.h"
89 bool pvm_running = false;
91 static string machine_name;
97 #ifdef mips_sgi_irix6_4
98 extern bool execIrixMPIProcess(vector<string> &argv);
101 #ifdef DETACH_ON_THE_FLY
102 extern void initDetachOnTheFly();
106 * These variables are global so that we can easily find out what
107 * machine/socket/etc we're connected to paradyn on; we may need to
108 * start up other paradynds (such as on the CM5), and need this later.
110 static string pd_machine;
111 static int pd_known_socket_portnum=0;
112 static int pd_flag=0;
113 static string pd_flavor;
115 void configStdIO(bool closeStdIn)
119 /* now make stdin, out and error things that we can't hurt us */
120 if ((nullfd = open("/dev/null", O_RDWR, 0)) < 0) {
124 if (closeStdIn) (void) dup2(nullfd, 0);
125 (void) dup2(nullfd, 1);
126 (void) dup2(nullfd, 2);
128 if (nullfd > 2) close(nullfd);
131 void sigtermHandler()
133 showErrorCallback(98,"paradynd has been terminated");
136 // Cleanup for pvm and exit.
137 // This function must be called when we exit, to clean up and exit from pvm.
138 // Now also cleans up shm segs by deleting all processes -ari
139 void cleanUpAndExit(int status) {
145 #if !defined(i386_unknown_nt4_0)
146 // delete the trace socket file
147 unlink(traceSocketPath.string_of());
150 #ifdef SHM_SAMPLING_DEBUG
151 cerr << "paradynd cleanUpAndExit: deleting all process structures now" << endl;
155 extern vector<process*> processVec;
157 for (unsigned lcv=0; lcv < processVec.size(); lcv++) {
158 process *theProc = processVec[lcv];
160 continue; // process has already been cleaned up
162 #if defined(i386_unknown_linux2_0) || defined(alpha_dec_osf4_0)
163 // Try to be a bit smarter when we clean up the processes - kill
164 // all processes that were created, leave all processes that were
165 // attached to running. This should really go into the process class,
166 // but I hesitate to do that this close to the release (3.0)
167 // -nick (24-Mar-2000)
168 int pid = theProc->getPid();
169 bool wasAttachedTo = theProc->wasCreatedViaAttach();
171 delete theProc; // calls process::~process, which fries the shm seg
172 #if defined(i386_unknown_linux2_0) || defined(alpha_dec_osf4_0)
173 if (!wasAttachedTo) OS::osKill(pid);
176 processVec[lcv] = NULL; // probably not needed here.
183 // mdc - I need to clean this up
185 RPC_undo_arg_list (string &flavor, unsigned argc, char **arg_list,
186 string &machine, int &well_known_socket, int &flag)
189 bool b_well_known=false; // found well-known socket port num
190 bool b_machine = false, b_flag = false, b_flavor=false;
192 for (unsigned loop=0; loop < argc; ++loop) {
193 // stop at the -runme argument since the rest are for the application
194 // process we are about to spawn
195 if (!P_strcmp(arg_list[loop], "-runme")) break;
196 if (!P_strncmp(arg_list[loop], "-p", 2)) {
197 well_known_socket = P_strtol (arg_list[loop] + 2, &ptr, 10);
198 if (ptr == (arg_list[loop] + 2))
202 else if (!P_strncmp(arg_list[loop], "-V", 2)) { // optional
203 cout << V_id << endl;
205 else if (!P_strncmp(arg_list[loop], "-v", 2)) {
207 //cerr << "paradynd: -v flag is obsolete (and ignored)" << endl;
209 else if (!P_strncmp(arg_list[loop], "-L", 2)) {
210 // this is an optional specification of the runtime library,
211 // overriding PARADYN_LIB (primarily for debugging/testing purposes)
212 process::dyninstName = (arg_list[loop] + 2);
213 if (!process::dyninstName.length()) return false;
215 else if (!P_strncmp(arg_list[loop], "-m", 2)) {
216 machine = (arg_list[loop] + 2);
217 if (!machine.length()) return false;
220 else if (!P_strncmp(arg_list[loop], "-l", 2)) {
221 flag = P_strtol (arg_list[loop] + 2, &ptr, 10);
222 if (ptr == (arg_list[loop] + 2))
226 else if (!P_strncmp(arg_list[loop], "-z", 2)) {
227 flavor = (arg_list[loop]+2);
228 if (!flavor.length()) return false;
233 // verify required parameters
234 return (b_flag && b_machine && b_well_known && b_flavor);
237 // PARADYND_DEBUG_XXX
238 static void initialize_debug_flag(void) {
241 if ( (p=getenv("PARADYND_DEBUG_INFRPC")) ) {
245 if ( (p=getenv("PARADYND_DEBUG_CATCHUP")) ) {
246 pd_debug_catchup = 1;
250 int main(unsigned argc, char *argv[]) {
252 initialize_debug_flag();
254 string *dir = new string("");
255 #if !defined(i386_unknown_nt4_0)
258 pdkill = getenv( "PARADYND_DEBUG" );
259 if( pdkill && ( *pdkill == 'y' || *pdkill == 'Y' ) ) {
261 cerr << "breaking for debug in controllerMainLoop...pid=" << pid << endl;
262 #if defined(i386_unknown_nt4_0)
264 #elif defined(sparc_sun_solaris2_4) || defined(i386_unknown_solaris2_5)
271 #endif // !defined(i386_unknown_nt4_0)
273 #if !defined(i386_unknown_nt4_0)
274 struct sigaction act;
280 #if defined(sparc_sun_sunos4_1_3) || defined(sparc_sun_solaris2_4)
281 act.sa_handler = (void (*)(...)) sigtermHandler;
283 act.sa_handler = (void (*)(int)) sigtermHandler;
287 /* for AIX - default (non BSD) library does not restart - jkh 7/26/95 */
288 #if defined(SA_RESTART)
289 act.sa_flags |= SA_RESTART;
292 sigfillset(&act.sa_mask);
294 if (sigaction(SIGTERM, &act, 0) == -1) {
295 perror("sigaction(SIGTERM)");
300 #ifdef DETACH_ON_THE_FLY
301 initDetachOnTheFly();
304 #if defined(i386_unknown_nt4_0)
305 // Windows NT needs to initialize winsock library
306 WORD wsversion = MAKEWORD(2,0);
308 WSAStartup(wsversion, &wsadata);
311 process::programName = argv[0];
312 // process command line args passed in
313 // pd_flag == 1 --> started by paradyn
315 aflag = RPC_undo_arg_list (pd_flavor, argc, argv, pd_machine,
316 pd_known_socket_portnum, pd_flag);
317 if (!aflag || pd_debug) {
318 if (!aflag) cerr << "Invalid/incomplete command-line args:" << endl;
319 cerr << " -z<flavor";
320 if (pd_flavor.length()) cerr << "=" << pd_flavor;
322 if (pd_flag) cerr << "=" << pd_flag;
323 cerr << "> -m<hostmachine";
324 if (pd_machine.length()) cerr << "=" << pd_machine;
325 cerr << "> -p<hostport";
326 if (pd_known_socket_portnum) cerr << "=" << pd_known_socket_portnum;
328 if (process::dyninstName.length())
329 cerr << " -L<library=" << process::dyninstName << ">" << endl;
330 if (!aflag) cleanUpAndExit(-1);
333 aflag = RPC_make_arg_list(process::arg_list,
334 pd_known_socket_portnum, pd_flag, 0,
337 string flav_arg(string("-z")+ pd_flavor);
338 process::arg_list += flav_arg;
339 machine_name = getNetworkName();
341 // kill(getpid(),SIGSTOP);
344 // See if we should fork an app process now.
347 // We want to find two things
348 // First, get the current working dir (PWD)
349 dir = new string(getenv("PWD"));
351 // Second, put the inferior application and its command line
352 // arguments into cmdLine. Basically, loop through argv until
353 // we find -runme, and put everything after it into cmdLine.
354 vector<string> cmdLine;
355 unsigned int argNum = 0;
356 while ((argNum < argc) && (strcmp(argv[argNum], "-runme")))
358 // Okay, argNum is the command line argument which is "-runme"
360 // Copy everything from argNum to < argc
361 for (unsigned int i = argNum; i < argc; i++)
364 process::pdFlavor = pd_flavor;
366 // There are 3 ways to get here
367 // started by pvm_spawn from first paradynd -- must report back
368 // started by rsh, rexec, ugly code --> connect via socket
369 // started by exec --> use pipe
371 // int pvm_id = pvm_mytid();
372 int pvmParent = PvmSysErr;
375 cerr << "pd_flavor: " << pd_flavor.string_of() << endl;
377 if (pd_flavor == string("pvm")) {
378 pvmParent = pvm_parent();
380 if (pvmParent == PvmSysErr) {
381 fprintf(stdout, "Unable to connect to PVM daemon, is PVM running?\n");
389 if (pvm_running && pvmParent != PvmNoParent) {
390 // started by pvm_spawn
391 // TODO -- report error here
392 if (!PDYN_initForPVM (argv, pd_machine, pd_known_socket_portnum, 0)) {
395 tp = new pdRPC(AF_INET, pd_known_socket_portnum, SOCK_STREAM, pd_machine,
399 tp->reportSelf (machine_name, argv[0], getpid(), "pvm");
400 } else if ( pd_flavor == "mpi" ) {
401 // Both IRIX and AIX MPI job-launchers will start paradynd,
402 // which must report to paradyn
403 // the pdRPC is allocated and reportSelf is called
404 tp = new pdRPC(AF_INET, pd_known_socket_portnum, SOCK_STREAM,
405 pd_machine, NULL, NULL, 2);
408 tp->reportSelf(machine_name, argv[0], getpid(), "mpi");
409 } else if (pd_flag == 2) {
411 tp = new pdRPC(AF_INET, pd_known_socket_portnum, SOCK_STREAM, pd_machine,
414 //assert(tp->net_obj()); // shouldn't this be part of pdRPC::pdRPC?
415 if (!tp->net_obj()) {
416 cerr << "Failed to establish connection to Paradyn on "
417 << pd_machine << " port " << pd_known_socket_portnum << endl;
420 tp->reportSelf(machine_name, argv[0], getpid(), pd_flavor);
423 && !PDYN_initForPVM (argv, pd_machine, pd_known_socket_portnum, 1))
426 } else if (!pd_flag) {
427 // not started by pvm_spawn; rather, started via rsh/rexec --> use socket
430 // configStdIO(true);
432 // TODO -- report error here
434 // We must get a connection with paradyn before starting any other daemons,
435 // or else one of the daemons we start (in PDYN_initForPVM), may get our
437 tp = new pdRPC(AF_INET, pd_known_socket_portnum, SOCK_STREAM, pd_machine,
441 if (pvm_running && !PDYN_initForPVM (argv, pd_machine, pd_known_socket_portnum, 1)) {
445 } else if (pid > 0) {
448 cerr << "Fatal error on paradyn daemon: fork failed." << endl;
453 // started via exec --> use pipe
454 // TODO -- report error here
455 if (pvm_running && !PDYN_initForPVM (argv, pd_machine, pd_known_socket_portnum, 1)) {
458 // already setup on this FD.
459 // disconnect from controlling terminal
461 tp = new pdRPC(0, NULL, NULL, 2);
467 if ( pd_flavor == "mpi" ) {
468 // Both IRIX and AIX MPI job-launchers will start paradynd,
469 // which must report to paradyn
470 // the pdRPC is allocated and reportSelf is called
471 tp = new pdRPC(AF_INET, pd_known_socket_portnum, SOCK_STREAM,
472 pd_machine, NULL, NULL, 2);
475 tp->reportSelf(machine_name, argv[0], getpid(), "mpi");
476 } else if (pd_flag == 2) {
478 tp = new pdRPC(AF_INET, pd_known_socket_portnum, SOCK_STREAM, pd_machine,
481 tp->reportSelf(machine_name, argv[0], getpid(), pd_flavor);
483 } else if (!pd_flag) {
484 #if !defined(i386_unknown_nt4_0)
490 // configStdIO(true);
493 tp = new pdRPC(AF_INET, pd_known_socket_portnum, SOCK_STREAM, pd_machine,
497 if (cmdLine.size()) {
498 tp->reportSelf(machine_name, argv[0], getpid(), pd_flavor);
500 } else if (!pd_flag) {
501 } else if (pid > 0) {
504 cerr << "Fatal error on paradyn daemon: fork failed." << endl;
511 #if !defined(i386_unknown_nt4_0)
514 PDSOCKET sock = _get_osfhandle(0);
515 #endif // defined(i386_unknown_nt4_0)
516 tp = new pdRPC(sock, NULL, NULL, 2);
519 // configStdIO(false);
523 #if defined(MT_THREAD)
524 statusLine(V_paradyndMT);
526 statusLine(V_paradynd);
529 // Note -- it is important that this daemon receives all mdl info
530 // before starting a process
531 aflag = mdl_get_initial(pd_flavor, tp);
534 initLibraryFunctions();
538 #ifdef mips_sgi_irix6_4
539 struct utsname unameInfo;
540 if ( P_uname(&unameInfo) == -1 )
546 // osName is used in irix.C and process.C
547 osName = unameInfo.sysname;
549 if ( pd_flavor == "mpi" && osName.prefixed_by("IRIX") )
551 if ( !execIrixMPIProcess(cmdLine) )
556 if (cmdLine.size()) {
558 addProcess(cmdLine, envp, *dir); // ignore return val (is this right?)
561 controllerMainLoop(true);