/*
* Example SunOS 5 multi-threaded STREAMS module.
* Using a per-queue-pair inner perimeter plus an outer perimeter.
*/
#include <sys/types.h>
#include <sys/errno.h>
#include <sys/stropts.h>
#include <sys/stream.h>
#include <sys/strlog.h>
#include <sys/cmn_err.h>
#include <sys/kmem.h>
#include <sys/conf.h>
#include <sys/ksynch.h>
#include <sys/modctl.h>
#include <sys/stat.h>
#include <sys/ddi.h>
#include <sys/sunddi.h>
/*
* Function prototypes.
*/
static int xxopen(queue_t *, dev_t *, int, int, cred_t *);
static int xxclose(queue_t *, int, cred_t *);
static int xxwput(queue_t *, mblk_t *);
static int xxwsrv(queue_t *);
static void xxwput_ioctl(queue_t *, mblk_t *);
static int xxrput(queue_t *, mblk_t *);
static void xxtick(caddr_t);
/*
* Streams Declarations
*/
static struct module_info xxm_info = {
99, /* mi_idnum */
"xx", /* mi_idname */
0, /* mi_minpsz */
INFPSZ, /* mi_maxpsz */
0, /* mi_hiwat */
0 /* mi_lowat */
};
/*
* Define the read-side qinit structure
*/
static struct qinit xxrinit = {
xxrput, /* qi_putp */
NULL, /* qi_srvp */
xxopen, /* qi_qopen */
xxclose, /* qi_qclose */
NULL, /* qi_qadmin */
&xxm_info, /* qi_minfo */
NULL /* qi_mstat */
};
/*
* Define the write-side qinit structure
*/
static struct qinit xxwinit = {
xxwput, /* qi_putp */
xxwsr, /* qi_srvp */
NULL, /* qi_qopen */
NULL, /* qi_qclose */
NULL, /* qi_qadmin */
&xxm_info, /* qi_minfo */
NULL /* qi_mstat */
};
static struct streamtab xxstrtab = {
&xxrini, /* st_rdinit */
&xxwini, /* st_wrinit */
NULL, /* st_muxrinit */
NULL /* st_muxwrinit */
};
/*
* define the fmodsw structure.
*/
static struct fmodsw xx_fsw = {
"xx", /* f_name */
&xxstrtab, /* f_str */
(D_NEW|D_MP|D_MTQPAIR|D_MTOUTPERIM|D_MTOCEXCL) /* f_flag */
};
/*
* Module linkage information for the kernel.
*/
static struct modlstrmod modlstrmod = {
&mod_strmodops, /* Type of module; a STREAMS module */
"xx module", /* Module name */
&xx_fsw, /* fmodsw */
};
static struct modlinkage modlinkage = {
MODREV_1,
&modlstrmod,
NULL
};
/*
* Module private data structure. One is allocated per stream.
*/
struct xxstr {
struct xxstr *xx_next; /* pointer to next in list */
queue_t *xx_rq; /* read side queue pointer */
int xx_timeoutid; /* id returned from timeout() */
};
/*
* Linked list of opened stream xxstr structures and other module
* global data. Protected by the outer perimeter.
*/
static struct xxstr *xxup = NULL;
static int some_module_global_data;
/*
* Module Config entry points
*/
int
_init(void)
{
return (mod_install(&modlinkage));
}
int
_fini(void)
{
return (mod_remove(&modlinkage));
}
int
_info(struct modinfo *modinfop)
{
return (mod_info(&modlinkage, modinfop));
}
static int
xxopen(queue_t *rq,dev_t *devp,int flag,int sflag, cred_t *credp)
{
struct xxstr *xxp;
/* If this stream already open - we're done. */
if (rq->q_ptr)
return (0);
/* We must be a module */
if (sflag != MODOPEN)
return (EINVAL);
/*
* The perimeter flag D_MTOCEXCL implies that the open and
* close routines have exclusive access to the module global
* data structures.
*
* Allocate our private per-stream data structure.
*/
xxp = kmem_alloc(sizeof (struct xxstr),KM_SLEEP);
/* Point q_ptr at it. */
rq->q_ptr = WR(rq)->q_ptr = (char *) xxp;
/* Initialize it. */
xxp->xx_rq = rq;
xxp->xx_timeoutid = 0;
/* Link new entry into the list of active entries. */
xxp->xx_next = xxup;
xxup = xxp;
/* Enable xxput() and xxsrv() procedures on this queue. */
qprocson(rq);
/* Return success */
return (0);
}
static int
xxclose(queue_t,*rq, int flag,cred_t *credp)
{
struct xxstr *xxp;
struct xxstr **prevxxp;
/* Disable xxput() and xxsrv() procedures on this queue. */
qprocsoff(rq);
/* Cancel any pending timeout. */
xxp = (struct xxstr *) rq->q_ptr;
if (xxp->xx_timeoutid != 0) {
(void) quntimeout(WR(rq), xxp->xx_timeoutid);
xxp->xx_timeoutid = 0;
}
/*
* D_MTOCEXCL implies that the open and close routines have
* exclusive access to the module global data structures.
*
* Unlink per-stream entry from the active list and free it.
*/
for (prevxxp = &xxup; (xxp = *prevxxp) != NULL;
prevxxp = &xxp->xx_next) {
if (xxp == (struct xxstr *) rq->q_ptr)
break;
}
*prevxxp = xxp->xx_next;
kmem_free (xxp, sizeof (struct xxstr));
rq->q_ptr = WR(rq)->q_ptr = NULL;
return (0);
}
static int
xxrput(queue_t, *wq, mblk_t *mp)
{
struct xxstr *xxp = (struct xxstr *)wq->q_ptr;
/*
* Write your code here. Can read "some_module_global_data"
* since we have shared access at the outer perimeter.
*/
putnext(wq, mp);
}
/* qwriter callback function for handling M_IOCTL messages */
static void
xxwput_ioctl(queue_t, *wq, mblk_t *mp)
{
struct xxstr *xxp = (struct xxstr *)wq->q_ptr;
/*
* Write your code here. Can modify "some_module_global_data"
* since we have exclusive access at the outer perimeter.
*/
mp->b_datap->db_type = M_IOCNAK;
qreply(wq, mp);
}
static
xxwput(queue_t *wq, mblk_t *mp)
{
struct xxstr *xxp = (struct xxstr *)wq->q_ptr;
if (mp->b_datap->db_type == M_IOCTL) {
/* M_IOCTL will modify the module global data */
qwriter(wq, mp, xxwput_ioctl, PERIM_OUTER);
return;
}
/*
* Write your code here. Can read "some_module_global_data"
* since we have exclusive access at the outer perimeter.
*/
putnext(wq, mp);
}
static
xxwsrv(queue_t wq)
{
mblk_t *mp;
struct xxstr *xxp= (struct xxstr *) wq->q_ptr;
while (mp = getq(wq)) {
/*
* Write your code here. Can read "some_module_global_data"
* since we have exclusive access at the outer perimeter.
*/
freemsg(mp);
/* for example, start a timeout */
if (xxp->xx_timeoutid != 0) {
/* cancel running timeout */
(void) quntimeout(wq, xxp->xx_timeoutid);
}
xxp->xx_timeoutid = qtimeout(wq, xxtick, (char *)xxp, 10);
}
}
static void
xxtick(arg)
caddr_t arg;
{
struct xxstr *xxp = (struct xxstr *)arg;
xxp->xx_timeoutid = 0; /* timeout has run */
/*
* Write your code here. Can read "some_module_global_data"
* since we have shared access at the outer perimeter.
*/
}
|