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. */
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;
/* 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);
}
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;
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;
}
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;
}
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);
#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);
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;
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)
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);
}
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;
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);
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;
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;
}
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 *
*===========================================================================*/
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. */