]> Zhao Yanbai Git Server - minix.git/commitdiff
pty select() support
authorBen Gras <ben@minix3.org>
Fri, 5 Aug 2005 13:50:58 +0000 (13:50 +0000)
committerBen Gras <ben@minix3.org>
Fri, 5 Aug 2005 13:50:58 +0000 (13:50 +0000)
drivers/tty/pty.c
drivers/tty/tty.c
drivers/tty/tty.h

index cdbf27efdcd11bbd644b16bae07c6a9b67131084..3977002b9243678c8ccde59f62d1b9bac023c6f4 100644 (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 */
index 438295b7845bb42c70eae97f71bf7d50aa207099..ec4bad598f0eb13883a3e7c8d86bc583dee09ddc 100644 (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);
 
index 4dff4dd033ee6af276181a3d5ed71c7e27b4274b..9ea6df5d787a694131854224d01243c8acb9b3ae 100644 (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 */