mirror of
https://github.com/PDP-10/klh10.git
synced 2026-02-26 16:54:11 +00:00
I only compile-tested it, I didn't run it. The main effect is to make hardware tape support ~optional, since OSX has no <sys/mtio.h>.
755 lines
19 KiB
C
755 lines
19 KiB
C
/* DPSUP.C - Device sub-Process Support facilities (OSD) for KLH10
|
||
*/
|
||
/* $Id: dpsup.c,v 2.5 2003/02/23 18:16:05 klh Exp $
|
||
*/
|
||
/* Copyright © 1994, 2001 Kenneth L. Harrenstien
|
||
** All Rights Reserved
|
||
**
|
||
** This file is part of the KLH10 Distribution. Use, modification, and
|
||
** re-distribution is permitted subject to the terms in the file
|
||
** named "LICENSE", which contains the full text of the legal notices
|
||
** and should always accompany this Distribution.
|
||
**
|
||
** This software is provided "AS IS" with NO WARRANTY OF ANY KIND.
|
||
**
|
||
** This notice (including the copyright and warranty disclaimer)
|
||
** must be included in all copies or derivations of this software.
|
||
*/
|
||
/*
|
||
* $Log: dpsup.c,v $
|
||
* Revision 2.5 2003/02/23 18:16:05 klh
|
||
* Tweak casts to avoid warnings on NetBSD/Alpha.
|
||
*
|
||
* Revision 2.4 2002/04/24 07:46:15 klh
|
||
* Change dpx_cnt from int to size_t, modify prototypes to match
|
||
*
|
||
* Revision 2.3 2001/11/10 21:28:59 klh
|
||
* Final 2.0 distribution checkin
|
||
*
|
||
*/
|
||
|
||
#include "klh10.h" /* Get config params */
|
||
|
||
#if !KLH10_DEV_DP && CENV_SYS_DECOSF
|
||
/* Stupid gubbish needed to prevent OSF/1 AXP compiler from
|
||
** halting merely because compiled file is empty!
|
||
*/
|
||
static int decosfcclossage;
|
||
#endif
|
||
|
||
#if KLH10_DEV_DP /* Moby conditional for entire file */
|
||
|
||
#include <stdio.h>
|
||
#include <stdlib.h>
|
||
#include <string.h> /* For strerror() if present */
|
||
|
||
#include "dpsup.h"
|
||
|
||
#if CENV_SYS_DECOSF || CENV_SYS_SUN || CENV_SYS_SOLARIS || CENV_SYS_XBSD || CENV_SYS_LINUX
|
||
# include <sys/types.h>
|
||
# include <sys/ipc.h> /* SysV stuff */
|
||
# include <sys/shm.h> /* SysV stuff */
|
||
# include <sys/wait.h>
|
||
# include <sys/mman.h>
|
||
# include <unistd.h>
|
||
# include <signal.h>
|
||
# if defined(MAXSIG)
|
||
# define SIGMAX MAXSIG /* Different wording on Sun */
|
||
# elif defined(NSIG)
|
||
# define SIGMAX NSIG
|
||
# elif defined(_NSIG)
|
||
# define SIGMAX _NSIG
|
||
# endif
|
||
#endif /* CENV_SYS_DECOSF || CENV_SYS_SUN || CENV_SYS_SOLARIS || CENV_SYS_XBSD || CENV_SYS_LINUX */
|
||
|
||
#ifdef RCSID
|
||
RCSID(dpsup_c,"$Id: dpsup.c,v 2.5 2003/02/23 18:16:05 klh Exp $")
|
||
#endif
|
||
|
||
static int dp_cxinit(struct dpc_s *, int, int, int, size_t, size_t);
|
||
|
||
/* DP_INIT - Called from superior (KLH10) to initialize device subprocess
|
||
** context and shared memory area.
|
||
**
|
||
** Note that the shared area is divided into three parts in this
|
||
** order:
|
||
** (1) DPC structure (of size dpcsiz)
|
||
** (2) Output buffer 10->DP (of size outsiz)
|
||
** (3) Input buffer 10<-DP (of size insiz)
|
||
**
|
||
** *** THE READ-REVERSE CODE FOR TM02/TM03 DEPENDS ON THIS ORDERING! ***
|
||
** (Check references to dptm_revpad)
|
||
*/
|
||
int dp_init(register struct dp_s *dp, size_t dpcsiz,
|
||
int intyp, int inarg, size_t insiz,
|
||
int outtyp, int outarg, size_t outsiz)
|
||
{
|
||
register size_t totsiz;
|
||
register int adj;
|
||
register key_t shmid;
|
||
register struct dpc_s *dpc;
|
||
|
||
dp->dp_type = 0; /* Ensure cleared in case bomb out */
|
||
dp->dp_shmid = -1;
|
||
dp->dp_adr = NULL;
|
||
dp->dp_chpid = 0;
|
||
|
||
/* Ensure all sizes are aligned to satisfy maximum restrictions */
|
||
if ((adj = (dpcsiz % sizeof(double))))
|
||
dpcsiz += sizeof(double) - adj;
|
||
if ((adj = (insiz % sizeof(double))))
|
||
insiz += sizeof(double) - adj;
|
||
if ((adj = (outsiz % sizeof(double))))
|
||
outsiz += sizeof(double) - adj;
|
||
|
||
totsiz = dpcsiz + insiz + outsiz;
|
||
|
||
/* Create shared mem segment of given size */
|
||
if (dpcsiz < sizeof(struct dpc_s)) { /* Ensure big enough for std stuff */
|
||
fprintf(stderr, "[dp_init: dpcsiz %ld]\r\n", (long)dpcsiz);
|
||
return FALSE;
|
||
}
|
||
|
||
/* Create a shared mem seg. Set perms to owner-only RW. */
|
||
if ((shmid = shmget(IPC_PRIVATE, (u_int)totsiz, 0600)) == -1) {
|
||
fprintf(stderr, "[dp_init: shmget failed - %d]\r\n", errno);
|
||
return FALSE;
|
||
}
|
||
|
||
/* Attempt to attach segment into our address space */
|
||
dpc = (struct dpc_s *)shmat(shmid, (void *)0, SHM_RND);
|
||
if (dpc == (struct dpc_s *)-1) {
|
||
shmctl(shmid, IPC_RMID, (struct shmid_ds *)NULL);
|
||
fprintf(stderr, "[dp_init: shmat failed - %d]\r\n", errno);
|
||
return FALSE;
|
||
}
|
||
|
||
/* Won, init the shared DPC struct */
|
||
memset((char *)dpc, 0, totsiz);
|
||
strncpy(dpc->dpc_magic, DPC_MAGIC, sizeof(dpc->dpc_magic));
|
||
dpc->dpc_fmtver = DPSUP_VERSION; /* Set to current version */
|
||
|
||
/* Set up output then input xfer stuff */
|
||
if (!dp_cxinit(dpc, 1, outtyp, outarg, dpcsiz, outsiz)
|
||
|| !dp_cxinit(dpc, 0, intyp, inarg, dpcsiz+outsiz, insiz)) {
|
||
|
||
shmdt((caddr_t)dpc); /* Detach attached segment */
|
||
shmctl(shmid, IPC_RMID, (struct shmid_ds *)NULL);
|
||
fprintf(stderr, "[dp_init: xinit failed]\r\n");
|
||
return FALSE;
|
||
}
|
||
|
||
/* Finally init the DP struct itself */
|
||
dp->dp_type = DP_XT_MSIG;
|
||
dp->dp_adr = dpc;
|
||
dp->dp_shmid = shmid;
|
||
|
||
return TRUE;
|
||
}
|
||
|
||
static int dp_cxinit(register struct dpc_s *dpc,
|
||
int dir, int type, int arg, size_t off, size_t siz)
|
||
{
|
||
register struct dpx_s *dx;
|
||
|
||
if (type != DP_XT_MSIG)
|
||
return FALSE; /* Unknown xfer type */
|
||
|
||
/* Arg is signal # to use for this direction */
|
||
if (arg <= 0 || SIGMAX <= arg)
|
||
return FALSE; /* Bad signal # */
|
||
|
||
if (dir) {
|
||
dx = &dpc->dpc_todp; /* Output to DP */
|
||
dx->dpx_dontyp = type;
|
||
dx->dpx_donflg = 0;
|
||
dx->dpx_donsig = arg; /* Say how to ack sender (10) */
|
||
dx->dpx_donpid = getpid();
|
||
dx->dpx_sbuf = (unsigned char *)dpc + off;
|
||
|
||
} else {
|
||
dx = &dpc->dpc_frdp; /* Input from DP */
|
||
dx->dpx_waktyp = type;
|
||
dx->dpx_wakflg = 0;
|
||
dx->dpx_waksig = arg; /* Say how to wakeup rcpt (10) */
|
||
dx->dpx_wakpid = getpid();
|
||
dx->dpx_rbuf = (unsigned char *)dpc + off;
|
||
}
|
||
|
||
dx->dpx_type = type; /* Is this necessary? */
|
||
|
||
dx->dpx_len = siz; /* Size of buffer */
|
||
dx->dpx_off = off; /* Offset of buffer from start of seg */
|
||
|
||
dx->dpx_rdyf = 0; /* No data */
|
||
dx->dpx_cmd = 0; /* No command */
|
||
|
||
return TRUE;
|
||
}
|
||
|
||
|
||
int dp_start(register struct dp_s *dp, char *prog)
|
||
{
|
||
int err;
|
||
int pid;
|
||
char idbuf[20];
|
||
sigset_t allmask, oldmask;
|
||
int debug = (dp->dp_adr ? dp->dp_adr->dpc_debug : 0);
|
||
|
||
/* Set up args for DP proc */
|
||
sprintf(idbuf, "-DPM:%ld", (long)dp->dp_shmid);
|
||
|
||
/* Check xct access for program */
|
||
if ((err = access(prog, X_OK)) < 0) {
|
||
fprintf(stderr, "[dp_exec: Cannot access \"%s\" - %s]\r\n",
|
||
prog ? prog : "(nullptr)", dp_strerror(err));
|
||
return FALSE;
|
||
}
|
||
|
||
/* Block all signals momentarily so new process isn't killed
|
||
** by asynch signals.
|
||
*/
|
||
sigfillset(&allmask);
|
||
(void) sigprocmask(SIG_SETMASK, &allmask, &oldmask);
|
||
|
||
if (debug)
|
||
fprintf(stderr, "[dp_start: Forking...]");
|
||
if ((pid = fork()) < 0) {
|
||
/* Cannot fork */
|
||
fprintf(stderr, "[dp_exec: Cannot fork for \"%s\" - %s]\r\n",
|
||
prog ? prog : "(nullptr)", dp_strerror(-1));
|
||
(void) sigprocmask(SIG_SETMASK, &oldmask, (sigset_t *)NULL);
|
||
return FALSE;
|
||
}
|
||
if (debug)
|
||
fprintf(stderr, "[dp_start: Forked %d]\r\n", pid);
|
||
if (pid == 0) {
|
||
/* We're the child process, start up specified program */
|
||
if (debug) {
|
||
fprintf(stderr,
|
||
"[dp_start: execing \"%s\" \"%s\" \"-debug\"]\r\n",
|
||
prog, idbuf);
|
||
execl(prog, prog, idbuf, "-debug", (char *)NULL);
|
||
} else
|
||
execl(prog, prog, idbuf, (char *)NULL);
|
||
|
||
fprintf(stderr, "[dp_exec: execl failed - %s]\r\n",
|
||
dp_strerror(-1));
|
||
_exit(1); /* Not exit(), to avoid muckage */
|
||
}
|
||
dp->dp_chpid = pid; /* Parent, remember child's PID */
|
||
|
||
#if 0 /* This has been needed sometimes to get child going!!! */
|
||
{
|
||
int i;
|
||
for (i = (1<<28); --i > 0;); /* Should take 8 sec or so */
|
||
}
|
||
#endif
|
||
(void) sigprocmask(SIG_SETMASK, &oldmask, (sigset_t *)NULL);
|
||
|
||
return TRUE;
|
||
}
|
||
|
||
|
||
int dp_reset(register struct dp_s *dp)
|
||
{
|
||
|
||
#if 0
|
||
if (dp->dp_chpid) {
|
||
kill(dp->dp_chpid, SIGKILL);
|
||
}
|
||
#endif
|
||
return 1;
|
||
}
|
||
|
||
/* DP_TERM - Terminate entire subproc hackery - opposite of dp_init.
|
||
*/
|
||
int dp_term(register struct dp_s *dp, int timeout)
|
||
{
|
||
dp_stop(dp, timeout); /* Stop, kill subproc */
|
||
|
||
/* Try to kill shared mem segment */
|
||
if (dp->dp_type == DP_XT_MSIG) {
|
||
shmdt((caddr_t)(dp->dp_adr)); /* Detach attached segment */
|
||
shmctl(dp->dp_shmid, IPC_RMID, /* then try to flush it */
|
||
(struct shmid_ds *)NULL);
|
||
dp->dp_adr = NULL;
|
||
dp->dp_shmid = 0;
|
||
dp->dp_type = 0;
|
||
}
|
||
return 1;
|
||
}
|
||
|
||
static int dp_killchild(pid_t pid, int timeout)
|
||
{
|
||
int status, res, cnt;
|
||
|
||
kill(pid, SIGKILL);
|
||
cnt = timeout ? timeout : 1;
|
||
for (; --cnt >= 0;) {
|
||
res = waitpid(pid, &status, WNOHANG);
|
||
if (res == -1) {
|
||
if (errno == EINTR) continue;
|
||
return (errno == ECHILD); /* TRUE if won */
|
||
}
|
||
if (res != 0) /* Nonzero result means got stopped proc */
|
||
return 1; /* Won! */
|
||
if (cnt > 0)
|
||
dp_sleep(1); /* Urgh, wait a bit, big crock */
|
||
}
|
||
return 0; /* Timed out, failed */
|
||
}
|
||
|
||
int dp_stop(register struct dp_s *dp, int timeout)
|
||
{
|
||
pid_t pid, pid2;
|
||
|
||
switch (dp->dp_type) {
|
||
case DP_XT_MSIG:
|
||
if ((pid = dp->dp_chpid)) {
|
||
(void) dp_killchild(pid, timeout);
|
||
|
||
/* For now, flush pid even if didn't find it when waited. */
|
||
dp->dp_chpid = 0;
|
||
}
|
||
|
||
/* Check for presence of 2nd child */
|
||
if ((pid2 = dp->dp_adr->dpc_frdp.dpx_donpid)
|
||
&& (pid != pid2)) {
|
||
(void) dp_killchild(pid2, timeout);
|
||
|
||
/* For now, flush pid even if didn't find it when waited. */
|
||
dp->dp_adr->dpc_frdp.dpx_donpid = 0;
|
||
}
|
||
break;
|
||
}
|
||
|
||
/* Clear up all xfer stuff from this side */
|
||
return 1;
|
||
}
|
||
|
||
/* Called from subprocess (dp) */
|
||
|
||
/*
|
||
The current method for signalling the subproc uses signals
|
||
combined with a "ready" flag. The ready flag is the true state indicator;
|
||
the signal merely serves as a method of waking up the subproc in case it
|
||
is run-blocked, either waiting for the flag to change --OR-- for some
|
||
system call to complete.
|
||
|
||
Normally the subproc runs with the wakeup signal masked (blocked),
|
||
and only permits it to interrupt when it makes a sigpause(0) call as part
|
||
of the flag check-and-wait procedure. In this respect the signal amounts
|
||
to little more than a semaphore.
|
||
However, the subproc also has the option of unmasking the signal
|
||
so that it can permit selected system calls to be interrupted. For this
|
||
reason, the sigaction which sets up the signal configures it to NOT
|
||
restart system calls.
|
||
The latter feature (along with avoiding the cleanup problems for
|
||
SYSV semaphores) is why signals are used instead of OS semaphores.
|
||
|
||
*/
|
||
|
||
static void dp_subsighan(int);
|
||
static int dp_signal(int sig, void (*func)(int));
|
||
|
||
int dp_main(register struct dp_s *dp, int argc, char **argv)
|
||
{
|
||
long shmarg;
|
||
register struct dpc_s *dpc;
|
||
register struct dpx_s *dpx;
|
||
int tosig, frsig;
|
||
sigset_t mask;
|
||
|
||
if ((argc < 2) || (strncmp(argv[1], "-DPM:", 5) != 0)) {
|
||
fprintf(stderr, "[%s: need -DPM: arg]\r\n",
|
||
(argc > 0 ? argv[0] : "(?) dp_main"));
|
||
return 0;
|
||
}
|
||
|
||
if (1 != sscanf(&argv[1][5], "%ld", &shmarg)) {
|
||
fprintf(stderr, "[%s: Couldn't parse \"%s\"]\r\n",
|
||
argv[0], argv[1]);
|
||
return 0;
|
||
}
|
||
|
||
/* Got shmid for segment from our parent, try attaching it! */
|
||
dpc = (struct dpc_s *)shmat((int)shmarg, (void *)NULL, SHM_RND);
|
||
if (dpc == (struct dpc_s *)-1) {
|
||
fprintf(stderr, "[%s: Couldn't attach shmid 0x%lx]\r\n",
|
||
argv[0], shmarg);
|
||
return 0;
|
||
}
|
||
|
||
/* Verify that we got a DP memory structure */
|
||
if (strncmp(dpc->dpc_magic, DPC_MAGIC, sizeof(dpc->dpc_magic)) != 0) {
|
||
fprintf(stderr, "[%s: Invalid DPM seg %ld - bad magic ID]\r\n",
|
||
argv[0], (long)shmarg);
|
||
return 0;
|
||
}
|
||
|
||
/* Verify what format the superior expects to be using.
|
||
Should this ignore patch revs?
|
||
*/
|
||
switch (dpc->dpc_fmtver) {
|
||
case DPSUP_VERSION:
|
||
break;
|
||
default:
|
||
fprintf(stderr,
|
||
"[%s: Incompatible DP versions - sup %d.%d.%d, sub %d.%d.%d]\r\n",
|
||
argv[0],
|
||
DPC_GV_MAJ(dpc->dpc_fmtver),
|
||
DPC_GV_MIN(dpc->dpc_fmtver),
|
||
DPC_GV_PAT(dpc->dpc_fmtver),
|
||
DPC_GV_MAJ(DPSUP_VERSION),
|
||
DPC_GV_MIN(DPSUP_VERSION),
|
||
DPC_GV_PAT(DPSUP_VERSION));
|
||
|
||
return 0;
|
||
}
|
||
|
||
/* Hurray, we're winning... set up our stuff */
|
||
dp->dp_type = DP_XT_MSIG; /* Should set this differently later */
|
||
dp->dp_adr = dpc;
|
||
dp->dp_shmid = shmarg;
|
||
|
||
/* Set up I/O to 10 - assume DP_XT_MSIG for now */
|
||
tosig = frsig = SIGURG; /* Set up signal(s) to use */
|
||
sigemptyset(&mask);
|
||
sigaddset(&mask, tosig); /* and combined mask */
|
||
sigaddset(&mask, frsig);
|
||
#if 1
|
||
sigprocmask(SIG_BLOCK, &mask, (sigset_t *)NULL); /* Ensure blocked */
|
||
#endif
|
||
/* Safe now if superior jumps gun */
|
||
|
||
dpx = &dp->dp_adr->dpc_frdp; /* Output from DP to 10 */
|
||
dpx->dpx_dontyp = DP_XT_MSIG; /* Say how to ack sender (dp) */
|
||
dpx->dpx_donsig = frsig; /* Use this signal # */
|
||
sigemptyset(&dpx->dpx_donmsk); /* Set corresponding mask bit */
|
||
sigaddset(&dpx->dpx_donmsk, dpx->dpx_donsig);
|
||
dpx->dpx_donpid = getpid();
|
||
dpx->dpx_sbuf = (unsigned char *)dpc + dpx->dpx_off;
|
||
|
||
dpx = &dp->dp_adr->dpc_todp; /* Input to DP from 10 */
|
||
dpx->dpx_waktyp = DP_XT_MSIG;
|
||
dpx->dpx_waksig = tosig; /* Say how to wakeup rcpt (dp) */
|
||
sigemptyset(&dpx->dpx_wakmsk); /* Set corresponding mask bit */
|
||
sigaddset(&dpx->dpx_wakmsk, dpx->dpx_waksig);
|
||
dpx->dpx_wakpid = getpid();
|
||
dpx->dpx_rbuf = (unsigned char *)dpc + dpx->dpx_off;
|
||
|
||
if (dp_signal(frsig, dp_subsighan) == -1) {
|
||
fprintf(stderr, "[%s: Couldn't set signal handler]\r\n", argv[0]);
|
||
return 0;
|
||
}
|
||
if (tosig != frsig /* Do second if necessary */
|
||
&& (dp_signal(tosig, dp_subsighan) == -1)) {
|
||
fprintf(stderr, "[%s: Couldn't set signal handler]\r\n", argv[0]);
|
||
return 0;
|
||
}
|
||
|
||
#if 1
|
||
/* Paranoia: check for pending signals before unblocking */
|
||
{
|
||
int sig;
|
||
int npend = 0;
|
||
sigset_t pendmask;
|
||
sigpending(&pendmask);
|
||
for (sig = 1; sig < SIGMAX; sig++) {
|
||
if (sigismember(&pendmask, sig)) {
|
||
if (npend++ == 0)
|
||
fprintf(stderr, "[%s: WARNING! sigpend %d", argv[0], sig);
|
||
else
|
||
fprintf(stderr, ", %d", sig);
|
||
}
|
||
}
|
||
if (npend)
|
||
fprintf(stderr, "]\r\n");
|
||
}
|
||
#endif
|
||
|
||
/* Unblock all but the DP sigs. Instead of restoring mask as it was
|
||
** at start of call, this actually CLEARS everything (except the DP sigs),
|
||
** in order to balance the suspend-everything action of dp_start for
|
||
** the child fork.
|
||
*/
|
||
sigprocmask(SIG_SETMASK, &mask, (sigset_t *)NULL);
|
||
|
||
/* Finally, check new MEMLOCK flag to see if superior wants
|
||
** us to propagate a memory-locked condition.
|
||
*/
|
||
if (dpc->dpc_flags & DPCF_MEMLOCK) {
|
||
/* Can only lock mem if superuser, but don't bother checking
|
||
** beforehand - only warn if an error isn't EPERM and hence is
|
||
** unusual.
|
||
*/
|
||
#if CENV_SYS_DECOSF || CENV_SYS_SOLARIS || CENV_SYS_LINUX
|
||
if (mlockall(MCL_CURRENT|MCL_FUTURE) != 0) {
|
||
if (errno != EPERM)
|
||
fprintf(stderr, "[%s: mlockall failed - %s]\r\n",
|
||
argv[0], dp_strerror(-1));
|
||
}
|
||
#endif
|
||
}
|
||
|
||
return 1;
|
||
}
|
||
|
||
void dp_exit(register struct dp_s *dp, int res)
|
||
{
|
||
if (dp->dp_chpid) {
|
||
kill(dp->dp_chpid, SIGKILL);
|
||
/* Perhaps later wait for that specific child */
|
||
}
|
||
exit(res);
|
||
}
|
||
|
||
static void dp_subsighan(int junk)
|
||
{
|
||
/* Do nothing -- call merely breaks out of sigpause(0) */
|
||
}
|
||
|
||
/* Called from both KLH10 and device subprocess */
|
||
|
||
int dp_xstest(register struct dpx_s *dx) /* TRUE if can send */
|
||
{
|
||
switch (dx->dpx_type) {
|
||
case DP_XT_MSIG:
|
||
return dp_xtmsig_stest(dx);
|
||
}
|
||
return FALSE;
|
||
}
|
||
|
||
void dp_xsblock(register struct dpx_s *dx) /* Block for a later test */
|
||
{
|
||
switch (dx->dpx_type) {
|
||
case DP_XT_MSIG:
|
||
dp_xtmsig_sblock(dx);
|
||
return;
|
||
}
|
||
return;
|
||
}
|
||
|
||
int dp_xswait(register struct dpx_s *dx) /* Wait until can send */
|
||
{
|
||
switch (dx->dpx_type) {
|
||
case DP_XT_MSIG:
|
||
dp_xtmsig_swait(dx);
|
||
return TRUE;
|
||
}
|
||
return FALSE;
|
||
}
|
||
|
||
|
||
unsigned char *dp_xsbuff(register struct dpx_s *dx,
|
||
register size_t *asiz) /* Get buffer for send data */
|
||
{
|
||
switch (dx->dpx_type) {
|
||
case DP_XT_MSIG:
|
||
return dp_xtmsig_sbuff(dx, asiz);
|
||
}
|
||
if (asiz)
|
||
*asiz = 0;
|
||
return NULL;
|
||
}
|
||
|
||
void dp_xswake(register struct dpx_s *dx) /* Send; say message ready */
|
||
{
|
||
switch (dx->dpx_type) {
|
||
case DP_XT_MSIG:
|
||
dp_xtmsig_swake(dx);
|
||
return;
|
||
}
|
||
}
|
||
|
||
void dp_xsend(register struct dpx_s *dx,
|
||
int cmd, size_t cnt) /* Send cmd and data */
|
||
{
|
||
switch (dx->dpx_type) {
|
||
case DP_XT_MSIG:
|
||
dp_xtmsig_send(dx, cmd, cnt);
|
||
return;
|
||
}
|
||
}
|
||
|
||
|
||
int dp_xrtest(register struct dpx_s *dx) /* TRUE if can receive */
|
||
{
|
||
switch (dx->dpx_type) {
|
||
case DP_XT_MSIG:
|
||
return dp_xtmsig_rtest(dx);
|
||
}
|
||
return FALSE;
|
||
}
|
||
|
||
void dp_xrblock(register struct dpx_s *dx) /* Block for a later test */
|
||
{
|
||
switch (dx->dpx_type) {
|
||
case DP_XT_MSIG:
|
||
dp_xtmsig_rblock(dx);
|
||
return;
|
||
}
|
||
return;
|
||
}
|
||
|
||
|
||
int dp_xrwait(register struct dpx_s *dx) /* Wait until can definitely recv */
|
||
{
|
||
switch (dx->dpx_type) {
|
||
case DP_XT_MSIG:
|
||
dp_xtmsig_rwait(dx);
|
||
return TRUE;
|
||
}
|
||
return FALSE;
|
||
}
|
||
|
||
|
||
unsigned char *dp_xrbuff(register struct dpx_s *dx,
|
||
register size_t *asiz) /* Get buffer for recv data */
|
||
{
|
||
switch (dx->dpx_type) {
|
||
case DP_XT_MSIG:
|
||
return dp_xtmsig_rbuff(dx, asiz);
|
||
}
|
||
if (asiz)
|
||
*asiz = 0;
|
||
return NULL;
|
||
}
|
||
|
||
void dp_xrdone(register struct dpx_s *dx) /* Done, ready for next msg */
|
||
{
|
||
switch (dx->dpx_type) {
|
||
case DP_XT_MSIG:
|
||
dp_xtmsig_rdone(dx);
|
||
return;
|
||
}
|
||
}
|
||
|
||
void dp_xrdoack(register struct dpx_s *dx, /* Done, ready for next msg */
|
||
int res)
|
||
{
|
||
switch (dx->dpx_type) {
|
||
case DP_XT_MSIG:
|
||
dp_xtmsig_rdoack(dx, res);
|
||
return;
|
||
}
|
||
}
|
||
|
||
int dp_xrcmd(register struct dpx_s *dx) /* Get command */
|
||
{
|
||
switch (dx->dpx_type) {
|
||
case DP_XT_MSIG:
|
||
return dp_xtmsig_rcmd(dx);
|
||
}
|
||
return 0;
|
||
}
|
||
|
||
size_t dp_xrcnt(register struct dpx_s *dx) /* Get data count */
|
||
{
|
||
switch (dx->dpx_type) {
|
||
case DP_XT_MSIG:
|
||
return dp_xtmsig_rcnt(dx);
|
||
}
|
||
return 0;
|
||
}
|
||
|
||
/* Same as os_strerror() from osdsup.c, put here to avoid having to
|
||
** grab the entire OSDSUP package when being built for DP procs.
|
||
*/
|
||
|
||
char *
|
||
dp_strerror(int err)
|
||
{
|
||
if (err == -1 && errno != err)
|
||
return dp_strerror(errno);
|
||
#if CENV_SYSF_STRERROR
|
||
return strerror(err);
|
||
#else
|
||
# if CENV_SYS_UNIX
|
||
{
|
||
# if !CENV_SYS_XBSD /* Already in signal.h */
|
||
extern int sys_nerr;
|
||
extern char *sys_errlist[];
|
||
# endif
|
||
if (0 < err && err <= sys_nerr)
|
||
return (char *)sys_errlist[err];
|
||
}
|
||
# endif
|
||
if (err == 0)
|
||
return "No error";
|
||
else {
|
||
static char ebuf[30];
|
||
sprintf(ebuf, "Unknown-error-%d", err);
|
||
return ebuf;
|
||
}
|
||
#endif /* !CENV_SYSF_STRERROR */
|
||
}
|
||
|
||
|
||
/* Likewise copied from OSDSUP.C */
|
||
|
||
static int
|
||
dp_signal(int sig, void (*func)(int))
|
||
{
|
||
#if CENV_SYSF_SIGSET
|
||
struct sigaction act, oact;
|
||
|
||
act.sa_handler = func;
|
||
act.sa_flags = 0 /*SA_RESTART*/; /* Do *NOT* ask for restart! */
|
||
sigemptyset(&act.sa_mask);
|
||
sigaddset(&act.sa_mask, sig); /* Suspend this sig during handler */
|
||
return sigaction(sig, &act, &oact);
|
||
#elif CENV_SYS_BSD
|
||
/* If really BSD, probably should use sigvec instead */
|
||
return (signal(sig, func) == (void (*)())-1) ? -1 : 0;
|
||
#else
|
||
*** ERROR *** need signal support
|
||
#endif
|
||
}
|
||
|
||
void
|
||
dp_sigwait(void)
|
||
{
|
||
sigset_t nomsk;
|
||
|
||
sigemptyset(&nomsk); /* Clear out mask */
|
||
sigsuspend(&nomsk); /* Block until something goes off */
|
||
}
|
||
|
||
/* DP_SLEEP - Sleep for N seconds. Copied from OSDSUP's os_sleep(),
|
||
** see that for more comments.
|
||
*/
|
||
void
|
||
dp_sleep(int secs)
|
||
{
|
||
#if CENV_SYS_DECOSF
|
||
sleep(secs); /* Independent of interval timers! */
|
||
|
||
#elif CENV_SYSF_BSDTIMEVAL && CENV_SYSF_SIGSET
|
||
/* Must save & restore ITIMER_REAL & SIGALRM, which conflict w/sleep() */
|
||
struct itimerval ztm, otm;
|
||
struct sigaction act, oact;
|
||
|
||
timerclear(&ztm.it_interval);
|
||
timerclear(&ztm.it_value);
|
||
setitimer(ITIMER_REAL, &ztm, &otm);
|
||
|
||
act.sa_handler = SIG_IGN;
|
||
act.sa_flags = 0;
|
||
sigemptyset(&act.sa_mask);
|
||
sigaction(SIGALRM, &act, &oact);
|
||
|
||
sleep(secs); /* Do the gubbish */
|
||
|
||
/* Now restore the world */
|
||
sigaction(SIGALRM, &oact, (struct sigaction *)NULL);
|
||
setitimer(ITIMER_REAL, &otm, (struct itimerval *)NULL);
|
||
|
||
#else
|
||
# error "Need implementation for dp_sleep()"
|
||
#endif
|
||
}
|
||
|
||
#endif /* KLH10_DEV_DP */
|