r = EINVAL;
break;
}
+ if (pp->rdgrant != GRANT_INVALID) {
+ r = ENOBUFS;
+ break;
+ }
pp->rdsendreply = TRUE;
pp->rdcaller = m_ptr->m_source;
pp->rdproc = m_ptr->USER_ENDPT;
pty_start(pp);
handle_events(tp);
if (pp->rdleft == 0) {
+ pp->rdgrant = GRANT_INVALID;
return; /* already done */
}
r = EINVAL;
break;
}
+ if (pp->wrgrant != GRANT_INVALID) {
+ r = ENOBUFS;
+ break;
+ }
pp->wrsendreply = TRUE;
pp->wrcaller = m_ptr->m_source;
pp->wrproc = m_ptr->USER_ENDPT;
pp->wrleft = m_ptr->COUNT;
handle_events(tp);
if (pp->wrleft == 0) {
+ pp->wrgrant = GRANT_INVALID;
return; /* already done */
}
/* Cancel a read from a PTY. */
r = pp->rdcum > 0 ? pp->rdcum : EAGAIN;
pp->rdleft = pp->rdcum = 0;
+ pp->rdgrant = GRANT_INVALID;
}
if (m_ptr->USER_ENDPT == pp->wrproc) {
/* Cancel a write to a PTY. */
r = pp->wrcum > 0 ? pp->wrcum : EAGAIN;
pp->wrleft = pp->wrcum = 0;
+ pp->wrgrant = GRANT_INVALID;
}
break;
pp = tp->tty_priv = &pty_table[line];
pp->tty = tp;
pp->select_ops = 0;
+ pp->rdgrant = GRANT_INVALID;
+ pp->wrgrant = GRANT_INVALID;
/* Set up output queue. */
pp->ohead = pp->otail = pp->obuf;
m_ptr->REP_ENDPT = pp->rdproc;
m_ptr->REP_IO_GRANT = pp->rdgrant;
m_ptr->REP_STATUS = pp->rdcum;
-
pp->rdleft = pp->rdcum = 0;
+ pp->rdgrant = GRANT_INVALID;
event_found = 1;
break;
}
m_ptr->REP_STATUS = pp->wrcum;
pp->wrleft = pp->wrcum = 0;
+ pp->wrgrant = GRANT_INVALID;
event_found = 1;
break;
}
tp->tty_inleft = tp->tty_incum = 0;
tp->tty_inrevived = 0; /* unmark revive event */
- event_found = 1;
- break;
+ tp->tty_ingrant = GRANT_INVALID;
+ event_found = 1;
+ break;
}
else if (tp->tty_outrevived && tp->tty_outcaller == m_ptr->m_source) {
tp->tty_outcum = 0;
tp->tty_outrevived = 0; /* unmark revive event */
- event_found = 1;
- break;
+ tp->tty_outgrant = GRANT_INVALID;
+ event_found = 1;
+ break;
}
else if (tp->tty_iorevived && tp->tty_iocaller == m_ptr->m_source) {
+
/* Suspended request finished. Send a REVIVE. */
m_ptr->m_type = DEV_REVIVE;
m_ptr->REP_ENDPT = tp->tty_ioproc;
m_ptr->REP_IO_GRANT = tp->tty_iogrant;
m_ptr->REP_STATUS = tp->tty_iostatus;
tp->tty_iorevived = 0; /* unmark revive event */
- event_found = 1;
- break;
+ tp->tty_iogrant = GRANT_INVALID;
+ event_found = 1;
+ break;
}
}
} else
if (m_ptr->COUNT <= 0) {
r = EINVAL;
+ } else if (tp->tty_ingrant != GRANT_INVALID) {
+ /* This is actually a fundamental problem with TTY; it can handle
+ * only one reader per minor device. If we don't return an error,
+ * we'll overwrite the previous reader and that process will get
+ * stuck forever. */
+ r = ENOBUFS;
} else {
/* Copy information from the message to the tty struct. */
tp->tty_inrepcode = TASK_REPLY;
/* ...then go back for more. */
handle_events(tp);
if (tp->tty_inleft == 0) {
- if (tp->tty_select_ops)
- select_retry(tp);
return; /* already done */
}
/* Try to write. */
handle_events(tp);
- if (tp->tty_outleft == 0)
+ if (tp->tty_outleft == 0)
return; /* already done */
/* None or not all the bytes could be written, so suspend the
tty_icancel(tp);
r = tp->tty_incum > 0 ? tp->tty_incum : EAGAIN;
tp->tty_inleft = tp->tty_incum = tp->tty_inrevived = 0;
+ tp->tty_ingrant = GRANT_INVALID;
}
if ((mode & W_BIT) && tp->tty_outleft != 0 && proc_nr == tp->tty_outproc &&
tp->tty_outgrant == (cp_grant_id_t) m_ptr->IO_GRANT) {
/* Process was writing when killed. Clean up output. */
r = tp->tty_outcum > 0 ? tp->tty_outcum : EAGAIN;
tp->tty_outleft = tp->tty_outcum = tp->tty_outrevived = 0;
+ tp->tty_outgrant = GRANT_INVALID;
}
if (tp->tty_ioreq != 0 && proc_nr == tp->tty_ioproc) {
/* Process was waiting for output to drain. */
tty_reply(tp->tty_inrepcode, tp->tty_incaller,
tp->tty_inproc, tp->tty_incum);
tp->tty_inleft = tp->tty_incum = 0;
+ tp->tty_inrevived = 0;
+ tp->tty_ingrant = GRANT_INVALID;
}
}
if (tp->tty_select_ops)
tty_reply(tp->tty_inrepcode, tp->tty_incaller,
tp->tty_inproc, tp->tty_incum);
tp->tty_inleft = tp->tty_incum = 0;
+ tp->tty_inrevived = 0;
+ tp->tty_ingrant = GRANT_INVALID;
}
}
}
tp->tty_intail = tp->tty_inhead = tp->tty_inbuf;
tp->tty_min = 1;
+ tp->tty_ingrant = tp->tty_outgrant = tp->tty_iogrant = GRANT_INVALID;
tp->tty_termios = termios_defaults;
tp->tty_icancel = tp->tty_ocancel = tp->tty_ioctl = tp->tty_close =
tty_devnop;