--- ray/src/rt/rc3.c 2012/06/16 17:09:49 2.10 +++ ray/src/rt/rc3.c 2018/05/27 18:35:57 2.23 @@ -1,14 +1,13 @@ #ifndef lint -static const char RCSid[] = "$Id: rc3.c,v 2.10 2012/06/16 17:09:49 greg Exp $"; +static const char RCSid[] = "$Id: rc3.c,v 2.23 2018/05/27 18:35:57 greg Exp $"; #endif /* * Accumulate ray contributions for a set of materials * Controlling process for multiple children */ +#include #include "rcontrib.h" -#include "platform.h" -#include "rtprocess.h" #include "selcall.h" #define MAXIQ (int)(PIPE_BUF/(sizeof(FVECT)*2)) @@ -24,12 +23,13 @@ typedef struct s_binq { static BINQ *out_bq = NULL; /* output bin queue */ static BINQ *free_bq = NULL; /* free queue entries */ +static SUBPROC kidpr[MAXPROCESS]; /* our child processes */ + static struct { RNUMBER r1; /* assigned ray starting index */ - SUBPROC pr; /* PID, i/o descriptors */ FILE *infp; /* file pointer to read from process */ int nr; /* number of rays to sum (0 if free) */ -} kida[MAXPROCESS]; /* our child processes */ +} kida[MAXPROCESS]; /* our child process i/o */ /* Get new bin queue entry */ @@ -89,6 +89,8 @@ free_binq(BINQ *bp) /* for (i = nmods; i--; ) memset(bp->mca[i]->cbin, 0, sizeof(DCOLOR)*bp->mca[i]->nbins); */ + if (bp->next != NULL) + error(CONSISTENCY, "free_binq() handed list"); bp->ndx = 0; bp->next = free_bq; /* push onto free list */ free_bq = bp; @@ -248,7 +250,7 @@ queue_results(int k) bq->nadded = kida[k].nr; /* read from child */ for (j = 0; j < nmods; j++) - if (fread(bq->mca[j]->cbin, sizeof(DCOLOR), bq->mca[j]->nbins, + if (getbinary(bq->mca[j]->cbin, sizeof(DCOLOR), bq->mca[j]->nbins, kida[k].infp) != bq->mca[j]->nbins) error(SYSTEM, "read error from render process"); @@ -266,7 +268,7 @@ set_stdout(const LUENT *le, void *p) } -/* Start child processes if we can */ +/* Start child processes if we can (call only once in parent!) */ int in_rchild() { @@ -274,14 +276,14 @@ in_rchild() while (nchild < nproc) { /* fork until target reached */ errno = 0; - rval = open_process(&kida[nchild].pr, NULL); + rval = open_process(&kidpr[nchild], NULL); if (rval < 0) error(SYSTEM, "open_process() call failed"); if (rval == 0) { /* if in child, set up & return true */ - lu_doall(&modconttab, set_stdout, NULL); + lu_doall(&modconttab, &set_stdout, NULL); lu_done(&ofiletab); while (nchild--) { /* don't share other pipes */ - close(kida[nchild].pr.w); + close(kidpr[nchild].w); fclose(kida[nchild].infp); } inpfmt = (sizeof(RREAL)==sizeof(double)) ? 'd' : 'f'; @@ -301,34 +303,36 @@ in_rchild() if (rval != PIPE_BUF) error(CONSISTENCY, "bad value from open_process()"); /* connect to child's output */ - kida[nchild].infp = fdopen(kida[nchild].pr.r, "rb"); + kida[nchild].infp = fdopen(kidpr[nchild].r, "rb"); if (kida[nchild].infp == NULL) error(SYSTEM, "out of memory in in_rchild()"); -#ifdef getc_unlocked - flockfile(kida[nchild].infp); /* avoid mutex overhead */ -#endif kida[nchild++].nr = 0; /* mark as available */ } +#ifdef getc_unlocked + for (rval = nchild; rval--; ) /* avoid mutex overhead */ + flockfile(kida[rval].infp); +#endif return(0); /* return "false" in parent */ } /* Close child processes */ void -end_children() +end_children(int immed) { - int status; - - while (nchild > 0) { - nchild--; - if ((status = close_process(&kida[nchild].pr)) > 0) { - sprintf(errmsg, - "rendering process returned bad status (%d)", - status); + int i; + +#ifdef SIGKILL /* error mode -- quick exit */ + for (i = nchild*immed; i-- > 0; ) + kill(kidpr[nchild].pid, SIGKILL); +#endif + if ((i = close_processes(kidpr, nchild)) > 0 && !immed) { + sprintf(errmsg, "rendering process returned bad status (%d)", + i); error(WARNING, errmsg); - } - fclose(kida[nchild].infp); } + while (nchild-- > 0) + fclose(kida[nchild].infp); } @@ -362,12 +366,12 @@ tryagain: /* catch up with output? */ n = nr = 0; for (i = nchild; i--; ) { if (kida[i].nr) { - FD_SET(kida[i].pr.r, &readset); + FD_SET(kidpr[i].r, &readset); ++nr; } - FD_SET(kida[i].pr.r, &errset); - if (kida[i].pr.r >= n) - n = kida[i].pr.r + 1; + FD_SET(kidpr[i].r, &errset); + if (kidpr[i].r >= n) + n = kidpr[i].r + 1; } if (!nr) /* nothing to wait for? */ return(-1); @@ -384,9 +388,9 @@ tryagain: /* catch up with output? */ FD_ZERO(&errset); n = -1; /* read results from child(ren) */ for (i = nchild; i--; ) { - if (FD_ISSET(kida[i].pr.r, &errset)) + if (FD_ISSET(kidpr[i].r, &errset)) error(USER, "rendering process died"); - if (FD_ISSET(kida[i].pr.r, &readset)) + if (FD_ISSET(kidpr[i].r, &readset)) queue_results(n = i); } return(n); /* first available child */ @@ -397,8 +401,7 @@ tryagain: /* catch up with output? */ void parental_loop() { - static int ignore_warning_given = 0; - int qlimit = (accumulate == 1) ? 1 : MAXIQ-1; + const int qlimit = (accumulate == 1) ? 1 : MAXIQ-1; int ninq = 0; FVECT orgdir[2*MAXIQ]; int i, n; @@ -407,39 +410,40 @@ parental_loop() flockfile(stdin); /* avoid lock/unlock overhead */ #endif while (getvec(orgdir[2*ninq]) == 0 && getvec(orgdir[2*ninq+1]) == 0) { - if (orgdir[2*ninq+1][0] == 0.0 && /* asking for flush? */ - (orgdir[2*ninq+1][1] == 0.0) & - (orgdir[2*ninq+1][2] == 0.0)) { - if (accumulate != 1) { - if (!ignore_warning_given++) - error(WARNING, - "dummy ray(s) ignored during accumulation\n"); - continue; - } - while (next_child_nq(1) >= 0) - ; /* clear the queue */ - lastdone = lastray = 0; - if ((yres <= 0) | (xres <= 0)) - waitflush = 1; /* flush next */ - put_zero_record(++lastray); - } else if (++ninq >= qlimit || + const int zero_ray = orgdir[2*ninq+1][0] == 0.0 && + (orgdir[2*ninq+1][1] == 0.0) & + (orgdir[2*ninq+1][2] == 0.0); + ninq += !zero_ray; + /* Zero ray cannot go in input queue */ + if (zero_ray ? ninq : ninq >= qlimit || lastray/accumulate != (lastray+ninq)/accumulate) { i = next_child_nq(0); /* manages output */ n = ninq; - if (accumulate != 1) /* request flush? */ + if (accumulate > 1) /* need terminator? */ memset(orgdir[2*n++], 0, sizeof(FVECT)*2); n *= sizeof(FVECT)*2; /* send assignment */ - if (writebuf(kida[i].pr.w, (char *)orgdir, n) != n) + if (writebuf(kidpr[i].w, (char *)orgdir, n) != n) error(SYSTEM, "pipe write error"); kida[i].r1 = lastray+1; lastray += kida[i].nr = ninq; /* mark as busy */ - ninq = 0; if (lastray < lastdone) { /* RNUMBER wrapped? */ while (next_child_nq(1) >= 0) ; - lastdone = lastray = 0; + lastray -= ninq; + lastdone = lastray %= accumulate; } + ninq = 0; } + if (zero_ray) { /* put bogus record? */ + if ((yres <= 0) | (xres <= 1) && + (lastray+1) % accumulate == 0) { + while (next_child_nq(1) >= 0) + ; /* clear the queue */ + lastdone = lastray = accumulate-1; + waitflush = 1; /* flush next */ + } + put_zero_record(++lastray); + } if (raysleft && !--raysleft) break; /* preemptive EOI */ } @@ -462,7 +466,7 @@ static int next_child_ready() { fd_set writeset, errset; - int i, n, nqr; + int i, n; for (i = nchild; i--; ) /* see if there's one free first */ if (!kida[i].nr) @@ -471,12 +475,12 @@ next_child_ready() FD_ZERO(&writeset); FD_ZERO(&errset); n = 0; for (i = nchild; i--; ) { - FD_SET(kida[i].pr.w, &writeset); - FD_SET(kida[i].pr.r, &errset); - if (kida[i].pr.w >= n) - n = kida[i].pr.w + 1; - if (kida[i].pr.r >= n) - n = kida[i].pr.r + 1; + FD_SET(kidpr[i].w, &writeset); + FD_SET(kidpr[i].r, &errset); + if (kidpr[i].w >= n) + n = kidpr[i].w + 1; + if (kidpr[i].r >= n) + n = kidpr[i].r + 1; } errno = 0; n = select(n, NULL, &writeset, &errset, NULL); @@ -484,9 +488,9 @@ next_child_ready() error(SYSTEM, "select() error in next_child_ready()"); n = -1; /* identify waiting child */ for (i = nchild; i--; ) { - if (FD_ISSET(kida[i].pr.r, &errset)) + if (FD_ISSET(kidpr[i].r, &errset)) error(USER, "rendering process died"); - if (FD_ISSET(kida[i].pr.w, &writeset)) + if (FD_ISSET(kidpr[i].w, &writeset)) kida[n = i].nr = 0; } return(n); /* first available child */ @@ -517,13 +521,13 @@ feeder_loop() if (++ninq >= MAXIQ) { i = next_child_ready(); /* get eager child */ n = sizeof(FVECT)*2 * ninq; /* give assignment */ - if (writebuf(kida[i].pr.w, (char *)orgdir, n) != n) + if (writebuf(kidpr[i].w, (char *)orgdir, n) != n) error(SYSTEM, "pipe write error"); kida[i].r1 = lastray+1; lastray += kida[i].nr = ninq; - ninq = 0; if (lastray < lastdone) /* RNUMBER wrapped? */ lastdone = lastray = 0; + ninq = 0; } if (raysleft && !--raysleft) break; /* preemptive EOI */ @@ -531,19 +535,20 @@ feeder_loop() if (ninq) { /* polish off input */ i = next_child_ready(); n = sizeof(FVECT)*2 * ninq; - if (writebuf(kida[i].pr.w, (char *)orgdir, n) != n) + if (writebuf(kidpr[i].w, (char *)orgdir, n) != n) error(SYSTEM, "pipe write error"); kida[i].r1 = lastray+1; lastray += kida[i].nr = ninq; ninq = 0; } - for (i = nchild; i--; ) { /* get results */ - close(kida[i].pr.w); + memset(orgdir, 0, sizeof(FVECT)*2); /* get results */ + for (i = nchild; i--; ) { + writebuf(kidpr[i].w, (char *)orgdir, sizeof(FVECT)*2); queue_results(i); } if (recover) /* and from before? */ queue_modifiers(); - end_children(); /* free up file descriptors */ + end_children(0); /* free up file descriptors */ for (i = 0; i < nmods; i++) mod_output(out_bq->mca[i]); /* output accumulated record */ end_record();