add static to c inline
[charm.git] / src / arch / net / charmrun / charmrun.c
1 #include "converse.h"
2
3 #include "../sockRoutines.h"
4 #include "../sockRoutines.c"
5 #include "../ccs-auth.h"
6 #include "../ccs-auth.c"
7 #include "../ccs-server.h"
8 #include "../ccs-server.c"
9
10 #include <stdio.h>
11 #include <string.h>
12 #include <ctype.h>
13 #include <errno.h>
14 #include <setjmp.h>
15 #include <stdlib.h>
16 #include <signal.h>
17 #include <fcntl.h>
18 #include <time.h>
19 #include <assert.h>
20 #if CMK_BPROC
21 #include <sys/bproc.h>
22 #endif
23
24 #if defined(_WIN32) && !defined(__CYGWIN__)
25 /*Win32 has screwy names for the standard UNIX calls:*/
26 #define getcwd _getcwd
27 #define strdup _strdup
28 #define unlink _unlink
29 #define open _open
30 #define fdopen _fdopen
31 #define ftruncate _chsize
32 #include <winbase.h>
33 #include <direct.h>
34 #include <io.h>
35 #include <sys/timeb.h>
36 #include <process.h>
37 #define DIRSEP "\\"
38 #define SIGBUS -1  /*These signals don't exist in Win32*/
39 #define SIGKILL -1
40 #define SIGQUIT -1
41
42
43 #else /*UNIX*/
44 #include <pwd.h>   /*getcwd*/
45 #include <unistd.h>
46 #define DIRSEP "/"
47 #endif
48
49 #if CMK_RSH_NOT_NEEDED /*No RSH-- use daemon to start node-programs*/
50 #  define CMK_USE_RSH 0
51
52 #else /*Use RSH to start node-programs*/
53 #  define CMK_USE_RSH 1
54 #ifdef __MINGW_H
55 #  include <rpc.h>
56 #elif !defined(__CYGWIN__)
57 #  include <rpc/rpc.h>
58 #else
59 #  include <w32api/rpc.h>
60 #endif
61 #  if CMK_RSH_IS_A_COMMAND
62 #    define RSH_CMD "rsh"
63 #  endif
64
65 #  if CMK_RSH_USE_REMSH
66 #    define RSH_CMD "remsh"
67 #  endif
68 #endif
69
70 #include "daemon.h"
71
72 /*#define DEBUGF(x) printf x*/
73 #define DEBUGF(x) 
74
75 #ifndef MAXPATHLEN
76 #define MAXPATHLEN 1024
77 #endif
78
79 static double ftTimer;
80
81 int *rsh_pids=NULL;
82                                                                                 
83 double GetClock(void)
84 {
85 #if defined(_WIN32) && !defined(__CYGWIN__)
86   struct _timeb tv;
87   _ftime(&tv);
88   return (tv.time * 1.0 + tv.millitm * 1.0E-3);
89 #else
90   struct timeval tv; int ok;
91   ok = gettimeofday(&tv, NULL);
92   if (ok<0) { perror("gettimeofday"); exit(1); }
93   return (tv.tv_sec * 1.0 + tv.tv_usec * 1.0E-6);
94 #endif
95 }
96
97
98 int probefile(path)
99     char *path;
100 {
101         FILE *f=fopen(path,"r");
102         if (f==NULL) return 0;
103         fclose(f);
104         return 1;
105 }
106
107 char *mylogin(void)
108 {
109 #if defined(_WIN32) && !defined(__CYGWIN__)
110         static char name[100]={'d','u','n','n','o',0};
111         int len=100;
112         GetUserName(name,&len);
113         return name;
114 #else /*UNIX*/
115   struct passwd *self;
116
117   self = getpwuid(getuid());
118   if (self==0) { return "unknown"; }
119   return self->pw_name;
120 #endif
121
122
123 /**************************************************************************
124  *
125  * ping_developers
126  *
127  * Sends a single UDP packet to the charm developers notifying them
128  * that charm is in use.
129  *
130  **************************************************************************/
131
132 void ping_developers()
133 {
134 #ifdef NOTIFY
135   char               info[1000];
136   /*This is the resolved IP address of elegance.cs.uiuc.edu */
137   skt_ip_t destination_ip=skt_lookup_ip("128.174.241.211");
138   unsigned int destination_port=6571;
139   struct sockaddr_in addr=skt_build_addr(destination_ip,destination_port);
140   SOCKET             skt;
141   
142   skt = socket(AF_INET, SOCK_DGRAM, 0);
143   if (skt == INVALID_SOCKET) return;
144
145   sprintf(info,"%s",mylogin());
146   
147   sendto(skt, info, strlen(info), 0, (struct sockaddr *)&addr, sizeof(addr));
148   skt_close(skt);
149 #endif /* NOTIFY */
150 }
151
152 /**************************************************************************
153  *
154  * Pathfix : alters a path according to a set of rewrite rules
155  *
156  *************************************************************************/
157
158 typedef struct pathfixlist {
159   char *s1;
160   char *s2;
161   struct pathfixlist *next;
162 } *pathfixlist;
163
164 pathfixlist pathfix_append(char *s1, char *s2, pathfixlist l)
165 {
166   pathfixlist pf = (pathfixlist)malloc(sizeof(struct pathfixlist));
167   pf->s1 = s1;
168   pf->s2 = s2;
169   pf->next = l;
170   return pf;
171 }
172
173 char *pathfix(char *path, pathfixlist fixes)
174 {
175   char buffer[MAXPATHLEN]; pathfixlist l; 
176   char buf2[MAXPATHLEN]; 
177   char *offs; int mod, len;
178   strcpy(buffer,path);
179   mod = 1;
180   while (mod) {
181     mod = 0;
182     for (l=fixes; l; l=l->next) {
183       len = strlen(l->s1);
184       offs = strstr(buffer, l->s1);
185       if (offs) {
186         offs[0]=0;
187         sprintf(buf2,"%s%s%s",buffer,l->s2,offs+len);
188         strcpy(buffer,buf2);
189         mod = 1;
190       }
191     }
192   }
193   return strdup(buffer);
194 }
195
196 char *pathextfix(char *path, pathfixlist fixes, char *ext)
197 {
198   char *newpath = pathfix(path, fixes);
199   char *ret;
200   if (ext == NULL) return newpath;
201   ret = (char *)malloc(strlen(newpath)+strlen(ext)+2);
202   strcpy(ret, newpath);
203   strcat(ret, ext);
204   return ret;
205 }
206
207 /****************************************************************************
208  *
209  * Miscellaneous minor routines.
210  *
211  ****************************************************************************/
212
213 int is_quote(char c)
214 {
215   return (c=='\'' || c == '"');
216 }
217
218 void zap_newline(char *s)
219 {
220   char *p;
221   p = s + strlen(s)-1;
222   if (*p == '\n') *p = '\0';
223   /* in case of DOS ^m */
224   p--;
225   if (*p == '\15') *p = '\0';
226 }
227
228 /* get substring from lo to hi, remove quote chars */
229 char *substr(char *lo, char *hi)
230 {
231   int len;
232   char *res;
233   if (is_quote(*lo)) lo++;
234   if (is_quote(*(hi-1))) hi--;
235   len = hi-lo;
236   res = (char *)malloc(1+len);
237   memcpy(res, lo, len);
238   res[len]=0;
239   return res;
240 }
241
242 int subeqs(char *lo, char *hi, char *str)
243 {
244   int len = strlen(str);
245   if (hi-lo != len) return 0;
246   if (memcmp(lo, str, len)) return 0;
247   return 1;
248 }
249
250 /* advance pointer over blank characters */
251 char *skipblanks(char *p)
252 {
253   while ((*p==' ')||(*p=='\t')) p++;
254   return p;
255 }
256
257 /* advance pointer over nonblank characters and a quoted string */
258 char *skipstuff(char *p)
259 {
260   char quote = 0;
261   if (*p && (*p=='\'' || *p=='"')) { quote=*p; p++; }
262   if (quote != 0) {
263     while (*p&&*p!=quote) p++;
264     if (*p!=quote) {
265       fprintf(stderr, "ERROR> Unmatched quote in nodelist file.\n");
266       exit(1);
267     }
268     p++;
269   }
270   else
271     while ((*p)&&(*p!=' ')&&(*p!='\t')) p++;
272   return p;
273 }
274
275 #if CMK_USE_RSH
276 char *getenv_rsh()
277 {
278   char *e;
279
280   e = getenv("CONV_RSH");
281   return e ? e : RSH_CMD;
282 }
283 #endif
284
285 #if !defined(_WIN32) || defined(__CYGWIN__)
286 char *getenv_display()
287 {
288   static char result[100],ipBuf[200];
289   char *e, *p;
290   
291   e = getenv("DISPLAY");
292   if (e==0) return NULL;
293   p = strrchr(e, ':');
294   if (p==0) return NULL;
295   if ((e[0]==':')||(strncmp(e,"unix:",5)==0)) {
296     sprintf(result,"%s:%s",skt_print_ip(ipBuf,skt_my_ip()),p+1);
297   }
298   else strcpy(result, e);
299   return result;
300 }
301 char *getenv_display_no_tamper()
302 {
303   static char result[100],ipBuf[200];
304   char *e, *p;
305   
306   e = getenv("DISPLAY");
307   if (e==0) return NULL;
308   p = strrchr(e, ':');
309   if (p==0) return NULL;
310   strcpy(result, e);
311   return result;
312 }
313
314 #endif
315
316 /*****************************************************************************
317  *                                                                           *
318  * PPARAM - obtaining "program parameters" from the user.                    *
319  *                                                                           *
320  *****************************************************************************/
321
322 typedef struct ppdef
323 {
324   union {
325       int *i;
326       double *r;
327       char **s;
328       int *f;
329     } where;/*Where to store result*/
330   const char *lname; /*Argument name on command line*/
331   const char *doc;
332   char  type; /*One of i, r, s, f.*/
333   struct ppdef *next;
334 }
335 *ppdef;
336
337 static ppdef ppdefs;
338
339 static int     pparam_pos;
340 static char  **pparam_argv;
341 static char    pparam_optc='-';
342 char           pparam_error[100];
343
344 static ppdef pparam_find(lname)
345     const char *lname;
346 {
347   ppdef def;
348   for (def=ppdefs; def; def=def->next)
349     if (strcmp(def->lname, lname)==0)
350       return def;
351   return 0;
352 }
353
354 static ppdef pparam_cell(lname)
355     const char *lname;
356 {
357   ppdef def = pparam_find(lname);
358   if (def) return def;
359   def = (ppdef)malloc(sizeof(struct ppdef));
360   def->lname = lname;
361   def->type  = 's';
362   def->doc   = "(undocumented)";
363   def->next  = ppdefs;
364   ppdefs = def;
365   return def;
366 }
367
368
369
370 void pparam_int(int *where,int defValue,
371                                    const char *arg,const char *doc)
372 {
373   ppdef def = pparam_cell(arg);
374   def->type  = 'i';
375   def->where.i = where; *where=defValue;
376   def->lname=arg;
377   def->doc=doc;
378 }
379
380 void pparam_flag(int *where,int defValue,
381                                    const char *arg,const char *doc)
382 {
383   ppdef def = pparam_cell(arg);
384   def->type  = 'f';
385   def->where.f = where; *where=defValue;
386   def->lname=arg;
387   def->doc=doc;
388 }
389
390 void pparam_real(double *where,double defValue,
391                                    const char *arg,const char *doc)
392 {
393   ppdef def = pparam_cell(arg);
394   def->type  = 'r';
395   def->where.r = where; *where=defValue;
396   def->lname=arg;
397   def->doc=doc;
398 }
399 void pparam_str(char **where,char *defValue,
400                                    const char *arg,const char *doc)
401 {
402   ppdef def = pparam_cell(arg);
403   def->type  = 's';
404   def->where.s = where; *where=defValue;
405   def->lname=arg;
406   def->doc=doc;
407 }
408
409 static int pparam_setdef(def, value)
410     ppdef def; char *value;
411 {
412   char *p;
413   switch(def->type)
414     {
415     case 'i' :
416       *def->where.i = strtol(value, &p, 10);
417       if (*p) return -1;
418       return 0;
419     case 'r' :
420       *def->where.r = strtod(value, &p);
421       if (*p) return -1;
422       return 0;
423     case 's' :
424       *def->where.s = strdup(value);
425       return 0;
426     case 'f' :
427       *def->where.f = strtol(value, &p, 10);
428       if (*p) return -1;
429       return 0;
430     }
431   return -1;
432 }
433
434 int pparam_set(lname, value)
435     char *lname; char *value;
436 {
437   ppdef def = pparam_cell(lname);
438   return pparam_setdef(def, value);
439 }
440
441 char *pparam_getdef(def)
442     ppdef def;
443 {
444   static char result[100];
445   switch(def->type)
446     {
447     case 'i': sprintf(result,"%d", *def->where.i); return result;
448     case 'r': sprintf(result,"%f",*def->where.r); return result;
449     case 's': return *def->where.s?*def->where.s:"";
450     case 'f': sprintf(result,"%d", *def->where.f); return result;
451     }
452   return NULL;
453 }
454
455 void pparam_printdocs()
456 {
457   ppdef def; int len, maxname, maxdoc;
458   maxname = 0;
459   maxdoc = 0;
460   for (def=ppdefs; def; def=def->next)
461     {
462       len = strlen(def->lname);
463       if (len>maxname) maxname=len;
464       len = strlen(def->doc);
465       if (len>maxdoc) maxdoc=len;
466     }
467   fprintf(stderr,"\n");
468   fprintf(stderr,"Charmrun Command-line Parameters:\n");
469   for (def=ppdefs; def; def=def->next)
470     {
471       fprintf(stderr,"  %c%c%-*s ",pparam_optc,pparam_optc,maxname,def->lname);
472       fprintf(stderr,"  %-*s [%s]\n",maxdoc,def->doc,pparam_getdef(def));
473     }
474   fprintf(stderr,"\n");
475 }
476
477 void pparam_delarg(i)
478     int i;
479 {
480   int j;
481   for (j=i; pparam_argv[j]; j++)
482     pparam_argv[j]=pparam_argv[j+1];
483 }
484
485 int pparam_countargs(argv)
486     char **argv;
487 {
488   int argc;
489   for (argc=0; argv[argc]; argc++);
490   return argc;
491 }
492
493 int pparam_parseopt()
494 {
495   int ok; ppdef def=NULL;
496   char *opt = pparam_argv[pparam_pos];
497   /* handle ++ by skipping to end */
498   if ((opt[1]=='+')&&(opt[2]==0))
499     {
500       pparam_delarg(pparam_pos);
501       while (pparam_argv[pparam_pos]) pparam_pos++;
502       return 0;
503     }
504   /* handle + by itself - an error */
505   if (opt[1]==0) 
506     {
507       sprintf(pparam_error,"Illegal option +\n");
508       return -1;
509     }
510   /* look up option definition */
511   if (opt[1]=='+') def = pparam_find(opt+2);
512   else
513     {
514       char name[2];
515       name[0]=opt[1];
516       name[1]=0;
517       def = pparam_find(name);
518     }
519   if (def==NULL)
520   {
521     if (opt[1]=='+')
522     {
523        sprintf(pparam_error,"Option %s not recognized.",opt);
524        return -1;
525     } else {
526            /*Unrecognized + option-- skip it.*/
527            pparam_pos++;
528            return 0;
529         }
530   }
531   /* handle flag-options */
532   if ((def->type=='f')&&(opt[1]!='+')&&(opt[2]))
533     {
534       sprintf(pparam_error,"Option %s should not include a value",opt);
535       return -1;
536     }
537   if (def->type=='f')
538     {
539       *def->where.f = 1;
540       pparam_delarg(pparam_pos);
541       return 0;
542     }
543   /* handle non-flag options */
544   if ((opt[1]=='+')||(opt[2]==0))
545     {
546       pparam_delarg(pparam_pos);
547       opt = pparam_argv[pparam_pos];
548     }
549   else opt+=2;
550   if ((opt == 0)||(opt[0] == 0))
551     {
552       sprintf(pparam_error,"%s must be followed by a value.",opt);
553       return -1;
554     }
555   ok = pparam_setdef(def, opt);
556   pparam_delarg(pparam_pos);
557   if (ok<0)
558     {
559       sprintf(pparam_error,"Illegal value for %s",opt);
560       return -1;
561     }
562   return 0;
563 }
564
565 int pparam_parsecmd(optchr, argv)
566     char optchr; char **argv;
567 {
568   pparam_error[0]=0;
569   pparam_argv = argv;
570   pparam_optc = optchr;
571   pparam_pos  = 0;
572   while(1)
573     {
574       char *opt = pparam_argv[pparam_pos];
575       if (opt==0) break;
576       if (opt[0]!=optchr) pparam_pos++;
577       else if (pparam_parseopt()<0) return -1;
578     }
579   return 0;
580 }
581
582 /****************************************************************************
583  * 
584  * ARG
585  *
586  * The following module computes a whole bunch of miscellaneous values, which
587  * are all constant throughout the program.  Naturally, this includes the
588  * value of the command-line arguments.
589  *
590  *****************************************************************************/
591
592
593 #define MAX_NODES 1000
594 #define MAX_LINE_LENGTH 1000
595
596 char **arg_argv;
597 int    arg_argc;
598
599 int   arg_requested_pes;
600 int   arg_timeout;
601 int   arg_verbose;
602 char *arg_nodelist;
603 char *arg_nodegroup;
604 char *arg_runscript; /* script to run the node-program with */
605 char *arg_charmrunip;
606 #if CONVERSE_VERSION_VMI
607 char *arg_vmispecfile;
608 #endif
609
610 int   arg_debug;
611 int   arg_debug_no_pause;
612 int   arg_charmdebug;
613
614 int   arg_local;        /* start node programs directly by exec on localhost */
615 int   arg_batch_spawn;  /* control starting node programs, several at a time */
616 int   arg_scalable_start;
617
618 int   arg_help;         /* print help message */
619 int   arg_ppn;          /* pes per node */
620 int   arg_usehostname;
621
622 #if CMK_USE_RSH
623 int   arg_maxrsh;
624 char *arg_shell;
625 int   arg_in_xterm;
626 char *arg_debugger;
627 char *arg_xterm;
628 char *arg_display;
629 int arg_ssh_display;
630 char *arg_mylogin;
631 #endif
632
633 char *arg_nodeprog_a;
634 char *arg_nodeprog_r;
635 char *arg_currdir_a;
636 char *arg_currdir_r;
637
638 int   arg_server;
639 int   arg_server_port=0;
640 char *arg_server_auth=NULL;
641
642 #if CMK_BPROC
643 int   arg_startpe;
644 int   arg_endpe;
645 int   arg_singlemaster;
646 int   arg_skipmaster;
647 #endif
648
649 void arg_init(int argc, char **argv)
650 {
651   static char buf[1024];
652   
653   int i, local_def=0;
654 #if CMK_CHARMRUN_LOCAL
655   local_def=1; /*++local is the default*/
656 #endif
657   
658   pparam_int(&arg_requested_pes, 1, "p",             "number of processes to create");
659   pparam_int(&arg_timeout,      60, "timeout",       "seconds to wait per host connection");
660   pparam_flag(&arg_verbose,      0, "verbose",       "Print diagnostic messages");
661   pparam_str(&arg_nodelist,      0, "nodelist",      "file containing list of nodes");
662   pparam_str(&arg_nodegroup,"main", "nodegroup",     "which group of nodes to use");
663
664 #if CMK_CCS_AVAILABLE
665   pparam_flag(&arg_server,       0, "server",        "Enable client-server (CCS) mode");
666   pparam_int(&arg_server_port,   0, "server-port",   "Port to listen for CCS requests");
667   pparam_str(&arg_server_auth,   0, "server-auth",   "CCS Authentication file");
668 #endif
669   pparam_flag(&arg_local,       local_def, "local", "Start node programs locally without daemon");
670   pparam_int(&arg_batch_spawn,   0, "batch", "Rsh several node programs at a time, avoiding overloading charmrun pe");
671   pparam_flag(&arg_scalable_start, 0, "scalable-start", "scalable start");
672   pparam_flag(&arg_usehostname,  0, "usehostname", "Send nodes our symbolic hostname instead of IP address");
673   pparam_str(&arg_charmrunip,    0, "useip",      "Use IP address provided for charmrun IP");
674 #if CMK_USE_RSH
675   pparam_flag(&arg_debug,         0, "debug",         "Run each node under gdb in an xterm window");
676   pparam_flag(&arg_debug_no_pause,0, "debug-no-pause","Like debug, except doesn't pause at beginning");
677
678   /* When the ++charmdebug flag is used, charmrun listens from its stdin for
679      commands, and forwards them to the gdb info program (a child), or to the
680      processor gdbs. The stderr is redirected to the stdout, so the two streams
681      are mixed together. The channel for stderr is reused to forward the replies
682      of gdb back to the java debugger. */
683 #if !defined(_WIN32)
684   pparam_flag(&arg_charmdebug,    0, "charmdebug",    "Used only when charmrun is started by charmdebug");
685 #endif
686
687   pparam_int(&arg_maxrsh,        16, "maxrsh",        "Maximum number of rsh's to run at a time");
688   pparam_str(&arg_shell,          0, "remote-shell",  "which remote shell to use");
689   pparam_str(&arg_debugger,       0, "debugger",      "which debugger to use");
690   pparam_str(&arg_display,        0, "display",       "X Display for xterm");
691   pparam_flag(&arg_ssh_display,   0, "ssh-display",   "use own X Display for each ssh session");
692   pparam_flag(&arg_in_xterm,      0, "in-xterm",      "Run each node in an xterm window");
693   pparam_str(&arg_xterm,          0, "xterm",         "which xterm to use");
694 #endif
695 #ifdef CMK_BPROC
696   /* options for Scyld */
697   pparam_int(&arg_startpe,   0, "startpe",   "first pe to start job(SCYLD)");
698   pparam_int(&arg_endpe,  1000000, "endpe",   "last pe to start job(SCYLD)");
699   pparam_flag(&arg_singlemaster, 0, "singlemaster", "Only assign one process to master node(SCYLD)");
700   pparam_flag(&arg_skipmaster, 0, "skipmaster", "Donot assign any process to master node(SCYLD)");
701   if (arg_skipmaster && arg_singlemaster) {
702     printf("Charmrun> 'singlemaster' is ignored due to 'skipmaster'. \n");
703     arg_singlemaster = 0;
704   }
705   pparam_flag(&arg_debug,         0, "debug",         "turn on more verbose debug print");
706 #endif
707 #ifdef CONVERSE_VERSION_VMI
708   pparam_str (&arg_vmispecfile, 0, "specfile", "device specfile to load (VMI)");
709 #endif
710   pparam_str(&arg_runscript,    0, "runscript", "script to run node-program with");
711   pparam_flag(&arg_help,        0, "help", "print help messages");
712   pparam_int(&arg_ppn,          0, "ppn",             "number of pes per node");
713
714   if (pparam_parsecmd('+', argv) < 0) {
715     fprintf(stderr,"ERROR> syntax: %s\n",pparam_error);
716     pparam_printdocs();
717     exit(1);
718   }
719   
720   /* Check for (but do *not* remove) the "-?", "-h", or "--help" flags */
721   for (i=0;argv[i];i++) {
722         if (0==strcmp(argv[i],"-?") ||
723             0==strcmp(argv[i],"-h") ||
724             0==strcmp(argv[i],"--help")) 
725                 arg_help=1;
726   }
727   if (arg_help) {
728     pparam_printdocs();
729     /*exit(0);*/
730   }
731
732   arg_argv = argv+1; /*Skip over charmrun (0) here and program name (1) later*/
733   arg_argc = pparam_countargs(arg_argv);
734   if (arg_argc<1) {
735     fprintf(stderr,"ERROR> You must specify a node-program.\n");
736     pparam_printdocs();
737     exit(1);
738   }
739   arg_argv++; arg_argc--;
740
741   if (arg_server_port || arg_server_auth) arg_server=1;
742
743   if (arg_debug || arg_debug_no_pause) {
744         arg_verbose=1;
745         /*Pass ++debug along to program (used by machine.c)*/
746         arg_argv[arg_argc++]="++debug";
747   }
748
749 #ifdef CMK_BPROC
750   if (arg_local) {
751     fprintf(stderr,"Warning> ++local cannot be used in bproc version, ignored!\n");
752     arg_local = 0;
753   }
754 #endif
755
756 #if CMK_USE_RSH
757   /* Find the current value of the CONV_RSH variable */
758   if(!arg_shell) arg_shell = getenv_rsh();
759
760   /* Find the current value of the DISPLAY variable */
761   if(!arg_display)
762     arg_display = getenv_display_no_tamper();
763   if ((arg_debug || arg_debug_no_pause || arg_in_xterm) && (arg_display==0)) {
764     fprintf(stderr,"ERROR> DISPLAY must be set to use debugging mode\n");
765     exit(1);
766   }
767   if (arg_debug || arg_debug_no_pause) 
768     arg_timeout=8*60*60; /* Wait 8 hours for ++debug */
769
770   /* default debugger is gdb */
771   if(!arg_debugger)
772     arg_debugger = "gdb" ;
773   /* default xterm is xterm */
774   if(!arg_xterm)
775     arg_xterm = "xterm" ;
776
777   arg_mylogin = mylogin();
778 #endif
779
780 #if CONVERSE_VERSION_VMI
781   if (!arg_vmispecfile) {
782     arg_vmispecfile = getenv ("VMI_SPECFILE");
783   }
784
785   if (!arg_vmispecfile) {
786     fprintf (stderr, "ERROR> ++specfile not specified and VMI_SPECFILE not given in environment\n");
787     exit (1);
788   }
789 #endif
790
791   /* find the current directory, absolute version */
792   getcwd(buf, 1023);
793   arg_currdir_a = strdup(buf);
794     
795   /* find the node-program, absolute version */
796   arg_nodeprog_r = argv[1];
797
798   if (arg_nodeprog_r[0]=='-' || arg_nodeprog_r[0]=='+') 
799   { /*If it starts with - or +, it ain't a node program.
800       Chances are, the user screwed up and passed some unknown flag to charmrun*/
801      printf("Charmrun does not recognize the flag '%s'.\n",arg_nodeprog_r);
802      if (arg_nodeprog_r[0]=='+')
803        printf("Charm++'s flags need to be placed *after* the program name.\n");
804      pparam_printdocs();
805      exit(1);
806   }
807
808
809 #if defined(_WIN32) && !defined(__CYGWIN__)
810   if (argv[1][1]==':' || argv[1][0]=='\\' && argv[1][1]=='\\') { /*E.g.: "C:\foo\bar.exe*/
811 #else
812   if (argv[1][0]=='/') { /*E.g.: "\foo\bar"*/
813 #endif
814           /*Absolute path to node-program*/
815     arg_nodeprog_a = argv[1];
816   } else {
817     sprintf(buf,"%s%s%s",arg_currdir_a,DIRSEP,arg_nodeprog_r);
818     arg_nodeprog_a = strdup(buf);
819   }
820   if (arg_scalable_start) {
821     printf("Charmrun> scalable start enabled. \n");
822     if (arg_debug || arg_debug_no_pause) {
823       fprintf(stderr, "Charmrun> Error: ++scalable-start does not support debugging mode. \n");
824       exit(1);
825     }
826   }
827 }
828
829 /****************************************************************************
830  *                                                                           
831  * NODETAB:  The nodes file and nodes table.
832  *
833  ****************************************************************************/
834
835 static int portOk = 1;
836 static const char *nodetab_tempName=NULL;
837 char *nodetab_file_find()
838 {
839   char buffer[MAXPATHLEN];
840
841   /* Find a nodes-file as specified by ++nodelist */
842   if (arg_nodelist) {
843     char *path = arg_nodelist;
844     if (probefile(path)) return strdup(path);
845     fprintf(stderr,"ERROR> No such nodelist file %s\n",path);
846     exit(1);
847   }
848   /* Find a nodes-file as specified by getenv("NODELIST") */
849   if (getenv("NODELIST")) {
850     char *path = getenv("NODELIST");        
851     if (path && probefile(path)) return strdup(path);
852     fprintf(stderr,"ERROR> Cannot find nodelist file %s\n",path);
853     exit(1);
854   }
855   /* Find a nodes-file by looking under 'nodelist' in the current directory */
856   if (probefile("./nodelist")) return strdup("./nodelist");
857 #if defined(_WIN32) && !defined(__CYGWIN__)
858   tmpnam(buffer);
859   nodetab_tempName=strdup(buffer);
860 #else /*UNIX*/
861   if (getenv("HOME")) {
862     sprintf(buffer,"%s/.nodelist",getenv("HOME"));
863   }
864 #endif
865   if (!probefile(buffer)) 
866   {
867     /*Create a simple nodelist in the user's home*/
868     FILE *f=fopen(buffer,"w");
869     if (f==NULL) {
870       fprintf(stderr,"ERROR> Cannot create a 'nodelist' file.\n");
871       exit(1);
872     }
873     fprintf(f,"group main\nhost localhost\n");
874     fclose(f);
875   }
876   return strdup(buffer);
877 }
878
879 typedef struct nodetab_host {
880   char    *name;  /*Host DNS name*/
881   skt_ip_t ip; /*IP address of host*/
882   pathfixlist pathfixes;
883   char    *ext;  /*FIXME: What the heck is this?  OSL 9/8/00*/
884   int      cpus;  /* # of physical CPUs*/
885   int      rank;  /*Rank of this CPU*/
886   double   speed; /*Relative speed of each CPU*/
887   int      nice;  /* process priority */
888   int      forks; /* number of processes to fork on remote node */
889   /*These fields are set during node-startup*/
890   int     dataport;/*UDP port number*/
891   SOCKET  ctrlfd;/*Connection to control port*/
892 #if CMK_USE_RSH
893   char    *shell;  /*Rsh to use*/
894   char    *debugger ; /*Debugger to use*/
895   char    *xterm ;  /*Xterm to use*/
896   char    *login;  /*User login name to use*/
897   char    *passwd;  /*User login password*/
898   char    *setup;  /*Commands to execute on login*/
899 #endif
900
901 #if CMK_USE_IBVERBS
902         ChInfiAddr *qpData;
903 #endif
904 #if CMK_USE_IBUD
905         ChInfiAddr qp;
906 #endif
907
908
909 } nodetab_host;
910
911 nodetab_host **nodetab_table;
912 int           nodetab_max;
913 int           nodetab_size;
914 int          *nodetab_rank0_table;
915 int           nodetab_rank0_size;
916
917 void nodetab_reset(nodetab_host *h)
918 {
919   h->name="SET_H->NAME";
920   h->ip=_skt_invalid_ip;
921   h->pathfixes = 0;
922   h->ext = NULL;
923   h->speed = 1.0;
924   h->cpus = 1;
925   h->rank = 0;
926   h->nice=-100;
927   h->forks = 0;
928   h->dataport=-1;
929   h->ctrlfd=-1;
930 #if CMK_USE_RSH
931   h->shell = arg_shell;
932   h->debugger = arg_debugger;
933   h->xterm = arg_xterm;
934   h->login = arg_mylogin;
935   h->passwd = "*";
936   h->setup = "*";
937 #endif
938 }
939
940 void nodetab_add(nodetab_host *h)
941 {
942   if (h->rank == 0)
943     nodetab_rank0_table[nodetab_rank0_size++] = nodetab_size;
944   nodetab_table[nodetab_size] = (nodetab_host *) malloc(sizeof(nodetab_host));
945
946   if (arg_verbose) {
947     char ips[200];
948     skt_print_ip(ips,h->ip);
949     printf("Charmrun> adding client %d: \"%s\", IP:%s\n", nodetab_size, h->name, ips);
950   }
951
952   *nodetab_table[nodetab_size++] = *h;
953 }
954
955 void nodetab_makehost(char *name,nodetab_host *h)
956 {
957   h->name=strdup(name);
958   h->ip = skt_innode_lookup_ip(name);
959   if (skt_ip_match(h->ip,_skt_invalid_ip)) {
960 #ifdef CMK_BPROC
961     /* only the master node is used */
962     if (!(1 == arg_requested_pes && atoi(name)==-1))
963 #endif
964     {
965     fprintf(stderr,"ERROR> Cannot obtain IP address of %s\n", name);
966     exit(1);
967     }
968   }
969   if (nodetab_size == nodetab_max) return;
970   nodetab_add(h);
971 }
972
973 char *nodetab_args(char *args,nodetab_host *h)
974 {
975   if (arg_ppn>0) h->cpus = arg_ppn;
976   while(*args != 0) {
977     char *b1 = skipblanks(args), *e1 = skipstuff(b1);
978     char *b2 = skipblanks(e1), *e2 = skipstuff(b2);
979     while (*b1=='+') b1++;/*Skip over "++" on parameters*/
980 #if CMK_USE_RSH
981     if (subeqs(b1,e1,"login")) h->login = substr(b2,e2);
982     else if (subeqs(b1,e1,"passwd")) h->passwd = substr(b2,e2);
983     else if (subeqs(b1,e1,"setup")) h->setup = strdup(b2);
984     else if (subeqs(b1,e1,"shell")) h->shell = substr(b2,e2);
985     else if (subeqs(b1,e1,"debugger")) h->debugger = substr(b2,e2);
986     else if (subeqs(b1,e1,"xterm")) h->xterm = substr(b2,e2);
987     else 
988 #endif
989     if (subeqs(b1,e1,"speed")) h->speed = atof(b2);
990     else if (subeqs(b1,e1,"cpus")) {
991       if (arg_ppn==0) h->cpus = atol(b2);       /* ignore if there is ++ppn */
992     }
993     else if (subeqs(b1,e1,"pathfix")) {
994       char *b3 = skipblanks(e2), *e3 = skipstuff(b3);
995       args = skipblanks(e3);
996       h->pathfixes=pathfix_append(substr(b2,e2),substr(b3,e3),h->pathfixes);
997       e2 = e3;       /* for the skipblanks at the end */
998     } 
999     else if (subeqs(b1,e1,"ext"))  h->ext = substr(b2,e2);
1000     else if (subeqs(b1,e1,"nice"))  h->nice = atoi(b2);
1001     else return args;
1002     args = skipblanks(e2);
1003   }
1004 #if CMK_SHARED_VARS_UNAVAILABLE
1005   if (h->cpus != 1) {
1006     fprintf(stderr,"Warning> Invalid cpus %d in nodelist ignored.\n", h->cpus);
1007     h->cpus = 1;
1008   }
1009 #endif
1010   return args;
1011 }
1012
1013 /*  setup nodetab as localhost only */
1014 void nodetab_init_for_local()
1015 {
1016   int tablesize, i, done=0;
1017   nodetab_host group;
1018
1019   tablesize = arg_requested_pes;
1020   nodetab_table=(nodetab_host**)malloc(tablesize*sizeof(nodetab_host*));
1021   nodetab_rank0_table=(int*)malloc(tablesize*sizeof(int));
1022   nodetab_max=tablesize;
1023
1024   nodetab_reset(&group);
1025   if (arg_ppn==0) arg_ppn=1;
1026 #if CMK_SHARED_VARS_UNAVAILABLE
1027   if (arg_ppn > 1) {
1028     fprintf(stderr,"Warning> Invalid ppn %d in nodelist ignored.\n", arg_ppn);
1029     arg_ppn=1;
1030   }
1031 #endif
1032   group.cpus = arg_ppn;
1033   i = 0;
1034   while (!done) {
1035     char *hostname = "127.0.0.1";
1036     for (group.rank = 0; group.rank<arg_ppn; group.rank++) {
1037       nodetab_makehost(hostname, &group);
1038       if (++i == arg_requested_pes) { done = 1; break; }
1039     }
1040   }
1041 }
1042
1043 void nodetab_init()
1044 {
1045   FILE *f,*fopen();
1046   char *nodesfile; 
1047   nodetab_host global,group,host;
1048   char input_line[MAX_LINE_LENGTH];
1049   int rightgroup, basicsize, i, remain;
1050   
1051   /* if arg_local is set, ignore the nodelist file */
1052   if (arg_local) {
1053     nodetab_init_for_local();
1054     goto fin;
1055   }
1056
1057   /* Open the NODES_FILE. */
1058   nodesfile = nodetab_file_find();
1059   if(arg_verbose)
1060     fprintf(stderr, "Charmrun> using %s as nodesfile\n", nodesfile);
1061   if (!(f = fopen(nodesfile,"r"))) {
1062     fprintf(stderr,"ERROR> Cannot read %s: %s\n",nodesfile,strerror(errno));
1063     exit(1);
1064   }
1065   
1066   nodetab_table=(nodetab_host**)malloc(arg_requested_pes*sizeof(nodetab_host*));
1067   nodetab_rank0_table=(int*)malloc(arg_requested_pes*sizeof(int));
1068   nodetab_max=arg_requested_pes;
1069   
1070   nodetab_reset(&global);
1071   group=global;
1072   rightgroup = (strcmp(arg_nodegroup,"main")==0);
1073   
1074   while(fgets(input_line,sizeof(input_line)-1,f)!=0) {
1075     if (nodetab_size == arg_requested_pes) break;
1076     if (input_line[0]=='#') continue;
1077     zap_newline(input_line);
1078         if (!nodetab_args(input_line,&global)) {
1079                 /*An option line-- also add options to current group*/
1080                 nodetab_args(input_line,&group);
1081         }
1082         else {/*Not an option line*/
1083                 char *b1 = skipblanks(input_line), *e1 = skipstuff(b1);
1084                 char *b2 = skipblanks(e1), *e2 = skipstuff(b2);
1085                 char *b3 = skipblanks(e2);
1086                 if (subeqs(b1,e1,"host")) {
1087                         if (rightgroup) {
1088                                 host=group;
1089                                 nodetab_args(b3,&host);
1090                                 for (host.rank=0; host.rank<host.cpus; host.rank++)
1091                                         nodetab_makehost(substr(b2,e2),&host);
1092                         }
1093                 } else if (subeqs(b1,e1, "group")) {
1094                         group=global;
1095                         nodetab_args(b3,&group);
1096                         rightgroup = subeqs(b2,e2,arg_nodegroup);
1097                 } else if (b1!=b3) {
1098                         fprintf(stderr,"ERROR> unrecognized command in nodesfile:\n");
1099                         fprintf(stderr,"ERROR> %s\n", input_line);
1100                         exit(1);
1101                 }
1102         }
1103   }
1104   fclose(f);
1105   if (nodetab_tempName!=NULL) unlink(nodetab_tempName);
1106
1107   /*Wrap nodes in table around if there aren't enough yet*/
1108   basicsize = nodetab_size;
1109   if (basicsize==0) {
1110     fprintf(stderr,"ERROR> No hosts in group %s\n", arg_nodegroup);
1111     exit(1);
1112   }
1113   while ((nodetab_size < arg_requested_pes)&&(arg_requested_pes!=MAX_NODES))
1114      nodetab_add(nodetab_table[nodetab_size%basicsize]);
1115   
1116 fin:
1117   /*Clip off excess CPUs at end*/
1118   for (i=0; i<nodetab_size; i++) {
1119     if (nodetab_table[i]->rank == 0)
1120       remain = nodetab_size - i;
1121     if (nodetab_table[i]->cpus > remain)
1122       nodetab_table[i]->cpus = remain;
1123   }
1124 }
1125
1126 /* Given a processor number, look up the nodetab info: */
1127 nodetab_host *nodetab_getinfo(int i)
1128 {
1129   if (nodetab_table==0) {
1130     fprintf(stderr,"ERROR> Node table not initialized.\n");
1131     exit(1);
1132   }
1133   return nodetab_table[i];
1134 }
1135
1136 /* Given a node number, look up the nodetab info: */
1137 nodetab_host *nodetab_getnodeinfo(int i)
1138 {
1139   return nodetab_getinfo(nodetab_rank0_table[i]);
1140 }
1141
1142 /*These routines all take *PE* numbers (NOT node numbers!)*/
1143 char        *nodetab_name(int i)     { return nodetab_getinfo(i)->name; }
1144 pathfixlist  nodetab_pathfixes(int i){ return nodetab_getinfo(i)->pathfixes; }
1145 char        *nodetab_ext(int i)      { return nodetab_getinfo(i)->ext; }
1146 skt_ip_t     nodetab_ip(int i)       { return nodetab_getinfo(i)->ip; }
1147 unsigned int nodetab_cpus(int i)     { return nodetab_getinfo(i)->cpus; }
1148 unsigned int nodetab_rank(int i)     { return nodetab_getinfo(i)->rank; }
1149 int          nodetab_dataport(int i) { return nodetab_getinfo(i)->dataport; }
1150 int          nodetab_nice(int i)     { return nodetab_getinfo(i)->nice; }
1151 SOCKET      nodetab_ctrlfd(int i)    { return nodetab_getinfo(i)->ctrlfd;}
1152 #if CMK_USE_RSH
1153 char        *nodetab_setup(int i)    { return nodetab_getinfo(i)->setup; }
1154 char        *nodetab_shell(int i)    { return nodetab_getinfo(i)->shell; }
1155 char        *nodetab_debugger(int i) { return nodetab_getinfo(i)->debugger; }
1156 char        *nodetab_xterm(int i)    { return nodetab_getinfo(i)->xterm; }
1157 char        *nodetab_login(int i)    { return nodetab_getinfo(i)->login; }
1158 char        *nodetab_passwd(int i)   { return nodetab_getinfo(i)->passwd; }
1159 #endif
1160
1161 /****************************************************************************
1162  *
1163  * Nodeinfo
1164  *
1165  * The global list of node PEs, IPs, and port numbers.
1166  * Stored in ChMachineInt_t format so the table can easily be sent
1167  * back to the nodes.
1168  *
1169  ****************************************************************************/
1170
1171 static ChNodeinfo *nodeinfo_arr;/*Indexed by node number.*/
1172
1173 void nodeinfo_allocate(void)
1174 {
1175         nodeinfo_arr=(ChNodeinfo *)malloc(nodetab_rank0_size*sizeof(ChNodeinfo));
1176 }
1177 void nodeinfo_add(const ChSingleNodeinfo *in,SOCKET ctrlfd)
1178 {
1179         int node=ChMessageInt(in->nodeNo);
1180         ChNodeinfo i=in->info;
1181         unsigned int nt;
1182         unsigned int pe;
1183         unsigned int dataport;
1184         int lid,qpn,psn;
1185         if (node<0 || node>=nodetab_rank0_size)
1186                 {fprintf(stderr,"Unexpected node %d registered!\n",node);exit(1);}
1187         nt=nodetab_rank0_table[node];/*Nodetable index for this node*/  
1188         i.nPE=ChMessageInt_new(nodetab_cpus(nt));
1189         i.IP=nodetab_ip(nt);
1190 #if CMK_USE_IBVERBS 
1191         nodeinfo_arr[node] = i;
1192         for (pe=0;pe<nodetab_cpus(nt);pe++){
1193                 nodetab_table[nt+pe]->ctrlfd=ctrlfd;
1194         }
1195         printf("Charmrun> client %d connected\n", nt);
1196 #else
1197         dataport = ChMessageInt(i.dataport);
1198         if (0==dataport)
1199                 {fprintf(stderr,"Node %d could not initialize network!\n",node);exit(1);}
1200         nodeinfo_arr[node]=i;
1201         for (pe=0;pe<nodetab_cpus(nt);pe++)
1202           {
1203             nodetab_table[nt+pe]->dataport=dataport;
1204             nodetab_table[nt+pe]->ctrlfd=ctrlfd;
1205 #if CMK_USE_IBUD
1206             nodetab_table[nt+pe]->qp=i.qp;
1207 #endif
1208           }
1209         if (arg_verbose) {
1210           char ips[200];
1211           skt_print_ip(ips,nodetab_ip(nt));
1212           printf("Charmrun> client %d connected (IP=%s data_port=%d)\n", nt, ips, dataport);
1213 #if CMK_USE_IBUD
1214           printf("Charmrun> client %d lid=%d qpn=%i psn=%i\n",nt,ChMessageInt(i.qp.lid),ChMessageInt(i.qp.qpn),ChMessageInt(i.qp.psn));
1215 #endif
1216         }
1217 #endif
1218 }
1219
1220 /****************************************************************************
1221  *
1222  * input handling
1223  *
1224  * You can use this module to read the standard input.  It supports
1225  * one odd function, input_scanf_chars, which is what makes it useful.
1226  * if you use this module, you may not read stdin yourself.
1227  *
1228  * void input_init(void)
1229  * char *input_gets(void)
1230  * char *input_scanf_chars(char *fmt)
1231  *
1232  ****************************************************************************/
1233
1234 char *input_buffer;
1235
1236 void input_extend()
1237 {
1238   char line[1024];
1239   int len = input_buffer?strlen(input_buffer):0;
1240   fflush(stdout);
1241   if (fgets(line, 1023, stdin)==0) { 
1242     fprintf(stderr,"end-of-file on stdin");
1243     exit(1);
1244   }
1245   input_buffer = realloc(input_buffer, len + strlen(line) + 1);
1246   strcpy(input_buffer+len, line);
1247 }
1248
1249 void input_init()
1250 {
1251   input_buffer = strdup("");
1252 }
1253
1254 char *input_extract(nchars)
1255     int nchars;
1256 {
1257   char *res = substr(input_buffer, input_buffer+nchars);
1258   char *tmp = substr(input_buffer+nchars, input_buffer+strlen(input_buffer));
1259   free(input_buffer);
1260   input_buffer = tmp;
1261   return res;
1262 }
1263
1264 char *input_gets()
1265 {
1266   char *p, *res; int len;
1267   while(1) {
1268     p = strchr(input_buffer,'\n');
1269     if (p) break;
1270     input_extend();
1271   }
1272   len = p-input_buffer;
1273   res = input_extract(len+1);
1274   res[len]=0;
1275   return res;
1276 }
1277
1278 /*FIXME: I am terrified by this routine. OSL 9/8/00*/
1279 char *input_scanf_chars(fmt)
1280     char *fmt;
1281 {
1282   char buf[8192]; int len, pos;
1283   static int fd; static FILE *file;
1284   fflush(stdout);
1285   if (file==0) {
1286 #if CMK_USE_MKSTEMP
1287     char tmp[128];
1288     strcpy(tmp, "/tmp/fnordXXXXXX");
1289     mkstemp(tmp);
1290 #else
1291     char *tmp=tmpnam(NULL);/*This was once /tmp/fnord*/
1292 #endif
1293     unlink(tmp);
1294     fd = open(tmp,O_RDWR | O_CREAT | O_TRUNC);
1295     if (fd<0) { 
1296       fprintf(stderr,"cannot open temp file /tmp/fnord");
1297       exit(1);
1298     }
1299     file = fdopen(fd, "r+");
1300     unlink(tmp);
1301   }
1302   while (1) {
1303     len = strlen(input_buffer);
1304     rewind(file);
1305     fwrite(input_buffer, len, 1, file);
1306     fflush(file);
1307     rewind(file);
1308     ftruncate(fd, len);
1309     fscanf(file, fmt, buf, buf, buf, buf, buf, buf, buf, buf, buf, buf, buf, buf, buf, buf, buf, buf, buf, buf);
1310     pos = ftell(file);
1311     if (pos<len) break;
1312     input_extend();
1313   }
1314   return input_extract(pos);
1315 }
1316
1317 /***************************************************************************
1318 CCS Interface:
1319   Charmrun forwards CCS requests on to the node-programs' control
1320 sockets.
1321 ***************************************************************************/
1322
1323 #if CMK_CCS_AVAILABLE
1324
1325 #define REDIRECT_STDIO  "redirect stdio"
1326 #define FETCH_STDIO "fetch stdio"
1327 char *stdio_buffer = NULL;
1328 int stdio_size = 0;
1329 int stdio_alloc = 0;
1330 int stdio_waiting = 0;
1331 CcsImplHeader stdio_waiting_hdr;
1332
1333 /*The Ccs Server socket became active-- 
1334 rec'v the message and respond to the request,
1335 by forwarding the request to the appropriate node.
1336  */
1337 void req_ccs_connect(void)
1338 {
1339   const void *bufs[3]; int lens[3];
1340   struct {
1341    ChMessageHeader ch;/*Make a charmrun header*/
1342    CcsImplHeader hdr;/*Ccs internal header*/
1343   } h;
1344   void *reqData;/*CCS request data*/
1345   int pe,reqBytes;
1346   if (0==CcsServer_recvRequest(&h.hdr,&reqData))
1347     return;/*Malformed request*/
1348   pe=ChMessageInt(h.hdr.pe);
1349   reqBytes=ChMessageInt(h.hdr.len);
1350
1351   if (pe<0 || pe>=nodetab_size) {
1352         pe=0;
1353         h.hdr.pe=ChMessageInt_new(pe);
1354   }
1355
1356   if (strncmp(REDIRECT_STDIO, h.hdr.handler, strlen(REDIRECT_STDIO))==0) {
1357     /*This is a request to make a duplicate to stdio*/
1358     if (stdio_alloc == 0) {
1359       stdio_alloc = 4096;
1360       stdio_buffer = malloc(stdio_alloc);
1361     }
1362     CcsServer_sendReply(&h.hdr,0,0);
1363   }
1364   else if (strncmp(FETCH_STDIO, h.hdr.handler, strlen(FETCH_STDIO))==0) {
1365     /*Reply with the data loaded until now*/
1366     if (stdio_size > 0) {
1367       h.hdr.len = ChMessageInt_new(1); /* fake len to prevent socket closed without reply! */
1368       CcsServer_sendReply(&h.hdr,stdio_size,stdio_buffer);
1369       stdio_size = 0;
1370     } else {
1371       if (stdio_waiting) {
1372         CcsServer_sendReply(&stdio_waiting_hdr,0,0);
1373       }
1374       stdio_waiting = 1;
1375       stdio_waiting_hdr = h.hdr;
1376       stdio_waiting_hdr.len = ChMessageInt_new(1); /* fake len to prevent socket closed without reply! */
1377     }
1378   }
1379   else {
1380
1381 #define LOOPBACK 0
1382 #if LOOPBACK /*Immediately reply "there's nothing!" (for performance testing)*/
1383   CcsServer_sendReply(&h.hdr,0,0);
1384 #else
1385   /*Fill out the charmrun header & forward the CCS request*/
1386   ChMessageHeader_new("req_fw",sizeof(h.hdr)+reqBytes,&h.ch);  
1387   
1388   bufs[0]=&h; lens[0]=sizeof(h);
1389   bufs[1]=reqData; lens[1]=reqBytes;
1390   skt_sendV(nodetab_ctrlfd(pe),2,bufs,lens);
1391
1392 #endif
1393   }
1394   free(reqData);
1395 }
1396
1397 /*
1398 Forward the CCS reply (if any) from this client back to the 
1399 original network requestor, on the original request socket.
1400  */
1401 int req_ccs_reply_fw(ChMessage *msg,SOCKET srcFd) {
1402   int len=msg->len; /* bytes of data remaining to receive */
1403   
1404   /* First pull down the CCS header sent by the client. */
1405   CcsImplHeader hdr;
1406   skt_recvN(srcFd,&hdr,sizeof(hdr)); len-=sizeof(hdr);
1407   
1408 #define m (4*1024) /* packets of message to recv/send at once */
1409   if (len<m || hdr.attr.auth) 
1410   { /* short or authenticated message: grab the whole thing first */
1411      void *data=malloc(len);
1412      skt_recvN(srcFd,data,len);
1413      CcsServer_sendReply(&hdr,len,data);
1414      free(data);
1415   } 
1416   else 
1417   { /* long messages: packetize (for pipelined sending; a 2x bandwidth improvement!) */
1418     ChMessageInt_t outLen;
1419     int destFd; /* destination for data */
1420     skt_abortFn old=skt_set_abort(reply_abortFn);
1421     int destErrs=0;
1422     
1423     destFd=ChMessageInt(hdr.replyFd);
1424     outLen=ChMessageInt_new(len);
1425     skt_sendN(destFd,&outLen,sizeof(outLen)); /* first comes the length */
1426     while(len>0) {
1427        char buf[m];
1428        int r=m; if (r>len) r=len;
1429        skt_recvN(srcFd,buf,r);
1430        if (0==destErrs) /* don't keep sending to dead clients, but *do* clean out srcFd */
1431           destErrs|=skt_sendN(destFd,buf,r);
1432        len-=m;
1433 #undef m
1434     }
1435     skt_close(destFd);
1436   
1437     skt_set_abort(old); 
1438   }
1439   return 0;
1440 }
1441
1442 #else
1443 int req_ccs_reply_fw(ChMessage *msg,SOCKET srcFd) {
1444   
1445 }
1446 #endif /*CMK_CCS_AVAILABLE*/
1447
1448 /****************************************************************************
1449  *
1450  * REQUEST SERVICER
1451  *
1452  * The request servicer accepts connections on a TCP port.  The client
1453  * sends a sequence of commands (each is one line).  It then closes the
1454  * connection.  The server must then contact the client, sending replies.
1455  *
1456  ****************************************************************************/
1457  /** Macro to switch on the case when charmrun stays up even if
1458  one of the processor crashes*/
1459 /*#define __FAULT__*/
1460
1461 SOCKET *req_clients; /*TCP request sockets for each node*/
1462 int  req_nClients;/*Number of entries in above list (==nodetab_rank0_size)*/
1463 int             req_ending=0;
1464
1465 /* socket and std streams for the gdb info program */
1466 int gdb_info_pid=0;
1467 int gdb_info_std[3];
1468 FILE *gdb_stream=NULL;
1469
1470 #define REQ_OK 0
1471 #define REQ_FAILED -1
1472
1473 /* This is the only place where charmrun talks back to anyone. 
1474 */
1475 int req_reply(SOCKET fd, char *type, 
1476               const char *data, int dataLen)
1477 {
1478   ChMessageHeader msg;
1479   if (fd == INVALID_SOCKET) return REQ_FAILED;
1480   ChMessageHeader_new(type,dataLen,&msg);
1481   skt_sendN(fd,(const char *)&msg,sizeof(msg));
1482   skt_sendN(fd,data,dataLen);
1483   return REQ_OK;
1484 }
1485
1486 /* Request handlers:
1487 When a client asks us to do something, these are the
1488 routines that actually respond to the request.
1489 */
1490 /*Stash this new node's control and data ports.
1491  */
1492 int req_handle_initnode(ChMessage *msg,SOCKET fd)
1493 {
1494 #if CMK_USE_IBVERBS
1495         int i;
1496         ChSingleNodeinfo *nodeInfo = (ChSingleNodeinfo *)msg->data;
1497 //      printf("Charmrun> msg->len %d sizeof(ChSingleNodeinfo) %d sizeof(ChInfiAddr) %d \n",msg->len,sizeof(ChSingleNodeinfo),sizeof(ChInfiAddr));
1498         if(msg->len != sizeof(ChSingleNodeinfo) + (nodetab_rank0_size-1)*sizeof(ChInfiAddr)){
1499     fprintf(stderr,"Charmrun: Bad initnode data length. Aborting\n");
1500                 exit(1);
1501         }
1502         nodeInfo->info.qpList = malloc(sizeof(ChInfiAddr)*(nodetab_rank0_size-1));
1503         memcpy((char *)nodeInfo->info.qpList,&msg->data[sizeof(ChSingleNodeinfo)],sizeof(ChInfiAddr)*(nodetab_rank0_size-1));
1504 /*      for(i=0;i<nodetab_rank0_size-1;i++){
1505                 printf("i %d  0x%0x 0x%0x 0x%0x\n",i,ChMessageInt(nodeInfo->info.qpList[i].lid),ChMessageInt(nodeInfo->info.qpList[i].qpn),ChMessageInt(nodeInfo->info.qpList[i].psn));
1506         }*/
1507 #else
1508   if (msg->len!=sizeof(ChSingleNodeinfo)) {
1509     fprintf(stderr,"Charmrun: Bad initnode data length. Aborting\n");
1510     fprintf(stderr,"Charmrun: possibly because: %s.\n", msg->data);
1511     exit(1);
1512   }
1513 #endif  
1514   nodeinfo_add((ChSingleNodeinfo *)msg->data,fd);
1515   return REQ_OK;
1516 }
1517
1518 /*Get the array of node numbers, IPs, and ports.
1519 This is used by the node-programs to talk to one another.
1520 */
1521 int req_handle_initnodetab(ChMessage *msg,SOCKET fd)
1522 {
1523         ChMessageHeader hdr;
1524         ChMessageInt_t nNodes=ChMessageInt_new(nodetab_rank0_size);
1525         ChMessageHeader_new("initnodetab",sizeof(ChMessageInt_t)+
1526                             sizeof(ChNodeinfo)*nodetab_rank0_size,&hdr);
1527         skt_sendN(fd,(const char *)&hdr,sizeof(hdr));
1528         skt_sendN(fd,(const char *)&nNodes,sizeof(nNodes));
1529         skt_sendN(fd,(const char *)nodeinfo_arr,
1530                   sizeof(ChNodeinfo)*nodetab_rank0_size);
1531                         
1532         return REQ_OK;
1533 }
1534
1535 /* Check this return code from "printf". */
1536 static void checkPrintfError(int err) {
1537   if (err<0) {
1538     static int warned=0;
1539     if (!warned) {
1540       perror("charmrun WARNING> error in printf");
1541       warned=1;
1542     }
1543   }
1544 }
1545
1546 void write_stdio_duplicate(char* data) {
1547   if (stdio_alloc > 0) {
1548     int size = strlen(data);
1549     
1550     if (stdio_waiting) {
1551       stdio_waiting = 0;
1552       CcsServer_sendReply(&stdio_waiting_hdr,size+1,data);
1553     }
1554     else {
1555       if (size+stdio_size >= stdio_alloc) {
1556         char *newbuf;
1557         stdio_alloc += (size>4096 ? size : 4096);
1558         newbuf = malloc(stdio_alloc);
1559         memcpy(newbuf, stdio_buffer, stdio_size);
1560         free(stdio_buffer);
1561         stdio_buffer = newbuf;
1562       }
1563       strcpy(&stdio_buffer[stdio_size], data);
1564       stdio_size += size;
1565     }
1566   }
1567 }
1568
1569 int req_handle_print(ChMessage *msg,SOCKET fd)
1570 {
1571   checkPrintfError(printf("%s",msg->data));
1572   checkPrintfError(fflush(stdout));
1573   write_stdio_duplicate(msg->data);
1574   return REQ_OK;
1575 }
1576
1577
1578 int req_handle_printerr(ChMessage *msg,SOCKET fd)
1579 {
1580   fprintf(stderr,"%s",msg->data);
1581   fflush(stderr);
1582   return REQ_OK;
1583 }
1584
1585
1586 int req_handle_printsyn(ChMessage *msg,SOCKET fd)
1587 {
1588   checkPrintfError(printf("%s",msg->data));
1589   checkPrintfError(fflush(stdout));
1590   write_stdio_duplicate(msg->data);
1591   req_reply(fd, "printdone", "", 1);
1592   return REQ_OK;
1593 }
1594
1595
1596 int req_handle_printerrsyn(ChMessage *msg,SOCKET fd)
1597 {
1598   fprintf(stderr,"%s",msg->data);
1599   fflush(stderr);
1600   req_reply(fd, "printdone", "", 1);
1601   return REQ_OK;
1602 }
1603
1604
1605 int req_handle_ending(ChMessage *msg,SOCKET fd)
1606 {  
1607   int i;
1608   req_ending++;
1609     
1610   if (req_ending == nodetab_size)
1611   {
1612     for (i=0;i<req_nClients;i++)
1613       skt_close(req_clients[i]);
1614     if (arg_verbose) printf("Charmrun> Graceful exit.\n");
1615     exit(0);
1616   }
1617   return REQ_OK;
1618 }
1619
1620
1621 int req_handle_abort(ChMessage *msg,SOCKET fd)
1622 {
1623   /*fprintf(stderr,"req_handle_abort called \n");*/
1624   if (msg->len==0) 
1625     fprintf(stderr,"Aborting!\n");
1626   else
1627     fprintf(stderr, "%s\n", msg->data);
1628   exit(1);
1629 }
1630
1631 int req_handle_scanf(ChMessage *msg,SOCKET fd)
1632 {
1633   char *fmt, *res, *p;
1634
1635   fmt = msg->data;
1636   fmt[msg->len-1]=0;
1637   res = input_scanf_chars(fmt);
1638   p = res; while (*p) { if (*p=='\n') *p=' '; p++; }
1639   req_reply(fd, "scanf-data", res, strlen(res)+1);
1640   free(res);
1641   return REQ_OK;
1642 }
1643
1644 #ifdef __FAULT__        
1645 void restart_node(int crashed_node);
1646 void reconnect_crashed_client(int socket_index,int crashed_node);
1647 void anounce_crash(int socket_index,int crashed_node);
1648
1649 static int _last_crash = 0;                     /* last crashed pe number */
1650 static int _crash_socket_index = 0;             /* last restart socket */
1651
1652 int req_handle_crashack(ChMessage *msg,SOCKET fd)
1653 {
1654   static int count = 0;
1655   count ++;
1656   if (count == req_nClients-1) {
1657     /* only after everybody else update its nodetab, can this
1658        restarted process continue */
1659     printf("Charmrun> continue node: %d\n", _last_crash);
1660     req_handle_initnodetab(NULL,req_clients[_crash_socket_index]);
1661     _last_crash = 0;
1662     count = 0;
1663   }
1664 }
1665 #endif
1666
1667 #ifdef __FAULT__
1668 void error_in_req_serve_client(SOCKET fd){
1669         SOCKET * new_req_clients=(SOCKET *)malloc((req_nClients-1)*sizeof(SOCKET));
1670         int count=0,i;
1671         int crashed_node,crashed_pe,node_index,socket_index;
1672         fprintf(stdout,"Socket %d failed \n",fd);
1673         for(i=0;i<nodetab_max;i++){
1674                 if(nodetab_ctrlfd(i) == fd){
1675                         break;
1676                 }
1677         }
1678         fflush(stdout);
1679         skt_close(fd);
1680         crashed_pe = i;
1681         node_index = i-nodetab_rank(crashed_pe);
1682         for(i=0;i<nodetab_rank0_size;i++){
1683                 if(node_index == nodetab_rank0_table[i]){
1684                         break;
1685                 }
1686         }
1687         crashed_node = i;
1688         /** should also send a message to all the other processors telling them that this guy has crashed*/
1689         /*anounce_crash(socket_index,crashed_node);*/
1690         restart_node(crashed_node);
1691         
1692         fprintf(stdout,"charmrun says Processor %d failed Node %d\n",crashed_pe,crashed_node);
1693         /** after the crashed processor has been recreated 
1694          it connects to charmrun. That data must now be filled 
1695          into the req_nClients array and the nodetab_table*/
1696
1697         for(i=0;i<req_nClients;i++){
1698                 if(req_clients[i] == fd){
1699                         break;
1700                 }
1701         }       
1702         socket_index = i;
1703         reconnect_crashed_client(socket_index,crashed_node);
1704 }
1705 #endif
1706
1707 int req_handler_dispatch(ChMessage *msg,SOCKET replyFd)
1708 {
1709   char *cmd=msg->header.type;
1710   int recv_status;
1711   DEBUGF(("Got request '%s'\n",cmd,replyFd));
1712 #if CMK_CCS_AVAILABLE   /* CCS *doesn't* want data yet, for faster forwarding */
1713   if (strcmp(cmd,"reply_fw")==0)   return req_ccs_reply_fw(msg,replyFd);
1714 #endif
1715
1716   /* grab request data */
1717   recv_status = ChMessageData_recv(replyFd,msg);
1718 #ifdef __FAULT__        
1719   if(recv_status < 0)  error_in_req_serve_client(replyFd);
1720 #endif
1721
1722        if (strcmp(cmd,"ping")==0)       return REQ_OK;
1723   else if (strcmp(cmd,"print")==0)      return req_handle_print(msg,replyFd);
1724   else if (strcmp(cmd,"printerr")==0)   return req_handle_printerr(msg,replyFd);
1725   else if (strcmp(cmd,"printsyn")==0)  return req_handle_printsyn(msg,replyFd);
1726   else if (strcmp(cmd,"printerrsyn")==0) return req_handle_printerrsyn(msg,replyFd);
1727   else if (strcmp(cmd,"scanf")==0)      return req_handle_scanf(msg,replyFd);
1728   else if (strcmp(cmd,"ending")==0)     return req_handle_ending(msg,replyFd);
1729   else if (strcmp(cmd,"abort")==0)      return req_handle_abort(msg,replyFd);
1730 #ifdef __FAULT__        
1731   else if (strcmp(cmd,"crash_ack")==0)   return req_handle_crashack(msg,replyFd);
1732 #endif
1733   else {
1734 #ifndef __FAULT__       
1735         fprintf(stderr,"Charmrun> Bad control socket request '%s'\n",cmd); 
1736         abort();
1737         return REQ_OK;
1738 #endif                          
1739   }
1740   return REQ_OK;
1741 }
1742
1743 void req_serve_client(SOCKET fd)
1744 {
1745   int recv_status;
1746   int status;
1747   ChMessage msg;
1748   DEBUGF(("Getting message from client...\n"));
1749   recv_status = ChMessageHeader_recv(fd,&msg);
1750 #ifdef __FAULT__        
1751   if(recv_status < 0) error_in_req_serve_client(fd);
1752 #endif
1753         
1754   DEBUGF(("Message is '%s'\n",msg.header.type));
1755   status = req_handler_dispatch(&msg,fd);
1756   switch (status) 
1757   {
1758     case REQ_OK: break;
1759     case REQ_FAILED: 
1760         fprintf(stderr,"Charmrun> Error processing control socket request %s\n",msg.header.type); 
1761         abort();
1762         break;
1763   }
1764   ChMessage_free(&msg);
1765 }
1766
1767
1768 int ignore_socket_errors(int c,const char *m)
1769 {  /*Abandon on further socket errors during error shutdown*/
1770   
1771 #ifndef __FAULT__       
1772   exit(2);
1773 #endif  
1774         return -1;
1775 }
1776
1777 /*A socket went bad somewhere!  Immediately disconnect,
1778 which kills everybody.
1779 */
1780 int socket_error_in_poll(int code,const char *msg)
1781 {
1782 /*commenting it for fault tolerance*/
1783 /*ifdef it*/
1784
1785         int i;
1786         skt_set_abort(ignore_socket_errors);
1787         fprintf(stderr,"Charmrun: error on request socket--\n"
1788                         "%s\n",msg);
1789 #ifndef __FAULT__                       
1790         for (i=0;i<req_nClients;i++)
1791                 skt_close(req_clients[i]);
1792         exit(1);
1793 #endif  
1794         ftTimer = GetClock();
1795         return -1;
1796 }
1797
1798 /*
1799 Wait for incoming requests on all client sockets,
1800 and the CCS socket (if present).
1801 */
1802 void req_poll()
1803 {
1804   int status,i;
1805   fd_set  rfds;
1806   struct timeval tmo;
1807   int readcount;
1808
1809   skt_set_abort(socket_error_in_poll);
1810
1811   tmo.tv_sec = 1;
1812   tmo.tv_usec = 0;
1813   FD_ZERO(&rfds);
1814   for (i=0;i<req_nClients;i++)
1815         FD_SET(req_clients[i],&rfds);
1816   if (CcsServer_fd()!=INVALID_SOCKET) FD_SET(CcsServer_fd(),&rfds);
1817   if (arg_charmdebug) {
1818     FD_SET(0, &rfds);
1819     FD_SET(gdb_info_std[1], &rfds);
1820     FD_SET(gdb_info_std[2], &rfds);
1821   }
1822   DEBUGF(("Req_poll: Calling select...\n"));
1823   status=select(FD_SETSIZE, &rfds, 0, 0, &tmo);
1824   DEBUGF(("Req_poll: Select returned %d...\n",status));
1825
1826   if (status==0) return;/*Nothing to do-- timeout*/
1827
1828   if (status<0){ 
1829                 fflush(stdout);
1830                 fflush(stderr);
1831                 socket_error_in_poll(1359,"Node program terminated unexpectedly!\n");
1832         }
1833   for (i=0;i<req_nClients;i++)
1834         if (FD_ISSET(req_clients[i],&rfds))
1835           {
1836             readcount=10;   /*number of successive reads we serve per socket*/
1837             /*This client is ready to read*/
1838             do { req_serve_client(req_clients[i]); readcount--;}
1839             while (1==skt_select1(req_clients[i],0) && readcount>0);
1840           }
1841
1842   if (CcsServer_fd()!=INVALID_SOCKET)
1843          if (FD_ISSET(CcsServer_fd(),&rfds)) {
1844                   DEBUGF(("Activity on CCS server port...\n"));
1845                   req_ccs_connect();
1846          }
1847
1848   if (arg_charmdebug) {
1849     char buf[2048];
1850     if (FD_ISSET(0, &rfds)) {
1851       int indata = read(0, buf, 5);
1852       buf[indata] = 0;
1853       if (indata < 5) fprintf(stderr,"Error reading command (%s)\n",buf);
1854       if (strncmp(buf,"info:",5)==0) {
1855         /* Found info command, forward data to gdb info program */
1856         char c;
1857         int num=0;
1858         //printf("Command to be forwarded\n");
1859         while (read(0, &c, 1)!=-1) {
1860           buf[num++]=c;
1861           if (c=='\n' || num >= 2045) {
1862             write(gdb_info_std[0], buf, num);
1863             if (c=='\n') break;
1864           }
1865         }
1866       }
1867       //printf("Command from charmdebug: %d(%s)\n",indata,buf);
1868     }
1869     /* All streams from gdb are forwarded to the stderr stream through the FILE
1870        gdb_stream which has been duplicated from stderr */
1871     /* NOTE: gdb_info_std[2] must be flushed before gdb_info_std[1] because the
1872        latter contains the string "(gdb) " ending the synchronization. Also the
1873        std[1] should be read with the else statement. It will not work without. */
1874     if (FD_ISSET(gdb_info_std[2], &rfds)) {
1875       int indata = read(gdb_info_std[2], buf, 100);
1876       /*printf("read data from gdb info stderr %d\n",indata);*/
1877       if (indata > 0) {
1878         buf[indata] = 0;
1879         //printf("printing %s\n",buf);
1880         //fflush(stdout);
1881         //fprintf(gdb_stream,"%s",buf);
1882         fflush(gdb_stream);
1883       }
1884     } else if (FD_ISSET(gdb_info_std[1], &rfds)) {
1885       int indata = read(gdb_info_std[1], buf, 100);
1886       /*printf("read data from gdb info stdout %d\n",indata);*/
1887       if (indata > 0) {
1888         buf[indata] = 0;
1889         //printf("printing %s\n",buf);
1890         //fflush(stdout);
1891         fprintf(gdb_stream,"%s",buf);
1892         fflush(gdb_stream);
1893       }
1894     }
1895   }
1896 }
1897
1898
1899
1900 static unsigned int server_port;
1901 static char server_addr[1024];/* IP address or hostname of charmrun*/
1902 static SOCKET server_fd;
1903
1904 int client_connect_problem(int code,const char *msg)
1905 {/*Called when something goes wrong during a client connect*/
1906
1907         fprintf(stderr,"Charmrun> error %d attaching to node:\n"
1908                 "%s\n",code,msg);
1909         exit(1);
1910         return -1;
1911 }
1912
1913 /** return 1 if connection is openned succesfully with client**/
1914 int errorcheck_one_client_connect(int client){
1915         unsigned int clientPort;/*These are actually ignored*/
1916         skt_ip_t clientIP;
1917         if (arg_verbose) printf("Charmrun> Waiting for %d-th client to connect.\n",client);
1918         if (0==skt_select1(server_fd,arg_timeout*1000))
1919                 client_connect_problem(client,"Timeout waiting for node-program to connect");
1920
1921                 
1922         req_clients[client]=skt_accept(server_fd,&clientIP,&clientPort);
1923
1924         
1925         if (req_clients[client]==SOCKET_ERROR) 
1926                 client_connect_problem(client,"Failure in node accept");
1927
1928         return 1;
1929 };
1930
1931
1932 #if CMK_C_INLINE
1933 inline static
1934 #endif
1935 void read_initnode_one_client(int client){
1936                 ChMessage msg;
1937                 if (!skt_select1(req_clients[client],arg_timeout*1000))
1938                    client_connect_problem(client,"Timeout on IP request");
1939                 ChMessage_recv(req_clients[client],&msg);
1940                 req_handle_initnode(&msg,req_clients[client]);
1941                 ChMessage_free(&msg);
1942 }
1943
1944
1945 #if CMK_IBVERBS_FAST_START
1946 void req_one_client_partinit(int client){
1947    ChMessage partStartMsg;
1948          int clientNode;
1949                 
1950          if(errorcheck_one_client_connect(client)){
1951            if (!skt_select1(req_clients[client],arg_timeout*1000))
1952                    client_connect_problem(client,"Timeout on partial init request");
1953                          
1954            ChMessage_recv(req_clients[client],&partStartMsg);
1955            clientNode =            ChMessageInt(*(ChMessageInt_t*)partStartMsg.data);
1956            assert(strncmp(partStartMsg.header.type,"partinit",8) == 0);
1957            ChMessage_free(&partStartMsg);
1958          } 
1959         
1960 };
1961 #endif
1962
1963 void req_set_client_connect(int start,int end) {
1964         fd_set sockset;
1965         ChMessage msg;
1966         int client,i;
1967         int done,maxdesc;
1968         int *finished;
1969         int curclient,curclientend,curclientstart;
1970         
1971         curclient=curclientend=curclientstart=start;
1972
1973         finished=malloc((end-start)*sizeof(int));
1974         for(i=0;i<(end-start);i++)
1975                 finished[i]=0;
1976
1977         done=0;
1978         while(!done) {
1979                 /* check server socket for messages */
1980                 while(curclientstart==curclientend||skt_select1(server_fd,1)!=0) {
1981                         errorcheck_one_client_connect(curclientend++);
1982                 }
1983                 /* check appropriate clients for messages */
1984                 for(client=curclientstart;client<curclientend;client++)
1985                         if(req_clients[client]>0) {
1986                                 if(skt_select1(req_clients[client],1)!=0) {
1987                                         ChMessage_recv(req_clients[client],&msg);
1988                                         req_handle_initnode(&msg,req_clients[client]);
1989                                         finished[client-start]=1;
1990                                 }
1991                         }
1992
1993
1994                 /* test if done */
1995                 done=1;
1996                 for(i=curclientstart-start;i<(end-start);i++)
1997                         if(finished[i]==0) {
1998                                 curclientstart=start+i;
1999                                 done=0;
2000                                 break;
2001                         }
2002
2003         }
2004         ChMessage_free(&msg);
2005
2006         free(finished);
2007 }
2008
2009
2010 /* allow one client to connect */
2011 void req_one_client_connect(int client)
2012 {
2013         if(errorcheck_one_client_connect(client))
2014         { /*This client has just connected-- fetch his name and IP*/
2015                 read_initnode_one_client(client);
2016         }
2017 }
2018
2019 #if CMK_USE_IBVERBS
2020 /* Each node has sent the qpn data for all the qpns it has created
2021    This data needs to be sent to all the other nodes
2022          This needs to be done for all nodes
2023 **/
2024 void exchange_qpdata_clients(){
2025         int proc,i;
2026         for( i=0;i<nodetab_rank0_size;i++){
2027                 int nt=nodetab_rank0_table[i];/*Nodetable index for this node*/ 
2028                 nodetab_table[nt]->qpData = malloc(sizeof(ChInfiAddr)*nodetab_rank0_size);
2029         }
2030         for(proc =0;proc< nodetab_rank0_size;proc++){
2031                 int count=0;
2032                 for(i=0;i<nodetab_rank0_size;i++){
2033                         if(i == proc){
2034                         }else{
2035                                 int nt=nodetab_rank0_table[i];/*Nodetable index for this node*/ 
2036                                 nodetab_table[nt]->qpData[proc] =  nodeinfo_arr[proc].qpList[count];
2037         //                      printf("Charmrun> nt %d proc %d lid 0x%x qpn 0x%x psn 0x%x\n",nt,proc,ChMessageInt(nodetab_table[nt]->qpData[proc].lid),ChMessageInt(nodetab_table[nt]->qpData[proc].qpn),ChMessageInt(nodetab_table[nt]->qpData[proc].psn));
2038                                 count++;
2039                         }
2040                 }
2041                 free(nodeinfo_arr[proc].qpList);
2042         }
2043 };
2044
2045 void    send_clients_nodeinfo_qpdata(){
2046         int node;
2047         int msgSize = sizeof(ChMessageInt_t)+sizeof(ChNodeinfo)*nodetab_rank0_size+sizeof(ChInfiAddr)*nodetab_rank0_size;
2048         for(node=0;node<nodetab_rank0_size;node++){
2049                 int nt=nodetab_rank0_table[node];/*Nodetable index for this node*/
2050 //              printf("Charmrun> Node %d proc %d sending initnodetab \n",node,nt);
2051                 ChMessageHeader hdr;
2052                 ChMessageInt_t nNodes=ChMessageInt_new(nodetab_rank0_size);
2053                 ChMessageHeader_new("initnodetab",msgSize,&hdr);
2054                 skt_sendN(nodetab_table[nt]->ctrlfd,(const char *)&hdr,sizeof(hdr));
2055                 skt_sendN(nodetab_table[nt]->ctrlfd,(const char *)&nNodes,sizeof(nNodes));
2056                 skt_sendN(nodetab_table[nt]->ctrlfd,(const char *)nodeinfo_arr,sizeof(ChNodeinfo)*nodetab_rank0_size);
2057                 skt_sendN(nodetab_table[nt]->ctrlfd,(const char *)&nodetab_table[nt]->qpData[0],sizeof(ChInfiAddr)*nodetab_rank0_size);                         
2058         }
2059 }
2060 #endif
2061
2062
2063 /*Wait for all the clients to connect to our server port*/
2064 void req_client_connect(void)
2065 {
2066         int client;
2067         nodeinfo_allocate();
2068         req_nClients=nodetab_rank0_size;
2069         req_clients=(SOCKET *)malloc(req_nClients*sizeof(SOCKET));
2070         for(client=0;client<req_nClients;client++)
2071                 req_clients[client]=-1;
2072         
2073         skt_set_abort(client_connect_problem);
2074         
2075 #if CMK_IBVERBS_FAST_START
2076         for (client=0;client<req_nClients;client++){
2077                 req_one_client_partinit(client);
2078         }
2079         for (client=0;client<req_nClients;client++){
2080                 read_initnode_one_client(client);
2081         }
2082 #else
2083         req_set_client_connect(0,req_nClients);
2084 #endif
2085         
2086         if (portOk == 0) exit(1);
2087         if (arg_verbose) printf("Charmrun> All clients connected.\n");
2088 #if CMK_USE_IBVERBS
2089         exchange_qpdata_clients();
2090         send_clients_nodeinfo_qpdata();
2091 #else
2092         for (client=0;client<req_nClients;client++)
2093                 req_handle_initnodetab(NULL,req_clients[client]);
2094 #endif
2095         if (arg_verbose) printf("Charmrun> IP tables sent.\n");
2096 }
2097
2098 #ifndef CMK_BPROC
2099
2100 void start_one_node_rsh(int rank0no);
2101 void finish_one_node(int rank0no);
2102 void finish_set_nodes(int start, int stop);
2103
2104
2105
2106 void req_client_start_and_connect(void)
2107 {
2108         int client, c;
2109         int batch = arg_batch_spawn;        /* fire several at a time */
2110         int clientgroup,clientstart;
2111         int counter;
2112
2113         nodeinfo_allocate();
2114         req_nClients=nodetab_rank0_size;
2115         req_clients=(SOCKET *)malloc(req_nClients*sizeof(SOCKET));
2116         
2117         skt_set_abort(client_connect_problem);
2118
2119         client=0;
2120         while(client<req_nClients) { /* initiate a batch */
2121                 clientstart=client;
2122
2123                 for(counter=0;counter<batch;counter++) { /* initiate batch number of nodes */
2124                         clientgroup=start_set_node_rsh(client);
2125                         client+=clientgroup;
2126                         if(client>=req_nClients) {
2127                                 client=req_nClients;
2128                                 break;
2129                         }
2130                 }
2131                 finish_set_nodes(clientstart,client);
2132
2133 #if CMK_IBVERBS_FAST_START
2134                 for (c=clientstart;c<client;c++) { 
2135                         req_one_client_partinit(c);
2136                 }
2137 #else
2138                 req_set_client_connect(clientstart,client);
2139 #endif                                          
2140         }
2141
2142
2143 #if CMK_IBVERBS_FAST_START
2144         for (client=0;client<req_nClients;client++){
2145                 read_initnode_one_client(client);
2146         }
2147 #endif
2148         if (portOk == 0) exit(1);
2149         if (arg_verbose) printf("Charmrun> All clients connected.\n");
2150         
2151 #if CMK_USE_IBVERBS
2152         exchange_qpdata_clients();      
2153         send_clients_nodeinfo_qpdata();
2154 #else
2155         for (client=0;client<req_nClients;client++) {
2156                 req_handle_initnodetab(NULL,req_clients[client]);
2157         }
2158 #endif    
2159         if (arg_verbose) printf("Charmrun> IP tables sent.\n");
2160         free(rsh_pids); /* done with rsh_pids */
2161 }
2162
2163 #endif
2164
2165 /*Start the server socket the clients will connect to.*/
2166 void req_start_server(void)
2167 {
2168   skt_ip_t ip=skt_innode_my_ip();
2169   if (arg_local)
2170       /* local execution, use localhost always */
2171     strcpy(server_addr, "127.0.0.1");
2172   else if (arg_charmrunip != NULL)
2173       /* user specify the IP at +useip */
2174     strcpy(server_addr, arg_charmrunip);
2175   else if ( (arg_charmrunip = getenv ("CHARMRUN_IP")) != NULL)
2176       /* user specify the env  */
2177     strcpy(server_addr, arg_charmrunip);
2178   else if (skt_ip_match(ip,_skt_invalid_ip)) {
2179       printf("Charmrun> Warning-- cannot find IP address for your hostname.  Using loopback.\n");
2180       strcpy(server_addr, "127.0.0.1");
2181   }
2182   else if (arg_usehostname || skt_ip_match(ip,skt_lookup_ip("127.0.0.1")))
2183       /*Use symbolic host name as charmrun address*/
2184     gethostname(server_addr,sizeof(server_addr));
2185   else 
2186     skt_print_ip(server_addr,ip);
2187
2188   server_port = 0;
2189   server_fd=skt_server(&server_port);
2190
2191   if (arg_verbose) {
2192     printf("Charmrun> Charmrun = %s, port = %d\n", server_addr, server_port);
2193   }
2194   
2195 #if CMK_CCS_AVAILABLE
2196   if(arg_server == 1) CcsServer_new(NULL,&arg_server_port,arg_server_auth);
2197 #endif
2198 }
2199
2200 /****************************************************************************
2201  *
2202  *  The Main Program
2203  *
2204  ****************************************************************************/
2205 void start_nodes_daemon(void);
2206 void start_nodes_rsh(void);
2207 #if CMK_BPROC
2208 void nodetab_init_for_scyld(void);
2209 void start_nodes_scyld(void);
2210 #endif
2211 void start_nodes_local(char **envp);
2212 void kill_nodes(void);
2213 void open_gdb_info(void);
2214 void read_global_segments_size(void);
2215
2216 static void fast_idleFn(void) {sleep(0);}
2217 void finish_nodes(void);
2218
2219 int main(int argc, char **argv, char **envp)
2220 {
2221   srand(time(0));
2222   skt_init();
2223   skt_set_idle(fast_idleFn);
2224   /* CrnSrand((int) time(0)); */
2225   /* notify charm developers that charm is in use */
2226   ping_developers();
2227   /* Compute the values of all constants */
2228   arg_init(argc, argv);
2229   if(arg_verbose) fprintf(stderr, "Charmrun> charmrun started...\n");
2230 #if CMK_BPROC
2231   /* check scyld configuration */
2232   if (arg_nodelist)
2233     nodetab_init();
2234   else
2235     nodetab_init_for_scyld();
2236 #else
2237   /* Initialize the node-table by reading nodesfile */
2238   nodetab_init();
2239 #endif
2240
2241   /* Start the server port */
2242   req_start_server();
2243   
2244   /* Initialize the IO module */
2245   input_init();
2246   
2247   /* start the node processes */
2248   if (0!=getenv("CONV_DAEMON"))
2249     start_nodes_daemon();
2250   else
2251 #if CMK_BPROC
2252     start_nodes_scyld();
2253 #else
2254 #if CMK_USE_IBVERBS
2255                 printf("Charmrun> IBVERBS version of charmrun\n");
2256 #endif
2257     if (!arg_local) {
2258       if (!arg_batch_spawn)
2259         start_nodes_rsh();
2260       else
2261         req_client_start_and_connect();
2262     }
2263     else
2264       start_nodes_local(envp);
2265 #endif
2266
2267   if (arg_charmdebug) {
2268 #if (defined(_WIN32) && !defined(__CYGWIN__)) || CMK_BPROC
2269     /* Gdb stream (and charmdebug) currently valid only with rsh subsystem */
2270     fprintf(stderr, "Charmdebug is supported currently only with the rsh subsystem\n");
2271     abort(); 
2272 #else
2273     /* Open an additional connection to node 0 with a gdb to grab info */
2274     printf("opening connection with node 0 for info gdb\n");
2275     read_global_segments_size();
2276     open_gdb_info();
2277     gdb_stream = fdopen(dup(2), "a");
2278     dup2(1, 2);
2279 #endif
2280   }
2281
2282   if(arg_verbose) fprintf(stderr, "Charmrun> node programs all started\n");
2283
2284   /* Wait for all clients to connect */
2285 #if !CMK_RSH_KILL
2286   if (!arg_batch_spawn) finish_nodes();
2287 #endif
2288   if (!arg_batch_spawn) req_client_connect();
2289 #if CMK_RSH_KILL
2290   kill_nodes();
2291 #endif
2292   if(arg_verbose) fprintf(stderr, "Charmrun> node programs all connected\n");
2293
2294   /* enter request-service mode */
2295   while (1) req_poll();
2296 }
2297
2298 /*This little snippet creates a NETSTART 
2299 environment variable entry for the given node #.
2300 It uses the idiotic "return reference to static buffer"
2301 string return idiom.
2302 */
2303 char *create_netstart(int node)
2304 {
2305   static char dest[1024];
2306   int port=0;
2307   sprintf(dest,"%d %s %d %d %d",node,server_addr,server_port,getpid()&0x7FFF, port);
2308   return dest;
2309 }
2310
2311 /* The remainder of charmrun is only concerned with starting all
2312 the node-programs, also known as charmrun clients.  We have to
2313 start nodetab_rank0_size processes on the remote machines.
2314 */
2315
2316 /*Ask the converse daemon running on each machine to start the node-programs.*/
2317 void start_nodes_daemon(void)
2318 {
2319   taskStruct task;
2320   char argBuffer[5000];/*Buffer to hold assembled program arguments*/
2321   int i,nodeNumber;
2322
2323   /*Set the parts of the task structure that will be the same for all nodes*/
2324   /*Figure out the command line arguments (same for all PEs)*/
2325   argBuffer[0]=0;
2326   for (i=0;arg_argv[i];i++) 
2327   {
2328     if (arg_verbose)
2329       printf("Charmrun> packing arg: %s\n", arg_argv[i]);
2330     strcat(argBuffer," ");
2331     strcat(argBuffer,arg_argv[i]);
2332   }
2333   
2334   task.magic=ChMessageInt_new(DAEMON_MAGIC);
2335
2336 /*Start up the user program, by sending a message
2337   to PE 0 on each node.*/
2338   for (nodeNumber=0;nodeNumber<nodetab_rank0_size;nodeNumber++)
2339   {
2340     char nodeArgBuffer[5000];/*Buffer to hold assembled program arguments*/
2341     char *argBuf;
2342     char* arg_nodeprog_r, *arg_currdir_r;
2343     char statusCode='N';/*Default error code-- network problem*/
2344     int fd;
2345     int pe0=nodetab_rank0_table[nodeNumber];
2346     
2347     arg_currdir_r = pathfix(arg_currdir_a, nodetab_pathfixes(nodeNumber));
2348     strcpy(task.cwd,arg_currdir_r);
2349
2350     arg_nodeprog_r = pathextfix(arg_nodeprog_a, nodetab_pathfixes(nodeNumber), nodetab_ext(nodeNumber));
2351     strcpy(task.pgm,arg_nodeprog_r);
2352
2353     if (arg_verbose)
2354       printf("Charmrun> Starting node program %d on '%s' as %s.\n",nodeNumber,nodetab_name(pe0), arg_nodeprog_r);
2355
2356     sprintf(task.env,"NETSTART=%s",create_netstart(nodeNumber));
2357
2358     if (nodetab_nice(nodeNumber) != -100) {
2359       if(arg_verbose) fprintf(stderr, "Charmrun> +nice %d\n", nodetab_nice(nodeNumber));
2360       sprintf(nodeArgBuffer, "%s +nice %d", argBuffer, nodetab_nice(nodeNumber));
2361       argBuf = nodeArgBuffer;
2362     }
2363     else 
2364       argBuf = argBuffer;
2365     task.argLength=ChMessageInt_new(strlen(argBuf));
2366
2367     /*Send request out to remote node*/
2368     fd = skt_connect(nodetab_ip(pe0),
2369                      DAEMON_IP_PORT,30);
2370     if (fd!=INVALID_SOCKET)
2371     {/*Contact!  Ask the daemon to start the program*/
2372       skt_sendN(fd, (const char *)&task, sizeof(task));
2373       skt_sendN(fd, (const char *)argBuf, strlen(argBuf));
2374       skt_recvN(fd, &statusCode,sizeof(char));
2375     }
2376     if (statusCode!='G')
2377     {/*Something went wrong--*/
2378       fprintf(stderr,"Error '%c' starting remote node program on %s--\n%s\n",
2379                   statusCode,nodetab_name(pe0),daemon_status2msg(statusCode));
2380           exit(1);
2381     } else if (arg_verbose)
2382           printf("Charmrun> Node program %d started.\n",nodeNumber);
2383   }
2384 }
2385
2386 #if defined(_WIN32) && !defined(__CYGWIN__)
2387 /*Sadly, interprocess communication on Win32 is quite
2388   different, so we can't use Rsh on win32 yet.  
2389   Fall back to the daemon.*/
2390 void start_nodes_rsh() {start_nodes_daemon();}
2391 void finish_nodes(void) {}
2392 void start_one_node_rsh(int rank0no) {}
2393 void finish_one_node(int rank0no) {}
2394
2395 int start_set_node_rsh(int client) {}
2396 void finish_set_nodes(int start, int stop) {}
2397
2398 void envCat(char *dest,LPTSTR oldEnv)
2399 {
2400   char *src=oldEnv;
2401   dest+=strlen(dest);//Advance to end of dest
2402   dest++;//Advance past terminating NULL character
2403   while ((*src)!='\0') {
2404     int adv=strlen(src)+1;//Length of newly-copied string plus NULL
2405     strcpy(dest,src);//Copy another environment string
2406     dest+=adv;//Advance past newly-copied string and NULL
2407     src+=adv;//Ditto for src
2408   }
2409   *dest='\0';//Paste on final terminating NULL character
2410   FreeEnvironmentStrings(oldEnv);
2411 }
2412
2413
2414 /* simple version of charmrun that avoids the rshd or charmd,   */
2415 /* it spawn the node program just on local machine using exec. */
2416 void start_nodes_local(char ** env)
2417 {
2418   int ret, i;
2419   PROCESS_INFORMATION pi;     /* process Information for the process spawned */
2420   char **p;
2421
2422   char environment[10000];/*Doubly-null terminated environment strings*/
2423   char cmdLine[10000];/*Program command line, including executable name*/
2424 /*Command line too long.*/
2425 /*
2426   if (strlen(pparam_argv[1])+strlen(args) > 10000) 
2427         return 0; 
2428 */
2429   strcpy(cmdLine,pparam_argv[1]);
2430   p = pparam_argv+2;
2431   while ((*p)!='\0') {
2432     strcat(cmdLine," ");
2433     strcat(cmdLine,*p);
2434     p++;
2435   }
2436
2437   for (i=0; i<arg_requested_pes; i++)
2438   {
2439     STARTUPINFO si={0};         /* startup info for the process spawned */
2440
2441     sprintf(environment, "NETSTART=%s",  create_netstart(i));
2442     /*Paste all system environment strings */
2443     envCat(environment,GetEnvironmentStrings());
2444   
2445     /* Initialise the security attributes for the process 
2446      to be spawned */
2447     si.cb = sizeof(si);   
2448     if (arg_verbose)
2449       printf("Charmrun> start %d node program on localhost.\n", i);
2450
2451     ret = CreateProcess(NULL,   /* application name */
2452                     cmdLine,    /* command line */
2453                     NULL,/*&sa,*/               /* process SA */
2454                     NULL,/*&sa,*/               /* thread SA */
2455                     FALSE,      /* inherit flag */
2456 #if 1
2457                     CREATE_NEW_PROCESS_GROUP|DETACHED_PROCESS, 
2458 #else
2459                     CREATE_NEW_PROCESS_GROUP|CREATE_NEW_CONSOLE,
2460 #endif
2461                         /* creation flags */
2462                     environment,                /* environment block */
2463                     ".",                        /* working directory */
2464                     &si,                        /* startup info */
2465                     &pi);
2466  
2467     if (ret==0)
2468     {
2469       /*Something went wrong!  Look up the Windows error code*/
2470 /*
2471       int error=GetLastError();
2472       char statusCode=daemon_err2status(error);
2473       fprintf(logfile,"******************* ERROR *****************\n"
2474               "Error in creating process!\n"
2475               "Error code = %ld-- %s\n\n\n", error,
2476               daemon_status2msg(statusCode));
2477           fflush(logfile);
2478 */
2479       int error=GetLastError();
2480       printf("startProcess failed to start process \"%s\" with status: %d\n", pparam_argv[1], error);
2481       exit(1) ;
2482     } 
2483   }
2484 }
2485
2486 #elif CMK_BPROC
2487
2488 int bproc_nodeisup(int node)
2489 {
2490     int status = 0;
2491 #if CMK_BPROC_VERSION < 4
2492     if (bproc_nodestatus(node) == bproc_node_up) status = 1;
2493     if (arg_verbose)
2494       printf("Charmrun> node %d status: %s\n", node, status?"up":"down");
2495 #else
2496     char nodestatus[128];
2497     if (node == -1) {           /* master node is always up */
2498       strcpy(nodestatus, "up");
2499       status = 1;
2500     }
2501     if (bproc_nodestatus(node, nodestatus, 128)) {
2502       if (strcmp(nodestatus, "up")==0) status = 1;
2503     }
2504     if (arg_verbose)
2505         printf("Charmrun> node %d status: %s\n", node, nodestatus);
2506 #endif
2507   return status;
2508 }
2509
2510 /**
2511   ++ppn now is supported in both SMP and non SMP version
2512   in SMP, ++ppn specifies number of threads on each node;
2513   in non-SMP, ++ppn specifies number of processes on each node.
2514 */
2515 void nodetab_init_for_scyld()
2516 {
2517   int maxNodes, i, node, npes, rank;
2518   nodetab_host group;
2519   int tablesize;
2520
2521   tablesize = arg_requested_pes;
2522   maxNodes = bproc_numnodes() + 1;
2523   if (arg_endpe < maxNodes) maxNodes=arg_endpe+1;
2524   if (maxNodes > tablesize) tablesize = maxNodes;
2525   nodetab_table=(nodetab_host**)malloc(tablesize*sizeof(nodetab_host*));
2526   nodetab_rank0_table=(int*)malloc(tablesize*sizeof(int));
2527   nodetab_max=tablesize;
2528
2529   nodetab_reset(&group);
2530
2531   if (arg_ppn==0) arg_ppn=1;
2532 /*
2533 #if CMK_SHARED_VARS_UNAVAILABLE
2534   if (arg_ppn > 1) {
2535     fprintf(stderr,"Warning> Invalid ppn %d in nodelist ignored.\n", arg_ppn);
2536     arg_ppn=1;
2537   }
2538 #endif
2539 */
2540   group.cpus = 1;
2541   group.rank = 0;
2542
2543   /* check which slave node is available from frompe to endpe */
2544   npes = 0;
2545   for (i=-1; i<maxNodes && npes < arg_requested_pes; i++) {
2546     char hostname[256];
2547     if (!bproc_nodeisup(i)) continue;
2548     if (i!= -1 && i<arg_startpe) continue;
2549     if (i==-1 && arg_skipmaster) continue;    /* skip master node -1 */
2550     sprintf(hostname, "%d", i);
2551 #if ! CMK_SHARED_VARS_UNAVAILABLE
2552     if (npes + arg_ppn > arg_requested_pes) group.cpus = arg_requested_pes-npes;
2553     else group.cpus = arg_ppn;
2554 #endif
2555     for (rank = 0; rank<arg_ppn; rank++) {
2556 #if ! CMK_SHARED_VARS_UNAVAILABLE
2557       group.rank = rank;
2558 #endif
2559       nodetab_makehost(hostname, &group);
2560       if (++npes == arg_requested_pes) break;
2561     }   
2562   }
2563   if (nodetab_rank0_size == 0) {
2564     fprintf(stderr, "Charmrun> no slave node available!\n");
2565     exit (1);
2566   }
2567   if (arg_verbose)
2568     printf("Charmrun> There are %d slave nodes available.\n", nodetab_rank0_size-(arg_skipmaster?0:1));
2569
2570   /* expand node table to arg_requested_pes */
2571   if (arg_requested_pes > npes) {
2572     int orig_size = npes;
2573     int node;
2574     int startnode = 0;
2575     if (arg_singlemaster && nodetab_rank0_size > 1 && !arg_skipmaster) 
2576         startnode = arg_ppn;      /* skip -1 */
2577     node = startnode; 
2578     while (npes < arg_requested_pes) {
2579 #if ! CMK_SHARED_VARS_UNAVAILABLE
2580       if (npes+arg_ppn > arg_requested_pes) group.cpus = arg_requested_pes-npes;
2581       else group.cpus = arg_ppn;
2582 #endif
2583       for (rank = 0; rank<arg_ppn; rank++) {
2584 #if ! CMK_SHARED_VARS_UNAVAILABLE
2585         group.rank = rank;
2586 #endif
2587         nodetab_makehost(nodetab_name(node), &group);
2588         if (++node == orig_size) node = startnode;
2589         if (++npes == arg_requested_pes) break;
2590       } 
2591     }
2592   }
2593 }
2594
2595 void start_nodes_scyld(void)
2596 {
2597   char *envp[2];
2598   int i;
2599
2600   envp[0] = (char *)malloc(256);
2601   envp[1] = 0;
2602   for (i=0;i<nodetab_rank0_size;i++)
2603   {
2604     int status = 0;
2605     int pid;
2606     int pe=nodetab_rank0_table[i];
2607     int nodeno = atoi(nodetab_name(pe));
2608
2609     if (arg_verbose)
2610       printf("Charmrun> start node program on slave node: %d.\n", nodeno);
2611     sprintf(envp[0], "NETSTART=%s",  create_netstart(i));
2612     pid = 0;
2613     pid = fork();
2614     if (pid < 0) exit(1);
2615     if (pid == 0)
2616     {
2617       int fd, fd1 = dup(1);
2618       if (!(arg_debug || arg_debug_no_pause)) {   /* debug mode */
2619         if (fd = open("/dev/null", O_RDWR)) {
2620           dup2(fd, 0); dup2(fd, 1); dup2(fd, 2);
2621         }
2622       }
2623       if (nodeno == -1) {
2624         status = execve(pparam_argv[1], pparam_argv+1, envp);
2625         dup2(fd1, 1);
2626         printf("execve failed to start process \"%s\" with status: %d\n", pparam_argv[1], status);
2627       }
2628       else {
2629         status = bproc_execmove(nodeno, pparam_argv[1], pparam_argv+1, envp);
2630         dup2(fd1, 1);
2631         printf("bproc_execmove failed to start remote process \"%s\" with status: %d\n", pparam_argv[1], status);
2632       }
2633       kill(getppid(), 9);
2634       exit(1);
2635     }
2636   }
2637   free(envp[0]);
2638 }
2639 void finish_nodes(void) {}
2640
2641 #else
2642 /*Unix systems can use Rsh normally*/
2643 /********** RSH-ONLY CODE *****************************************/
2644 /*                                                                          */
2645 /* Rsh_etc                                                                  */
2646 /*                                                                          */
2647 /* this starts all the node programs.  It executes fully in the background. */
2648 /*                                                                          */
2649 /****************************************************************************/
2650 #include <sys/wait.h>
2651
2652 extern char **environ;
2653 void removeEnv(const char *doomedEnv)
2654 { /*Remove a value from the environment list*/
2655       char **oe, **ie;
2656       oe=ie=environ;
2657       while (*ie != NULL) {
2658         if (0!=strncmp(*ie,doomedEnv,strlen(doomedEnv)))
2659           *oe++ = *ie;
2660         ie++;
2661       }
2662       *oe=NULL;/*NULL-terminate list*/
2663 }
2664
2665 int rsh_fork(int nodeno,const char *startScript)
2666 {
2667   char **rshargv;
2668   int pid;
2669   int num=0;
2670   char *s, *e;
2671
2672   /* figure out size and dynamic allocate */
2673   s=nodetab_shell(nodeno); e=skipstuff(s);
2674   while (*s) {
2675     num++;
2676     s = skipblanks(e); e = skipstuff(s);
2677   }
2678   rshargv = (char **)malloc(sizeof(char *)*(num+6));
2679
2680   num = 0;
2681   s=nodetab_shell(nodeno); e=skipstuff(s);
2682   while (*s) {
2683     rshargv[num++]=substr(s, e);
2684     s = skipblanks(e); e = skipstuff(s);
2685   }
2686
2687   rshargv[num++]=nodetab_name(nodeno);
2688   rshargv[num++]="-l";
2689   rshargv[num++]=nodetab_login(nodeno);
2690   rshargv[num++]="/bin/sh -f";
2691   rshargv[num++]=0;
2692   if (arg_verbose) printf("Charmrun> Starting %s %s -l %s %s\n",nodetab_shell(nodeno), nodetab_name(nodeno),nodetab_login(nodeno), rshargv[num-2]);
2693   
2694   pid = fork();
2695   if (pid < 0) 
2696         { perror("ERROR> starting rsh"); exit(1); }
2697   if (pid == 0)
2698   {/*Child process*/
2699       int i;
2700       int fdScript=open(startScript,O_RDONLY);
2701   /**/  unlink(startScript); /**/
2702       dup2(fdScript,0);/*Open script as standard input*/
2703       //removeEnv("DISPLAY="); /*No DISPLAY disables ssh's slow X11 forwarding*/
2704       for(i=3; i<1024; i++) close(i);
2705       execvp(rshargv[0], rshargv);
2706       fprintf(stderr,"Charmrun> Couldn't find rsh program '%s'!\n",rshargv[0]);
2707       exit(1);
2708   }
2709   free(rshargv);
2710   if (arg_verbose)
2711     fprintf(stderr,"Charmrun> remote shell (%s:%d) started\n",
2712         nodetab_name(nodeno),nodeno);
2713   return pid;
2714 }
2715
2716 void fprint_arg(FILE *f,char **argv)
2717 {
2718   while (*argv) { 
2719         fprintf(f," %s",*argv); 
2720         argv++; 
2721   }
2722 }
2723 void rsh_Find(FILE *f,const char *program,const char *dest)
2724 {
2725     fprintf(f,"Find %s\n",program);
2726     fprintf(f,"%s=$loc\n",dest);
2727 }
2728 void rsh_script(FILE *f, int nodeno, int rank0no, char **argv)
2729 {
2730   char *netstart;
2731   char *arg_nodeprog_r,*arg_currdir_r;
2732   char *dbg=nodetab_debugger(nodeno);
2733   char *host=nodetab_name(nodeno);
2734 #define CLOSE_ALL " < /dev/null 1> /dev/null 2> /dev/null &"
2735
2736   fprintf(f, /*Echo: prints out status message*/
2737         "Echo() {\n"
2738         "  echo 'Charmrun remote shell(%s.%d)>' $*\n"
2739         "}\n",host,nodeno);
2740   fprintf(f, /*Exit: exits with return code*/
2741         "Exit() {\n"
2742         "  if [ $1 -ne 0 ]\n"
2743         "  then\n"
2744         "    Echo Exiting with error code $1\n"
2745         "  fi\n"
2746 #if CMK_RSH_KILL /*End by killing ourselves*/
2747         "  sleep 5\n" /*Delay until any error messages are flushed*/
2748         "  kill -9 $$\n"
2749 #else /*Exit normally*/
2750         "  exit $1\n"
2751 #endif
2752         "}\n");
2753   fprintf(f, /*Find: locates a binary program in PATH, sets loc*/
2754         "Find() {\n"
2755         "  loc=''\n"
2756         "  for dir in `echo $PATH | sed -e 's/:/ /g'`\n"
2757         "  do\n"
2758         "    test -f \"$dir/$1\" && loc=\"$dir/$1\"\n"
2759         "  done\n"
2760         "  if [ \"x$loc\" = x ]\n"
2761         "  then\n"
2762         "    Echo $1 not found in your PATH \"($PATH)\"--\n"
2763         "    Echo set your path in your ~/.charmrunrc\n"
2764         "    Exit 1\n"
2765         "  fi\n"
2766         "}\n");
2767   
2768   if (arg_verbose) fprintf(f,"Echo 'remote responding...'\n");
2769   
2770   fprintf(f,"test -f \"$HOME/.charmrunrc\" && . \"$HOME/.charmrunrc\"\n");
2771 /* let's leave DISPLAY untouched and rely on X11 forwarding,
2772    changing DISPLAY to charmrun does not always work if X11 forwarding presents 
2773 */
2774   if (arg_display && !arg_ssh_display)
2775     fprintf(f,"DISPLAY='%s';export DISPLAY\n",arg_display);
2776   netstart = create_netstart(rank0no);
2777   fprintf(f,"NETSTART='%s';export NETSTART\n",netstart);
2778   fprintf(f,"CmiMyNode='%d'; export CmiMyNode\n",rank0no);
2779   fprintf(f,"CmiMyNodeSize='%d'; export CmiMyNodeSize\n",nodetab_getnodeinfo(rank0no)->cpus);
2780   fprintf(f,"CmiMyForks='%d'; export CmiMyForks\n",nodetab_getnodeinfo(rank0no)->forks);
2781   fprintf(f,"CmiNumNodes='%d'; export CmiNumNodes\n",nodetab_rank0_size);
2782 #if CONVERSE_VERSION_VMI
2783   /* VMI environment variable */
2784   fprintf (f, "VMI_PROCS='%d'; export VMI_PROCS\n", arg_requested_pes);
2785   fprintf (f, "VMI_KEY='charmrun%d'; export VMI_KEY\n", getpid ());
2786   fprintf (f, "VMI_SPECFILE='%s'; export VMI_SPECFILE\n", arg_vmispecfile);
2787 #endif
2788 #ifdef CMK_G95
2789   fprintf(f,"G95_UNBUFFERED_ALL=TRUE; export G95_UNBUFFERED_ALL\n");
2790 #endif
2791 #ifdef CMK_GFORTRAN
2792   fprintf(f,"GFORTRAN_UNBUFFERED_ALL=YES; export GFORTRAN_UNBUFFERED_ALL\n");
2793 #endif
2794 #if CMK_USE_MX
2795   fprintf(f,"MX_MONOTHREAD=1; export MX_MONOTHREAD\n");
2796   /*fprintf(f,"MX_RCACHE=1; export MX_RCACHE\n");*/
2797 #endif
2798   
2799   if (arg_verbose) {
2800     printf("Charmrun> Sending \"%s\" to client %d.\n", netstart, rank0no);
2801   }
2802   fprintf(f,"PATH=\"$PATH:/bin:/usr/bin:/usr/X/bin:/usr/X11/bin:/usr/local/bin:"
2803         "/usr/X11R6/bin:/usr/openwin/bin\"\n");
2804   
2805   /* find the node-program */
2806   arg_nodeprog_r = pathextfix(arg_nodeprog_a, nodetab_pathfixes(nodeno), nodetab_ext(nodeno));
2807   
2808   /* find the current directory, relative version */
2809   arg_currdir_r = pathfix(arg_currdir_a, nodetab_pathfixes(nodeno));
2810
2811   if (arg_verbose) {
2812     printf("Charmrun> find the node program \"%s\" at \"%s\" for %d.\n", arg_nodeprog_r, arg_currdir_r, nodeno);
2813   }
2814
2815   if (arg_debug || arg_debug_no_pause || arg_in_xterm) {
2816     rsh_Find(f,nodetab_xterm(nodeno),"F_XTERM");
2817     if(!arg_ssh_display)
2818       rsh_Find(f,"xrdb","F_XRDB");
2819     if(arg_verbose) fprintf(f,"Echo 'using xterm' $F_XTERM\n");
2820   }
2821
2822   if (arg_debug || arg_debug_no_pause)
2823   {/*Look through PATH for debugger*/
2824     rsh_Find(f,dbg,"F_DBG");
2825     if (arg_verbose) fprintf(f,"Echo 'using debugger' $F_DBG\n");
2826   }
2827
2828    if (!arg_ssh_display && (arg_debug || arg_debug_no_pause ||
2829       arg_in_xterm)) {
2830      /*    if (arg_debug || arg_debug_no_pause || arg_in_xterm) {*/
2831     fprintf(f,"$F_XRDB -query > /dev/null\n");
2832     fprintf(f,"if test $? != 0\nthen\n");
2833     fprintf(f,"  Echo 'Cannot contact X Server '$DISPLAY'.  You probably'\n");
2834     fprintf(f,"  Echo 'need to run xhost to authorize connections.'\n");
2835     fprintf(f,"  Echo '(See manual for xhost for security issues)'\n");
2836     fprintf(f,"  Echo 'Or try ++batch 1 ++ssh-display to rely on SSH X11 forwarding'\n");
2837     fprintf(f,"  Exit 1\n");
2838     fprintf(f,"fi\n");
2839   }
2840   
2841   fprintf(f,"if test ! -x \"%s\"\nthen\n",arg_nodeprog_r);
2842   fprintf(f,"  Echo 'Cannot locate this node-program: %s'\n",arg_nodeprog_r);
2843   fprintf(f,"  Exit 1\n");
2844   fprintf(f,"fi\n");
2845   
2846   fprintf(f,"cd \"%s\"\n",arg_currdir_r);
2847   fprintf(f,"if test $? = 1\nthen\n");
2848   fprintf(f,"  Echo 'Cannot propagate this current directory:'\n"); 
2849   fprintf(f,"  Echo '%s'\n",arg_currdir_r);
2850   fprintf(f,"  Exit 1\n");
2851   fprintf(f,"fi\n");
2852   
2853   if (strcmp(nodetab_setup(nodeno),"*")) {
2854     fprintf(f,"%s\n",nodetab_setup(nodeno));
2855     fprintf(f,"if test $? = 1\nthen\n");
2856     fprintf(f,"  Echo 'this initialization command failed:'\n");
2857     fprintf(f,"  Echo '\"%s\"'\n",nodetab_setup(nodeno));
2858     fprintf(f,"  Echo 'edit your nodes file to fix it.'\n");
2859     fprintf(f,"  Exit 1\n");
2860     fprintf(f,"fi\n");
2861   }
2862
2863   fprintf(f,"rm -f /tmp/charmrun_err.$$\n");
2864   if(arg_verbose) fprintf(f,"Echo 'starting node-program...'\n");  
2865   /* This is the start of the the run-nodeprogram script */
2866   fprintf(f,"(");
2867   
2868   if (arg_debug || arg_debug_no_pause ) {
2869          if ( strcmp(dbg, "gdb") == 0 || strcmp(dbg, "idb") == 0 ) {
2870            fprintf(f,"cat > /tmp/charmrun_gdb.$$ << END_OF_SCRIPT\n");
2871            if ( strcmp(dbg, "idb") == 0 ) {
2872              fprintf(f,"set \\$cmdset=\"gdb\"\n");
2873            }
2874            fprintf(f,"shell /bin/rm -f /tmp/charmrun_gdb.$$\n");
2875            fprintf(f,"handle SIGPIPE nostop noprint\n");
2876            fprintf(f,"handle SIGWINCH nostop noprint\n");
2877            fprintf(f,"handle SIGWAITING nostop noprint\n");
2878            fprintf(f,"set args");
2879            fprint_arg(f,argv);
2880            fprintf(f,"\n");
2881            if (arg_debug_no_pause) fprintf(f,"run\n");
2882            fprintf(f,"END_OF_SCRIPT\n");
2883            if (arg_runscript)
2884              fprintf(f,"\"%s\" ",arg_runscript);
2885            fprintf(f,"$F_XTERM");
2886            fprintf(f," -title 'Node %d (%s)' ",nodeno,nodetab_name(nodeno));
2887            if ( strcmp(dbg, "idb") == 0 )
2888              fprintf(f," -e $F_DBG %s -c /tmp/charmrun_gdb.$$ \n", arg_nodeprog_r);
2889            else 
2890              fprintf(f," -e $F_DBG %s -x /tmp/charmrun_gdb.$$ \n", arg_nodeprog_r);
2891          } else if ( strcmp(dbg, "dbx") == 0 ) {
2892            fprintf(f,"cat > /tmp/charmrun_dbx.$$ << END_OF_SCRIPT\n");
2893            fprintf(f,"sh /bin/rm -f /tmp/charmrun_dbx.$$\n");
2894            fprintf(f,"dbxenv suppress_startup_message 5.0\n");
2895            fprintf(f,"ignore SIGPOLL\n");
2896            fprintf(f,"ignore SIGPIPE\n");
2897            fprintf(f,"ignore SIGWINCH\n");
2898            fprintf(f,"ignore SIGWAITING\n");
2899            fprintf(f,"END_OF_SCRIPT\n");
2900            if (arg_runscript)
2901              fprintf(f,"\"%s\" ",arg_runscript);
2902            fprintf(f,"$F_XTERM");
2903            fprintf(f," -title 'Node %d (%s)' ",nodeno,nodetab_name(nodeno));
2904            fprintf(f," -e $F_DBG %s ",arg_debug_no_pause?"-r":"");
2905            if(arg_debug) {
2906               fprintf(f,"-c \'runargs ");
2907               fprint_arg(f,argv);
2908               fprintf(f,"\' ");
2909            }
2910            fprintf(f, "-s/tmp/charmrun_dbx.$$ %s",arg_nodeprog_r);
2911            if(arg_debug_no_pause) 
2912               fprint_arg(f,argv);
2913            fprintf(f,"\n");
2914          } else { 
2915           fprintf(stderr, "Unknown debugger: %s.\n Exiting.\n", 
2916             nodetab_debugger(nodeno));
2917          }
2918   } else if (arg_in_xterm) {
2919     if(arg_verbose)
2920       fprintf(stderr, "Charmrun> node %d: xterm is %s\n", 
2921               nodeno, nodetab_xterm(nodeno));
2922     fprintf(f,"cat > /tmp/charmrun_inx.$$ << END_OF_SCRIPT\n");
2923     fprintf(f,"#!/bin/sh\n");
2924     fprintf(f,"/bin/rm -f /tmp/charmrun_inx.$$\n");
2925     fprintf(f,"%s", arg_nodeprog_r);
2926     fprint_arg(f,argv);
2927     fprintf(f,"\n");
2928     fprintf(f,"echo 'program exited with code '\\$?\n");
2929     fprintf(f,"read eoln\n");
2930     fprintf(f,"END_OF_SCRIPT\n");
2931     fprintf(f,"chmod 700 /tmp/charmrun_inx.$$\n");
2932     if (arg_runscript)
2933        fprintf(f,"\"%s\" ",arg_runscript);
2934     fprintf(f,"$F_XTERM -title 'Node %d (%s)' ",nodeno,nodetab_name(nodeno));
2935     fprintf(f," -sl 5000");
2936     fprintf(f," -e /tmp/charmrun_inx.$$\n");
2937   } else {
2938     if (arg_runscript)
2939        fprintf(f,"\"%s\" ",arg_runscript);
2940     fprintf(f,"\"%s\" ",arg_nodeprog_r);
2941     fprint_arg(f,argv);
2942     if (nodetab_nice(nodeno) != -100) {
2943       if(arg_verbose) fprintf(stderr, "Charmrun> nice -n %d\n", nodetab_nice(nodeno));
2944       fprintf(f," +nice %d ",nodetab_nice(nodeno));
2945     }
2946     fprintf(f,"\nres=$?\n");
2947     /* If shared libraries fail to load, the program dies without
2948        calling charmrun back.  Since we *have* to close down stdin/out/err,
2949        we have to smuggle this failure information out via a file,
2950        /tmp/charmrun_err.<pid> */
2951     fprintf(f,
2952         "if [ $res -eq 127 ]\n"
2953         "then\n"
2954         "  ( \n" /* Re-run, spitting out errors from a subshell: */
2955         "    \"%s\" \n"
2956         "    ldd \"%s\"\n"
2957         "  ) > /tmp/charmrun_err.$$ 2>&1 \n"
2958         "fi\n",arg_nodeprog_r,arg_nodeprog_r);
2959   }
2960   
2961   /* End the node-program subshell. To minimize the number 
2962      of open ports on the front-end, we must close down rsh;
2963      to do this, we have to close stdin, stdout, stderr, and 
2964      run the subshell in the background. */
2965   fprintf(f,")");
2966   fprintf(f,CLOSE_ALL "\n");
2967   
2968   if (arg_verbose) fprintf(f,"Echo 'rsh phase successful.'\n");
2969   fprintf(f, /* Check for startup errors: */
2970      "sleep 1\n"
2971      "if [ -r /tmp/charmrun_err.$$ ]\n"
2972      "then\n"
2973      "  cat /tmp/charmrun_err.$$ \n"
2974      "  rm -f /tmp/charmrun_err.$$ \n"
2975      "  Exit 1\n"
2976      "fi\n");
2977   fprintf(f,"Exit 0\n");
2978 }
2979
2980
2981 /* use the command "size" to get information about the position of the ".data"
2982    and ".bss" segments inside the program memory */
2983 void read_global_segments_size() {
2984   char **rshargv;
2985   int childPid;
2986
2987   /* find the node-program */
2988   arg_nodeprog_r = pathextfix(arg_nodeprog_a, nodetab_pathfixes(0), nodetab_ext(0));
2989
2990   rshargv = (char **)malloc(sizeof(char *)*6);
2991   rshargv[0]=nodetab_shell(0);
2992   rshargv[1]=nodetab_name(0);
2993   rshargv[2]="-l";
2994   rshargv[3]=nodetab_login(0);
2995   rshargv[4] = (char *)malloc(sizeof(char)*9+strlen(arg_nodeprog_r));
2996   sprintf(rshargv[4],"size -A %s",arg_nodeprog_r);
2997   rshargv[5]=0;
2998
2999   childPid = fork();
3000   if (childPid < 0) {
3001     perror("ERROR> getting the size of the global variables segments"); exit(1);
3002   } else if (childPid == 0) {
3003     /* child process */
3004     dup2(2, 1);
3005     /*printf("executing: \"%s\" \"%s\" \"%s\" \"%s\" \"%s\"\n",rshargv[0],rshargv[1],rshargv[2],rshargv[3],rshargv[4]);*/
3006     execvp(rshargv[0], rshargv);
3007     fprintf(stderr,"Charmrun> Couldn't find rsh program '%s'!\n",rshargv[0]);
3008     exit(1);
3009   } else {
3010     /* else we are in the parent */
3011     free(rshargv[4]);
3012     free(rshargv);
3013     waitpid(childPid, NULL, 0);
3014   }
3015 }
3016
3017 /* open a rsh connection with processor 0 and open a gdb session for info */
3018 void open_gdb_info() {
3019   char **rshargv;
3020   int fdin[2];
3021   int fdout[2];
3022   int fderr[2];
3023   int i;
3024
3025   /* find the node-program */
3026   arg_nodeprog_r = pathextfix(arg_nodeprog_a, nodetab_pathfixes(0), nodetab_ext(0));
3027
3028   rshargv = (char **)malloc(sizeof(char *)*6);
3029   rshargv[0]=nodetab_shell(0);
3030   rshargv[1]=nodetab_name(0);
3031   rshargv[2]="-l";
3032   rshargv[3]=nodetab_login(0);
3033   rshargv[4] = (char *)malloc(sizeof(char)*8+strlen(arg_nodeprog_r));
3034   sprintf(rshargv[4],"gdb -q %s",arg_nodeprog_r);
3035   rshargv[5]=0;
3036
3037   pipe(fdin);
3038   pipe(fdout);
3039   pipe(fderr);
3040
3041   gdb_info_pid = fork();
3042   if (gdb_info_pid < 0) {
3043     perror("ERROR> starting info gdb"); exit(1);
3044   } else if (gdb_info_pid == 0) {
3045     /* child process */
3046     close(fdin[1]);
3047     close(fdout[0]);
3048     close(fderr[0]);
3049     printf("executing: \"%s\" \"%s\" \"%s\" \"%s\" \"%s\"\n",rshargv[0],rshargv[1],rshargv[2],rshargv[3],rshargv[4]);
3050     dup2(fdin[0],0);
3051     dup2(fdout[1],1);
3052     dup2(fderr[1],2);
3053     for(i=3; i<1024; i++) close(i);
3054     execvp(rshargv[0], rshargv);
3055     fprintf(stderr,"Charmrun> Couldn't find rsh program '%s'!\n",rshargv[0]);
3056     exit(1);
3057   }
3058   /* else we are in the parent */
3059   free(rshargv[4]);
3060   free(rshargv);
3061   gdb_info_std[0] = fdin[1];
3062   gdb_info_std[1] = fdout[0];
3063   gdb_info_std[2] = fderr[0];
3064   close(fdin[0]);
3065   close(fdout[1]);
3066   close(fderr[1]);
3067 }
3068
3069 /* returns pid */
3070 void start_one_node_rsh(int rank0no)
3071 {
3072      int pe=nodetab_rank0_table[rank0no];
3073      FILE *f;
3074      char startScript[200];
3075      sprintf(startScript,"/tmp/charmrun.%d.%d",getpid(),pe);
3076      f=fopen(startScript,"w");
3077      if (f==NULL) {
3078        /* now try current directory */
3079        sprintf(startScript,"charmrun.%d.%d",getpid(),pe);
3080        f=fopen(startScript,"w");
3081        if (f==NULL) {
3082          fprintf(stderr,"Charmrun> Can not write file %s!\n", startScript);
3083          exit(1);
3084        }
3085      }
3086      rsh_script(f,pe,rank0no,arg_argv);
3087      fclose(f);
3088      if (!rsh_pids)
3089        rsh_pids=(int *)malloc(sizeof(int)*nodetab_rank0_size);
3090      rsh_pids[rank0no] = rsh_fork(pe,startScript);
3091 }
3092
3093 int start_set_node_rsh(int client) {
3094         /* a search function could be inserted here instead of sequential lookup for more complex node lists (e.g. interleaving) */
3095         int clientgroup;
3096 #if CMK_SMP || defined(_WIN32)
3097         clientgroup=client+1; /* smp already handles this functionality */
3098 #else
3099         if(!arg_scalable_start)
3100                 clientgroup=client+1; /* only launch 1 core per rsh call */
3101         else {
3102                 clientgroup=client;
3103                 do {
3104                         clientgroup++; /* add one more client to group if not greater than nodes and shares the same name as client */
3105                 } while(clientgroup<nodetab_rank0_size&&(!strcmp(nodetab_name(clientgroup),nodetab_name(client))));
3106         }
3107 #endif
3108
3109         nodetab_getnodeinfo(client)->forks=clientgroup-client-1; /* already have 1 process launching */
3110
3111         start_one_node_rsh(client);
3112         return clientgroup-client; /* return number of entries in group */
3113 }
3114
3115 void start_nodes_rsh()
3116 {
3117         int client,clientgroup;
3118         rsh_pids=(int *)malloc(sizeof(int)*nodetab_rank0_size);
3119
3120         client=0;
3121         while(client<nodetab_rank0_size) {
3122                 /* start a group of processes per node */
3123                 clientgroup=start_set_node_rsh(client);
3124                 client+=clientgroup;
3125         }
3126 }
3127
3128 void finish_set_nodes(int start, int stop) {
3129         int status,done,i;
3130         char *host;
3131
3132         if (!rsh_pids) return; /*nothing to do*/
3133
3134         done=0;
3135         while(!done) {
3136                 done=1;
3137                 for(i=start;i<stop;i++) { /* check all nodes */
3138                         if(rsh_pids[i]!=0) {
3139                                 done=0; /* we are not finished yet */
3140                                 status=0;
3141                                 waitpid(rsh_pids[i],&status,0); /* check if the process is finished */
3142                                 if(WIFEXITED(status)) {
3143                                         if (!WEXITSTATUS(status)) { /* good */
3144                                                 rsh_pids[i]=0; /* process is finished */
3145                                         } else {
3146                                                 host=nodetab_name(nodetab_rank0_table[i]);
3147                                                 fprintf(stderr,"Charmrun> Error %d returned from rsh (%s:%d)\n",
3148                                                 WEXITSTATUS(status),host,i);
3149                                                 exit(1);
3150                                         } 
3151                                 }
3152                         }
3153                 }
3154         }
3155 }
3156
3157 void finish_nodes()
3158 {
3159         finish_set_nodes(0,nodetab_rank0_size);
3160         free(rsh_pids);
3161 }
3162
3163 void kill_nodes()
3164 {
3165   int rank0no;
3166   if (!rsh_pids) return; /*nothing to do*/
3167   /*Now wait for all the rsh'es to finish*/
3168   for (rank0no=0;rank0no<nodetab_rank0_size;rank0no++)
3169   {
3170      const char *host=nodetab_name(nodetab_rank0_table[rank0no]);
3171      int status=0;
3172      if (arg_verbose) printf("Charmrun> waiting for rsh (%s:%d), pid %d\n",
3173                 host,rank0no,rsh_pids[rank0no]);
3174      kill(rsh_pids[rank0no],9);
3175      waitpid(rsh_pids[rank0no],&status,0); /*<- no zombies*/
3176   }
3177   free(rsh_pids);
3178 }
3179
3180 /* simple version of charmrun that avoids the rshd or charmd,   */
3181 /* it spawn the node program just on local machine using exec. */
3182 void start_nodes_local(char ** env)
3183 {
3184   char **envp;
3185   int envc, rank0no, i;
3186
3187   /* copy environ and expanded to hold NETSTART */ 
3188   for (envc=0; env[envc]; envc++);
3189   envp = (char **)malloc((envc+2)*sizeof(void *));
3190   for (i=0; i<envc; i++) envp[i] = env[i];
3191   envp[envc] = (char *)malloc(256);
3192   envp[envc+1] = 0;
3193
3194   for (rank0no=0;rank0no<nodetab_rank0_size;rank0no++)
3195   {
3196     int status = 0;
3197     int pid;
3198     int pe=nodetab_rank0_table[rank0no];
3199
3200     if (arg_verbose)
3201       printf("Charmrun> start %d node program on localhost.\n", pe);
3202     sprintf(envp[envc], "NETSTART=%s",  create_netstart(rank0no));
3203     pid = 0;
3204     pid = fork();
3205     if (pid < 0) exit(1);
3206     if (pid == 0)
3207     {
3208       int fd, fd1 = dup(1);
3209       if (-1!=(fd = open("/dev/null", O_RDWR))) {
3210         dup2(fd, 0); dup2(fd, 1); dup2(fd, 2);
3211       }
3212       status = execve(pparam_argv[1], pparam_argv+1, envp);
3213       dup2(fd1, 1);
3214       printf("execve failed to start process \"%s\" with status: %d\n", pparam_argv[1], status);
3215       kill(getppid(), 9);
3216       exit(1);
3217     }
3218   }
3219   free(envp[envc]);
3220   free(envp);
3221 }
3222
3223 #ifdef __FAULT__
3224
3225 void refill_nodetab_entry(int crashed_node);
3226 nodetab_host *replacement_host(int pe);
3227
3228 void restart_node(int crashed_node){
3229         int pe = nodetab_rank0_table[crashed_node];
3230         FILE *f;
3231         char startScript[200];
3232         int restart_rsh_pid;
3233         char **restart_argv;
3234         int status=0;
3235         int i;
3236         /** write the startScript file to be sent**/
3237         sprintf(startScript,"/tmp/charmrun.%d.%d",getpid(),pe);
3238         f=fopen(startScript,"w");
3239         
3240         /** add an argument to the argv of the new process
3241         so that the restarting processor knows that it 
3242         is a restarting processor */
3243         i=0;
3244         while(arg_argv[i]!= NULL){
3245                 i++;
3246         }
3247         restart_argv = (char **)malloc(sizeof(char *)*(i+2));
3248         i=0;
3249         while(arg_argv[i]!= NULL){
3250                 restart_argv[i] = arg_argv[i];
3251                 i++;
3252         }
3253         restart_argv[i] = "+restartaftercrash";
3254         restart_argv[i+1]=NULL;
3255
3256         rsh_script(f,pe,crashed_node,restart_argv);
3257         fclose(f);
3258         /** change the nodetable entry of the crashed
3259         processor to connect it to a new one**/
3260         refill_nodetab_entry(crashed_node);
3261         /**start the new processor */
3262         restart_rsh_pid =rsh_fork(pe,startScript);
3263         /**wait for the reply from the new process*/
3264         status=0;
3265         if (arg_debug_no_pause || arg_debug) ;
3266         else {
3267         do{
3268                 waitpid(restart_rsh_pid,&status,0);
3269         }while(!WIFEXITED(status));
3270         if (WEXITSTATUS(status)!=0){
3271          fprintf(stderr,"Charmrun> Error %d returned from new attempted rsh \n",
3272          WEXITSTATUS(status));
3273          exit(1);
3274         }     
3275         }
3276         printf("Charmrun finished launching new process in %fs\n", GetClock()-ftTimer);
3277 }
3278
3279
3280
3281 void refill_nodetab_entry(int crashed_node){
3282         int pe =  nodetab_rank0_table[crashed_node];
3283         nodetab_host *h = nodetab_table[pe];
3284         *h = *(replacement_host(pe));
3285 }
3286
3287 nodetab_host *replacement_host(int pe){
3288         int x=pe;
3289         while(x == pe){
3290          x = rand()%nodetab_size;        
3291         }
3292         return nodetab_table[x];
3293 }
3294
3295 void reconnect_crashed_client(int socket_index,int crashed_node){
3296         int i;
3297         unsigned int clientPort;
3298         skt_ip_t clientIP;
3299         ChSingleNodeinfo *in;
3300         if(0==skt_select1(server_fd,arg_timeout*1000)){
3301                         client_connect_problem(socket_index,"Timeout waiting forrestarted node-program to connect");
3302         }
3303         req_clients[socket_index] = skt_accept(server_fd,&clientIP,&clientPort);
3304         if(req_clients[socket_index] == SOCKET_ERROR){
3305                 client_connect_problem(socket_index,"Failure in restarted node accept");
3306         }else{
3307                 ChMessage msg;
3308                 if(!skt_select1(req_clients[socket_index],arg_timeout*1000)){
3309                         client_connect_problem(socket_index,"Timeout on IP request for restarted processor");
3310                 }
3311                 ChMessage_recv(req_clients[socket_index],&msg);
3312                 if(msg.len != sizeof(ChSingleNodeinfo)){
3313                 fprintf(stderr,"Charmrun: Bad initnode data length. Aborting\n");
3314                 fprintf(stderr,"Charmrun: possibly because: %s.\n", msg.data);
3315                 }
3316                 /** update the nodetab entry corresponding to
3317                 this node, skip the restarted one */
3318                 in = (ChSingleNodeinfo *)msg.data;
3319                 nodeinfo_add(in,req_clients[socket_index]);
3320                 for(i=0;i<req_nClients;i++){
3321                         if(i != socket_index){
3322                                 req_handle_initnodetab(NULL,req_clients[i]);
3323                         }       
3324                 }
3325
3326                 /* tell every one there is a crash */
3327                 anounce_crash(socket_index,crashed_node);
3328                 if (_last_crash != 0) {
3329                   fprintf(stderr, "ERROR> Charmrun detected multiple crashes.\n");
3330                   exit(1);
3331                 }
3332                 _last_crash = crashed_node;
3333                 _crash_socket_index = socket_index;
3334                 /*holds the restarted process until I got ack back from
3335                   everyone in req_handle_crashack
3336                   now the restarted one can only continue until 
3337                   req_handle_crashack calls req_handle_initnodetab(socket_index)
3338                   req_handle_initnodetab(NULL,req_clients[socket_index]); */
3339                 ChMessage_free(&msg);
3340         }       
3341 }
3342
3343 void anounce_crash(int socket_index,int crashed_node){
3344         int i;
3345         ChMessageHeader hdr;
3346         ChMessageInt_t crashNo=ChMessageInt_new(crashed_node);
3347         ChMessageHeader_new("crashnode",sizeof(ChMessageInt_t),&hdr);
3348         for(i=0;i<req_nClients;i++){
3349                 if(i != socket_index){
3350                         skt_sendN(req_clients[i],(const char *)&hdr,sizeof(hdr));
3351                         skt_sendN(req_clients[i],(const char *)&crashNo,sizeof(ChMessageInt_t));
3352                 }
3353         }
3354 }
3355
3356 #endif
3357
3358 #endif /*CMK_USE_RSH*/
3359
3360
3361
3362