summaryrefslogtreecommitdiffstats
path: root/funtools/util/zprocess.c
diff options
context:
space:
mode:
authorWilliam Joye <wjoye@cfa.harvard.edu>2016-10-27 17:38:41 (GMT)
committerWilliam Joye <wjoye@cfa.harvard.edu>2016-10-27 17:38:41 (GMT)
commit5b44fb0d6530c4ff66a446afb69933aa8ffd014f (patch)
treee059f66d1f612e21fe9d83f9620c8715530353ec /funtools/util/zprocess.c
parentda2e3d212171bbe64c1af39114fd067308656990 (diff)
parent23c7930d27fe11c4655e1291a07a821dbbaba78d (diff)
downloadblt-5b44fb0d6530c4ff66a446afb69933aa8ffd014f.zip
blt-5b44fb0d6530c4ff66a446afb69933aa8ffd014f.tar.gz
blt-5b44fb0d6530c4ff66a446afb69933aa8ffd014f.tar.bz2
Merge commit '23c7930d27fe11c4655e1291a07a821dbbaba78d' as 'funtools'
Diffstat (limited to 'funtools/util/zprocess.c')
-rw-r--r--funtools/util/zprocess.c373
1 files changed, 373 insertions, 0 deletions
diff --git a/funtools/util/zprocess.c b/funtools/util/zprocess.c
new file mode 100644
index 0000000..6abf3af
--- /dev/null
+++ b/funtools/util/zprocess.c
@@ -0,0 +1,373 @@
+/*
+ * Copyright (c) 1999-2003 Smithsonian Astrophysical Observatory
+ */
+
+/*
+ *
+ * zprocess.c -- routines to start up and communicate with a slave process
+ *
+ * based on zfiopr.c from NOAO IRAF system (more loosely than previously,
+ * since we replaces the fork/exec with our own Launch()).
+ *
+ */
+
+#include <zprocess.h>
+
+#ifndef min
+#define min(a,b) (((a)<(b))?(a):(b))
+#endif
+
+/*
+ *
+ * Private Routines
+ *
+ *
+ */
+
+static int pr_debug = 0;
+
+/*
+ *
+ * Process table management code
+ *
+ */
+
+#define MAXPROCS 512
+
+static struct proctable {
+ int pr_pid; /* process id */
+ int pr_active; /* if YES, process is still active */
+ int pr_inchan; /* input IPC channel */
+ int pr_outchan; /* output IPC channel */
+ int pr_exit_status; /* process exit_status */
+} prtable[MAXPROCS];
+
+/* PR_FINDPID -- Search the process table for a process. NULL is returned if
+ * the process cannot be found, otherwise a pointer to the table entry is
+ * returned.
+ */
+#ifdef ANSI_FUNC
+static struct proctable *pr_findpid(int pid)
+#else
+static struct proctable *pr_findpid(pid)
+ int pid;
+#endif
+{
+ register int pr;
+
+ for (pr=0; pr<MAXPROCS; pr++){
+ if (prtable[pr].pr_pid == pid)
+ return (&prtable[pr]);
+ }
+ return (NULL);
+}
+
+/* PR_ENTER -- Make a new entry in the process table. Something is very wrong
+ * if the table overflows.
+ */
+#ifdef ANSI_FUNC
+static int pr_enter(int pid, int inchan, int outchan)
+#else
+static int pr_enter(pid, inchan, outchan)
+ int pid;
+ int inchan, outchan;
+#endif
+{
+ int pr;
+
+ for (pr=0; pr<MAXPROCS; pr++){
+ if (prtable[pr].pr_pid == 0){
+ prtable[pr].pr_pid = pid;
+ prtable[pr].pr_active = 1;
+ prtable[pr].pr_inchan = inchan;
+ prtable[pr].pr_outchan = outchan;
+ return(1);
+ }
+ }
+ return(0);
+}
+
+/* PR_GETCHAN -- Get the codes for the IPC channels assigned to a process.
+ */
+#ifdef ANSI_FUNC
+static int pr_getchan (int pid, int *inchan, int *outchan)
+#else
+static int pr_getchan (pid, inchan, outchan)
+ int pid;
+ int *inchan, *outchan;
+#endif
+{
+ register struct proctable *pr;
+
+ /* Lookup process in table. Return an error if there is no entry.
+ */
+ if ((pr = pr_findpid(pid)) == NULL)
+ return(-1);
+ else {
+ *inchan = pr->pr_inchan;
+ *outchan = pr->pr_outchan;
+ return (pid);
+ }
+}
+
+/* PR_RELEASE -- Release the table entry for the process. Used when a process
+ * is killed and we do not wish to wait for process termination.
+ */
+#ifdef ANSI_FUNC
+static void pr_release (int pid)
+#else
+static void pr_release (pid)
+ int pid;
+#endif
+{
+ register struct proctable *pr;
+
+ if ((pr = pr_findpid (pid)) != NULL){
+ pr->pr_pid = 0;
+ pr->pr_active = 0;
+ pr->pr_inchan = 0;
+ pr->pr_outchan = 0;
+ }
+}
+
+/*
+ *----------------------------------------------------------------------------
+ *
+ * Routine: PRSleep
+ *
+ * Purpose: sleep for specified milliseconds
+ *
+ * Returns: none
+ *
+ *----------------------------------------------------------------------------
+ */
+#ifdef ANSI_FUNC
+static void PRSleep (int msec)
+#else
+static void PRSleep(msec)
+ int msec;
+#endif
+{
+ struct timeval tv;
+
+ if( msec > 0 ){
+ tv.tv_sec = msec / 1000;
+ tv.tv_usec = (msec % 1000) * 1000;
+ select(1, NULL, NULL, NULL, &tv);
+ }
+}
+
+/*
+ *
+ * Public Routines
+ *
+ *
+ */
+
+
+#ifdef ANSI_FUNC
+int ProcessOpen(char *cmd, int *inchan, int *outchan, int *pid)
+#else
+int ProcessOpen(cmd, argv, inchan, outchan, pid)
+ char *cmd; /* command line to Launch */
+ int *inchan, *outchan; /* IPC channels (parent reads inchan) */
+ int *pid; /* returned process id */
+#endif
+{
+ int pipes[2];
+ if( Launch(cmd, 0, NULL, pipes) != 0 ){
+ /* failure */
+ *inchan = -1;
+ *outchan = -1;
+ *pid = 0;
+ return 0;
+ }
+ else{
+ /* package up process info for return */
+ *inchan = pipes[0];
+ *outchan = pipes[1];
+ *pid = LaunchPid();
+ /* and also save process info for later */
+ pr_enter (*pid, *inchan, *outchan);
+ /* success */
+ return 1;
+ }
+}
+
+/*
+ *
+ * ProcessClose -- Close a connected subprocess and
+ * wait for subprocess to terminate.
+ *
+ */
+#ifdef ANSI_FUNC
+int ProcessClose(int pid, int *exit_status)
+#else
+int ProcessClose(pid, exit_status)
+ int pid;
+ int *exit_status;
+#endif
+{
+ int inchan, outchan;
+ int tries=0;
+
+ if (pr_getchan (pid, &inchan, &outchan) == -1)
+ *exit_status = 0;
+ else {
+ close (outchan);
+ close (inchan);
+ pr_release(pid);
+#if HAVE_MINGW32==0
+retry:
+ if( (waitpid(pid, exit_status, WNOHANG)==0) && (tries<10) ){
+ PRSleep(10);
+ tries++;
+ goto retry;
+ }
+#endif
+ }
+ if (pr_debug)
+ fprintf (stderr, "[%d] terminated, exit code %d\n",
+ pid, *exit_status);
+ return(*exit_status);
+}
+
+
+/*
+ *
+ * ProcessRead -- Read next record from an IPC channel.
+ *
+ * Since UNIX pipes are byte streams we must take special measures to
+ * transmit data through a pipe in records.
+ * Each block of data is preceded by a header of sizeof(int) consisting
+ * containing the number of bytes in the block.
+ * To read a block we must read the count and then issue successive read
+ * requests until the entire block has been read.
+ *
+*/
+#ifdef ANSI_FUNC
+void *ProcessRead(int fd, void *buf, int maxbytes, int *got)
+#else
+void *ProcessRead(fd, buf, maxbytes, got)
+ int fd;
+ void *buf;
+ int maxbytes;
+ int *got;
+#endif
+{
+ register char *op;
+ register int nbytes;
+ char *obuf;
+ int record_length, status;
+ int temp;
+
+ /* no data read as yet */
+ *got = 0;
+
+ if (pr_debug)
+ fprintf (stderr,
+ "[%d] initiate read for %d bytes from IPC channel %d\n",
+ (int)getpid(), maxbytes, fd);
+
+ /* Get byte count of record.
+ */
+ if (read (fd, &temp, sizeof(int)) != sizeof(int))
+ return NULL;
+
+ record_length = temp;
+ if( maxbytes >= 0 )
+ nbytes = min(record_length, maxbytes);
+ else
+ nbytes = record_length;
+
+ /* allocate output buffer, if necessary */
+ if( buf )
+ obuf = buf;
+ else{
+ obuf = (char *)malloc(nbytes);
+ if( !obuf )
+ return NULL;
+ }
+ op = (char *)obuf;
+
+ /* Now read exactly nbytes of data from channel into user buffer.
+ * Return actual byte count if EOF is seen. If an error is seen, return.
+ * If necessary multiple read requests are issued to read the
+ * entire record.
+ */
+ while (nbytes > 0)
+ switch (status = read (fd, op, nbytes)) {
+ case -1:
+ if( !buf ) free(obuf);
+ *got = 0;
+ return NULL;
+ case 0:
+ return(obuf);
+ default:
+ nbytes -= status;
+ *got += status;
+ op += status;
+ }
+
+ if (pr_debug) {
+ fprintf (stderr, "[%d] read %d bytes from IPC channel %d:\n",
+ (int)getpid(), (int)(op - (char *)buf), fd);
+ }
+
+ /* If the record is larger than maxbytes, we must read and discard
+ * the additional bytes. The method used is inefficient but it is
+ * unlikely that we will be called to read less than a full record.
+ */
+ if( maxbytes >= 0 ){
+ for (nbytes = maxbytes; nbytes < record_length; nbytes++)
+ if (read (fd, &temp, 1) <= 0)
+ break;
+ }
+
+ return(obuf);
+}
+
+/*
+ *
+ * ProcessWrite -- Write to an IPC channel.
+ * Write the IPC block header followed by the data block.
+ *
+*/
+#ifdef ANSI_FUNC
+int ProcessWrite(int fd, void *buf, int nbytes)
+#else
+int ProcessWrite(fd, buf, nbytes)
+ int fd;
+ void *buf;
+ int nbytes;
+#endif
+{
+ int got;
+
+ /* write byte count */
+ write(fd, &nbytes, sizeof(int));
+
+ /* write data block */
+ got = write(fd, buf, nbytes);
+
+ if (pr_debug) {
+ fprintf (stderr, "[%d] wrote %d bytes to IPC channel %d:\n",
+ (int)getpid(), (int)nbytes, fd);
+ }
+
+ return(got);
+}
+
+/*
+ * ProcessGetChan -- Get the codes for the IPC channels assigned to a process.
+ */
+#ifdef ANSI_FUNC
+int ProcessGetChan (int pid, int *inchan, int *outchan)
+#else
+int ProcessGetChan (pid, inchan, outchan)
+ int pid;
+ int *inchan, *outchan;
+#endif
+{
+ return pr_getchan(pid, inchan, outchan);
+}