From 97172a1db0316f3687646b1ff318d7198bcdf913 Mon Sep 17 00:00:00 2001 From: David van Moolenbroek Date: Fri, 30 Aug 2013 10:48:34 +0200 Subject: [PATCH] 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 --- drivers/log/log.c | 4 +- drivers/printer/printer.c | 5 ++- drivers/tty/arch/i386/keyboard.c | 4 ++ drivers/tty/pty.c | 13 ++++++- drivers/tty/tty.c | 48 +++++++++++++++-------- servers/inet/sr.c | 19 ++++++--- servers/vfs/device.c | 67 +++++++++----------------------- 7 files changed, 85 insertions(+), 75 deletions(-) diff --git a/drivers/log/log.c b/drivers/log/log.c index 5de3d89df..756d59088 100644 --- a/drivers/log/log.c +++ b/drivers/log/log.c @@ -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; diff --git a/drivers/printer/printer.c b/drivers/printer/printer.c index 5ab2a9491..a0059f91b 100644 --- a/drivers/printer/printer.c +++ b/drivers/printer/printer.c @@ -220,8 +220,9 @@ register message *m_ptr; /* pointer to the newly arrived message */ /* Reject command if last write is not yet finished, the count is not * positive, or the user address is bad. */ - if (writing) r = EIO; - else if (m_ptr->COUNT <= 0) r = EINVAL; + 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); diff --git a/drivers/tty/arch/i386/keyboard.c b/drivers/tty/arch/i386/keyboard.c index fb02ce2a8..20d0dfc1d 100644 --- a/drivers/tty/arch/i386/keyboard.c +++ b/drivers/tty/arch/i386/keyboard.c @@ -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; diff --git a/drivers/tty/pty.c b/drivers/tty/pty.c index 72e4724eb..f009fa23b 100644 --- a/drivers/tty/pty.c +++ b/drivers/tty/pty.c @@ -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; } diff --git a/drivers/tty/tty.c b/drivers/tty/tty.c index bc532cc04..894571d84 100644 --- a/drivers/tty/tty.c +++ b/drivers/tty/tty.c @@ -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,11 +688,16 @@ 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. - */ - r = SUSPEND; /* suspend the caller */ - tp->tty_inrepcode = TTY_REVIVE; + /* 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) @@ -728,11 +736,15 @@ 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. - */ - r = SUSPEND; /* suspend the caller */ - tp->tty_outrepcode = TTY_REVIVE; + /* 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) { - /* 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; + 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; diff --git a/servers/inet/sr.c b/servers/inet/sr.c index a84792c45..201bdd467 100644 --- a/servers/inet/sr.c +++ b/servers/inet/sr.c @@ -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; } diff --git a/servers/vfs/device.c b/servers/vfs/device.c index 4d0ce596d..a4a7d5d8c 100644 --- a/servers/vfs/device.c +++ b/servers/vfs/device.c @@ -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,33 +454,28 @@ 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 { - /* select() will do suspending itself. */ - if(op != DEV_SELECT) { - /* Suspend user. */ - wait_for(dp->dmap_driver); - } - assert(!GRANT_VALID(fp->fp_grant)); - 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); + 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. */ + wait_for(dp->dmap_driver); + } + assert(!GRANT_VALID(fp->fp_grant)); + fp->fp_grant = gid; /* revoke this when unsuspended. */ + fp->fp_ioproc = ioproc; + + return(SUSPEND); } /* No suspend, or cancelled suspend, so I/O is over and can be cleaned up. */ -- 2.44.0