%**************************************************************************** % \section[Sysman.lc]{GUM Sysman Program} % % (c) The Parade/AQUA Projects, Glasgow University, 1994-1995. % P. Trinder, November 30th. 1994. % %**************************************************************************** The Sysman task controls initiation, termination, global GC synchronisation and statistics gathering. Based on K. Hammond's SysMan.lc in Graph for PVM. \begin{code} #define NON_POSIX_SOURCE /* so says Solaris */ #include "rtsdefs.h" #include "LLC.h" \end{code} \begin{code} static GLOBAL_TASK_ID gtids[MAX_PES], StatsTask = 0; static long PEbuffer[MAX_PES]; static int nPEs = 0; \end{code} \begin{code} static GLOBAL_TASK_ID sysman_id, sender_id, mainThread_id; GLOBAL_TASK_ID mytid; static unsigned PEsTerminated = 0; static rtsBool Finishing = rtsFalse; \end{code} \begin{code} #define checkerr(c) do {if((c)<0) { pvm_perror("Sysman"); EXIT(EXIT_FAILURE); }} while(0) \end{code} This Function not yet implemented for GUM \begin{code} static void DoGlobalGC(STG_NO_ARGS) {} /* static void HandleException(STG_NO_ARGS) {} */ \end{code} \begin{code} main(int argc, char **argv) { int rbufid; int opcode, nbytes; char **pargv; int i, cc; int spawn_flag = PvmTaskDefault; char *petask, *pvmExecutable; setbuf(stdout, NULL); setbuf(stderr, NULL); if (argc > 1) { if (*argv[1] == '-') { spawn_flag = PvmTaskDebug; argv[1] = argv[0]; argv++; argc--; } mainThread_id = pvm_mytid();/* This must be the first PVM call */ checkerr(mainThread_id); nPEs = atoi(argv[1]); if ((petask = getenv(PETASK)) == NULL) petask = PETASK; #if 0 fprintf(stderr, "nPEs (%s) = %d\n", petask, nPEs); #endif /* Check that we can create the number of PE and IMU tasks requested */ if (nPEs > MAX_PES) { fprintf(stderr, "No more than %d PEs allowed (%d requested)\n", MAX_PES, nPEs); EXIT(EXIT_FAILURE); } /* Get the full path and filename of the pvm executable (stashed in some PVM directory. */ pvmExecutable = argv[2]; /* Create the PE Tasks */ if (nPEs > 0) { /* Spawn nPEs-1 pvm threads: the Main Thread (starts execution and performs IO is created by forking SysMan */ nPEs--; #if 1 fprintf(stderr, "Spawning %d PEs(%s) ...\n", nPEs, petask); fprintf(stderr, " args: "); for (i = 0; pargv[i]; ++i) fprintf(stderr, "%s, ", pargv[i]); fprintf(stderr, "\n"); #endif /* Initialise the PE task arguments from Sysman's arguments */ pargv = argv + 2; checkerr(pvm_spawn(petask, pargv, spawn_flag, "", nPEs, gtids)); PEbuffer[0] = mainThread_id; for (i = 0; i < nPEs; i++) PEbuffer[i++] = (long) gtids[i]; #if 1 fprintf(stderr, "Spawned /* PWT */\n"); #endif } /* SysMan joins PECTLGROUP, so that it can wait (at the barrier sysnchronisation a few instructions later) for the other PE-tasks to start. Other comments on PVM groupery: The manager group (MGRGROUP) is vestigial at the moment. It may eventually include a statistics manager, garbage collector manager. I suspect that you're [Kei Davis] right: Sysman shouldn't be in PEGROUP, it's a hangover from GRIP. (Phil Trinder, 95/10) */ checkerr(pvm_joingroup(PECTLGROUP)); #if 1 fprintf(stderr, "Joined PECTLGROUP /* PWT */\n"); #endif /* Wait for all the PEs and IMUs to arrive */ checkerr(pvm_barrier(PECTLGROUP, nPEs + 1)); #if 1 fprintf(stderr, "PECTLGROUP barrier passed /* HWL */\n"); #endif /* Create the MainThread PE by forking SysMan. This arcane coding is required to allow MainThread to read stdin and write to stdout. PWT 18/1/96 */ if (cc = fork()) { checkerr(cc); exec($some path$/petask) /* Parent task become Main Thread PE */ } else { /* Child continues as SysMan */ pvmendtask(); /* Disconnect from PVM to avoid confusion */ sysman_id = pvm_mytid(); /* Reconnect to PVM to get new task id */ /* Broadcast Global Task Ids of all PEs */ pvm_initsend(PvmDataDefault); PutArgs(PEbuffer, nPEs); pvm_bcast(PEGROUP, PP_PETIDS); #if 1 fprintf(stderr, "Main Thread Task is [t%x]\n", mainThread_id); #endif pvm_initsend(PvmDataDefault); pvm_send(mainThread_id, PP_IO_INIT); pvm_initsend(PvmDataDefault); pvm_bcast(PEGROUP, PP_INIT); #if 1 fprintf(stderr, "Broadcast PP_INIT to all PEs\n"); #endif /* HWL-DEBUG */ #if 1 fprintf(stderr, "Sysman successfully initialized!\n"); #endif /* Process incoming messages */ while (1) { if ((rbufid = pvm_recv(ANY_TASK, ANY_OPCODE)) < 0) pvm_perror("Sysman: Receiving Message"); else { pvm_bufinfo(rbufid, &nbytes, &opcode, &sender_id); #if 0 fprintf(stderr, "HWL-DBG(SysMan; main loop): rbufid=%x, nbytes = %d, opcode = %x, sender_id = %x\n", rbufid, nbytes, opcode, sender_id); #endif switch (opcode) { case PP_GC_INIT: /* This Function not yet implemented for GUM */ fprintf(stderr, "Global GC from %x Not yet implemented for GUM!\n", sender_id); sync(PECTLGROUP, PP_FULL_SYSTEM); broadcast(PEGROUP, PP_GC_INIT); DoGlobalGC(); broadcast(PEGROUP, PP_INIT); break; case PP_STATS_ON: case PP_STATS_OFF: /* This Function not yet implemented for GUM */ break; case PP_FINISH: fprintf(stderr, "Finish from %x\n", sender_id); if (!Finishing) { long buf = (long) StatsTask; Finishing = rtsTrue; pvm_initsend(PvmDataDefault); pvm_pklong(&buf, 1, 1); pvm_bcast(PEGROUP, PP_FINISH); } else { ++PEsTerminated; } if (PEsTerminated >= nPEs) { broadcast(PEGROUP, PP_FINISH); broadcast(MGRGROUP, PP_FINISH); pvm_lvgroup(PEGROUP); pvm_lvgroup(PECTLGROUP); pvm_lvgroup(MGRGROUP); pvm_exit(); EXIT(EXIT_SUCCESS); } break; case PP_FAIL: fprintf(stderr, "Fail from %x\n", sender_id); if (!Finishing) { Finishing = rtsTrue; broadcast(PEGROUP, PP_FAIL); } break; default: { /* char *opname = GetOpName(opcode); fprintf(stderr,"Sysman: Unrecognised opcode %s (%x)\n", opname,opcode); */ fprintf(stderr, "Sysman: Unrecognised opcode (%x)\n", opcode); } break; } } } } return(0); } \end{code} @myexit@ for the system manager. \begin{code} void myexit(n) I_ n; { #ifdef exit #undef exit #endif exit(n); } \end{code}