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. */