Back to index

radiance  4R0+20100331
Classes | Defines | Functions | Variables
raypcalls.c File Reference
#include "copyright.h"
#include "rtprocess.h"
#include "ray.h"
#include "ambient.h"
#include <sys/types.h>
#include <sys/wait.h>
#include "selcall.h"

Go to the source code of this file.

Classes

struct  child_proc

Defines

#define RAYQLEN   12 /* # rays to send at once */
#define MAX_NPROCS   (FD_SETSIZE/2-4)
#define sendq_full()   (r_send_next >= RAYQLEN)

Functions

static int ray_pflush (void)
static void ray_pchild (int fd_in, int fd_out)
void ray_pinit (char *otnm, int nproc)
int ray_psend (RAY *r)
int ray_pqueue (RAY *r)
int ray_presult (RAY *r, int poll)
void ray_pdone (int freall)
void ray_popen (int nadd)
void ray_pclose (int nsub)

Variables

static const char RCSid [] = "$Id: raypcalls.c,v 2.26 2009/12/16 01:06:50 greg Exp $"
char * shm_boundary
int ray_pnprocs = 0
int ray_pnidle = 0
static struct child_proc r_proc [MAX_NPROCS]
static RAY r_queue [2 *RAYQLEN]
static int r_send_next = 0
static int r_recv_first = RAYQLEN
static int r_recv_next = RAYQLEN

Class Documentation

struct child_proc

Definition at line 166 of file raypcalls.c.

Class Members
int fd_recv
int fd_send
int npending
int pid
RNUMBER rno

Define Documentation

#define MAX_NPROCS   (FD_SETSIZE/2-4)

Definition at line 155 of file raypcalls.c.

#define RAYQLEN   12 /* # rays to send at once */

Definition at line 150 of file raypcalls.c.

#define sendq_full ( )    (r_send_next >= RAYQLEN)

Definition at line 179 of file raypcalls.c.


Function Documentation

static void ray_pchild ( int  fd_in,
int  fd_out 
) [static]

Definition at line 399 of file raypcalls.c.

{
       int    n;
       register int  i;
                                   /* flag child process for quit() */
       ray_pnprocs = -1;
                                   /* read each ray request set */
       while ((n = read(fd_in, (char *)r_queue, sizeof(r_queue))) > 0) {
              int    n2;
              if (n < sizeof(RAY))
                     break;
                                   /* get smuggled set length */
              n2 = sizeof(RAY)*r_queue[0].crtype - n;
              if (n2 < 0)
                     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)
                            break;
                     n += n2;
              }
              n /= sizeof(RAY);
                                   /* evaluate rays */
              for (i = 0; i < n; i++) {
                     r_queue[i].crtype = r_queue[i].rtype;
                     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]);
              }
                                   /* 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()");
       }
       if (n)
              error(SYSTEM, "read error in ray_pchild()");
       ambsync();
       quit(0);                    /* normal exit */
}

Here is the call graph for this function:

Here is the caller graph for this function:

void ray_pclose ( int  nsub)

Definition at line 499 of file raypcalls.c.

{
       static int    inclose = 0;
       RAY    res;
                                   /* 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;
                                   /* 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_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",
                                   r_proc[ray_pnprocs].pid, status>>8);
                     error(WARNING, errmsg);
              }
              ray_pnidle--;
       }
       inclose--;
}

Here is the call graph for this function:

void ray_pdone ( int  freall)

Definition at line 383 of file raypcalls.c.

{
       ray_pclose(0);                     /* close child processes */

       if (shm_boundary != NULL) { /* clear shared memory boundary */
              free((void *)shm_boundary);
              shm_boundary = NULL;
       }

       ray_done(freall);           /* free rendering data */
}

Here is the call graph for this function:

static int ray_pflush ( void  ) [static]

Definition at line 201 of file raypcalls.c.

