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