--- ray/src/rt/raypcalls.c 2008/02/20 05:21:29 2.19 +++ ray/src/rt/raypcalls.c 2009/12/16 01:06:50 2.26 @@ -1,5 +1,5 @@ #ifndef lint -static const char RCSid[] = "$Id: raypcalls.c,v 2.19 2008/02/20 05:21:29 greg Exp $"; +static const char RCSid[] = "$Id: raypcalls.c,v 2.26 2009/12/16 01:06:50 greg Exp $"; #endif /* * raypcalls.c - interface for parallel rendering using Radiance @@ -13,11 +13,11 @@ static const char RCSid[] = "$Id: raypcalls.c,v 2.19 2 * These calls are designed similarly to the ones in raycalls.c, * but allow for multiple rendering processes on the same host * machine. There is no sense in specifying more child processes - * than you have processors, but one child may help by allowing + * than you have processor cores, but one child may help by allowing * asynchronous ray computation in an interactive program, and * will protect the caller from fatal rendering errors. * - * You should first read and undrstand the header in raycalls.c, + * You should first read and understand the header in raycalls.c, * as some things are explained there that are not repated here. * * The first step is opening one or more rendering processes @@ -25,13 +25,15 @@ static const char RCSid[] = "$Id: raypcalls.c,v 2.19 2 * ray_pinit() loads the octree and data structures into the * caller's memory, and ray_popen() synchronizes the ambient * file, if any. Shared memory permits all sorts of queries - * that wouldn't be possible otherwise, without causing any real + * that wouldn't be possible otherwise without causing any real * memory overhead, since all the static data are shared - * between processes. Rays are then traced using a simple + * between processes. Rays are traced using a simple * queuing mechanism, explained below. * * The ray queue buffers RAYQLEN rays before sending to - * children, each of which may internally buffer RAYQLEN rays. + * children, each of which may internally buffer RAYQLEN rays + * during evaluation. Rays are not returned in the order + * they are sent when multiple processes are open. * * Rays are queued and returned by a single * ray_pqueue() call. A ray_pqueue() return @@ -71,9 +73,11 @@ static const char RCSid[] = "$Id: raypcalls.c,v 2.19 2 * results aren't ready, but will immediately return 0. * 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_close(0) is automatically called to close + * happens, ray_pclose(0) is automatically called to close * all child processes, and ray_pnprocs is set to zero. * * If you just want to fill the ray queue without checking for @@ -84,17 +88,21 @@ static const char RCSid[] = "$Id: raypcalls.c,v 2.19 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. * Any queued ray calculations will be awaited and discarded. * As with ray_done(), ray_pdone(0) hangs onto data files * and fonts that are likely to be used in subsequent renderings. - * Whether you want to bother cleaning up memory or not, you - * should at least call ray_pclose(0) to clean the child processes. + * Whether you need to clean up memory or not, you should + * at least call ray_pclose(0) to await the child processes. + * The caller should define a quit() function that calls + * ray_pclose(0) if ray_pnprocs > 0. * * Warning: You cannot affect any of the rendering processes * by changing global parameter values onece ray_pinit() has @@ -124,7 +132,7 @@ static const char RCSid[] = "$Id: raypcalls.c,v 2.19 2 * returning a negative value from ray_pqueue() or * ray_presult(). If you get a negative value from either * of these calls, you can assume that the processes have - * been cleaned up with a call to ray_close(), though you + * been cleaned up with a call to ray_pclose(), though you * will have to call ray_pdone() yourself if you want to * free memory. Obviously, you cannot continue rendering * without risking further errors, but otherwise your @@ -160,13 +168,13 @@ static struct child_proc { int fd_send; /* write to child here */ int fd_recv; /* read from child here */ int npending; /* # rays in process */ - unsigned long rno[RAYQLEN]; /* working on these rays */ + RNUMBER rno[RAYQLEN]; /* working on these rays */ } r_proc[MAX_NPROCS]; /* our child processes */ static RAY r_queue[2*RAYQLEN]; /* ray i/o buffer */ -static int r_send_next; /* next send ray placement */ -static int r_recv_first; /* position of first unreported ray */ -static int r_recv_next; /* next receive ray placement */ +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 */ #define sendq_full() (r_send_next >= RAYQLEN) @@ -174,7 +182,7 @@ static int ray_pflush(void); static void ray_pchild(int fd_in, int fd_out); -extern void +void ray_pinit( /* initialize ray-tracing processes */ char *otnm, int nproc @@ -185,15 +193,6 @@ ray_pinit( /* initialize ray-tracing processes */ ray_init(otnm); /* load the shared scene */ - preload_objs(); /* preload auxiliary data */ - - /* set shared memory boundary */ - shm_boundary = (char *)malloc(16); - strcpy(shm_boundary, "SHM_BOUNDARY"); - - r_send_next = 0; /* set up queue */ - r_recv_first = r_recv_next = RAYQLEN; - ray_popen(nproc); /* fork children */ } @@ -227,28 +226,31 @@ 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 */ } -extern 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); } -extern int +int ray_pqueue( /* queue a ray for computation */ RAY *r ) @@ -263,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 */ @@ -277,7 +279,7 @@ ray_pqueue( /* queue a ray for computation */ } -extern int +int ray_presult( /* check for a completed ray */ RAY *r, int poll @@ -295,6 +297,9 @@ ray_presult( /* check for a completed ray */ *r = r_queue[r_recv_first++]; return(1); } + if (poll < 0) /* immediate polling mode? */ + return(0); + n = ray_pnprocs - ray_pnidle; /* pending before flush? */ if (ray_pflush() < 0) /* send new rays to process */ @@ -314,7 +319,7 @@ getready: /* any children waiting for us? */ if (FD_ISSET(r_proc[pn].fd_recv, &readset) || FD_ISSET(r_proc[pn].fd_recv, &errset)) break; - /* call select if we must */ + /* call select() if we must */ if (pn < 0) { FD_ZERO(&readset); FD_ZERO(&errset); n = 0; for (pn = ray_pnprocs; pn--; ) { @@ -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); } @@ -374,7 +379,7 @@ getready: /* any children waiting for us? */ } -extern void +void ray_pdone( /* reap children and free data */ int freall ) @@ -385,6 +390,7 @@ ray_pdone( /* reap children and free data */ free((void *)shm_boundary); shm_boundary = NULL; } + ray_done(freall); /* free rendering data */ } @@ -407,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) @@ -421,6 +427,7 @@ ray_pchild( /* process rays (never returns) */ r_queue[i].parent = NULL; r_queue[i].clipset = NULL; r_queue[i].slights = NULL; + r_queue[i].rlvl = 0; samplendx++; rayclear(&r_queue[i]); rayvalue(&r_queue[i]); @@ -428,16 +435,16 @@ 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 */ } -extern void +void ray_popen( /* open the specified # processes */ int nadd ) @@ -448,6 +455,12 @@ ray_popen( /* open the specified # processes */ if (nadd <= 0) return; ambsync(); /* load any new ambient values */ + if (shm_boundary == NULL) { /* first child process? */ + preload_objs(); /* preload auxiliary data */ + /* set shared memory boundary */ + shm_boundary = (char *)malloc(16); + strcpy(shm_boundary, "SHM_BOUNDARY"); + } fflush(NULL); /* clear pending output */ while (nadd--) { /* fork each new process */ int p0[2], p1[2]; @@ -460,6 +473,7 @@ 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]); } @@ -481,7 +495,7 @@ ray_popen( /* open the specified # processes */ } -extern void +void ray_pclose( /* close one or more child processes */ int nsub ) @@ -492,20 +506,25 @@ 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; /* clear our ray queue */ while (ray_presult(&res,0) > 0) ; + 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_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", @@ -515,14 +534,4 @@ ray_pclose( /* close one or more child processes */ ray_pnidle--; } inclose--; -} - - -void -quit(ec) /* make sure exit is called */ -int ec; -{ - if (ray_pnprocs > 0) /* close children if any */ - ray_pclose(0); - exit(ec); }