From: Ben Gras Date: Fri, 5 Aug 2005 13:50:58 +0000 (+0000) Subject: pty select() support X-Git-Tag: v3.1.0~427 X-Git-Url: http://zhaoyanbai.com/repos/README?a=commitdiff_plain;h=0e3bef859756eb4866a16a8657765d45292acaf4;p=minix.git pty select() support --- diff --git a/drivers/tty/pty.c b/drivers/tty/pty.c index cdbf27efd..3977002b9 100644 --- a/drivers/tty/pty.c +++ b/drivers/tty/pty.c @@ -22,6 +22,7 @@ #include #include #include +#include #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; istate & 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 */ diff --git a/drivers/tty/tty.c b/drivers/tty/tty.c index 438295b78..ec4bad598 100644 --- a/drivers/tty/tty.c +++ b/drivers/tty/tty.c @@ -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); diff --git a/drivers/tty/tty.h b/drivers/tty/tty.h index 4dff4dd03..9ea6df5d7 100644 --- a/drivers/tty/tty.h +++ b/drivers/tty/tty.h @@ -2,6 +2,13 @@ #include +/* 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 */