mirror of
https://github.com/PDP-10/klh10.git
synced 2026-02-07 08:47:52 +00:00
by the late MRC, Mark Crispin. Source: probably the former http://panda.com/tops-20/ . panda-dist.tar.gz dated Mar 30 2007.
305 lines
10 KiB
C
305 lines
10 KiB
C
/* DPSUP.H - Device sub-Process Support definitions (OSD) for KLH10
|
||
*/
|
||
/* $Id: dpsup.h,v 2.4 2002/04/24 07:46:15 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.h,v $
|
||
* 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
|
||
*
|
||
*/
|
||
|
||
/*
|
||
This file defines the IPC mechanism used to communicate between
|
||
virtual device code in the KLH10 and the various sub-processes that
|
||
may be needed to carry out their operations. For our purposes, "input"
|
||
and "output" are defined relative to the virtual PDP10; input is data
|
||
coming from a device to the 10, and output is generated by the 10 for
|
||
transfer to a device.
|
||
|
||
Note that the sub-processes may, in various configurations, be
|
||
any of:
|
||
|
||
(1) Full subprocess (forked child)
|
||
Possible on most process-oriented platforms (Unix).
|
||
One process for output; another process for input if
|
||
asynch input is possible for device.
|
||
Signalling DP done with either user-defined OS signal
|
||
or OS semaphore.
|
||
Signalling 10 done with user-defined OS signal (10 cannot
|
||
waste time polling semaphores).
|
||
DP reset done with OS signal and/or process kill.
|
||
|
||
(2) Threaded process within KLH10
|
||
Ideal but only possible if platform has reliable threads support.
|
||
One thread for output; another for input if asynch input is
|
||
possible for device.
|
||
Signalling DP done by condition vars (fast semaphores).
|
||
OS semaphores also possible though slower.
|
||
Signalling 10 done with direct lock & intf setting.
|
||
OS signals also possible but slower.
|
||
DP reset done with condvar setting and/or thread kill.
|
||
|
||
(3) Asynchronous (non-blocking interrupt-driven) within KLH10
|
||
Not always possible, even on Unix (disk in particular).
|
||
No distinct DP process/thread, so no DP/10 comm needed.
|
||
I/O never blocks; OS signals given when input avail or
|
||
output ready. Signal handler can either perform I/O
|
||
or set flag for main loop.
|
||
DP reset done directly.
|
||
|
||
(4) Synchronous within KLH10
|
||
Maximally portable, but slowest mechanism.
|
||
No distinct DP process/thread, so no DP/10 comm needed.
|
||
Output always blocks; input is polled.
|
||
DP reset done directly.
|
||
|
||
Only one mechanism (DP_XT_MSIG) is actually implemented at present.
|
||
|
||
*/
|
||
|
||
/*
|
||
The DP IPC mechanism implemented here has some remote
|
||
similarities to the 10-11 communication protocol. Two identical
|
||
comm/transfer regions are used, one for each direction to and from the
|
||
subprocess. Messages consist of simple commands that may or may not
|
||
point to large quantities of information elsewhere.
|
||
|
||
To send a message:
|
||
Sender waits until Ready flag is clear.
|
||
Sender sets up all necessary data for the message, then sets
|
||
Ready flag to -1 and signals receiver.
|
||
If result is important, can wait until Ready is clear, then
|
||
examine Result value.
|
||
|
||
To receive a message:
|
||
Receiver waits until signaled and Ready flag is set.
|
||
Receiver carries out operation specified by data, then sets
|
||
Result value and clears Ready.
|
||
Receiver signals sender.
|
||
|
||
|
||
Should regions be arranged so each is R/W for sender, and RO for receiver?
|
||
Can distribute variables appropriately. Prevents wild subproc from
|
||
messing up... a little.
|
||
|
||
For now, keep everything in one mutually R/W region for simplicity.
|
||
|
||
*/
|
||
|
||
#ifndef DPSUP_INCLUDED
|
||
#define DPSUP_INCLUDED 1
|
||
|
||
#ifdef RCSID
|
||
RCSID(dpsup_h,"$Id: dpsup.h,v 2.4 2002/04/24 07:46:15 klh Exp $")
|
||
#endif
|
||
|
||
#ifndef OSDSUP_INCLUDED
|
||
# include "osdsup.h" /* For osintf_t etc */
|
||
#endif
|
||
|
||
#define DP_XT_MSIG 1 /* Shared mem, use signal for doorbell */
|
||
#define DP_XT_MSEM 2 /* Shared mem, use semaphore for doorbell */
|
||
#define DP_XT_THCV 3 /* Same mem, use thread condition var */
|
||
|
||
#if 0
|
||
union dpcxmech {
|
||
struct dpc_xt_msig {
|
||
ospid_t dpxt_pid; /* S: Owner/Sender */
|
||
osshm_t dpxt_mem; /* S: Shared mem identifier */
|
||
oscad_t dpxt_sadr; /* S: Loc in sender address space */
|
||
ossig_t dpxt_sig; /* Signal # to use for doorbell */
|
||
} msig;
|
||
};
|
||
#endif
|
||
|
||
/* DP one-way transfer region
|
||
** Ready flag is set to -1 when sender has deposited a message for
|
||
** the reader. It is cleared to 0 when receiver has
|
||
** processed the message.
|
||
**
|
||
*/
|
||
/* C=Creator, S=Sender, R=Receiver */
|
||
struct dpx_s {
|
||
int dpx_type; /* C: Type of comm mechanism */
|
||
#if 0
|
||
union dpx_osd; /* S/R: OSD stuff for comm mech */
|
||
#else
|
||
int dpx_waktyp; /* R: How to wake up rcpt */
|
||
int dpx_wakflg; /* R/S: R sets 1 when trying to do wake */
|
||
int dpx_waksig; /* C: Signal # to use */
|
||
sigset_t dpx_wakmsk; /* C: Mask for signal # */
|
||
int dpx_wakpid;
|
||
unsigned char *dpx_rbuf; /* R: R's ptr into buffer */
|
||
|
||
int dpx_dontyp; /* S: How to Ack sender */
|
||
int dpx_donflg; /* S/R: S sets 1 when trying to do ack */
|
||
int dpx_donsig; /* C: Signal # to use */
|
||
sigset_t dpx_donmsk; /* C: Mask for signal # */
|
||
int dpx_donpid;
|
||
unsigned char *dpx_sbuf; /* S: S's ptr into same buffer */
|
||
#endif
|
||
|
||
size_t dpx_len; /* C: Buffer length */
|
||
size_t dpx_off; /* C: Buffer offset from beg of segment */
|
||
volatile
|
||
osintf_t dpx_rdyf; /* S/R: Ready flag */
|
||
int dpx_res; /* R: Result value */
|
||
int dpx_cmd; /* S: Command */
|
||
size_t dpx_cnt; /* S: Count of data bytes */
|
||
|
||
/* Args of various types -- later could be union */
|
||
int dpx_int;
|
||
long dpx_long;
|
||
unsigned char *dpx_ucp;
|
||
#if 0
|
||
paddr_t dpx_pa;
|
||
w10_t dpx_w;
|
||
dw10_t dpx_dw;
|
||
#endif
|
||
};
|
||
typedef struct dpx_s dpx_t;
|
||
|
||
/* DP common area, shared between Main (superior) and DP (subproc)
|
||
**
|
||
*/
|
||
struct dpc_s {
|
||
char dpc_magic[4]; /* M: Magic chars saying this is DPC mem seg */
|
||
int dpc_fmtver; /* M: Format version */
|
||
char dpc_id[8]; /* M: App identifier chars */
|
||
int dpc_flags; /* M/DP: Flags */
|
||
int dpc_debug; /* M: Debug flag (separate for efficiency) */
|
||
struct dpx_s dpc_todp; /* M: To subproc from KLH10 */
|
||
struct dpx_s dpc_frdp; /* DP: From subproc to KLH10 */
|
||
|
||
/* Various other DPC info */
|
||
|
||
/* Device-dependent stuff, extensible to arbitrary size */
|
||
};
|
||
|
||
/* Defs for DPC contents */
|
||
|
||
#define DPC_MAGIC "DPM"
|
||
|
||
#define DPC_VERSION(maj,min,pat) (((maj)<<10) | ((min)<<5) | (pat))
|
||
#define DPC_GV_MAJ(a) (((a)>>10)&037)
|
||
#define DPC_GV_MIN(a) (((a)>>5)&037)
|
||
#define DPC_GV_PAT(a) (((a)>>0)&037)
|
||
|
||
#define DPSUP_VERSION DPC_VERSION(1,2,0) /* This version of DPSUP */
|
||
|
||
#define DPCF_MEMLOCK 0x1 /* M wants DP to lock its mem if possible */
|
||
|
||
|
||
/* DP handle - private memory */
|
||
struct dp_s {
|
||
int dp_type;
|
||
long dp_shmid; /* Change to osmid_t later */
|
||
struct dpc_s *dp_adr;
|
||
int dp_chpid; /* Change to ospid_t */
|
||
};
|
||
typedef struct dp_s dp_t;
|
||
|
||
/* General Facilities */
|
||
|
||
/* Called from superior (KLH10) */
|
||
|
||
int dp_init (dp_t *dp, size_t, int, int, size_t in,
|
||
int, int, size_t out);
|
||
int dp_start(dp_t *dp, char *pgm);
|
||
int dp_stop (dp_t *dp, int timeout);
|
||
int dp_reset(dp_t *dp); /* What would this do? */
|
||
int dp_term (dp_t *dp, int timeout);
|
||
void dp_exit(dp_t *dp, int res);
|
||
|
||
|
||
/* Called from subprocess (dp) */
|
||
|
||
int dp_main (dp_t *dp, int argc, char **argv);
|
||
|
||
|
||
/* Called from both for communications */
|
||
|
||
/* struct dpx_s *dp_dpxto(dp_t *); */ /* "To DP" direction */
|
||
/* struct dpx_s *dp_dpxfr(dp_t *); */ /* "From DP" direction */
|
||
#define dp_dpxto(dp) (&((dp)->dp_adr->dpc_todp))
|
||
#define dp_dpxfr(dp) (&((dp)->dp_adr->dpc_frdp))
|
||
|
||
int dp_xstest (dpx_t *); /* TRUE if can send */
|
||
void dp_xsblock(dpx_t *); /* Block for later testing */
|
||
int dp_xswait (dpx_t *); /* Wait until can send */
|
||
unsigned char *
|
||
dp_xsbuff(dpx_t *, size_t *); /* Get buffer for send data */
|
||
void dp_xswake(dpx_t *); /* Send; say message ready */
|
||
void dp_xsend(dpx_t *, int, size_t); /* Send cmd & data */
|
||
|
||
int dp_xrtest (dpx_t *); /* TRUE if can receive (have input) */
|
||
void dp_xrblock(dpx_t *); /* Block for later testing */
|
||
int dp_xrwait (dpx_t *); /* Wait until can rcv (have input) */
|
||
unsigned char *
|
||
dp_xrbuff(dpx_t *, size_t *); /* Get pointer to data */
|
||
void dp_xrdone(dpx_t *); /* Receive; say message done */
|
||
void dp_xrdoack(dpx_t *, int); /* Receive; say done, w/res */
|
||
int dp_xrcmd(dpx_t *); /* Get command for msg */
|
||
size_t dp_xrcnt(dpx_t *); /* Get cnt for msg */
|
||
|
||
/* Misc internals */
|
||
void dp_sigwait(void); /* Wait until any sig happens */
|
||
void dp_sleep(int); /* Sleep for N seconds */
|
||
|
||
/* Facilities for DPCXT_MSIG */
|
||
|
||
#define dp_xtmsig_stest(dpx) ((dpx)->dpx_rdyf == 0) /* TRUE if can send */
|
||
#define dp_xtmsig_swake(dpx) (((dpx)->dpx_rdyf = 1), \
|
||
((dpx)->dpx_wakflg = 1), \
|
||
kill((dpx)->dpx_wakpid, (dpx)->dpx_waksig))
|
||
#define dp_xtmsig_sblock(dpx) dp_sigwait()
|
||
#define dp_xtmsig_swait(dpx) \
|
||
while (!dp_xtmsig_stest(dpx)) dp_xtmsig_sblock(dpx)
|
||
#define dp_xtmsig_sbuff(dpx, asiz) \
|
||
((asiz ? (*(asiz) = (dpx)->dpx_len) : 0), (dpx)->dpx_sbuf)
|
||
#define dp_xtmsig_send(dpx, cmd, cnt) \
|
||
((dpx)->dpx_cmd = (cmd), (dpx)->dpx_cnt = (cnt), dp_xtmsig_swake(dpx))
|
||
|
||
#define dp_xtmsig_rtest(dpx) ((dpx)->dpx_rdyf != 0) /* TRUE if can recv */
|
||
#define dp_xtmsig_rdone(dpx) (((dpx)->dpx_rdyf = 0), \
|
||
((dpx)->dpx_donflg = 1), \
|
||
kill((dpx)->dpx_donpid, (dpx)->dpx_donsig))
|
||
#define dp_xtmsig_rdoack(dpx, res) ((dpx)->dpx_res = (res), \
|
||
dp_xtmsig_rdone(dpx))
|
||
#define dp_xtmsig_rblock(dpx) dp_sigwait()
|
||
#define dp_xtmsig_rwait(dpx) \
|
||
while (!dp_xtmsig_rtest(dpx)) dp_xtmsig_rblock(dpx)
|
||
#define dp_xtmsig_rbuff(dpx, asiz) \
|
||
((asiz ? (*(asiz) = (dpx)->dpx_len) : 0), (dpx)->dpx_rbuf)
|
||
#define dp_xtmsig_rcmd(dpx) ((dpx)->dpx_cmd)
|
||
#define dp_xtmsig_rcnt(dpx) ((dpx)->dpx_cnt)
|
||
|
||
#if 0
|
||
/* For device to register its dp with 10 via device vector */
|
||
int dpcxt_msig_register(struct dpc_s *dpc, struct device *d);
|
||
#endif
|
||
|
||
/* Misc auxiliary unrelated to DP support but one that exists and
|
||
which all DP procs need anyway (to avoid needing full OSDSUP module)
|
||
*/
|
||
extern char *dp_strerror(int);
|
||
|
||
#endif /* ifndef DPSUP_INCLUDED */
|