--- ray/src/rt/raypcalls.c 2009/12/12 19:01:00 2.23 +++ ray/src/rt/raypcalls.c 2011/08/20 06:05:53 2.27 @@ -1,5 +1,5 @@ #ifndef lint -static const char RCSid[] = "$Id: raypcalls.c,v 2.23 2009/12/12 19:01:00 greg Exp $"; +static const char RCSid[] = "$Id: raypcalls.c,v 2.27 2011/08/20 06:05:53 greg Exp $"; #endif /* * raypcalls.c - interface for parallel rendering using Radiance @@ -71,11 +71,11 @@ static const char RCSid[] = "$Id: raypcalls.c,v 2.23 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. @@ -88,9 +88,11 @@ static const char RCSid[] = "$Id: raypcalls.c,v 2.23 2 * ray_psend(&myRay); * } * - * Note that it is a fatal error to call ra_psend() when - * ray_pnidle is zero. The ray_presult() and/or ray_pqueue() - * functions may be called subsequently to read back the results. + * Note that it is a mistake to call ra_psend() when + * ray_pnidle is zero, and nothing will be sent in + * this case. Otherwise, the ray_presult() and/or ray_pqueue() + * functions may be called subsequently to read back the results + * of rays queued by ray_psend(). * * When you are done, you may call ray_pdone(1) to close * all child processes and clean up memory used by Radiance. @@ -224,24 +226,27 @@ ray_pflush(void) /* send queued rays to idle childre ray_pnidle--; /* now she's busy */ } if (sfirst != r_send_next) - error(CONSISTENCY, "code screwup in ray_pflush"); + error(CONSISTENCY, "code screwup in ray_pflush()"); r_send_next = 0; return(sfirst); /* return total # sent */ } -void +int ray_psend( /* add a ray to our send queue */ RAY *r ) { - if (r == NULL) - return; + int rv; + + if ((r == NULL) | (ray_pnidle <= 0)) + return(0); /* flush output if necessary */ - if (sendq_full() && ray_pflush() <= 0) - error(INTERNAL, "ray_pflush failed in ray_psend"); + if (sendq_full() && (rv = ray_pflush()) <= 0) + return(rv); r_queue[r_send_next++] = *r; + return(1); } @@ -260,7 +265,7 @@ ray_pqueue( /* queue a ray for computation */ return(-1); /* put new ray in queue */ r_queue[r_send_next++] = mySend; - /* XXX r_send_next may now be > RAYQLEN */ + return(1); } /* else add ray to send queue */ @@ -329,7 +334,7 @@ getready: /* any children waiting for us? */ poll ? &tpoll : (struct timeval *)NULL)) < 0) if (errno != EINTR) { error(WARNING, - "select call failed in ray_presult"); + "select call failed in ray_presult()"); ray_pclose(0); return(-1); } @@ -408,7 +413,7 @@ ray_pchild( /* process rays (never returns) */ /* get smuggled set length */ n2 = sizeof(RAY)*r_queue[0].crtype - n; if (n2 < 0) - error(INTERNAL, "buffer over-read in ray_pchild"); + error(INTERNAL, "buffer over-read in ray_pchild()"); if (n2 > 0) { /* read the rest of the set */ i = readbuf(fd_in, (char *)r_queue + n, n2); if (i != n2) @@ -430,10 +435,10 @@ ray_pchild( /* process rays (never returns) */ /* write back our results */ i = writebuf(fd_out, (char *)r_queue, sizeof(RAY)*n); if (i != sizeof(RAY)*n) - error(SYSTEM, "write error in ray_pchild"); + error(SYSTEM, "write error in ray_pchild()"); } if (n) - error(SYSTEM, "read error in ray_pchild"); + error(SYSTEM, "read error in ray_pchild()"); ambsync(); quit(0); /* normal exit */ } @@ -468,12 +473,15 @@ ray_popen( /* open the specified # processes */ close(r_proc[pn].fd_recv); } close(p0[0]); close(p1[1]); + close(0); /* don't share stdin */ /* following call never returns */ ray_pchild(p1[0], p0[1]); } if (r_proc[ray_pnprocs].pid < 0) error(SYSTEM, "cannot fork child process"); close(p1[0]); close(p0[1]); + if (rand_samp) /* desynchronize random function */ + srandom((long)r_proc[ray_pnprocs].pid); /* * Close write stream on exec to avoid multiprocessing deadlock. * No use in read stream without it, so set flag there as well. @@ -500,6 +508,9 @@ ray_pclose( /* close one or more child processes */ 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; @@ -512,10 +523,10 @@ ray_pclose( /* close one or more child processes */ while (nsub--) { int status; ray_pnprocs--; - close(r_proc[ray_pnprocs].fd_recv); close(r_proc[ray_pnprocs].fd_send); if (waitpid(r_proc[ray_pnprocs].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",