Coherent4.2.10/conf/streams/src/strinit.c
/*
* This file contains the entry points into the STREAMS system called by the
* Coherent kernel. This includes the startup and the system-call entry
* points; part of the reason for bundling this stuff together is that when
* bound into a Driver.a the system-call entry points are referred to by
* code that comes later in the link, and so are not pulled in unless the
* requirement for the init routine forces them to be present.
*/
#define _DDI_DKI 1
#define _SYSV3 1
#include <common/ccompat.h>
#include <kernel/strmlib.h>
#include <sys/cmn_err.h>
#include <sys/types.h>
#include <sys/errno.h>
#include <sys/stat.h>
#include <stropts.h>
#include <stddef.h>
#define _KERNEL 1
#include <sys/inode.h>
#include <sys/fd.h>
#include <sys/proc.h>
extern long _streams_maxctl;
extern long _streams_maxdata;
extern size_t _streams_size;
extern uchar_t _streams_heap [];
__EXTERN_C__ int STRMEM_INIT __PROTO ((uchar_t * _mem,
size_t _size));
/*
*-STATUS:
* SVR3
*
*-NAME:
* getmsg () Get next message off a stream
*
*-SYNOPSIS:
* #include <stropts.h>
*
* int getmsg (int fd, struct strbuf * ctlptr, struct strbuf * dataptr,
* int * flagsp);
*
*-DESCRIPTION:
* getmsg () retrieves the contents of a message located at the stream
* head read queue from a STREAMS file, and places the contents into user
* specified buffer(s). The message must contain either a data part, a
* control part, or both. The data and control parts of the message are
* placed into separate buffers, as described below. The semantics of
* each part is defined by the STREAMS module that generated the message.
*
* "fd" specifies a file descriptor referencing an open stream. "ctlptr"
* and "dataptr" each point to a "strbuf" structure, which contains the
* following members:
* int maxlen; Maximum buffer length
* int len; Length of data
* void * buf; Pointer to buffer
*
* "buf" points to a buffer in which the data or control information is
* to be placed, and "maxlen" indicates the maximum number of bytes this
* buffer can hold. On return, "len" contains the number of bytes of data
* or control information actually received, or 0 if there is a zero-
* length control or data part, or -1 if no data or control information
* is present in the message. "flagsp" should point to an integer that
* indicates the type of message the user is able to receive. This is
* described later.
*
* "ctlptr" is user to hold the control part from the message and
* "dataptr" is used to hold the data part from the message. If "ctlptr"
* or "dataptr" is NULL or the "maxlen" field is -1, the control or data
* part of the message is not processed and is left on the stream head
* read queue. If "ctlptr" or "dataptr" is not NULL and there is no
* corresponding control or data part of the message on the stream head
* read queue, "len" is set to -1. If the "maxlen" field is set to 0
* and there is a zero-length control or data part, the zero-length part
* is removed from the read queue and "len" is set to 0. If the "maxlen"
* field is set to 0 and there are more than zero bytes of control or
* data information, that information is left on the read queue and "len"
* is set to 0. If the "maxlen" field in "ctlptr" or "dataptr" is less
* than, respectively, the control or data part of the message, "maxlen"
* bytes are retrieved. In this case, the remainder of the message is
* left on the stream head read queue and a non-zero return value is
* provided, as described below under DIAGNOSTICS.
*
* By default, getmsg () processes the first available message on the
* stream head read queue. However, a user may choose to retrieve only
* high priority messages by setting the integer pointed to by "flagsp"
* to RS_HIPRI. In this case, getmsg () processes the next message only
* if it is a high priority message. If the integer pointed to by
* "flagsp" is 0, getmsg () retrieves any message available on the stream
* head read queue. In this case, the integer pointed to by "flagsp" will
* be set to RS_HIPRI if a high priority message was received, or 0
* otherwise.
*
* If O_NDELAY and O_NONBLOCK are clear, getmsg () blocks until a message
* of the type specified by "flagsp" is available on the stream head read
* queue. If O_NDELAY or O_NONBLOCK has been set and a message of the
* specified type is not present on the read, queue, getmsg () fails and
* set errno to EAGAIN.
*
* If a hangup occurs on the stream from which messages are to be
* retrieved, getmsg () continues to operate normally, as described
* above, until the stream head read queue is empty. Thereafter, it
* returns 0 in the "len" fields of "ctlptr" and "dataptr".
*
* getmsg () will fail if one or more of the following are true:
*
* EAGAIN The O_NDELAY or O_NONBLOCK flag is set and no messages
* are available.
*
* EBADF "fd" is not a valid file descriptor open for reading.
*
* EBADMSG Queued message to be read is not valid for getmsg ().
*
* EFAULT "ctlptr", "dataptr" or "flagsp" points outside the
* process's allocated address space.
*
* EINTR A signal was caught during the getmsg () system call.
*
* EINVAL An illegal value was specified in "flagsp", or the
* stream referenced by "fd" is linked under a
* multiplexor.
*
* ENOSTR A stream is not associated with "fd".
*
* getmsg () can also fail if a STREAMS error message had been received
* at the stream header before the call to getmsg (). The error returned
* is the value contained in the STREAMS error message.
*
*-DIAGNOSTICS:
* Upon sucessful completion, a non-negative value is returned. A value
* of 0 indicates that a full message was read successfully. A return
* value of MORECTL indicates that more control information is waiting
* for retrieval. A return value of MOREDATA indicates that more data are
* waiting for retrieval. A return value of MORECTL | MOREDATA indicates
* that both types of information remain. Subsequent getmsg () calls
* retrieve the remainder of the information. However, if a message of
* higher priority has come in on the stream head read queue, the next
* call to getmsg () will retrieve that higher priority message before
* retrieving the remainder of the previously received partial message.
*/
#if __USE_PROTO__
int ugetmsg (fd_t fd, struct strbuf * ctlptr, struct strbuf * dataptr,
int * flagsp)
#else
int
ugetmsg (fd, ctlptr, dataptr, flagsp)
fd_t fd;
struct strbuf * ctlptr;
struct strbuf * dataptr;
int * flagsp;
#endif
{
struct strbuf ctlbuf;
struct strbuf * kctlptr;
struct strbuf databuf;
struct strbuf * kdataptr;
__fd_t * fdp;
int flags;
int retval;
int band;
if ((fdp = fd_get (fd)) == NULL) {
set_user_error (EBADF);
return -1;
}
if (! S_ISCHR (fdp->f_ip->i_mode) ||
fdp->f_ip->i_private == NULL) {
set_user_error (ENOSTR);
return;
}
if (flagsp == NULL ||
ukcopy (flagsp, & flags, sizeof (flags)) != sizeof (flags)) {
set_user_error (EFAULT);
return -1;
}
if ((flags & ~ RS_HIPRI) != 0) {
set_user_error (EINVAL);
return -1;
}
if (ctlptr != NULL) {
if (ukcopy (ctlptr, & ctlbuf, sizeof (ctlbuf)) !=
sizeof (ctlbuf)) {
set_user_error (EFAULT);
return -1;
}
kctlptr = & ctlbuf;
} else
kctlptr = NULL;
if (dataptr != NULL) {
if (ukcopy (dataptr, & databuf, sizeof (databuf)) !=
sizeof (databuf)) {
set_user_error (EFAULT);
return -1;
}
kdataptr = & databuf;
} else
kdataptr = NULL;
flags = (flags & RS_HIPRI) != 0 ? MSG_HIPRI : MSG_BAND;
retval = 0;
band = 0;
set_user_error (STREAMS_GETPMSG ((shead_t *) fdp->f_ip->i_private,
kctlptr, kdataptr, & band, & flags,
MAKE_MODE (fdp->f_flag),
SELF->p_credp, & retval));
flags = (flags & MSG_HIPRI) != 0 ? RS_HIPRI : 0;
kucopy (& flags, flagsp, sizeof (flags));
if (ctlptr != NULL)
kucopy (kctlptr, ctlptr, sizeof (ctlbuf));
if (dataptr != NULL)
kucopy (kdataptr, dataptr, sizeof (databuf));
return retval;
}
/*
*-STATUS:
* SVR3
*
*-NAME:
* putmsg () send a message on a stream
*
*-SYNOPSIS:
* #include <stropts.h>
*
* int putmsg (int fd, const struct strbuf * ctlptr,
* const struct strbuf * dataptr, int flags);
*
*-DESCRIPTION:
* putmsg () creates a message from user-specified buffer(s) and sends
* the message to a STREAMS file. The message may contain either a data
* part, a control part, or both. The data and control parts to be sent
* are distinguished by placement in separate buffers, as described
* below. The semantics of each part is defined by the STREAMS module
* that receives the message.
*
* "fd" specifies a file descriptor referencing an open stream. "ctlptr"
* and "dataptr" each point to a "strbuf" structure containing the
* following members:
* int maxlen; Not used
* int len; Length of data
* void * buf; Pointer to buffer
*
* "ctlptr" points to the structure describing the control part, if any,
* to be included in the message. The "buf" field in the "strbuf"
* structure points to the buffer where the control information resides,
* and the "len" field indicates the number of bytes to be sent. The
* "maxlen" field is not used in putmsg (). In a similar manner,
* "dataptr" specifies the data, if any, to be included in the message.
* "flags" indicates what type of message should be sent and is described
* later.
*
* To send the data part of a message, "dataptr" must not be NULL and the
* "len" field of "dataptr" bust have a value of 0 or greater. To send
* the control part of a message, the corresponding values must be set
* for "ctlptr". No data or control) part is sent if either "dataptr"
* or "ctlptr" is NULL or if the len field of "dataptr" or "ctlptr" is
* set to -1.
*
* For putmsg (), if a control part is specified, and flags is set to
* RS_HIPRI, a high priority message is sent. If no control part is
* specified, and flags is set to RS_HIPRI, putmsg () fails and sets
* "errno" to EINVAL. If "flags" is set to 0, a normal priority message
* is sent. If no control part and no data part are specified, and
* flags is set to 0, no message is sent, and 0 is returned.
*
* The stream head guarantees that the control part of a message
* generated by putmsg () is at least 64 bytes in length.
*
* Normally, putmsg () will block if the stream head write queue is full
* due to internal flow control conditions. For high-priority messages,
* putmsg () does not block on this condition. For other messages,
* putmsg () does not block when the write queue is full and O_NDELAY or
* O_NONBLOCK has been specified. No partial message is sent.
*
* putmsg () fails if one or more of the following is true:
*
* EAGAIN A non-priority message was specified, the O_NDELAY or
* O_NONBLOCK flag is set and the stream write queue is
* full due to internal flow control conditions.
*
* EBADF "fd" is not a valid file descriptor open for writing.
*
* EFAULT "ctlptr" or "dataptr" points outside the process's
* allocated address space.
*
* EINTR A signal was caught during the putmsg () system call.
*
* EINVAL An undefined value was specified in "flags" or "flags"
* is set to RS_HIPRI and no control part was supplied.
*
* EINVAL The stream referenced by "fd" is linked below a
* multiplexor.
*
* ENOSR Buffers could not be allocated for the message that
* was to be send due to insufficient STREAMS memory
* resources.
*
* ENOSTR A stream is not associated with "fd".
*
* ENXIO A hangup condition was generated downstream for the
* specified stream, or the other end of the pipe is
* closed.
*
* ERANGE The size of the data part of the message does not fall
* within the minimum and maximum packet sizes of the
* topmost stream module. This value is also returned if
* the control part of the message is larger than the
* maximum configured size for the control part of a
* message, or if the data part of a message is larger
* than the maximum configured size for the data part of
* a message.
*
* putmsg () also fails is a STREAMS error message had been processed by
* the stream head before the call to putmsg (). The error returned is
* the value contained in the STREAMS error message.
*
*-DIAGNOSTICS:
* Upon successful completion, a value of 0 is returned. Otherwise, a
* value of -1 is returned and "errno" is set to indicate the error.
*/
#if __USE_PROTO__
int uputmsg (fd_t fd, __CONST__ struct strbuf * ctlptr,
__CONST__ struct strbuf * dataptr, int flags)
#else
int
uputmsg (fd, ctlptr, dataptr, flags)
fd_t fd;
__CONST__ struct strbuf
* ctlptr;
__CONST__ struct strbuf
* dataptr;
int flags;
#endif
{
struct strbuf ctlbuf;
struct strbuf databuf;
__fd_t * fdp;
int retval;
if ((fdp = fd_get (fd)) == NULL) {
set_user_error (EBADF);
return -1;
}
if ((flags & ~ RS_HIPRI) != 0) {
set_user_error (EINVAL);
return -1;
}
if (! S_ISCHR (fdp->f_ip->i_mode) ||
fdp->f_ip->i_private == NULL) {
set_user_error (ENOSTR);
return;
}
if (ctlptr != NULL) {
if (ukcopy (ctlptr, & ctlbuf, sizeof (ctlbuf)) !=
sizeof (ctlbuf)) {
set_user_error (EFAULT);
return -1;
}
ctlptr = & ctlbuf;
}
if (dataptr != NULL) {
if (ukcopy (dataptr, & databuf, sizeof (databuf)) !=
sizeof (databuf)) {
set_user_error (EFAULT);
return -1;
}
dataptr = & databuf;
}
flags = (flags & RS_HIPRI) != 0 ? MSG_HIPRI : MSG_BAND;
retval = 0;
set_user_error (STREAMS_PUTPMSG ((shead_t *) fdp->f_ip->i_private,
ctlptr, dataptr, 0, flags,
MAKE_MODE (fdp->f_flag),
SELF->p_credp, & retval));
return retval;
}
/*
* Start things up, in the right order. If we can't proceed, panic.
*/
#if __USE_PROTO__
void (streamsinit) (void)
#else
void
streamsinit __ARGS (())
#endif
{
/*
* Bootstrap the message allocator. Note that memory management in
* Coherent is sane, this is quite simple.
*/
while (STRMEM_INIT (_streams_heap, _streams_size) != 0)
cmn_err (CE_PANIC, "Unable to initalise STREAMS heap");
str_mem->sm_maxctlsize = _streams_maxctl;
str_mem->sm_maxdatasize = _streams_maxdata;
}