--- ray/src/util/rad.c 2003/06/30 14:59:13 2.65 +++ ray/src/util/rad.c 2003/07/21 22:30:19 2.70 @@ -1,5 +1,5 @@ #ifndef lint -static const char RCSid[] = "$Id: rad.c,v 2.65 2003/06/30 14:59:13 schorsch Exp $"; +static const char RCSid[] = "$Id: rad.c,v 2.70 2003/07/21 22:30:19 schorsch Exp $"; #endif /* * Executive program for oconv, rpict and pfilt @@ -8,12 +8,21 @@ static const char RCSid[] = "$Id: rad.c,v 2.65 2003/06 #include "standard.h" #include +#include #include "platform.h" #include "view.h" #include "paths.h" #include "vars.h" +#ifdef _WIN32 + #define DELCMD "del" + #define RENAMECMD "rename" +#else + #define DELCMD "rm -f" + #define RENAMECMD "mv" +#endif + /* variables (alphabetical by name) */ #define AMBFILE 0 /* ambient file name */ #define DETAIL 1 /* level of scene detail */ @@ -80,7 +89,6 @@ char overfile[] = NULL_DEVICE; char overfile[] = "overture.unf"; #endif -extern time_t time(); time_t scenedate; /* date of latest scene or object file */ time_t octreedate; /* date of octree */ @@ -96,19 +104,23 @@ int nowarn = 0; /* no warnings */ int explicate = 0; /* explicate variables */ int silent = 0; /* do work silently */ int touchonly = 0; /* touch files only */ -int noaction = 0; /* don't do anything */ +int nprocs = 1; /* maximum executing processes */ int sayview = 0; /* print view out */ char *rvdevice = NULL; /* rview output device */ char *viewselect = NULL; /* specific view only */ int overture = 0; /* overture calculation needed */ +int children_running = 0; /* set negative in children */ + char *progname; /* global argv[0] */ char *rifname; /* global rad input file name */ char radname[PATH_MAX]; /* root Radiance file name */ +#define inchild() (children_running < 0) + main(argc, argv) int argc; char *argv[]; @@ -125,8 +137,13 @@ char *argv[]; silent++; break; case 'n': - noaction++; + nprocs = 0; break; + case 'N': + nprocs = atoi(argv[++i]); + if (nprocs < 0) + nprocs = 0; + break; case 't': touchonly++; break; @@ -151,6 +168,9 @@ char *argv[]; if (i >= argc) goto userr; rifname = argv[i]; + /* check command-line options */ + if (nprocs > 1 & viewselect != NULL) + nprocs = 1; /* assign Radiance root file name */ rootname(radname, rifname); /* load variable values */ @@ -185,7 +205,7 @@ char *argv[]; quit(0); userr: fprintf(stderr, -"Usage: %s [-w][-s][-n][-t][-e][-V][-v view][-o dev] rfile [VAR=value ..]\n", +"Usage: %s [-w][-s][-n|-N npr][-t][-e][-V][-v view][-o dev] rfile [VAR=value ..]\n", progname); quit(1); } @@ -298,8 +318,8 @@ double org[3], *sizp; FILE *fp; register int i; - if (osiz <= FTINY) - if (noaction && fdate(oct1name) < + if (osiz <= FTINY) { + if (!nprocs && fdate(oct1name) < (scenedate>illumdate?scenedate:illumdate)) { /* run getbbox */ sprintf(buf, "getbbox -w -h %s", @@ -334,6 +354,7 @@ double org[3], *sizp; } pclose(fp); } + } org[0] = oorg[0]; org[1] = oorg[1]; org[2] = oorg[2]; *sizp = osiz; } @@ -538,11 +559,12 @@ checkambfile() /* check date on ambient file */ return; if (!(afdate = fdate(vval(AMBFILE)))) return; - if (oct1date > afdate) + if (oct1date > afdate) { if (touchonly) touch(vval(AMBFILE)); else rmfile(vval(AMBFILE)); + } } @@ -1030,8 +1052,10 @@ char *vn; /* returned view name */ } -printview(vopts) /* print out selected view */ +int +myprintview(vopts, fp) /* print out selected view */ register char *vopts; +FILE *fp; { VIEW vwr; char buf[128]; @@ -1045,16 +1069,16 @@ again: goto again; } #endif - copystruct(&vwr, &stdview); + vwr = stdview; sscanview(&vwr, cp=vopts); /* set initial options */ while ((cp = strstr(cp, "-vf ")) != NULL && *atos(buf, sizeof(buf), cp += 4)) { viewfile(buf, &vwr, NULL); /* load -vf file */ sscanview(&vwr, cp); /* reset tail */ } - fputs(VIEWSTR, stdout); - fprintview(&vwr, stdout); /* print full spec. */ - fputc('\n', stdout); + fputs(VIEWSTR, fp); + fprintview(&vwr, fp); /* print full spec. */ + fputc('\n', fp); return(0); } @@ -1068,7 +1092,7 @@ char *opts, *po; if (touchonly || (vw = getview(0, NULL)) == NULL) return; if (sayview) - printview(vw); + myprintview(vw, stdout); sprintf(combuf, "rview %s%s%s -R %s ", vw, po, opts, rifname); if (rvdevice != NULL) sprintf(combuf+strlen(combuf), "-o %s ", rvdevice); @@ -1088,9 +1112,11 @@ char *opts, *po; char combuf[PATH_MAX]; char rawfile[PATH_MAX], picfile[PATH_MAX]; char zopt[PATH_MAX+4], rep[PATH_MAX+16], res[32]; + char rppopt[128], *pfile = NULL; char pfopts[128]; char vs[32], *vw; int vn, mult; + FILE *fp; time_t rfdt, pfdt; /* get pfilt options */ pfiltopts(pfopts); @@ -1132,11 +1158,17 @@ char *opts, *po; else badvalue(REPORT); } - /* do each view */ - vn = 0; + /* set up parallel rendering */ + if (nprocs > 1 & !vdef(ZFILE)) { + strcpy(rppopt, "-S 1 -PP pfXXXXXX"); + pfile = rppopt+9; + if (mktemp(pfile) == NULL) + pfile = NULL; + } + vn = 0; /* do each view */ while ((vw = getview(vn++, vs)) != NULL) { if (sayview) - printview(vw); + myprintview(vw, stdout); if (!vs[0]) sprintf(vs, "%d", vn); sprintf(picfile, "%s_%s.pic", vval(PICTURE), vs); @@ -1160,11 +1192,19 @@ char *opts, *po; touch(picfile); continue; } + if (next_process()) { /* parallel running? */ + if (pfile != NULL) + sleep(20); + continue; + } + /* XXX Remember to call finish_process() */ /* build rpict command */ - if (rfdt >= oct1date) /* recover */ + if (rfdt >= oct1date) { /* recover */ sprintf(combuf, "rpict%s%s%s%s -ro %s %s", rep, po, opts, zopt, rawfile, oct1name); - else { + if (runcom(combuf)) /* run rpict */ + goto rperror; + } else { if (overture) { /* run overture calculation */ sprintf(combuf, "rpict%s %s%s -x 64 -y 64 -ps 1 %s > %s", @@ -1181,14 +1221,27 @@ char *opts, *po; #endif } sprintf(combuf, "rpict%s %s %s%s%s%s %s > %s", - rep, vw, res, po, opts, zopt, - oct1name, rawfile); + rep, vw, res, po, opts, + zopt, oct1name, rawfile); + if (pfile != NULL && inchild()) { + /* rpict persistent mode */ + if (!silent) + printf("\t%s\n", combuf); + sprintf(combuf, "rpict%s %s %s%s%s %s > %s", + rep, rppopt, res, po, opts, + oct1name, rawfile); + fflush(stdout); + fp = popen(combuf, "w"); + if (fp == NULL) + goto rperror; + myprintview(vw, fp); + if (pclose(fp)) + goto rperror; + } else { /* rpict normal mode */ + if (runcom(combuf)) + goto rperror; + } } - if (runcom(combuf)) { /* run rpict */ - fprintf(stderr, "%s: error rendering view %s\n", - progname, vs); - quit(1); - } if (!vdef(RAWFILE) || strcmp(vval(RAWFILE),vval(PICTURE))) { /* build pfilt command */ if (mult > 1) @@ -1197,7 +1250,7 @@ char *opts, *po; else sprintf(combuf, "pfilt%s %s > %s", pfopts, rawfile, picfile); - if (runcom(combuf)) { /* run pfilt */ + if (runcom(combuf)) { /* run pfilt */ fprintf(stderr, "%s: error filtering view %s\n\t%s removed\n", progname, vs, picfile); @@ -1211,7 +1264,23 @@ char *opts, *po; mvfile(rawfile, combuf); } else rmfile(rawfile); + finish_process(); /* leave if child */ } + wait_process(1); /* wait for children to finish */ + if (pfile != NULL) { /* clean up rpict persistent mode */ + int pid; + fp = fopen(pfile, "r"); + if (fp != NULL) { + if (fscanf(fp, "%*s %d", &pid) != 1 || + kill(pid, 1) == -1) + unlink(pfile); + fclose(fp); + } + } + return; +rperror: + fprintf(stderr, "%s: error rendering view %s\n", progname, vs); + quit(1); } @@ -1220,7 +1289,7 @@ char *fn; { if (!silent) printf("\ttouch %s\n", fn); - if (noaction) + if (!nprocs) return(0); #ifdef notused if (access(fn, F_OK) == -1) /* create it */ @@ -1236,7 +1305,7 @@ char *cs; { if (!silent) /* echo it */ printf("\t%s\n", cs); - if (noaction) + if (!nprocs) return(0); fflush(stdout); /* flush output and pass to shell */ return(system(cs)); @@ -1247,12 +1316,8 @@ rmfile(fn) /* remove a file */ char *fn; { if (!silent) -#ifdef _WIN32 - printf("\tdel %s\n", fn); -#else - printf("\trm -f %s\n", fn); -#endif - if (noaction) + printf("\t%s %s\n", DELCMD, fn); + if (!nprocs) return(0); return(unlink(fn)); } @@ -1262,16 +1327,94 @@ mvfile(fold, fnew) /* move a file */ char *fold, *fnew; { if (!silent) -#ifdef _WIN32 - printf("\trename %s %s\n", fold, fnew); -#else - printf("\tmv %s %s\n", fold, fnew); -#endif - if (noaction) + printf("\t%s %s %s\n", RENAMECMD, fold, fnew); + if (!nprocs) return(0); return(rename(fold, fnew)); } + +#ifdef RHAS_FORK_EXEC +int +next_process() /* fork the next process (max. nprocs) */ +{ + int child_pid; + + if (nprocs <= 1) + return(0); /* it's us or no one */ + if (inchild()) { + fprintf(stderr, "%s: internal error 1 in spawn_process()\n", + progname); + quit(1); + } + if (children_running >= nprocs) + wait_process(0); /* wait for someone to finish */ + fflush(stdout); + child_pid = fork(); /* split process */ + if (child_pid == 0) { /* we're the child */ + children_running = -1; + return(0); + } + if (child_pid > 0) { /* we're the parent */ + ++children_running; + return(1); + } + fprintf(stderr, "%s: warning -- fork() failed\n", progname); + return(0); +} + +wait_process(all) /* wait for process(es) to finish */ +int all; +{ + int ourstatus = 0; + int pid, status; + + if (all) + all = children_running; + else if (children_running > 0) + all = 1; + while (all-- > 0) { + pid = wait(&status); + if (pid < 0) + syserr(progname); + status = status>>8 & 0xff; + --children_running; + if (status != 0) { /* child's problem is our problem */ + if (ourstatus == 0 & children_running > 0) + fprintf(stderr, "%s: waiting for remaining processes\n", + progname); + ourstatus = status; + all = children_running; + } + } + if (ourstatus != 0) + quit(ourstatus); /* bad status from child */ +} +#else /* ! RHAS_FORK_EXEC */ +int +next_process() +{ + return(0); /* cannot start new process */ +} +wait_process(all) +int all; +{ + (void)all; /* no one to wait for */ +} +int +kill(pid, sig) /* win|unix_process.c should also wait and kill */ +int pid, sig; +{ + return 0; +} +#endif /* ! RHAS_FORK_EXEC */ + +finish_process() /* exit a child process */ +{ + if (!inchild()) + return; /* in parent -- noop */ + exit(0); +} #ifdef _WIN32 setenv(vname, value) /* set an environment variable */