pty select() support

This commit is contained in:
Ben Gras 2005-08-05 13:50:58 +00:00
parent 2713ed6cde
commit 0e3bef8597
3 changed files with 120 additions and 53 deletions

View file

@ -22,6 +22,7 @@
#include <signal.h>
#include <minix/com.h>
#include <minix/callnr.h>
#include <sys/select.h>
#include "tty.h"
#if NR_PTYS > 0
@ -51,6 +52,11 @@ typedef struct pty {
int ocount; /* # characters in the buffer */
char *ohead, *otail; /* head and tail of the circular buffer */
char obuf[128]; /* buffer for bytes going to the pty reader */
/* select() data. */
int select_ops, /* Which operations do we want to know about? */
select_proc, /* Who wants to know about it? */
select_ready_ops; /* For callback. */
} pty_t;
#define PTY_ACTIVE 0x01 /* pty is open/active */
@ -64,10 +70,11 @@ FORWARD _PROTOTYPE( int pty_write, (tty_t *tp, int try) );
FORWARD _PROTOTYPE( void pty_echo, (tty_t *tp, int c) );
FORWARD _PROTOTYPE( void pty_start, (pty_t *pp) );
FORWARD _PROTOTYPE( void pty_finish, (pty_t *pp) );
FORWARD _PROTOTYPE( int pty_read, (tty_t *tp, int try) );
FORWARD _PROTOTYPE( int pty_close, (tty_t *tp, int try) );
FORWARD _PROTOTYPE( int pty_icancel, (tty_t *tp, int try) );
FORWARD _PROTOTYPE( int pty_ocancel, (tty_t *tp, int try) );
FORWARD _PROTOTYPE( int pty_read, (tty_t *tp, int try) );
FORWARD _PROTOTYPE( int pty_close, (tty_t *tp, int try) );
FORWARD _PROTOTYPE( int pty_icancel, (tty_t *tp, int try) );
FORWARD _PROTOTYPE( int pty_ocancel, (tty_t *tp, int try) );
FORWARD _PROTOTYPE( int pty_select, (tty_t *tp, message *m) );
/*==========================================================================*
@ -182,6 +189,10 @@ message *m_ptr;
}
break;
case DEV_SELECT:
r = pty_select(tp, m_ptr);
break;
case CANCEL:
if (m_ptr->PROC_NR == pp->rdproc) {
/* Cancel a read from a PTY. */
@ -215,6 +226,7 @@ int try;
int count, ocount, s;
phys_bytes user_phys;
/* PTY closed down? */
if (pp->state & PTY_CLOSED) {
if(try) return 1;
@ -229,14 +241,12 @@ int try;
/* While there is something to do. */
for (;;) {
ocount = buflen(pp->obuf) - pp->ocount;
if(try) return (ocount > 0);
count = bufend(pp->obuf) - pp->ohead;
if (count > ocount) count = ocount;
if (count > tp->tty_outleft) count = tp->tty_outleft;
if (count == 0 || tp->tty_inhibited) {
if(try) return 0;
if (count == 0 || tp->tty_inhibited)
break;
}
if(try) return 1;
/* Copy from user space to the PTY output buffer. */
if((s = sys_vircopy(tp->tty_outproc, D, (vir_bytes) tp->tty_out_vir,
@ -339,7 +349,6 @@ pty_t *pp;
/* Finish the read request of a PTY reader if there is at least one byte
* transferred.
*/
if (pp->rdcum > 0) {
if (pp->rdsendreply) {
tty_reply(TASK_REPLY, pp->rdcaller, pp->rdproc, pp->rdcum);
@ -348,6 +357,7 @@ pty_t *pp;
else
notify(pp->rdcaller);
}
}
@ -364,6 +374,7 @@ int try;
pty_t *pp = tp->tty_priv;
char c;
if (pp->state & PTY_CLOSED) {
if(try) return 1;
if (tp->tty_inleft > 0) {
@ -482,6 +493,7 @@ tty_t *tp;
line = tp - &tty_table[NR_CONS + NR_RS_LINES];
pp = tp->tty_priv = &pty_table[line];
pp->tty = tp;
pp->select_ops = 0;
/* Set up output queue. */
pp->ohead = pp->otail = pp->obuf;
@ -493,6 +505,7 @@ tty_t *tp;
tp->tty_icancel = pty_icancel;
tp->tty_ocancel = pty_ocancel;
tp->tty_close = pty_close;
tp->tty_select_ops = 0;
}
@ -506,7 +519,7 @@ PUBLIC int pty_status(message *m_ptr)
event_found = 0;
for (i= 0, pp = pty_table; i<NR_PTYS; i++, pp++) {
if (((pp->state & TTY_CLOSED && pp->rdleft > 0) ||
if ((((pp->state & TTY_CLOSED) && pp->rdleft > 0) ||
pp->rdcum > 0) &&
pp->rdcaller == m_ptr->m_source)
{
@ -519,7 +532,7 @@ PUBLIC int pty_status(message *m_ptr)
break;
}
if (((pp->state & TTY_CLOSED && pp->wrleft > 0) ||
if ((((pp->state & TTY_CLOSED) && pp->wrleft > 0) ||
pp->wrcum > 0) &&
pp->wrcaller == m_ptr->m_source)
{
@ -534,8 +547,79 @@ PUBLIC int pty_status(message *m_ptr)
event_found = 1;
break;
}
if(pp->select_ready_ops && pp->select_proc == m_ptr->m_source) {
m_ptr->m_type = DEV_IO_READY;
m_ptr->DEV_MINOR = PTYPX_MINOR + i;
m_ptr->DEV_SEL_OPS = pp->select_ready_ops;
pp->select_ready_ops = 0;
event_found = 1;
break;
}
}
return event_found;
}
/*==========================================================================*
* select_try_pty *
*==========================================================================*/
PRIVATE int select_try_pty(tty_t *tp, int ops)
{
pty_t *pp = tp->tty_priv;
int r = 0;
if(ops & SEL_WR) {
/* Write won't block on error. */
if (pp->state & TTY_CLOSED) r |= SEL_WR;
else if (pp->wrleft != 0 || pp->wrcum != 0) r |= SEL_WR;
else r |= SEL_WR;
}
if(ops & SEL_RD) {
/* Read won't block on error. */
if (pp->state & TTY_CLOSED) r |= SEL_RD;
else if(pp->rdleft != 0 || pp->rdcum != 0) r |= SEL_RD;
else if(pp->ocount > 0) r |= SEL_RD; /* Actual data. */
}
return r;
}
/*==========================================================================*
* select_retry_pty *
*==========================================================================*/
PUBLIC void select_retry_pty(tty_t *tp)
{
pty_t *pp = tp->tty_priv;
int r;
/* See if the pty side of a pty is ready to return a select. */
if(pp->select_ops && (r=select_try_pty(tp, pp->select_ops))) {
pp->select_ops &= ~r;
pp->select_ready_ops |= r;
notify(pp->select_proc);
}
}
/*==========================================================================*
* pty_select *
*==========================================================================*/
PRIVATE int pty_select(tty_t *tp, message *m)
{
pty_t *pp = tp->tty_priv;
int ops, ready_ops = 0, watch;
ops = m->PROC_NR & (SEL_RD|SEL_WR|SEL_ERR);
watch = (m->PROC_NR & SEL_NOTIFY) ? 1 : 0;
ready_ops = select_try_pty(tp, ops);
if(!ready_ops && ops && watch) {
pp->select_ops |= ops;
pp->select_proc = m->m_source;
}
return ready_ops;
}
#endif /* NR_PTYS > 0 */

View file

@ -82,15 +82,9 @@ unsigned long rs_irq_set = 0;
/* Address of a tty structure. */
#define tty_addr(line) (&tty_table[line])
/* First minor numbers for the various classes of TTY devices. */
#define CONS_MINOR 0
#define LOG_MINOR 15
#define RS232_MINOR 16
#define TTYPX_MINOR 128
#define PTYPX_MINOR 192
/* Macros for magic tty types. */
#define isconsole(tp) ((tp) < tty_addr(NR_CONS))
#define ispty(tp) ((tp) >= tty_addr(NR_CONS+NR_RS_LINES))
/* Macros for magic tty structure pointers. */
#define FIRST_TTY tty_addr(0)
@ -181,7 +175,6 @@ PUBLIC void main(void)
panic("TTY","Couldn't obtain kernel environment.", s);
}
printf("\n");
while (TRUE) {
/* Check for and handle any events on any of the ttys. */
@ -476,11 +469,8 @@ register message *m_ptr; /* pointer to message sent to the task */
/* Try to write. */
handle_events(tp);
if (tp->tty_outleft == 0) {
if(tp->tty_select_ops)
select_retry(tp);
return; /* already done */
}
if (tp->tty_outleft == 0)
return; /* already done */
/* None or not all the bytes could be written, so either suspend the
* caller or break off the write if nonblocking.
@ -494,8 +484,6 @@ register message *m_ptr; /* pointer to message sent to the task */
}
}
tty_reply(TASK_REPLY, m_ptr->m_source, m_ptr->PROC_NR, r);
if(tp->tty_select_ops)
select_retry(tp);
}
@ -807,7 +795,6 @@ PUBLIC int select_try(struct tty *tp, int ops)
* (and it can be seen as an exceptional condition.)
*/
if (tp->tty_termios.c_ospeed == B0) {
printf("tty: hangup always ok\n");
ready_ops |= ops;
}
@ -816,8 +803,8 @@ PUBLIC int select_try(struct tty *tp, int ops)
if (tp->tty_inleft > 0) {
ready_ops |= SEL_RD; /* EIO - no blocking */
} else if(tp->tty_incount > 0) {
/* is a regular read possible? tty_incount
* says there is data. but a read will only succeed
/* Is a regular read possible? tty_incount
* says there is data. But a read will only succeed
* in canonical mode if a newline has been seen.
*/
if(!(tp->tty_termios.c_lflag & ICANON) ||
@ -827,13 +814,9 @@ PUBLIC int select_try(struct tty *tp, int ops)
}
}
if(ops & SEL_WR) {
if (tp->tty_outleft > 0) {
ready_ops |= SEL_WR; /* EIO - no blocking */
}
if((*tp->tty_devwrite)(tp, 1)) {
ready_ops |= SEL_WR; /* real write possible */
}
if(ops & SEL_WR) {
if (tp->tty_outleft > 0) ready_ops |= SEL_WR;
else if((*tp->tty_devwrite)(tp, 1)) ready_ops |= SEL_WR;
}
return ready_ops;
@ -841,21 +824,8 @@ PUBLIC int select_try(struct tty *tp, int ops)
PUBLIC int select_retry(struct tty *tp)
{
#if DEAD_CODE
int ops;
if((ops = select_try(tp, tp->tty_select_ops))) {
message m;
m.NOTIFY_TYPE = DEV_SELECTED;
m.NOTIFY_ARG = tp->tty_index;
m.NOTIFY_FLAGS = ops;
notify(tp->tty_select_proc, &m);
tp->tty_select_ops &= ~ops;
}
#else
if (select_try(tp, tp->tty_select_ops))
notify(tp->tty_select_proc);
#endif
return OK;
}
@ -915,6 +885,10 @@ tty_t *tp; /* TTY to check for events. */
tp->tty_inleft = tp->tty_incum = 0;
#endif
}
if(tp->tty_select_ops)
select_retry(tp);
if(ispty(tp))
select_retry_pty(tp);
}
@ -1559,11 +1533,14 @@ PRIVATE void tty_init()
tty_devnop;
if (tp < tty_addr(NR_CONS)) {
scr_init(tp);
tp->tty_minor = CONS_MINOR + s;
} else
if (tp < tty_addr(NR_CONS+NR_RS_LINES)) {
rs_init(tp);
tp->tty_minor = RS232_MINOR + s-NR_CONS;
} else {
pty_init(tp);
tp->tty_minor = s + TTYPX_MINOR + s-(NR_CONS+RS232_MINOR);
}
}
@ -1671,7 +1648,6 @@ register tty_t *tp; /* pointer to tty struct */
register message *m_ptr; /* pointer to message sent to the task */
{
int ops, ready_ops = 0, watch;
printf("doing select..\n");
ops = m_ptr->PROC_NR & (SEL_RD|SEL_WR|SEL_ERR);
watch = (m_ptr->PROC_NR & SEL_NOTIFY) ? 1 : 0;
@ -1679,11 +1655,9 @@ register message *m_ptr; /* pointer to message sent to the task */
ready_ops = select_try(tp, ops);
if(!ready_ops && ops && watch) {
printf("doing select.. ops %d\n", ops);
tp->tty_select_ops |= ops;
tp->tty_select_proc = m_ptr->m_source;
} else printf("not doing select.. ready_ops %d ops %d watch %d\n",
ready_ops, ops, watch);
}
tty_reply(TASK_REPLY, m_ptr->m_source, m_ptr->PROC_NR, ready_ops);

View file

@ -2,6 +2,13 @@
#include <timers.h>
/* First minor numbers for the various classes of TTY devices. */
#define CONS_MINOR 0
#define LOG_MINOR 15
#define RS232_MINOR 16
#define TTYPX_MINOR 128
#define PTYPX_MINOR 192
#define LINEWRAP 1 /* console.c - wrap lines at column 80 */
#define TTY_IN_BYTES 256 /* tty input queue size */
@ -20,6 +27,7 @@ typedef _PROTOTYPE( void (*devfunarg_t), (struct tty *tp, int c) );
typedef struct tty {
int tty_events; /* set when TTY should inspect this line */
int tty_index; /* index into TTY table */
int tty_minor; /* device minor number */
/* Input queue. Typed characters are stored here until read by a program. */
u16_t *tty_inhead; /* pointer to place where next char goes */
@ -156,6 +164,7 @@ _PROTOTYPE( void kbd_interrupt, (message *m) );
/* pty.c */
_PROTOTYPE( void do_pty, (struct tty *tp, message *m_ptr) );
_PROTOTYPE( void pty_init, (struct tty *tp) );
_PROTOTYPE( void select_retry_pty, (struct tty *tp) );
_PROTOTYPE( int pty_status, (message *m_ptr) );
/* vidcopy.s */