pty select() support
This commit is contained in:
parent
2713ed6cde
commit
0e3bef8597
3 changed files with 120 additions and 53 deletions
|
@ -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 */
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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 */
|
||||
|
|
Loading…
Reference in a new issue