--- ray/src/util/rpiece.c 1992/08/09 23:05:17 2.11 +++ ray/src/util/rpiece.c 2003/07/27 22:12:04 2.41 @@ -1,49 +1,79 @@ -/* Copyright (c) 1992 Regents of the University of California */ - #ifndef lint -static char SCCSid[] = "$SunId$ LBL"; +static const char RCSid[] = "$Id: rpiece.c,v 2.41 2003/07/27 22:12:04 schorsch Exp $"; #endif - /* * Generate sections of a picture. */ #include "standard.h" -#include + +#ifndef F_SETLKW + +main(argc, argv) +int argc; +char *argv[]; +{ + fprintf(stderr, "%s: no NFS lock manager on this machine\n", argv[0]); + exit(1); +} + +#else + #include + #include "color.h" #include "view.h" -#include "resolu.h" +#include "rtprocess.h" +#ifndef NFS +#define NFS 1 +#endif /* set the following to 0 to forgo forking */ #ifndef MAXFORK +#if NFS #define MAXFORK 3 /* allotment of duped processes */ +#else +#define MAXFORK 0 #endif +#endif + /* protection from SYSV signals(!) */ +#if defined(sgi) +#define guard_io() sighold(SIGALRM) +#define unguard() sigrelse(SIGALRM) +#endif +#ifndef guard_io +#define guard_io() 0 +#define unguard() 0 +#endif +extern char *strerror(); + /* rpict command */ -char *rpargv[128] = {"rpict", "-S", "1", "-x", "512", "-y", "512", "-pa", "1"}; -int rpargc = 9; -int rpd[3]; +char *rpargv[128] = {"rpict", "-S", "1"}; +int rpargc = 3; FILE *torp, *fromrp; COLR *pbuf; /* our view parameters */ VIEW ourview = STDVIEW; double pixaspect = 1.0; -int hres = 512, vres = 512, hmult = 2, vmult = 2; +int hres = 1024, vres = 1024, hmult = 4, vmult = 4; /* output file */ char *outfile = NULL; int outfd; long scanorig; -int syncfd = -1; /* lock file descriptor */ +FILE *syncfp = NULL; /* synchronization file pointer */ +int synclst = F_UNLCK; /* synchronization file lock status */ int nforked = 0; +#define sflock(t) if ((t)!=synclst) dolock(fileno(syncfp),synclst=t) + char *progname; int verbose = 0; +unsigned timelim = 0; +int rvrlim = -1; -extern long lseek(), ftell(); - int gotalrm = 0; -int onalrm() { gotalrm++; } +void onalrm(int i) { gotalrm++; } main(argc, argv) @@ -54,6 +84,14 @@ char *argv[]; progname = argv[0]; for (i = 1; i < argc; i++) { + /* expand arguments */ + while ((rval = expandarg(&argc, &argv, i)) > 0) + ; + if (rval < 0) { + fprintf(stderr, "%s: cannot expand '%s'", + argv[0], argv[i]); + exit(1); + } if (argv[i][0] == '-') switch (argv[i][1]) { case 'v': @@ -78,17 +116,25 @@ char *argv[]; } break; case 'p': /* pixel aspect ratio? */ - if (argv[i][2] == 'a' && !argv[i][3]) - pixaspect = atof(argv[i+1]); + if (argv[i][2] != 'a' || argv[i][3]) + break; + pixaspect = atof(argv[++i]); + continue; + case 'T': /* time limit (hours) */ + if (argv[i][2]) + break; + timelim = atof(argv[++i])*3600. + .5; break; - case 'x': /* piece x resolution */ - if (!argv[i][2]) - hres = atoi(argv[i+1]); - break; - case 'y': /* piece y resolution */ - if (!argv[i][2]) - vres = atoi(argv[i+1]); - break; + case 'x': /* overall x resolution */ + if (argv[i][2]) + break; + hres = atoi(argv[++i]); + continue; + case 'y': /* overall y resolution */ + if (argv[i][2]) + break; + vres = atoi(argv[++i]); + continue; case 'X': /* horizontal multiplier */ if (argv[i][2]) break; @@ -99,59 +145,101 @@ char *argv[]; break; vmult = atoi(argv[++i]); continue; + case 'R': /* recover */ + if (argv[i][2]) + break; + rvrlim = 0; + /* fall through */ case 'F': /* syncronization file */ if (argv[i][2]) break; - if ((syncfd = open(argv[++i], O_RDWR)) < 0) { + if ((syncfp = + fdopen(open(argv[++i],O_RDWR|O_CREAT,0666),"r+")) == NULL) { fprintf(stderr, "%s: cannot open\n", argv[i]); exit(1); } continue; + case 'z': /* z-file ist verbotten */ + fprintf(stderr, "%s: -z option not allowed\n", + argv[0]); + exit(1); case 'o': /* output file */ if (argv[i][2]) break; outfile = argv[++i]; continue; - } + } else if (i >= argc-1) + break; rpargv[rpargc++] = argv[i]; } - rpargv[rpargc] = NULL; + if (i >= argc) { + fprintf(stderr, "%s: missing octree argument\n", argv[0]); + exit(1); + } if (outfile == NULL) { fprintf(stderr, "%s: missing output file\n", argv[0]); exit(1); } init(argc, argv); rpiece(); - rval = cleanup(0); - exit(rval); + exit(cleanup(0)); } +dolock(fd, ltyp) /* lock or unlock a file */ +int fd; +int ltyp; +{ + static struct flock fls; /* static so initialized to zeroes */ + + fls.l_type = ltyp; + if (fcntl(fd, F_SETLKW, &fls) < 0) { + fprintf(stderr, "%s: cannot lock/unlock file: %s\n", + progname, strerror(errno)); + exit(1); + } +} + + init(ac, av) /* set up output file and start rpict */ int ac; char **av; { + static char hrbuf[16], vrbuf[16]; extern char VersionID[]; char *err; FILE *fp; int hr, vr; + SUBPROC rpd; /* since we don't close_process(), this can be local */ /* set up view */ if ((err = setview(&ourview)) != NULL) { fprintf(stderr, "%s: %s\n", progname, err); exit(1); } - if (syncfd != -1) { - char buf[32]; - buf[read(syncfd, buf, sizeof(buf)-1)] = '\0'; - sscanf(buf, "%d %d", &hmult, &vmult); + if (syncfp != NULL) { + sflock(F_RDLCK); + fscanf(syncfp, "%d %d", &hmult, &vmult); + sflock(F_UNLCK); } + /* compute piece size */ + hres /= hmult; + vres /= vmult; normaspect(viewaspect(&ourview)*hmult/vmult, &pixaspect, &hres, &vres); + sprintf(hrbuf, "%d", hres); + rpargv[rpargc++] = "-x"; rpargv[rpargc++] = hrbuf; + sprintf(vrbuf, "%d", vres); + rpargv[rpargc++] = "-y"; rpargv[rpargc++] = vrbuf; + rpargv[rpargc++] = "-pa"; rpargv[rpargc++] = "0"; + rpargv[rpargc++] = av[ac-1]; + rpargv[rpargc] = NULL; /* open output file */ if ((outfd = open(outfile, O_WRONLY|O_CREAT|O_EXCL, 0666)) >= 0) { + dolock(outfd, F_WRLCK); if ((fp = fdopen(dup(outfd), "w")) == NULL) goto filerr; - printargs(ac, av, fp); /* write header */ + newheader("RADIANCE", fp); /* create header */ + printargs(ac, av, fp); fprintf(fp, "SOFTWARE= %s\n", VersionID); fputs(VIEWSTR, fp); fprintview(&ourview, fp); @@ -162,10 +250,11 @@ char **av; putc('\n', fp); fprtresolu(hres*hmult, vres*vmult, fp); } else if ((outfd = open(outfile, O_RDWR)) >= 0) { + dolock(outfd, F_RDLCK); if ((fp = fdopen(dup(outfd), "r+")) == NULL) goto filerr; - getheader(fp, NULL); /* skip header */ - if (fscnresolu(&hr, &vr, fp) < 0 || /* check resolution */ + getheader(fp, NULL, NULL); /* skip header */ + if (!fscnresolu(&hr, &vr, fp) || /* check resolution */ hr != hres*hmult || vr != vres*vmult) { fprintf(stderr, "%s: resolution mismatch on file \"%s\"\n", progname, outfile); @@ -179,23 +268,25 @@ char **av; scanorig = ftell(fp); /* record position of first scanline */ if (fclose(fp) == -1) /* done with stream i/o */ goto filerr; - sync(); /* flush NFS buffers */ + dolock(outfd, F_UNLCK); /* start rpict process */ - if (open_process(rpd, rpargv) <= 0) { + if (open_process(&rpd, rpargv) <= 0) { fprintf(stderr, "%s: cannot start %s\n", progname, rpargv[0]); exit(1); } - if ((fromrp = fdopen(rpd[0], "r")) == NULL || - (torp = fdopen(rpd[1], "w")) == NULL) { + if ((fromrp = fdopen(rpd.r, "r")) == NULL || + (torp = fdopen(rpd.w, "w")) == NULL) { fprintf(stderr, "%s: cannot open stream to %s\n", progname, rpargv[0]); exit(1); } - if ((pbuf = (COLR *)malloc(hres*vres*sizeof(COLR))) == NULL) { + if ((pbuf = (COLR *)bmalloc(hres*vres*sizeof(COLR))) == NULL) { fprintf(stderr, "%s: out of memory\n", progname); exit(1); } signal(SIGALRM, onalrm); + if (timelim) + alarm(timelim); return; filerr: fprintf(stderr, "%s: i/o error on file \"%s\"\n", progname, outfile); @@ -207,54 +298,95 @@ int nextpiece(xp, yp) /* get next piece assignment */ int *xp, *yp; { - extern char *fgets(); - struct flock fls; - char buf[64]; - if (gotalrm) /* someone wants us to quit */ return(0); - if (syncfd != -1) { /* use sync file */ - fls.l_type = F_WRLCK; /* gain exclusive access */ - fls.l_whence = 0; - fls.l_start = 0L; - fls.l_len = 0L; - fcntl(syncfd, F_SETLKW, &fls); - lseek(syncfd, 0L, 0); - buf[read(syncfd, buf, sizeof(buf)-1)] = '\0'; - if (sscanf(buf, "%*d %*d %d %d", xp, yp) < 2) { + if (syncfp != NULL) { /* use sync file */ + /* + * So we don't necessarily have to lock and unlock the file + * multiple times (very slow), we establish an exclusive + * lock at the beginning on our synchronization file and + * maintain it in the subroutine rvrpiece(). + */ + sflock(F_WRLCK); + fseek(syncfp, 0L, 0); /* read position */ + if (fscanf(syncfp, "%*d %*d %d %d", xp, yp) < 2) { *xp = hmult-1; *yp = vmult; } + if (rvrlim == 0) /* initialize recovery limit */ + rvrlim = *xp*vmult + *yp; + if (rvrpiece(xp, yp)) { /* do stragglers first */ + sflock(F_UNLCK); + return(1); + } if (--(*yp) < 0) { /* decrement position */ *yp = vmult-1; - if (--(*xp) < 0) { /* all done! */ - close(syncfd); + if (--(*xp) < 0) { /* all done */ + sflock(F_UNLCK); return(0); } } - sprintf(buf, "%d %d\n%d %d\n", hmult, vmult, *xp, *yp); - lseek(syncfd, 0L, 0); /* write new position */ - write(syncfd, buf, strlen(buf)); - fls.l_type = F_UNLCK; /* release sync file */ - fcntl(syncfd, F_SETLKW, &fls); + fseek(syncfp, 0L, 0); /* write new position */ + fprintf(syncfp, "%4d %4d\n%4d %4d\n\n", hmult, vmult, *xp, *yp); + fflush(syncfp); + sflock(F_UNLCK); /* release sync file */ return(1); } - if (fgets(buf, sizeof(buf), stdin) == NULL) /* use stdin */ - return(0); - if (sscanf(buf, "%d %d", xp, yp) == 2) - return(1); - fprintf(stderr, "%s: input format error\n", progname); - exit(cleanup(1)); + return(scanf("%d %d", xp, yp) == 2); /* use stdin */ } int +rvrpiece(xp, yp) /* check for recoverable pieces */ +register int *xp, *yp; +{ + static char *pdone = NULL; /* which pieces are done */ + static long readpos = -1; /* how far we've read */ + register int i; + /* + * This routine is called by nextpiece() with an + * exclusive lock on syncfp and the file pointer at the + * appropriate position to read in the finished pieces. + */ + if (rvrlim < 0) + return(0); /* only check if asked */ + if (pdone == NULL) /* first call */ + pdone = calloc(hmult*vmult, sizeof(char)); + if (pdone == NULL) { + fprintf(stderr, "%s: out of memory\n", progname); + exit(1); + } + if (readpos != -1) /* mark what's been done */ + fseek(syncfp, readpos, 0); + while (fscanf(syncfp, "%d %d", xp, yp) == 2) + pdone[*xp*vmult+*yp] = 1; + if (!feof(syncfp)) { + fprintf(stderr, "%s: format error in sync file\n", progname); + exit(1); + } + readpos = ftell(syncfp); + i = hmult*vmult; /* find an unaccounted for piece */ + while (i-- > rvrlim) + if (!pdone[i]) { + *xp = i / vmult; + *yp = i % vmult; + pdone[i] = 1; /* consider it done */ + return(1); + } + rvrlim = -1; /* nothing left to recover */ + free(pdone); + pdone = NULL; + return(0); +} + + +int cleanup(rstat) /* close rpict process and clean up */ int rstat; { int status; - free((char *)pbuf); + bfree((char *)pbuf, hres*vres*sizeof(COLR)); fclose(torp); fclose(fromrp); while (wait(&status) != -1) @@ -269,7 +401,7 @@ rpiece() /* render picture piece by piece */ VIEW pview; int xorg, yorg; /* compute view parameters */ - copystruct(&pview, &ourview); + pview = ourview; switch (ourview.type) { case VT_PER: pview.horiz = 2.*180./PI*atan( @@ -282,6 +414,11 @@ rpiece() /* render picture piece by piece */ pview.horiz = ourview.horiz / hmult; pview.vert = ourview.vert / vmult; break; + case VT_CYL: + pview.horiz = ourview.horiz / hmult; + pview.vert = 2.*180./PI*atan( + tan(PI/180./2.*ourview.vert)/vmult ); + break; case VT_HEM: pview.horiz = 2.*180./PI*asin( sin(PI/180./2.*ourview.horiz)/hmult ); @@ -295,17 +432,13 @@ rpiece() /* render picture piece by piece */ } /* render each piece */ while (nextpiece(&xorg, &yorg)) { - pview.hoff = ourview.hoff + xorg - 0.5*(hmult-1); - pview.voff = ourview.voff + yorg - 0.5*(vmult-1); + pview.hoff = ourview.hoff*hmult + xorg - 0.5*(hmult-1); + pview.voff = ourview.voff*vmult + yorg - 0.5*(vmult-1); fputs(VIEWSTR, torp); fprintview(&pview, torp); putc('\n', torp); fflush(torp); /* assigns piece to rpict */ putpiece(xorg, yorg); /* place piece in output */ - if (verbose) { /* notify caller */ - printf("%d %d done\n", xorg, yorg); - fflush(stdout); - } } } @@ -319,25 +452,34 @@ int xpos, ypos; int hr, vr; register int y; /* check bounds */ - if (xpos < 0 | ypos < 0 | xpos >= hmult | ypos >= vmult) { + if ((xpos < 0) | (ypos < 0) | (xpos >= hmult) | (ypos >= vmult)) { fprintf(stderr, "%s: requested piece (%d,%d) out of range\n", progname, xpos, ypos); exit(cleanup(1)); } /* check header from rpict */ - getheader(fromrp, NULL); - if (fscnresolu(&hr, &vr, fromrp) < 0 || hr != hres | vr != vres) { + guard_io(); + getheader(fromrp, NULL, NULL); + if (!fscnresolu(&hr, &vr, fromrp) || (hr != hres) | (vr != vres)) { fprintf(stderr, "%s: resolution mismatch from %s\n", progname, rpargv[0]); exit(cleanup(1)); } + if (verbose) { /* notify caller */ + printf("%d %d begun\n", xpos, ypos); + fflush(stdout); + } + unguard(); /* load new piece into buffer */ - for (y = 0; y < vr; y++) + for (y = 0; y < vr; y++) { + guard_io(); if (freadcolrs(pbuf+y*hr, hr, fromrp) < 0) { fprintf(stderr, "%s: read error from %s\n", progname, rpargv[0]); exit(cleanup(1)); } + unguard(); + } #if MAXFORK /* fork so we don't slow rpict down */ if ((pid = fork()) > 0) { @@ -352,39 +494,62 @@ int xpos, ypos; #else pid = -1; /* no forking */ #endif + fls.l_start = scanorig + + ((long)(vmult-1-ypos)*vres*hmult+xpos)*hres*sizeof(COLR); +#if NFS + fls.l_len = ((long)(vres-1)*hmult+1)*hres*sizeof(COLR); /* lock file section so NFS doesn't mess up */ fls.l_whence = 0; - fls.l_len = (long)vres*hmult*hres*sizeof(COLR); - fls.l_start = scanorig + (vmult-1-ypos)*fls.l_len; fls.l_type = F_WRLCK; - fcntl(outfd, F_SETLKW, &fls); + if (fcntl(outfd, F_SETLKW, &fls) < 0) + filerr("lock"); +#endif /* write new piece to file */ - if (lseek(outfd, fls.l_start+(long)xpos*hres*sizeof(COLR), 0) == -1) - goto seekerr; + if (lseek(outfd, (off_t)fls.l_start, 0) < 0) + filerr("seek"); if (hmult == 1) { if (writebuf(outfd, (char *)pbuf, vr*hr*sizeof(COLR)) != vr*hr*sizeof(COLR)) - goto writerr; + filerr("write"); } else for (y = 0; y < vr; y++) { if (writebuf(outfd, (char *)(pbuf+y*hr), hr*sizeof(COLR)) != hr*sizeof(COLR)) - goto writerr; + filerr("write"); if (y < vr-1 && lseek(outfd, - (long)(hmult-1)*hr*sizeof(COLR), - 1) == -1) - goto seekerr; + (off_t)(hmult-1)*hr*sizeof(COLR), + 1) < 0) + filerr("seek"); } - if (pid == -1) { /* fork failed */ - fls.l_type = F_UNLCK; /* release lock */ - fcntl(outfd, F_SETLKW, &fls); - return(0); +#if NFS + fls.l_type = F_UNLCK; /* release lock */ + if (fcntl(outfd, F_SETLKW, &fls) < 0) + filerr("lock"); +#endif + if (verbose) { /* notify caller */ + printf("%d %d done\n", xpos, ypos); + fflush(stdout); } - _exit(0); /* else exit child process (releasing lock) */ -seekerr: - fprintf(stderr, "%s: seek error on file \"%s\"\n", progname, outfile); + if (syncfp != NULL) { /* record what's been done */ + sflock(F_WRLCK); + fseek(syncfp, 0L, 2); /* append index */ + fprintf(syncfp, "%4d %4d\n", xpos, ypos); + fflush(syncfp); + /*** Unlock not necessary, since + sflock(F_UNLCK); _exit() or nextpiece() is next ***/ + } + if (pid == -1) /* didn't fork or fork failed */ + return(0); + _exit(0); /* else exit child process (releasing locks) */ +} + + +filerr(t) /* report file error and exit */ +char *t; +{ + fprintf(stderr, "%s: %s error on file \"%s\": %s\n", + progname, t, outfile, strerror(errno)); _exit(1); -writerr: - fprintf(stderr, "%s: write error on file \"%s\"\n", progname, outfile); - _exit(1); } + +#endif