Sync char protocol: add nonblocking transfer flag

The async char protocol already has this, so this patch closes the
gap between the two protocols a bit. Support for this flag has been
added to all sync char drivers that support CANCEL at all.

The LOG driver was already using the asynchronous protocol, but it
did not support the nonblocking transfer flag. This has been fixed
as well.

Change-Id: Ia55432c9f102765b59ad3feb45a8bd47a782c93f
This commit is contained in:
David van Moolenbroek 2013-08-30 10:48:34 +02:00 committed by Lionel Sambuc
parent a75c47e5ac
commit 97172a1db0
7 changed files with 85 additions and 75 deletions

View file

@ -282,7 +282,7 @@ static int log_transfer(
iovec_t *iov, /* pointer to read or write request vector */
unsigned int nr_req, /* length of request vector */
endpoint_t user_endpt, /* endpoint of user process */
unsigned int UNUSED(flags)
unsigned int flags
)
{
/* Read or write one the driver's minor devices. */
@ -317,6 +317,8 @@ static int log_transfer(
if (!log->log_size) {
if(accumulated_read)
return OK;
if (flags & FLG_OP_NONBLOCK)
return EAGAIN;
/* No data available; let caller block. */
log->log_source = endpt;
log->log_iosize = count;

View file

@ -222,6 +222,7 @@ register message *m_ptr; /* pointer to the newly arrived message */
*/
if (writing) r = EIO;
else if (m_ptr->COUNT <= 0) r = EINVAL;
else if (m_ptr->FLAGS & FLG_OP_NONBLOCK) r = EAGAIN; /* not supported */
/* Reply to FS, no matter what happened, possible SUSPEND caller. */
reply(TASK_REPLY, m_ptr->m_source, m_ptr->USER_ENDPT, r);

View file

@ -246,6 +246,10 @@ message *m;
}
if (kbdp->avail == 0)
{
if (m->FLAGS & FLG_OP_NONBLOCK) {
r = EAGAIN;
break;
}
/* Should record proc */
kbdp->req_size= m->COUNT;
kbdp->req_proc= m->USER_ENDPT;

View file

@ -118,7 +118,11 @@ void do_pty(tty_t *tp, message *m_ptr)
return; /* already done */
}
{
if (m_ptr->FLAGS & FLG_OP_NONBLOCK) {
r = pp->rdcum > 0 ? pp->rdcum : EAGAIN;
pp->rdleft = pp->rdcum = 0;
pp->rdgrant = GRANT_INVALID;
} else {
r = SUSPEND; /* do suspend */
pp->rdsendreply = FALSE;
}
@ -154,7 +158,12 @@ void do_pty(tty_t *tp, message *m_ptr)
return; /* already done */
}
{
if (m_ptr->FLAGS & FLG_OP_NONBLOCK) {
r = pp->wrcum > 0 ? pp->wrcum : EAGAIN;
pp->wrleft = pp->wrcum = 0;
pp->wrgrant = GRANT_INVALID;
r = EAGAIN;
} else {
pp->wrsendreply = FALSE; /* do suspend */
r = SUSPEND;
}

View file

@ -309,6 +309,7 @@ set_color(tty_t *tp, int color)
buf[0] = '\033';
snprintf(&buf[1], sizeof(buf) - 1, "[1;%dm", color);
memset(&msg, 0, sizeof(msg));
msg.m_source = KERNEL;
msg.IO_GRANT = buf;
msg.COUNT = sizeof(buf);
@ -324,6 +325,7 @@ reset_color(tty_t *tp)
#define SGR_COLOR_RESET 39
buf[0] = '\033';
snprintf(&buf[1], sizeof(buf) - 1, "[0;%dm", SGR_COLOR_RESET);
memset(&msg, 0, sizeof(msg));
msg.m_source = KERNEL;
msg.IO_GRANT = buf;
msg.COUNT = sizeof(buf);
@ -499,6 +501,7 @@ do_new_kmess(void)
if (kernel_msg_color != 0)
set_color(tp, kernel_msg_color);
memset(&print_kmsg, 0, sizeof(print_kmsg));
print_kmsg.m_source = KERNEL;
print_kmsg.IO_GRANT = kernel_buf_copy;
print_kmsg.COUNT = bytes;
@ -685,12 +688,17 @@ register message *m_ptr; /* pointer to message sent to the task */
return; /* already done */
}
/* There were no bytes in the input queue available, so suspend
* the caller.
*/
/* There were no bytes in the input queue available. */
if (m_ptr->FLAGS & FLG_OP_NONBLOCK) {
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;
} else {
r = SUSPEND; /* suspend the caller */
tp->tty_inrepcode = TTY_REVIVE;
}
}
tty_reply(TASK_REPLY, m_ptr->m_source, m_ptr->USER_ENDPT, r);
if (tp->tty_select_ops)
select_retry(tp);
@ -728,12 +736,16 @@ register message *m_ptr; /* pointer to message sent to the task */
if (tp->tty_outleft == 0)
return; /* already done */
/* None or not all the bytes could be written, so suspend the
* caller.
*/
/* None or not all the bytes could be written. */
if (m_ptr->FLAGS & FLG_OP_NONBLOCK) {
r = tp->tty_outcum > 0 ? tp->tty_outcum : EAGAIN;
tp->tty_outleft = tp->tty_outcum = tp->tty_outrevived = 0;
tp->tty_outgrant = GRANT_INVALID;
} else {
r = SUSPEND; /* suspend the caller */
tp->tty_outrepcode = TTY_REVIVE;
}
}
tty_reply(TASK_REPLY, m_ptr->m_source, m_ptr->USER_ENDPT, r);
}
@ -800,12 +812,16 @@ message *m_ptr; /* pointer to message sent to task */
case TCSETSF:
case TCDRAIN:
if (tp->tty_outleft > 0) {
if (m_ptr->FLAGS & FLG_OP_NONBLOCK) {
r = EAGAIN;
} else {
/* Wait for all ongoing output processing to finish. */
tp->tty_iocaller = m_ptr->m_source;
tp->tty_ioproc = m_ptr->USER_ENDPT;
tp->tty_ioreq = m_ptr->REQUEST;
tp->tty_iogrant = (cp_grant_id_t) m_ptr->IO_GRANT;
r = SUSPEND;
}
break;
}
if (m_ptr->TTY_REQUEST == TCDRAIN) break;

