--- ray/src/rt/raypcalls.c 2009/12/15 18:21:53 2.25 +++ ray/src/rt/raypcalls.c 2020/06/16 17:58:11 2.34 @@ -1,5 +1,5 @@ #ifndef lint -static const char RCSid[] = "$Id: raypcalls.c,v 2.25 2009/12/15 18:21:53 greg Exp $"; +static const char RCSid[] = "$Id: raypcalls.c,v 2.34 2020/06/16 17:58:11 greg Exp $"; #endif /* * raypcalls.c - interface for parallel rendering using Radiance @@ -71,11 +71,11 @@ static const char RCSid[] = "$Id: raypcalls.c,v 2.25 2 * * If the second argument is 1, the call won't block when * results aren't ready, but will immediately return 0. - * (A special value of -1 returns 0 unless a ray is - * ready in the queue and no system calls are needed.) * If the second argument is 0, the call will block * until a value is available, returning 0 only if the - * queue is completely empty. A negative return value + * queue is completely empty. Setting the second argument + * to -1 returns 0 unless a ray is ready in the queue and + * no system calls are needed. A negative return value * indicates that a rendering process died. If this * happens, ray_pclose(0) is automatically called to close * all child processes, and ray_pnprocs is set to zero. @@ -147,7 +147,7 @@ static const char RCSid[] = "$Id: raypcalls.c,v 2.25 2 #include "selcall.h" #ifndef RAYQLEN -#define RAYQLEN 12 /* # rays to send at once */ +#define RAYQLEN 24 /* # rays to send at once */ #endif #ifndef MAX_RPROCS @@ -164,7 +164,7 @@ int ray_pnprocs = 0; /* number of child processes */ int ray_pnidle = 0; /* number of idle children */ static struct child_proc { - int pid; /* child process id */ + RT_PID pid; /* child process id */ int fd_send; /* write to child here */ int fd_recv; /* read from child here */ int npending; /* # rays in process */ @@ -176,6 +176,8 @@ static int r_send_next = 0; /* next send ray placement static int r_recv_first = RAYQLEN; /* position of first unreported ray */ static int r_recv_next = RAYQLEN; /* next received ray placement */ +static int samplestep = 1; /* sample step size */ + #define sendq_full() (r_send_next >= RAYQLEN) static int ray_pflush(void); @@ -210,7 +212,7 @@ ray_pflush(void) /* send queued rays to idle childre for (i = ray_pnprocs; nc && i--; ) { if (r_proc[i].npending > 0) continue; /* child looks busy */ - n = (r_send_next - sfirst)/nc--; + n = (r_send_next - sfirst) / nc--; if (!n) continue; /* smuggle set size in crtype */ @@ -288,7 +290,7 @@ ray_presult( /* check for a completed ray */ static struct timeval tpoll; /* zero timeval struct */ static fd_set readset, errset; int n, ok; - register int pn; + int pn; if (r == NULL) return(0); @@ -366,7 +368,7 @@ getready: /* any children waiting for us? */ } /* preen returned rays */ for (n = r_recv_next - r_recv_first; n--; ) { - register RAY *rp = &r_queue[r_recv_first + n]; + RAY *rp = &r_queue[r_recv_first + n]; rp->rno = r_proc[pn].rno[n]; rp->parent = NULL; rp->newcset = rp->clipset = NULL; @@ -402,7 +404,7 @@ ray_pchild( /* process rays (never returns) */ ) { int n; - register int i; + int i; /* flag child process for quit() */ ray_pnprocs = -1; /* read each ray request set */ @@ -428,7 +430,7 @@ ray_pchild( /* process rays (never returns) */ r_queue[i].clipset = NULL; r_queue[i].slights = NULL; r_queue[i].rlvl = 0; - samplendx++; + samplendx += samplestep; rayclear(&r_queue[i]); rayvalue(&r_queue[i]); } @@ -462,6 +464,7 @@ ray_popen( /* open the specified # processes */ strcpy(shm_boundary, "SHM_BOUNDARY"); } fflush(NULL); /* clear pending output */ + samplestep = ray_pnprocs + nadd; while (nadd--) { /* fork each new process */ int p0[2], p1[2]; if (pipe(p0) < 0 || pipe(p1) < 0) @@ -480,6 +483,10 @@ ray_popen( /* open the specified # processes */ if (r_proc[ray_pnprocs].pid < 0) error(SYSTEM, "cannot fork child process"); close(p1[0]); close(p0[1]); + if (rand_samp) /* decorrelate random sequence */ + srandom(random()); + else + samplendx++; /* * Close write stream on exec to avoid multiprocessing deadlock. * No use in read stream without it, so set flag there as well. @@ -501,11 +508,15 @@ ray_pclose( /* close one or more child processes */ ) { static int inclose = 0; - RAY res; + RAY res; + int i, status = 0; /* check recursion */ if (inclose) return; inclose++; + /* check no child / in child */ + if (ray_pnprocs <= 0) + return; /* check argument */ if ((nsub <= 0) | (nsub > ray_pnprocs)) nsub = ray_pnprocs; @@ -514,21 +525,31 @@ ray_pclose( /* close one or more child processes */ ; r_send_next = 0; /* hard reset in case of error */ r_recv_first = r_recv_next = RAYQLEN; - /* clean up children */ - while (nsub--) { - int status; - ray_pnprocs--; - close(r_proc[ray_pnprocs].fd_send); - if (waitpid(r_proc[ray_pnprocs].pid, &status, 0) < 0) + /* close send pipes */ + for (i = ray_pnprocs-nsub; i < ray_pnprocs; i++) + close(r_proc[i].fd_send); + + if (nsub == 1) { /* awaiting single process? */ + if (waitpid(r_proc[ray_pnprocs-1].pid, &status, 0) < 0) status = 127<<8; - close(r_proc[ray_pnprocs].fd_recv); - if (status) { - sprintf(errmsg, - "rendering process %d exited with code %d", - r_proc[ray_pnprocs].pid, status>>8); - error(WARNING, errmsg); + close(r_proc[ray_pnprocs-1].fd_recv); + } else /* else unordered wait */ + for (i = 0; i < nsub; ) { + int j, mystatus; + RT_PID pid = wait(&mystatus); + for (j = ray_pnprocs-nsub; j < ray_pnprocs; j++) + if (r_proc[j].pid == pid) { + if (mystatus) + status = mystatus; + close(r_proc[j].fd_recv); + ++i; + } } - ray_pnidle--; + ray_pnprocs -= nsub; + ray_pnidle -= nsub; + if (status) { + sprintf(errmsg, "rendering process exited with code %d", status>>8); + error(WARNING, errmsg); } inclose--; }