{
       int    nc, n, nw, i, sfirst;

       if ((ray_pnidle <= 0) | (r_send_next <= 0))
              return(0);           /* nothing we can send */
       
       sfirst = 0;                 /* divvy up labor */
       nc = ray_pnidle;
       for (i = ray_pnprocs; nc && i--; ) {
              if (r_proc[i].npending > 0)
                     continue;     /* child looks busy */
              n = (r_send_next - sfirst)/nc--;
              if (!n)
                     continue;
                                   /* smuggle set size in crtype */
              r_queue[sfirst].crtype = n;
              nw = writebuf(r_proc[i].fd_send, (char *)&r_queue[sfirst],
                            sizeof(RAY)*n);
              if (nw != sizeof(RAY)*n)
                     return(-1);   /* write error */
              r_proc[i].npending = n;
              while (n--)          /* record ray IDs */
                     r_proc[i].rno[n] = r_queue[sfirst+n].rno;
              sfirst += r_proc[i].npending;
              ray_pnidle--;        /* now she's busy */
       }
       if (sfirst != r_send_next)
              error(CONSISTENCY, "code screwup in ray_pflush()");
       r_send_next = 0;
       return(sfirst);                    /* return total # sent */
}

Here is the call graph for this function:

Here is the caller graph for this function:

void ray_pinit ( char *  otnm,
int  nproc 
)

Definition at line 186 of file raypcalls.c.

{
       if (nobjects > 0)           /* close old calculation */
              ray_pdone(0);

       ray_init(otnm);                    /* load the shared scene */

       ray_popen(nproc);           /* fork children */
}

Here is the call graph for this function:

void ray_popen ( int  nadd)

Definition at line 448 of file raypcalls.c.

{
                                   /* check if our table has room */
       if (ray_pnprocs + nadd > MAX_NPROCS)
              nadd = MAX_NPROCS - ray_pnprocs;
       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];
              if (pipe(p0) < 0 || pipe(p1) < 0)
                     error(SYSTEM, "cannot create pipe");
              if ((r_proc[ray_pnprocs].pid = fork()) == 0) {
                     int    pn;    /* close others' descriptors */
                     for (pn = ray_pnprocs; pn--; ) {
                            close(r_proc[pn].fd_send);
                            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]);
              /*
               * Close write stream on exec to avoid multiprocessing deadlock.
               * No use in read stream without it, so set flag there as well.
               */
              fcntl(p1[1], F_SETFD, FD_CLOEXEC);
              fcntl(p0[0], F_SETFD, FD_CLOEXEC);
              r_proc[ray_pnprocs].fd_send = p1[1];
              r_proc[ray_pnprocs].fd_recv = p0[0];
              r_proc[ray_pnprocs].npending = 0;
              ray_pnprocs++;
              ray_pnidle++;
       }
}

Here is the call graph for this function:

int ray_pqueue ( RAY r)

Definition at line 254 of file raypcalls.c.

{
       if (r == NULL)
              return(0);
                                   /* check for full send queue */
       if (sendq_full()) {
              RAY    mySend = *r;
                                   /* wait for a result */
              if (ray_presult(r, 0) <= 0)
                     return(-1);
                                   /* put new ray in queue */
              r_queue[r_send_next++] = mySend;

              return(1);
       }
                                   /* else add ray to send queue */
       r_queue[r_send_next++] = *r;
                                   /* check for returned ray... */
       if (r_recv_first >= r_recv_next)
              return(0);
                                   /* ...one is sitting in queue */
       *r = r_queue[r_recv_first++];
       return(1);
}

Here is the call graph for this function:

int ray_presult ( RAY r,
int  poll 
)

Definition at line 283 of file raypcalls.c.

