665 lines
16 KiB
C
665 lines
16 KiB
C
|
/*++
|
|||
|
|
|||
|
Copyright (c) 1991 Microsoft Corporation
|
|||
|
|
|||
|
Module Name:
|
|||
|
|
|||
|
sh_get.c
|
|||
|
|
|||
|
Abstract:
|
|||
|
|
|||
|
This source file contains those functions of the Stream Head Driver that
|
|||
|
deal with receiving messages from a stream.
|
|||
|
|
|||
|
Author:
|
|||
|
|
|||
|
Eric Chin (ericc) August 16, 1991
|
|||
|
|
|||
|
Revision History:
|
|||
|
|
|||
|
Notes:
|
|||
|
|
|||
|
The read error state of a stream is represented by ms->e_rerror. Once
|
|||
|
set, this is never reset. This corresponds to the STREAMS semantics as
|
|||
|
defined by AT&T. Once a user is notified of a read error on a stream,
|
|||
|
about the only recourse is to close the stream.
|
|||
|
|
|||
|
--*/
|
|||
|
#include "sh_inc.h"
|
|||
|
|
|||
|
|
|||
|
//
|
|||
|
// Local (Private) Functions
|
|||
|
//
|
|||
|
STATIC
|
|||
|
VOID
|
|||
|
cancel_get(
|
|||
|
IN PDEVICE_OBJECT device,
|
|||
|
IN PIRP irp
|
|||
|
);
|
|||
|
|
|||
|
NTSTATUS
|
|||
|
do_getmsg(
|
|||
|
IN PIRP irp,
|
|||
|
IN PFILE_OBJECT pfileobj,
|
|||
|
IN int flags
|
|||
|
);
|
|||
|
|
|||
|
|
|||
|
|
|||
|
NTSTATUS
|
|||
|
SHDispGetMsg(
|
|||
|
IN PIRP irp,
|
|||
|
IN PIO_STACK_LOCATION irpsp
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This routine implements the getmsg(2) API.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
irp - pointer to the IRP representing this request
|
|||
|
irpsp - pointer to the IRP stack location for this request
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
An NT status code. Whatever the return value, this function will arrange
|
|||
|
for the IRP to be completed.
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
int spl_level;
|
|||
|
NTSTATUS status;
|
|||
|
PSTREAM_ENDPOINT ms;
|
|||
|
int MyErrno, pri;
|
|||
|
PGETMSG_ARGS_INOUT inbuf;
|
|||
|
int ret;
|
|||
|
mblk_t *mp;
|
|||
|
int more = 0;
|
|||
|
struct strbuf *strbufp;
|
|||
|
int ctlsize, datasize, flags, *pretval, remains;
|
|||
|
|
|||
|
ASSERT((irpsp->Parameters.DeviceIoControl.IoControlCode & 0x3) ==
|
|||
|
METHOD_BUFFERED);
|
|||
|
|
|||
|
ms = (PSTREAM_ENDPOINT) irpsp->FileObject->FsContext;
|
|||
|
|
|||
|
if (irpsp->Parameters.DeviceIoControl.InputBufferLength <
|
|||
|
sizeof(GETMSG_ARGS_INOUT) - 1) {
|
|||
|
IF_STRMDBG(TERSE) {
|
|||
|
STRMTRACE(("SHEAD: SHDispGetMsg(%lx) insufficient nbytes = %lx\n",
|
|||
|
irp, irpsp->Parameters.DeviceIoControl.InputBufferLength));
|
|||
|
}
|
|||
|
shortreply(irp, STATUS_INVALID_PARAMETER, 0);
|
|||
|
return(STATUS_INVALID_PARAMETER);
|
|||
|
}
|
|||
|
|
|||
|
// Need to ensure that the output buffer is big enough.
|
|||
|
{
|
|||
|
int cbOut = irpsp->Parameters.DeviceIoControl.OutputBufferLength;
|
|||
|
NTSTATUS LengthStatus = STATUS_INVALID_PARAMETER;
|
|||
|
|
|||
|
if (cbOut >= (sizeof(GETMSG_ARGS_INOUT) - 1))
|
|||
|
{
|
|||
|
pretval = (int *) irp->AssociatedIrp.SystemBuffer;
|
|||
|
flags = * (pretval + 1);
|
|||
|
strbufp = (struct strbuf *) (pretval + 2);
|
|||
|
ctlsize = strbufp->maxlen;
|
|||
|
datasize = (++strbufp)->maxlen;
|
|||
|
|
|||
|
cbOut -= (sizeof(GETMSG_ARGS_INOUT) - 1);
|
|||
|
|
|||
|
if (cbOut >= ctlsize)
|
|||
|
{
|
|||
|
cbOut -= ctlsize;
|
|||
|
|
|||
|
if (cbOut >= datasize)
|
|||
|
{
|
|||
|
// cbOut -= datasize;
|
|||
|
LengthStatus = STATUS_SUCCESS;
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
if (LengthStatus != STATUS_SUCCESS)
|
|||
|
{
|
|||
|
IF_STRMDBG(TERSE) {
|
|||
|
STRMTRACE(("SHEAD: SHDispGetMsg(%lx) outbuf insufficient nbytes = %lx\n",
|
|||
|
irp, irpsp->Parameters.DeviceIoControl.OutputBufferLength));
|
|||
|
}
|
|||
|
shortreply(irp, LengthStatus, 0);
|
|||
|
return (LengthStatus);
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// the caller marshalled the input arguments contiguously thus:
|
|||
|
//
|
|||
|
// typedef struct _GETMSG_ARGS_INOUT_ { // getmsg()
|
|||
|
// int a_retval; // ignore on input
|
|||
|
// long a_flags; // 0 or RS_HIPRI
|
|||
|
// struct strbuf a_ctlbuf; // (required)
|
|||
|
// struct strbuf a_databuf; // (required)
|
|||
|
// char a_stuff[1]; // a_ctlbuf.buf (optional)
|
|||
|
// // a_databuf.buf (optional)
|
|||
|
// } GETMSG_ARGS_INOUT, *PGETMSG_ARGS_INOUT;
|
|||
|
//
|
|||
|
inbuf = (PGETMSG_ARGS_INOUT) irp->AssociatedIrp.SystemBuffer;
|
|||
|
|
|||
|
IF_STRMDBG(VERBOSE) {
|
|||
|
STRMTRACE(("SHEAD: SHDispGetMsg(irp = %lx)\n", irp));
|
|||
|
}
|
|||
|
|
|||
|
IoAcquireCancelSpinLock(&irp->CancelIrql);
|
|||
|
|
|||
|
spl_level = lock_strm(ms->e_strm);
|
|||
|
|
|||
|
if (ms->e_rerror) {
|
|||
|
MyErrno = ms->e_rerror;
|
|||
|
}
|
|||
|
else if (ms->e_linked) {
|
|||
|
MyErrno = EINVAL;
|
|||
|
}
|
|||
|
else {
|
|||
|
MyErrno = 0;
|
|||
|
}
|
|||
|
|
|||
|
if (MyErrno) {
|
|||
|
|
|||
|
IF_STRMDBG(TERSE) {
|
|||
|
STRMTRACE(("SHEAD: SHDispGetMsg() error = %d\n", MyErrno));
|
|||
|
}
|
|||
|
unlock_strm(ms->e_strm, spl_level);
|
|||
|
IoReleaseCancelSpinLock(irp->CancelIrql);
|
|||
|
SHpGenReply(irp, -1, MyErrno);
|
|||
|
return(STATUS_SUCCESS);
|
|||
|
}
|
|||
|
pri = (inbuf->a_flags == RS_HIPRI) ? QPCTL : 0;
|
|||
|
|
|||
|
if (shready(ms->e_strm, pri)) {
|
|||
|
|
|||
|
IF_STRMDBG(VERBOSE) {
|
|||
|
STRMTRACE(("SHEAD: SHDispGetMsg() stream's shready()\n"));
|
|||
|
}
|
|||
|
// The two lines below are replaced by the lines between the vvv/^^^'s
|
|||
|
// temp = msgreply(ms, irp);
|
|||
|
// ASSERT(temp == 0);
|
|||
|
|
|||
|
// vvvvvvvv
|
|||
|
// vvvvvvvv
|
|||
|
/*
|
|||
|
* the arguments are marshalled in one contiguous chunk, laid out as:
|
|||
|
*
|
|||
|
* an unused int (required)
|
|||
|
* flags (required)
|
|||
|
* struct strbuf ctrlbuf (required)
|
|||
|
* struct strbuf databuf (required)
|
|||
|
*/
|
|||
|
pretval = (int *) irp->AssociatedIrp.SystemBuffer;
|
|||
|
flags = * (pretval + 1);
|
|||
|
strbufp = (struct strbuf *) (pretval + 2);
|
|||
|
ctlsize = strbufp->maxlen;
|
|||
|
datasize = (++strbufp)->maxlen;
|
|||
|
|
|||
|
/*
|
|||
|
* st_getmsg() may set MORECTL and/or MOREDATA in *pretval; we must
|
|||
|
* return it to the user-level runtime !!
|
|||
|
*/
|
|||
|
ret = st_getmsg(ms->e_strm, ctlsize, datasize, &flags, pretval,
|
|||
|
&mp, &remains);
|
|||
|
|
|||
|
ASSERT(!ret);
|
|||
|
ASSERT(mp);
|
|||
|
// ^^^^^^^^
|
|||
|
// ^^^^^^^^
|
|||
|
unlock_strm(ms->e_strm, spl_level);
|
|||
|
IoReleaseCancelSpinLock(irp->CancelIrql);
|
|||
|
|
|||
|
// vvvvvvvv
|
|||
|
// vvvvvvvv
|
|||
|
mptoirp(mp, irp);
|
|||
|
freemsg(mp);
|
|||
|
// ^^^^^^^^
|
|||
|
// ^^^^^^^^
|
|||
|
|
|||
|
return(STATUS_SUCCESS);
|
|||
|
}
|
|||
|
if (ms->e_hup) {
|
|||
|
|
|||
|
IF_STRMDBG(TERSE) {
|
|||
|
STRMTRACE(("SHEAD: SHDispGetMsg() stream's was hung up\n"));
|
|||
|
}
|
|||
|
unlock_strm(ms->e_strm, spl_level);
|
|||
|
IoReleaseCancelSpinLock(irp->CancelIrql);
|
|||
|
SHpGenReply(irp, -1, EINTR);
|
|||
|
return(STATUS_SUCCESS);
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// enqueue this request in the waiting list of readers.
|
|||
|
//
|
|||
|
IoMarkIrpPending(irp);
|
|||
|
|
|||
|
if (irp->Cancel) {
|
|||
|
|
|||
|
unlock_strm(ms->e_strm, spl_level);
|
|||
|
|
|||
|
IoSetCancelRoutine(irp, NULL);
|
|||
|
IoReleaseCancelSpinLock(irp->CancelIrql);
|
|||
|
shortreply(irp, STATUS_CANCELLED, 0);
|
|||
|
return(STATUS_CANCELLED);
|
|||
|
}
|
|||
|
|
|||
|
status = SHAddPendingIrp(&(ms->e_readers), FALSE, irp, NULL);
|
|||
|
|
|||
|
ASSERT(!shready(ms->e_strm, 0));
|
|||
|
|
|||
|
unlock_strm(ms->e_strm, spl_level);
|
|||
|
|
|||
|
if (status != STATUS_SUCCESS) {
|
|||
|
|
|||
|
IF_STRMDBG(TERSE) {
|
|||
|
STRMTRACE(("SHEAD: SHDispGetMsg() failed to SHAddPendingIrp\n"));
|
|||
|
}
|
|||
|
IoReleaseCancelSpinLock(irp->CancelIrql);
|
|||
|
shortreply(irp, status, 0);
|
|||
|
return(status);
|
|||
|
}
|
|||
|
|
|||
|
IoSetCancelRoutine(irp, cancel_get);
|
|||
|
IoReleaseCancelSpinLock(irp->CancelIrql);
|
|||
|
|
|||
|
IF_STRMDBG(VERBOSE) {
|
|||
|
STRMTRACE(("SHEAD: SHDispGetMsg(irp = %lx) q_count = %ld\n",
|
|||
|
irp, RD(ms->e_strm->str_sq)->q_count ));
|
|||
|
}
|
|||
|
return(STATUS_PENDING);
|
|||
|
|
|||
|
} // SHDispGetMsg
|
|||
|
|
|||
|
|
|||
|
|
|||
|
int
|
|||
|
SHpStreamError(
|
|||
|
IN PLIST_ENTRY listhead,
|
|||
|
IN int error
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This routine completes the IRPs waiting on a stream when an M_ERROR or
|
|||
|
M_HANGUP arrives from downstream.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
listhead - either e_readers, e_writers or e_ioctlers
|
|||
|
error - the POSIX error code to return
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
The number of pending IRPs that were completed.
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
int count = 0;
|
|||
|
PLIST_ENTRY tmp;
|
|||
|
PWAITING_IRP item;
|
|||
|
|
|||
|
IF_STRMDBG(TERSE) {
|
|||
|
STRMTRACE(("SHEAD: ShpStreamError() for M_HANGUP/M_ERROR\n"));
|
|||
|
}
|
|||
|
|
|||
|
while (!IsListEmpty(listhead)) {
|
|||
|
|
|||
|
tmp = RemoveHeadList(listhead);
|
|||
|
item = CONTAINING_RECORD(tmp,
|
|||
|
WAITING_IRP,
|
|||
|
w_list);
|
|||
|
|
|||
|
SHpGenReply(item->w_irp, -1, error);
|
|||
|
ExFreePool(item);
|
|||
|
count++;
|
|||
|
}
|
|||
|
return(count);
|
|||
|
|
|||
|
} // SHpStreamError
|
|||
|
|
|||
|
|
|||
|
|
|||
|
|
|||
|
STATIC
|
|||
|
VOID
|
|||
|
cancel_get(
|
|||
|
IN PDEVICE_OBJECT device,
|
|||
|
IN PIRP irp
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This routine is called when a getmsg() is cancelled.
|
|||
|
|
|||
|
It must release the cancel spinlock before returning !! The caller
|
|||
|
has already acquired the cancel spinlock. ref: IoCancelIrp().
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
device - pointer to the device object
|
|||
|
irp - pointer to the irp of this request
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
none.
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
int spl_level;
|
|||
|
PLIST_ENTRY tmp;
|
|||
|
PWAITING_IRP item;
|
|||
|
PSTREAM_ENDPOINT ms;
|
|||
|
PIO_STACK_LOCATION irpsp = IoGetCurrentIrpStackLocation(irp);
|
|||
|
|
|||
|
ASSERT(device == (PDEVICE_OBJECT) StreamDevice);
|
|||
|
ASSERT(irpsp->MajorFunction == IRP_MJ_DEVICE_CONTROL);
|
|||
|
ASSERT(irpsp->Parameters.DeviceIoControl.IoControlCode ==
|
|||
|
IOCTL_STREAMS_GETMSG);
|
|||
|
IF_STRMDBG(CALL) {
|
|||
|
STRMTRACE(("SHEAD: cancel_get(irp = %lx) entered\n", irp));
|
|||
|
}
|
|||
|
IoSetCancelRoutine(irp, NULL); /* unnecessary, but cheap */
|
|||
|
IoReleaseCancelSpinLock(irp->CancelIrql);
|
|||
|
|
|||
|
ms = (PSTREAM_ENDPOINT) irpsp->FileObject->FsContext;
|
|||
|
|
|||
|
spl_level = lock_strm(ms->e_strm);
|
|||
|
|
|||
|
for (tmp = ms->e_readers.Flink; tmp != &ms->e_readers; tmp = tmp->Flink) {
|
|||
|
|
|||
|
item = CONTAINING_RECORD(tmp,
|
|||
|
WAITING_IRP,
|
|||
|
w_list);
|
|||
|
|
|||
|
if (irp != item->w_irp) {
|
|||
|
continue;
|
|||
|
}
|
|||
|
RemoveEntryList(&(item->w_list));
|
|||
|
|
|||
|
unlock_strm(ms->e_strm, spl_level);
|
|||
|
ExFreePool(item);
|
|||
|
|
|||
|
shortreply(irp, STATUS_CANCELLED, 0);
|
|||
|
|
|||
|
IF_STRMDBG(CALL) {
|
|||
|
STRMTRACE(("SHEAD: cancel_get(irp = %lx) cancelled ok\n", irp));
|
|||
|
}
|
|||
|
return;
|
|||
|
}
|
|||
|
unlock_strm(ms->e_strm, spl_level);
|
|||
|
|
|||
|
IF_STRMDBG(CALL) {
|
|||
|
STRMTRACE(("SHEAD: cancel_get(irp = %lx) not found\n", irp));
|
|||
|
}
|
|||
|
|
|||
|
} // cancel_get
|
|||
|
|
|||
|
|
|||
|
|
|||
|
void
|
|||
|
msgrdy(
|
|||
|
IN struct msg_strm *ms,
|
|||
|
IN int mtype
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This function is called by the Stream Head Driver when a message arrives
|
|||
|
at the read queue of the specified stream.
|
|||
|
|
|||
|
Call this function with the stream endpoint locked !!
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
ms - pointer to the stream endpoint
|
|||
|
mtype - type of the STREAMS message
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
none.
|
|||
|
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
PIRP irp;
|
|||
|
int check, pri;
|
|||
|
PLIST_ENTRY tmp;
|
|||
|
PWAITING_IRP item;
|
|||
|
PGETMSG_ARGS_INOUT inbuf;
|
|||
|
|
|||
|
IF_STRMDBG(CALL) {
|
|||
|
STRMTRACE(("SHEAD: msgrdy(ms = %lx, mtype = %x)\n", ms, mtype));
|
|||
|
}
|
|||
|
|
|||
|
switch (mtype) {
|
|||
|
case M_DATA:
|
|||
|
case M_PROTO:
|
|||
|
if (ms->e_strm_flags & POLLIN) {
|
|||
|
ms->e_strm_flags &= ~POLLIN;
|
|||
|
|
|||
|
KeReleaseSemaphore(
|
|||
|
&Poll_fired, // semaphore
|
|||
|
SEMAPHORE_INCREMENT, // priority increment
|
|||
|
1, // adjustment
|
|||
|
FALSE // wait
|
|||
|
);
|
|||
|
}
|
|||
|
break;
|
|||
|
|
|||
|
case M_PCPROTO:
|
|||
|
if (ms->e_strm_flags & POLLPRI) {
|
|||
|
ms->e_strm_flags &= ~POLLPRI;
|
|||
|
|
|||
|
KeReleaseSemaphore(
|
|||
|
&Poll_fired, // semaphore
|
|||
|
SEMAPHORE_INCREMENT, // priority increment
|
|||
|
1, // adjustment
|
|||
|
FALSE // wait
|
|||
|
);
|
|||
|
}
|
|||
|
break;
|
|||
|
|
|||
|
case M_SIG:
|
|||
|
if (ms->e_strm_flags & POLLMSG) {
|
|||
|
ms->e_strm_flags &= ~POLLMSG;
|
|||
|
|
|||
|
KeReleaseSemaphore(
|
|||
|
&Poll_fired, // semaphore
|
|||
|
SEMAPHORE_INCREMENT, // priority increment
|
|||
|
1, // adjustment
|
|||
|
FALSE // wait
|
|||
|
);
|
|||
|
}
|
|||
|
break;
|
|||
|
|
|||
|
default:
|
|||
|
IF_STRMDBG(TERSE) {
|
|||
|
STRMTRACE(("SHEAD: msgrdy(), msg type = %x unexpected\n", mtype));
|
|||
|
}
|
|||
|
ASSERT(0);
|
|||
|
}
|
|||
|
|
|||
|
while (!IsListEmpty( &(ms->e_readers) )) {
|
|||
|
|
|||
|
tmp = RemoveHeadList( &(ms->e_readers) );
|
|||
|
item = CONTAINING_RECORD(tmp,
|
|||
|
WAITING_IRP,
|
|||
|
w_list);
|
|||
|
irp = item->w_irp;
|
|||
|
|
|||
|
//
|
|||
|
// get the RS_HIPRI flag, if any, from the irp.
|
|||
|
//
|
|||
|
inbuf = (PGETMSG_ARGS_INOUT) irp->AssociatedIrp.SystemBuffer;
|
|||
|
pri = (inbuf->a_flags == RS_HIPRI) ? QPCTL : 0;
|
|||
|
|
|||
|
if (!shready(ms->e_strm, pri)) {
|
|||
|
InsertHeadList( &(ms->e_readers), &(item->w_list) );
|
|||
|
return;
|
|||
|
}
|
|||
|
check = msgreply(ms, irp);
|
|||
|
ASSERT(check == 0);
|
|||
|
|
|||
|
ExFreePool(item);
|
|||
|
}
|
|||
|
|
|||
|
IF_STRMDBG(CALL) {
|
|||
|
STRMTRACE(("SHEAD: msgrdy() completed ok\n"));
|
|||
|
}
|
|||
|
return;
|
|||
|
|
|||
|
} // msgrdy
|
|||
|
|
|||
|
|
|||
|
void
|
|||
|
strmevent(
|
|||
|
IN STREAM_ENDPOINT *ms,
|
|||
|
IN int rerror,
|
|||
|
IN int werror,
|
|||
|
IN int t
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This function handles special messages that arrive at the stream head.
|
|||
|
It is based on the SpiderStreams function of the same name.
|
|||
|
|
|||
|
Only M_ERROR and M_HANGUP messages are handled at present. M_ERROR is
|
|||
|
straightforward to deal with. The error status in the stream structure
|
|||
|
is set, and any pending requests failed.
|
|||
|
|
|||
|
M_HANGUP is very similar, except that read requests are allowed to
|
|||
|
complete, and subsequent reads are treated as end of file, rather than
|
|||
|
an error condition.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
ms - pointer to stream endpoint
|
|||
|
rerror - read queue error
|
|||
|
werror - write queue error
|
|||
|
t - type of STREAMS message
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
PIRP irp;
|
|||
|
int succeeded;
|
|||
|
|
|||
|
IF_STRMDBG(CALL) {
|
|||
|
STRMTRACE(("SHEAD: strmevent(ms = %lx) entered\n", ms));
|
|||
|
}
|
|||
|
|
|||
|
if (ms->TdiStreamPtr) {
|
|||
|
TdiStreamEvent(ms, rerror, werror, t);
|
|||
|
return;
|
|||
|
}
|
|||
|
|
|||
|
if (rerror == NOERROR) {
|
|||
|
rerror = ms->e_rerror; // get current value
|
|||
|
}
|
|||
|
else {
|
|||
|
ms->e_rerror = rerror; // set read error status
|
|||
|
}
|
|||
|
|
|||
|
if (werror == NOERROR) {
|
|||
|
werror = ms->e_werror; // get current value
|
|||
|
}
|
|||
|
else {
|
|||
|
ms->e_werror = werror; // set write error status
|
|||
|
}
|
|||
|
|
|||
|
if ((rerror == 0) && (werror == 0)) { // errors zeroed out
|
|||
|
IF_STRMDBG(TERSE) {
|
|||
|
STRMTRACE(("SHEAD: strmevent(ms = %lx) [rw]error = 0\n", ms));
|
|||
|
}
|
|||
|
return;
|
|||
|
}
|
|||
|
|
|||
|
switch (t) {
|
|||
|
case M_HANGUP:
|
|||
|
ms->e_hup = 1;
|
|||
|
break;
|
|||
|
|
|||
|
default:
|
|||
|
ASSERT(0);
|
|||
|
/* fall through */
|
|||
|
|
|||
|
case M_ERROR:
|
|||
|
break;
|
|||
|
}
|
|||
|
|
|||
|
if (rerror) {
|
|||
|
SHpStreamError(&(ms->e_readers), rerror);
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// in response to an M_ERROR or M_HANGUP for the write-side, fail
|
|||
|
// any pending ioctl(), putmsg() or write() requests.
|
|||
|
//
|
|||
|
// If a pending ioctl() is being failed, don't forget to abort its
|
|||
|
// timeout !!
|
|||
|
//
|
|||
|
if (werror) {
|
|||
|
irp = ms->e_active_ioctl;
|
|||
|
|
|||
|
if (irp) {
|
|||
|
ms->e_active_ioctl = NULL;
|
|||
|
succeeded = 1;
|
|||
|
|
|||
|
if (irp->IoStatus.Information) {
|
|||
|
succeeded = untimeout((int)irp->IoStatus.Information);
|
|||
|
|
|||
|
ASSERT((succeeded == 0) || (succeeded == 1));
|
|||
|
}
|
|||
|
|
|||
|
if (succeeded) {
|
|||
|
SHpGenReply(irp, -1, werror);
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
SHpStreamError(&(ms->e_ioctlers), werror);
|
|||
|
SHpStreamError(&(ms->e_writers), werror);
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// let poll()'ers know of the error/hangup
|
|||
|
//
|
|||
|
KeReleaseSemaphore(
|
|||
|
&Poll_fired, // semaphore
|
|||
|
SEMAPHORE_INCREMENT, // priority increment
|
|||
|
1, // adjustment
|
|||
|
FALSE // wait
|
|||
|
);
|
|||
|
|
|||
|
IF_STRMDBG(CALL) {
|
|||
|
STRMTRACE(("SHEAD: strmevent(ms = %lx) completed\n", ms));
|
|||
|
}
|
|||
|
return;
|
|||
|
|
|||
|
} // strmevent
|