diff options
author | William Joye <wjoye@cfa.harvard.edu> | 2016-10-27 17:38:41 (GMT) |
---|---|---|
committer | William Joye <wjoye@cfa.harvard.edu> | 2016-10-27 17:38:41 (GMT) |
commit | 5b44fb0d6530c4ff66a446afb69933aa8ffd014f (patch) | |
tree | e059f66d1f612e21fe9d83f9620c8715530353ec /funtools/util/zprocess.c | |
parent | da2e3d212171bbe64c1af39114fd067308656990 (diff) | |
parent | 23c7930d27fe11c4655e1291a07a821dbbaba78d (diff) | |
download | blt-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.c | 373 |
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); +} |