{
       static struct timeval       tpoll; /* zero timeval struct */
       static fd_set readset, errset;
       int    n, ok;
       register int  pn;

       if (r == NULL)
              return(0);
                                   /* check queued results first */
       if (r_recv_first < r_recv_next) {
              *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 */
              return(-1);
                                   /* reset receive queue */
       r_recv_first = r_recv_next = RAYQLEN;

       if (!poll)                  /* count newly sent unless polling */
              n = ray_pnprocs - ray_pnidle;
       if (n <= 0)                 /* return if nothing to await */
              return(0);
       if (!poll && ray_pnprocs == 1)     /* one process -> skip select() */
              FD_SET(r_proc[0].fd_recv, &readset);

getready:                          /* any children waiting for us? */
       for (pn = ray_pnprocs; pn--; )
              if (FD_ISSET(r_proc[pn].fd_recv, &readset) ||
                            FD_ISSET(r_proc[pn].fd_recv, &errset))
                     break;
                                   /* call select() if we must */
       if (pn < 0) {
              FD_ZERO(&readset); FD_ZERO(&errset); n = 0;
              for (pn = ray_pnprocs; pn--; ) {
                     if (r_proc[pn].npending > 0)
                            FD_SET(r_proc[pn].fd_recv, &readset);
                     FD_SET(r_proc[pn].fd_recv, &errset);
                     if (r_proc[pn].fd_recv >= n)
                            n = r_proc[pn].fd_recv + 1;
              }
                                   /* find out who is ready */
              while ((n = select(n, &readset, (fd_set *)NULL, &errset,
                            poll ? &tpoll : (struct timeval *)NULL)) < 0)
                     if (errno != EINTR) {
                            error(WARNING,
                                   "select call failed in ray_presult()");
                            ray_pclose(0);
                            return(-1);
                     }
              if (n > 0)           /* go back and get it */
                     goto getready;
              return(0);           /* else poll came up empty */
       }
       if (r_recv_next + r_proc[pn].npending > sizeof(r_queue)/sizeof(RAY))
              error(CONSISTENCY, "buffer shortage in ray_presult()");

                                   /* read rendered ray data */
       n = readbuf(r_proc[pn].fd_recv, (char *)&r_queue[r_recv_next],
                     sizeof(RAY)*r_proc[pn].npending);
       if (n > 0) {
              r_recv_next += n/sizeof(RAY);
              ok = (n == sizeof(RAY)*r_proc[pn].npending);
       } else
              ok = 0;
                                   /* reset child's status */
       FD_CLR(r_proc[pn].fd_recv, &readset);
       if (n <= 0)
              FD_CLR(r_proc[pn].fd_recv, &errset);
       r_proc[pn].npending = 0;
       ray_pnidle++;
                                   /* check for rendering errors */
       if (!ok) {
              ray_pclose(0);              /* process died -- clean up */
              return(-1);
       }
                                   /* preen returned rays */
       for (n = r_recv_next - r_recv_first; n--; ) {
              register RAY  *rp = &r_queue[r_recv_first + n];
              rp->rno = r_proc[pn].rno[n];
              rp->parent = NULL;
              rp->newcset = rp->clipset = NULL;
              rp->rox = NULL;
              rp->slights = NULL;
       }
                                   /* return first ray received */
       *r = r_queue[r_recv_first++];
       return(1);
}

Here is the call graph for this function:

int ray_psend ( RAY r)

Definition at line 236 of file raypcalls.c.

{
       int    rv;

       if ((r == NULL) | (ray_pnidle <= 0))
              return(0);
                                   /* flush output if necessary */
       if (sendq_full() && (rv = ray_pflush()) <= 0)
              return(rv);

       r_queue[r_send_next++] = *r;
       return(1);
}

Here is the call graph for this function:


Variable Documentation

struct child_proc r_proc[MAX_NPROCS] [static]
RAY r_queue[2 *RAYQLEN] [static]

Definition at line 174 of file raypcalls.c.

int r_recv_first = RAYQLEN [static]

Definition at line 176 of file raypcalls.c.

int r_recv_next = RAYQLEN [static]

Definition at line 177 of file raypcalls.c.

int r_send_next = 0 [static]

Definition at line 175 of file raypcalls.c.

int ray_pnidle = 0

Definition at line 164 of file raypcalls.c.

int ray_pnprocs = 0

Definition at line 163 of file raypcalls.c.

const char RCSid[] = "$Id: raypcalls.c,v 2.26 2009/12/16 01:06:50 greg Exp $" [static]

Definition at line 2 of file raypcalls.c.

char* shm_boundary

Definition at line 107 of file raycalls.c.