--- ray/src/rt/persist.c 1996/07/04 09:54:59 2.13
+++ ray/src/rt/persist.c 2003/02/22 02:07:29 2.26
@@ -1,38 +1,101 @@
-/* Copyright (c) 1996 Regents of the University of California */
-
#ifndef lint
-static char SCCSid[] = "$SunId$ LBL";
+static const char RCSid[] = "$Id: persist.c,v 2.26 2003/02/22 02:07:29 greg Exp $";
#endif
-
/*
* Routines for persistent rtrace and rpict processes.
+ *
+ * External symbols declared in ray.h
*/
+/* ====================================================================
+ * The Radiance Software License, Version 1.0
+ *
+ * Copyright (c) 1990 - 2002 The Regents of the University of California,
+ * through Lawrence Berkeley National Laboratory. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * 3. The end-user documentation included with the redistribution,
+ * if any, must include the following acknowledgment:
+ * "This product includes Radiance software
+ * (http://radsite.lbl.gov/)
+ * developed by the Lawrence Berkeley National Laboratory
+ * (http://www.lbl.gov/)."
+ * Alternately, this acknowledgment may appear in the software itself,
+ * if and wherever such third-party acknowledgments normally appear.
+ *
+ * 4. The names "Radiance," "Lawrence Berkeley National Laboratory"
+ * and "The Regents of the University of California" must
+ * not be used to endorse or promote products derived from this
+ * software without prior written permission. For written
+ * permission, please contact radiance@radsite.lbl.gov.
+ *
+ * 5. Products derived from this software may not be called "Radiance",
+ * nor may "Radiance" appear in their name, without prior written
+ * permission of Lawrence Berkeley National Laboratory.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL Lawrence Berkeley National Laboratory OR
+ * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
+ * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+ * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
+ * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ * ====================================================================
+ *
+ * This software consists of voluntary contributions made by many
+ * individuals on behalf of Lawrence Berkeley National Laboratory. For more
+ * information on Lawrence Berkeley National Laboratory, please see
+ * .
+ */
+
#include "standard.h"
+#include "random.h"
#ifdef F_SETLKW
-
#include "paths.h"
+#include "selcall.h"
#include
-#include
#include
#ifndef TIMELIM
#define TIMELIM (8*3600) /* time limit for holding pattern */
#endif
-extern char *strcpy(), *index();
+#ifndef freebsd
+#define mkfifo(fn,md) mknod(fn, S_IFIFO|(md), 0)
+#endif
+extern void io_process();
+
extern int headismine; /* boolean true if header belongs to me */
extern char *progname; /* global program name */
+extern char *errfile; /* global error file name */
+
static char *persistfname = NULL; /* persist file name */
static int persistfd = -1; /* persist file descriptor */
-static char inpname[TEMPLEN+1], outpname[TEMPLEN+1];
+static char inpname[TEMPLEN+1], outpname[TEMPLEN+1], errname[TEMPLEN+1];
+void
pfdetach() /* release persist (and header) resources */
{
if (persistfd >= 0)
@@ -41,10 +104,12 @@ pfdetach() /* release persist (and header) resources
persistfname = NULL;
inpname[0] = '\0';
outpname[0] = '\0';
+ errname[0] = '\0';
headismine = 0;
}
+void
pfclean() /* clean up persist files */
{
if (persistfd >= 0)
@@ -55,9 +120,12 @@ pfclean() /* clean up persist files */
unlink(inpname);
if (outpname[0])
unlink(outpname);
+ if (errname[0])
+ unlink(errname);
}
+void
pflock(lf) /* place or release exclusive lock on file */
int lf;
{
@@ -94,47 +162,70 @@ char *pfn;
static int got_io;
-static int sig_io() { got_io++; }
+static void sig_io() { got_io++; }
-static int sig_alrm() { quit(0); }
+static void sig_alrm() { quit(0); }
+void
pfhold() /* holding pattern for idle rendering process */
{
- int (*oldalrm)();
+ void (*oldalrm)();
char buf[512];
register int n;
/* close input and output descriptors */
close(fileno(stdin));
close(fileno(stdout));
+ if (errfile == NULL)
+ close(fileno(stderr));
/* create named pipes for input and output */
- if (mknod(mktemp(strcpy(inpname,TEMPLATE)), S_IFIFO|0600, 0) < 0)
+ if (mkfifo(mktemp(strcpy(inpname,TEMPLATE)), 0600) < 0)
goto createrr;
- if (mknod(mktemp(strcpy(outpname,TEMPLATE)), S_IFIFO|0600, 0) < 0)
+ if (mkfifo(mktemp(strcpy(outpname,TEMPLATE)), 0600) < 0)
goto createrr;
- sprintf(buf, "%s %d\n%s\n%s\n", progname, getpid(), inpname, outpname);
- if (lseek(persistfd, 0L, 0) < 0 || ftruncate(persistfd, 0L) < 0)
- error(SYSTEM, "seek/truncate error on persist file");
+ if (errfile == NULL &&
+ mkfifo(mktemp(strcpy(errname,TEMPLATE)), 0600) < 0)
+ goto createrr;
+ sprintf(buf, "%s %d\n%s\n%s\n%s\n", progname, getpid(),
+ inpname, outpname, errname);
n = strlen(buf);
if (write(persistfd, buf, n) < n)
error(SYSTEM, "error writing persist file");
+ lseek(persistfd, (off_t)0L, 0);
/* wait TIMELIM for someone to signal us */
got_io = 0;
signal(SIGIO, sig_io);
- oldalrm = (int (*)())signal(SIGALRM, sig_alrm);
+ oldalrm = (void (*)())signal(SIGALRM, sig_alrm);
alarm(TIMELIM);
- pflock(0);
+ pflock(0); /* unlock persist file for attach */
while (!got_io)
- pause();
- alarm(0);
+ pause(); /* wait for attach */
+ alarm(0); /* turn off alarm */
signal(SIGALRM, oldalrm);
signal(SIGIO, SIG_DFL);
- pflock(1);
+ pflock(1); /* grab persist file back */
/* someone wants us; reopen stdin and stdout */
+ /*
if (freopen(inpname, "r", stdin) == NULL)
goto openerr;
if (freopen(outpname, "w", stdout) == NULL)
goto openerr;
+ */
+ close(0);
+ if (open(inpname, O_RDONLY) != 0)
+ error(INTERNAL, "unexpected stdin file number");
+ clearerr(stdin);
+ close(1);
+ if (open(outpname, O_WRONLY) != 1)
+ error(INTERNAL, "unexpected stdout file number");
+ sleep(3); /* give them a chance to open their pipes */
+ if (errname[0]) {
+ close(2);
+ if (open(errname, O_WRONLY) != 2)
+ error(INTERNAL, "unexpected stderr file number");
+ unlink(errname);
+ errname[0] = '\0';
+ }
unlink(inpname);
inpname[0] = '\0';
unlink(outpname);
@@ -147,19 +238,30 @@ openerr:
}
-io_process() /* just act as conduits to and from actual process */
+void
+io_process() /* just act as go-between for actual process */
{
register char *cp;
register int nr, n;
- char buf[512], *pfin, *pfout;
- int pid;
- /* load and close persist file */
- sleep(5); /* helps synchronization */
- nr = read(persistfd, buf, sizeof(buf)-1);
- pfdetach();
- if (nr <= 0)
- error(SYSTEM, "cannot read persist file");
- buf[nr] = '\0';
+ char buf[BUFSIZ], *pfin, *pfout, *pferr;
+ int pid, nfds;
+ int fdout, fderr = -1;
+ int status = 0;
+ fd_set readfds, excepfds;
+ /* load persist file */
+ n = 40;
+ while ((nr = read(persistfd, buf, sizeof(buf)-1)) == 0) {
+ if (!n--)
+ error(USER, "unattended persist file?");
+ pflock(0);
+ sleep(3+(3*getpid()+random())%13); /* wait until ready */
+ pflock(1);
+ }
+ if (nr < 0)
+ error(SYSTEM, "error reading persist file");
+ ftruncate(persistfd, (off_t)0L); /* truncate persist file */
+ pfdetach(); /* close & release persist file */
+ buf[nr] = '\0'; /* parse what we got */
if ((cp = index(buf, ' ')) == NULL)
goto formerr;
*cp++ = '\0';
@@ -175,51 +277,127 @@ io_process() /* just act as conduits to and from actu
if ((cp = index(cp, '\n')) == NULL)
goto formerr;
*cp++ = '\0';
+ pferr = cp;
+ if ((cp = index(cp, '\n')) == NULL)
+ goto formerr;
+ *cp++ = '\0';
if (cp-buf != nr)
goto formerr;
if (strcmp(buf, progname)) {
sprintf(errmsg, "persist file for %s, not %s", buf, progname);
error(USER, errmsg);
}
- /* wake up rendering process */
+ /* wake up rendering process */
if (kill(pid, SIGIO) < 0)
error(SYSTEM, "cannot signal rendering process in io_process");
- pid = fork(); /* fork i/o process */
+ /* fork child feeder process */
+ pid = fork();
if (pid < 0)
error(SYSTEM, "fork failed in io_process");
- /* connect to appropriate pipe */
- if (pid) { /* parent passes renderer output */
- close(0);
- if (open(pfout, O_RDONLY) != 0)
- error(SYSTEM, "cannot open input pipe in io_process");
- } else { /* child passes renderer input */
- close(1);
- if (open(pfin, O_WRONLY) != 1)
- error(SYSTEM, "cannot open output pipe in io_process");
+ if (pid == 0) { /* feeder loop */
+ int fdin;
+ close(1); /* open input pipe */
+ if ((fdin = open(pfin, O_WRONLY)) < 0)
+ error(SYSTEM, "cannot open feed pipe in io_process");
+ /* renderer stdin */
+ while ((nr = read(0, cp=buf, sizeof(buf))) > 0) {
+ do {
+ if ((n = write(fdin, cp, nr)) <= 0)
+ goto writerr;
+ cp += n;
+ } while ((nr -= n) > 0);
+ }
+ if (nr < 0)
+ goto readerr;
+ _exit(0);
}
- /* pass input to output */
- /* read as much as we can, write all of it */
- while ((nr = read(0, cp=buf, sizeof(buf))) > 0)
- do {
- if ((n = write(1, cp, nr)) <= 0)
- goto writerr;
- cp += n;
- } while ((nr -= n) > 0);
- if (nr < 0)
- error(SYSTEM, "read error in io_process");
- close(0); /* close input */
- close(1); /* close output */
- if (pid) /* parent waits for child */
- wait(0);
- exit(0); /* all done, exit (not quit!) */
+ close(0);
+ /* open output pipes, in order */
+ if ((fdout = open(pfout, O_RDONLY)) < 0)
+ error(SYSTEM, "cannot open output pipe in io_process");
+ if (pferr[0] && (fderr = open(pferr, O_RDONLY)) < 0)
+ error(SYSTEM, "cannot open error pipe in io_process");
+ for ( ; ; ) { /* eater loop */
+ FD_ZERO(&readfds);
+ FD_ZERO(&excepfds);
+ nfds = 0;
+ if (fdout >= 0) {
+ FD_SET(fdout, &readfds);
+ FD_SET(fdout, &excepfds);
+ nfds = fdout+1;
+ }
+ if (fderr >= 0) {
+ FD_SET(fderr, &readfds);
+ FD_SET(fderr, &excepfds);
+ nfds = fderr+1;
+ }
+ if (nfds == 0)
+ break; /* all done, exit */
+ if (select(nfds, &readfds, NULL, &excepfds, NULL) < 0)
+ error(SYSTEM, "error in select call in io_process");
+ /* renderer stderr */
+ if (fderr >= 0 && (FD_ISSET(fderr, &readfds) ||
+ FD_ISSET(fderr, &excepfds))) {
+ nr = read(fderr, cp=buf, sizeof(buf));
+ if (nr < 0)
+ goto readerr;
+ if (nr == 0) {
+ close(fderr);
+ /* close(2); don't close stderr! */
+ fderr = -1;
+ } else {
+ cp[nr] = '\0'; /* deduce status if we can */
+ n = strlen(progname);
+ if (!strncmp(cp, progname, n) &&
+ cp[n++] == ':' &&
+ cp[n++] == ' ') {
+ register struct erract *ep;
+ for (ep = erract; ep < erract+NERRS;
+ ep++)
+ if (ep->pre[0] &&
+ !strncmp(cp+n, ep->pre,
+ strlen(ep->pre))) {
+ status = ep->ec;
+ break;
+ }
+ }
+ do { /* write message */
+ if ((n = write(2, cp, nr)) <= 0)
+ goto writerr;
+ cp += n;
+ } while ((nr -= n) > 0);
+ }
+ }
+ /* renderer stdout */
+ if (fdout >= 0 && (FD_ISSET(fdout, &readfds) ||
+ FD_ISSET(fdout, &excepfds))) {
+ nr = read(fdout, cp=buf, sizeof(buf));
+ if (nr < 0)
+ goto readerr;
+ if (nr == 0) { /* EOF */
+ close(fdout);
+ close(1);
+ fdout = -1;
+ } else
+ do { /* write it all */
+ if ((n = write(1, cp, nr)) <= 0)
+ goto writerr;
+ cp += n;
+ } while ((nr -= n) > 0);
+ }
+ }
+ wait(0); /* wait for feeder process */
+ _exit(status);
formerr:
error(USER, "format error in persist file");
+readerr:
+ error(SYSTEM, "read error in io_process");
writerr:
error(SYSTEM, "write error in io_process");
}
#else
-pfclean() {}
+void pfclean() {}
#endif