View file

@ -156,9 +156,10 @@ mq_t *m;
case DEV_WRITE_S:
case DEV_IOCTL_S:
result= sr_rwio(m);
assert(result == OK || result == SUSPEND);
send_reply= (result == SUSPEND);
free_mess= 0;
assert(result == OK || result == EAGAIN || result == EINTR ||
result == SUSPEND);
send_reply= (result == EAGAIN || result == SUSPEND);
free_mess= (result == EAGAIN);
break;
case CANCEL:
result= sr_cancel(&m->mq_mess);
@ -323,6 +324,9 @@ mq_t *m;
assert(sr_fd->srf_flags & susp_flag);
assert(*q_head_ptr);
if (m->mq_mess.FLAGS & FLG_OP_NONBLOCK)
return EAGAIN;
(*q_tail_ptr)->mq_next= m;
*q_tail_ptr= m;
return SUSPEND;
@ -368,9 +372,14 @@ mq_t *m;
assert(r == OK || r == SUSPEND ||
(printf("r= %d\n", r), 0));
if (r == SUSPEND)
if (r == SUSPEND) {
sr_fd->srf_flags |= susp_flag;
else
if (m->mq_mess.FLAGS & FLG_OP_NONBLOCK) {
r= sr_cancel(&m->mq_mess);
assert(r == OK); /* must have been head of queue */
return EINTR;
}
} else
mq_free(m);
return r;
}

View file

@ -361,32 +361,6 @@ u32_t *pos_lo;
return(0);
}
static int cancel_nblock(struct dmap * dp,
int minor,
int call,
endpoint_t ioproc,
cp_grant_id_t gid)
{
message dev_mess;
dev_mess.m_type = CANCEL;
dev_mess.USER_ENDPT = ioproc;
dev_mess.IO_GRANT = (char *) gid;
/* This R_BIT/W_BIT check taken from suspend()/unpause()
* logic. Mode is expected in the COUNT field.
*/
dev_mess.COUNT = 0;
if (call == READ)
dev_mess.COUNT = R_BIT;
else if (call == WRITE)
dev_mess.COUNT = W_BIT;
dev_mess.DEVICE = minor;
(*dp->dmap_io)(dp->dmap_driver, &dev_mess);
return dev_mess.REP_STATUS;
}
/*===========================================================================*
* dev_io *
*===========================================================================*/
@ -480,14 +454,18 @@ int dev_io(
ret = dev_mess.REP_STATUS;
/* Legacy support: translate EINTR to EAGAIN for nonblocking calls. */
if (ret == EINTR && (flags & O_NONBLOCK))
ret = EAGAIN;
/* Task has completed. See if call completed. */
if (ret == SUSPEND) {
if ((flags & O_NONBLOCK) && !is_asyn) {
/* Not supposed to block. */
ret = cancel_nblock(dp, minor_dev, job_call_nr, ioproc, gid);
if (ret == EINTR)
ret = EAGAIN;
} else {
printf("VFS: sync char driver %u sent SUSPEND on NONBLOCK\n",
dp->dmap_driver);
/* We'd cancel, but the other side won't play ball anyway.. */
}
/* select() will do suspending itself. */
if(op != DEV_SELECT) {
/* Suspend user. */
@ -497,17 +475,8 @@ int dev_io(
fp->fp_grant = gid; /* revoke this when unsuspended. */
fp->fp_ioproc = ioproc;
if ((flags & O_NONBLOCK) && !is_asyn) {
/* Not supposed to block, send cancel message */
cancel_nblock(dp, minor_dev, job_call_nr, ioproc, gid);
/*
* FIXME Should do something about EINTR -> EAGAIN
* mapping
*/
}
return(SUSPEND);
}
}
/* No suspend, or cancelled suspend, so I/O is over and can be cleaned up. */
if(safe) cpf_revoke(gid);