bug-hurd
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

the big term patch


From: Marcus Brinkmann
Subject: the big term patch
Date: Thu, 7 Feb 2002 15:16:52 +0100
User-agent: Mutt/1.3.27i

Hi,

this is my current version of the error handling patch plus my new hurdio.c
bottom handler.  I can provide (and apply) both patches seperately, but there
is not much overlap anyway, and it's time for me to not only talk about the
hurdio bottom handler but also to show it to you.  It seems to work
reasonably, but as a terminal has a bit weird semantics, I could only test
it partially so far.  The next step will be to test it with a fifo, there
seems to be a problem in draining the output for that.  So, there are
definitely some bugs.

Another change I will have to do is to change the argument parsing and
startup of term.  I think it should use argp, and allow hurdio translators
to be set up by a normal user.  Currently, it doesn't allow that.

Thanks,
Marcus

Index: ChangeLog
===================================================================
RCS file: /cvsroot/hurd/hurd/term/ChangeLog,v
retrieving revision 1.69
diff -u -r1.69 ChangeLog
--- ChangeLog   30 Jan 2002 17:52:50 -0000      1.69
+++ ChangeLog   7 Feb 2002 14:04:00 -0000
@@ -1,3 +1,73 @@
+2002-02-07  Marcus Brinkmann  <marcus@gnu.org>
+
+       * hurdio.c: New file.
+       * main.c (main): Add hurdio bottom handler case.
+       * users.c (S_term_get_bottom_type): Add TERM_ON_HURDIO case.
+       * term.h (extern struct bottomhalf): Add hurdio_bottom.
+
+2002-02-06  Marcus Brinkmann  <marcus@gnu.org>
+
+       * users.c (set_state): Rework logic to take possible errors into
+       account, and to delay changing the termstate until we know that we
+       won't fail.
+       (open_hook): Call set_bits with correct arguments.
+
+       * munge.c (drop_output): Change return value to error_t.  Only
+       clear queue if there was no error.
+       * term.h: Change return value of drop_output to error_t.
+
+       * users.c (trivfs_S_io_write): Do not call start_output if it just
+       failed, or if there was no data to be written.
+       (S_tioctl_tiocflush): Return errors properly, and clear queue only
+       if notice_input_flushed succeeded.
+
+       * devio.c (devio_set_bits): Accept a pointer to a termios as
+       argument and use that instead the global termstate.
+       * ptyio.c (ptyio_set_bits): Likewise.
+       * term.h (struct bottomhalf): Likewise for set_bits prototype.
+
+2002-02-01  Marcus Brinkmann  <marcus@gnu.org>
+
+       * users.c (open_hook): Save error value of set_bits.  Save old
+       termflags and restore them if if set_bits failed.
+       (S_tioctl_tiocmods): Set err to result of mdmctl.
+       (S_tioctl_tiocmset): Likewise.
+       (S_tioctl_tiocmbic): Likewise.
+       (S_tioctl_tiocmbis): Likewise.
+       (S_tioctl_tioccdtr): Likewise.
+       (S_tioctl_tiocsdtr): Likewise.
+       (S_tioctl_tioccbrk): Likewise for clear_break.
+       (S_tioctl_tiocsbrk): Likewise for set_break.
+       (S_tioctl_tiocstart): Likewise for start_output.  Save old
+       termflags and restore them if if start_output failed.
+       (S_tioctl_tiocstop): Likewise for stop_output.
+       (S_trivfs_io_write): Abort the operation if start_output fails.
+
+       * term.h (struct bottomhalf): Change the return types of the
+       following members from void to error_t: abandon_physical_output,
+       suspend_physical_output, notice_input_flushed, desert_dtr,
+       set_break, clear_break, start_output, set_bits, mdmctl.
+       * devio.c (devio_abandon_physical_output): Change return value to
+       error_t, and return 0.
+       (devio_suspend_physical_output): Likewise.
+       (devio_notice_input_flushed): Likewise.
+       (devio_desert_dtr): Likewise.
+       (devio_set_break): Likewise.
+       (devio_clear_break): Likewise.
+       (devio_start_output): Likewise.
+       (devio_set_bits): Likewise.
+       (devio_mdmctl): Likewise.
+       * ptyio.c (ptyio_suspend_physical_output): Likewise.
+       (ptyio_notice_input_flushed): Likewise.
+       (ptyio_desert_dtr): Likewise.
+       (ptyio_set_bits): Likewise.
+       (ptyio_set_break): Likewise.
+       (ptyio_clear_break): Likewise.
+       (ptyio_mdmctl): Likewise.
+       (ptyio_start_output): Likewise.
+       (ptyio_abandon_physical_output): Likewise.
+
 2002-01-30  Marcus Brinkmann  <marcus@gnu.org>
 
        * users.c (trivfs_S_io_select): Remove IDTAG argument.
Index: Makefile
===================================================================
RCS file: /cvsroot/hurd/hurd/term/Makefile,v
retrieving revision 1.8
diff -u -r1.8 Makefile
--- Makefile    26 Jul 2000 12:22:49 -0000      1.8
+++ Makefile    7 Feb 2002 14:04:00 -0000
@@ -22,7 +22,7 @@
 makemode := server
 
 target = term
-SRCS = devio.c munge.c users.c main.c ptyio.c
+SRCS = devio.c munge.c users.c main.c ptyio.c hurdio.c
 LCLHDRS = term.h
 DIST_FILES = ourmsg.defs
 
Index: devio.c
===================================================================
RCS file: /cvsroot/hurd/hurd/term/devio.c,v
retrieving revision 1.28
diff -u -r1.28 devio.c
--- devio.c     4 Jan 2002 00:11:21 -0000       1.28
+++ devio.c     7 Feb 2002 14:04:01 -0000
@@ -98,7 +98,7 @@
 static int char_size_mask_xxx = 0xff;
 
 /* Forward */
-static void devio_desert_dtr ();
+static error_t devio_desert_dtr ();
 
 static void init_devio (void) __attribute__ ((constructor));
 static void
@@ -237,7 +237,7 @@
 
 /* If there are characters on the output queue and no
    pending output requests, then send them. */
-static void
+static error_t
 devio_start_output ()
 {
   char *cp;
@@ -247,7 +247,7 @@
   size = qsize (outputq);
 
   if (!size || output_pending || (termflags & USER_OUTPUT_SUSP))
-    return;
+    return 0;
 
   if (output_stopped)
     {
@@ -278,6 +278,7 @@
     devio_desert_dtr ();
   else if (!err)
     output_pending = 1;
+  return 0;
 }
 
 error_t
@@ -368,19 +369,21 @@
   return 0;
 }
 
-static void
+static error_t
 devio_set_break ()
 {
   device_set_status (phys_device, TTY_SET_BREAK, 0, 0);
+  return 0;
 }
 
-static void
+static error_t
 devio_clear_break ()
 {
   device_set_status (phys_device, TTY_CLEAR_BREAK, 0, 0);
+  return 0;
 }
 
-static void
+static error_t
 devio_abandon_physical_output ()
 {
   int val = D_WRITE;
@@ -388,7 +391,7 @@
   /* If this variable is clear, then carrier is gone, so we
      have nothing to do. */
   if (!phys_reply_writes_pi)
-    return;
+    return 0;
 
   mach_port_deallocate (mach_task_self (), phys_reply_writes);
   ports_reallocate_port (phys_reply_writes_pi);
@@ -397,9 +400,10 @@
   device_set_status (phys_device, TTY_FLUSH, &val, TTY_FLUSH_COUNT);
   npending_output = 0;
   output_pending = 0;
+  return 0;
 }
 
-static void
+static error_t
 devio_suspend_physical_output ()
 {
   if (!output_stopped)
@@ -407,11 +411,13 @@
       device_set_status (phys_device, TTY_STOP, 0, 0);
       output_stopped = 1;
     }
+  return 0;
 }
 
-static void
+static error_t
 devio_notice_input_flushed ()
 {
+  return 0;
 }
 
 static int
@@ -460,7 +466,7 @@
   return err;
 }
 
-static void
+static error_t
 devio_desert_dtr ()
 {
   int bits;
@@ -471,6 +477,7 @@
                     (dev_status_t) &bits, TTY_MODEM_COUNT);
 
   report_carrier_off ();
+  return 0;
 }
 
 static error_t
@@ -580,20 +587,20 @@
 /* Adjust physical state on the basis of the terminal state.
    Where it isn't possible, mutate terminal state to match
    reality. */
-static void
-devio_set_bits ()
+static error_t
+devio_set_bits (struct termios *state)
 {
-  if (!(termstate.c_cflag & CIGNORE) && phys_device != MACH_PORT_NULL)
+  if (!(state->c_cflag & CIGNORE) && phys_device != MACH_PORT_NULL)
     {
       struct tty_status ttystat;
       int cnt = TTY_STATUS_COUNT;
 
       /* Find the current state. */
       device_get_status (phys_device, TTY_STATUS, (dev_status_t) &ttystat, 
&cnt);
-      if (termstate.__ispeed)
-       real_speed_to_bogus_speed (termstate.__ispeed, &ttystat.tt_ispeed);
-      if (termstate.__ospeed)
-       real_speed_to_bogus_speed (termstate.__ospeed, &ttystat.tt_ospeed);
+      if (state->__ispeed)
+       real_speed_to_bogus_speed (state->__ispeed, &ttystat.tt_ispeed);
+      if (state->__ospeed)
+       real_speed_to_bogus_speed (state->__ospeed, &ttystat.tt_ospeed);
 
       /* Try and set it. */
       device_set_status (phys_device, TTY_STATUS,
@@ -602,19 +609,19 @@
       /* And now make termstate match reality. */
       cnt = TTY_STATUS_COUNT;
       device_get_status (phys_device, TTY_STATUS, (dev_status_t) &ttystat, 
&cnt);
-      termstate.__ispeed = bogus_speed_to_real_speed (ttystat.tt_ispeed);
-      termstate.__ospeed = bogus_speed_to_real_speed (ttystat.tt_ospeed);
+      state->__ispeed = bogus_speed_to_real_speed (ttystat.tt_ispeed);
+      state->__ospeed = bogus_speed_to_real_speed (ttystat.tt_ospeed);
 
       /* Mach forces us to use the normal stop bit convention:
         two bits at 110 bps; 1 bit otherwise. */
-      if (termstate.__ispeed == 110)
-       termstate.c_cflag |= CSTOPB;
+      if (state->__ispeed == 110)
+       state->c_cflag |= CSTOPB;
       else
-       termstate.c_cflag &= ~CSTOPB;
+       state->c_cflag &= ~CSTOPB;
 
       /* Figure out how to munge input, since we are unable to actually
         affect what the hardware does. */
-      switch (termstate.c_cflag & CSIZE)
+      switch (state->c_cflag & CSIZE)
        {
        case CS5:
          char_size_mask_xxx = 0x1f;
@@ -633,12 +640,13 @@
          char_size_mask_xxx = 0xff;
          break;
        }
-      if (termstate.c_cflag & PARENB)
+      if (state->c_cflag & PARENB)
        char_size_mask_xxx |= 0x80;
     }
+  return 0;
 }
 
-static void
+static error_t
 devio_mdmctl (int how, int bits)
 {
   int oldbits, newbits;
@@ -661,6 +669,8 @@
 
   device_set_status (phys_device, TTY_MODEM,
                     (dev_status_t) &newbits, TTY_MODEM_COUNT);
+
+  return 0;
 }
 
 static int
Index: main.c
===================================================================
RCS file: /cvsroot/hurd/hurd/term/main.c,v
retrieving revision 1.22
diff -u -r1.22 main.c
--- main.c      17 Mar 2000 17:26:00 -0000      1.22
+++ main.c      7 Feb 2002 14:04:02 -0000
@@ -88,6 +88,18 @@
       peercntl = 0;
       pterm_name = argv[3];
     }
+  if (!strcmp (argv[2], "hurdio"))
+    {
+      type = T_DEVICE;
+      bottom = &hurdio_bottom;
+      ourclass = tty_class;
+      ourcntlclass = tty_cntl_class;
+      ourcntl = &termctl;
+      peerclass = 0;
+      peercntlclass = 0;
+      peercntl = 0;
+      pterm_name = argv[3];
+    }
   else if (!strcmp (argv[2], "pty-master"))
     {
       type = T_PTYMASTER;
Index: munge.c
===================================================================
RCS file: /cvsroot/hurd/hurd/term/munge.c,v
retrieving revision 1.11
diff -u -r1.11 munge.c
--- munge.c     18 Dec 2001 04:05:42 -0000      1.11
+++ munge.c     7 Feb 2002 14:04:03 -0000
@@ -688,12 +688,16 @@
     input_character (unquote_char (buf[i]));
 }
 
-void
+
+error_t
 drop_output ()
 {
-  clear_queue (outputq);
-  (*bottom->abandon_physical_output) ();
+  error_t err = (*bottom->abandon_physical_output) ();
+  if (!err)
+    clear_queue (outputq);
+  return err;
 }
+
 
 error_t
 drain_output ()
Index: ptyio.c
===================================================================
RCS file: /cvsroot/hurd/hurd/term/ptyio.c,v
retrieving revision 1.32
diff -u -r1.32 ptyio.c
--- ptyio.c     30 Jan 2002 17:43:26 -0000      1.32
+++ ptyio.c     7 Feb 2002 14:04:04 -0000
@@ -138,7 +138,7 @@
 
 /* Lower half for tty node */
 
-static void 
+static error_t
 ptyio_start_output ()
 {
   if (packet_mode && output_stopped && (!(termflags & USER_OUTPUT_SUSP)))
@@ -148,9 +148,10 @@
       output_stopped = 0;
     }
   wake_reader ();
+  return 0;
 }
 
-static void
+static error_t
 ptyio_abandon_physical_output ()
 {
   if (packet_mode)
@@ -158,9 +159,10 @@
       control_byte |= TIOCPKT_FLUSHWRITE;
       wake_reader ();
     }
+  return 0;
 }
 
-static void
+static error_t
 ptyio_suspend_physical_output ()
 {
   if (packet_mode)
@@ -170,6 +172,7 @@
       output_stopped = 1;
       wake_reader ();
     }
+  return 0;
 }
 
 static int 
@@ -179,7 +182,7 @@
   return 0;
 }
 
-static void
+static error_t
 ptyio_notice_input_flushed ()
 {
   if (packet_mode)
@@ -187,6 +190,7 @@
       control_byte |= TIOCPKT_FLUSHREAD;
       wake_reader ();
     }
+  return 0;
 }
 
 static error_t 
@@ -196,22 +200,23 @@
   return 0;
 }
 
-static void 
+static error_t 
 ptyio_desert_dtr ()
 {
   dtr_on = 0;
   wake_reader ();
+  return 0;
 }
 
-static void 
-ptyio_set_bits ()
+static error_t 
+ptyio_set_bits (struct termios *state)
 {
   if (packet_mode)
     {
       int wakeup = 0;
-      int stop = ((termstate.c_iflag & IXON) 
-                 && CCEQ (termstate.c_cc[VSTOP], CHAR_DC3)
-                 && CCEQ (termstate.c_cc[VSTART], CHAR_DC1));
+      int stop = ((state->c_iflag & IXON) 
+                 && CCEQ (state->c_cc[VSTOP], CHAR_DC3)
+                 && CCEQ (state->c_cc[VSTART], CHAR_DC1));
   
       if (external_processing)
        {
@@ -237,23 +242,27 @@
       if (wakeup)
        wake_reader ();
     }
+  return 0;
 }
 
 /* These do nothing.  In BSD the associated ioctls get errors, but
    I'd rather just ignore them. */
-static void 
+static error_t 
 ptyio_set_break ()
 {
+  return 0;
 }
 
-static void 
+static error_t
 ptyio_clear_break ()
 {
+  return 0;
 }
 
-static void
+static error_t
 ptyio_mdmctl (int a, int b)
 {
+  return 0;
 }
 
 static int
Index: term.h
===================================================================
RCS file: /cvsroot/hurd/hurd/term/term.h,v
retrieving revision 1.45
diff -u -r1.45 term.h
--- term.h      30 Jan 2002 17:52:50 -0000      1.45
+++ term.h      7 Feb 2002 14:04:04 -0000
@@ -140,22 +140,22 @@
 /* Functions a bottom half defines */
 struct bottomhalf
 {
-  void (*start_output) (void);
-  void (*set_break) (void);
-  void (*clear_break) (void);
-  void (*abandon_physical_output) (void);
-  void (*suspend_physical_output) (void);
+  error_t (*start_output) (void);
+  error_t (*set_break) (void);
+  error_t (*clear_break) (void);
+  error_t (*abandon_physical_output) (void);
+  error_t (*suspend_physical_output) (void);
   int (*pending_output_size) (void);
-  void (*notice_input_flushed) (void);
+  error_t (*notice_input_flushed) (void);
   error_t (*assert_dtr) (void);
-  void (*desert_dtr) (void);
-  void (*set_bits) (void);
-  void (*mdmctl) (int, int);
+  error_t (*desert_dtr) (void);
+  error_t (*set_bits) (struct termios *state);
+  error_t (*mdmctl) (int, int);
   int (*mdmstate) (void);
 };
 
 struct bottomhalf *bottom;
-extern struct bottomhalf devio_bottom, ptyio_bottom;
+extern struct bottomhalf devio_bottom, hurdio_bottom, ptyio_bottom;
 
 
 /* Character queues */
@@ -313,7 +313,7 @@
 
 
 /* Other decls */
-void drop_output (void);
+error_t drop_output (void);
 void send_signal (int);
 error_t drain_output ();
 void output_character (int);
Index: users.c
===================================================================
RCS file: /cvsroot/hurd/hurd/term/users.c,v
retrieving revision 1.93
diff -u -r1.93 users.c
--- users.c     30 Jan 2002 17:43:26 -0000      1.93
+++ users.c     7 Feb 2002 14:04:07 -0000
@@ -212,8 +212,13 @@
 
   if (!err)
     {
-      termflags |= TTY_OPEN;
-      (*bottom->set_bits) ();
+      struct termios state = termstate;
+      err = (*bottom->set_bits) (&state);
+      if (!err)
+       {
+         termstate = state;
+         termflags |= TTY_OPEN;
+       }
     }
 
   mutex_unlock (&global_lock);
@@ -560,6 +565,7 @@
 {
   int i;
   int cancel;
+  error_t err = 0;
 
   if (!cred)
     return EOPNOTSUPP;
@@ -595,9 +601,14 @@
     {
       while (!qavail (outputq) && !cancel)
        {
-         (*bottom->start_output) ();
-         if (!qavail (outputq))
-           cancel = hurd_condition_wait (outputq->wait, &global_lock);
+         err = (*bottom->start_output) ();
+         if (err)
+           cancel = 1;
+         else
+           {
+             if (!qavail (outputq))
+               cancel = hurd_condition_wait (outputq->wait, &global_lock);
+           }
        }
       if (cancel)
        break;
@@ -607,7 +618,8 @@
 
   *amt = i;
 
-  (*bottom->start_output) ();
+  if (!datalen && !err)
+    (*bottom->start_output) ();
 
   trivfs_set_mtime (termctl);
 
@@ -615,7 +627,7 @@
 
   mutex_unlock (&global_lock);
 
-  return ((cancel && datalen && !*amt) ? EINTR : 0);
+  return ((cancel && datalen && !*amt) ? (err ?: EINTR) : 0);
 }
 
 /* Called for user reads from the terminal. */
@@ -922,10 +934,7 @@
   if (!(cred->po->openmodes & (O_READ|O_WRITE)))
     err = EBADF;
   else
-    {
-      (*bottom->mdmctl) (MDMCTL_SET, state);
-      err = 0;
-    }
+    err = (*bottom->mdmctl) (MDMCTL_SET, state);
 
   mutex_unlock (&global_lock);
 
@@ -1024,14 +1033,13 @@
 
       if (flags & O_READ)
        {
-         clear_queue (inputq);
-         (*bottom->notice_input_flushed) ();
+         err = (*bottom->notice_input_flushed) ();
+         if (!err)
+           clear_queue (inputq);
        }
-
-      if (flags & O_WRITE)
-       drop_output ();
-
-      err = 0;
+      
+      if (!err && (flags & O_WRITE))
+       err = drop_output ();
     }
 
   mutex_unlock (&global_lock);
@@ -1084,6 +1092,7 @@
   struct trivfs_protid *cred = ports_lookup_port (term_bucket, port, 0);
   error_t err;
   int oldlflag;
+  struct termios state;
 
   if (!cred)
     return EOPNOTSUPP;
@@ -1105,42 +1114,47 @@
     {
       if (cred->pi.class == pty_class)
        {
+         err = (*bottom->abandon_physical_output) ();
+         if (err)
+           goto leave;
          clear_queue (outputq);
-         (*bottom->abandon_physical_output) ();
        }
 
       if (draino)
        {
          err = drain_output ();
          if (err)
-           {
-             mutex_unlock (&global_lock);
-             ports_port_deref (cred);
-             return err;
-           }
+           goto leave;
        }
 
       if (flushi)
        {
+         err = (*bottom->notice_input_flushed) ();
+         if (err)
+           goto leave;
          clear_queue (inputq);
-         (*bottom->notice_input_flushed) ();
        }
 
-      oldlflag = termstate.c_lflag;
-      termstate.c_iflag = modes[0];
-      termstate.c_oflag = modes[1];
-      termstate.c_cflag = modes[2];
-      termstate.c_lflag = modes[3];
-      bcopy (ccs, termstate.c_cc, NCCS);
-      termstate.__ispeed = speeds[0];
-      termstate.__ospeed = speeds[1];
+      state = termstate;
+      state.c_iflag = modes[0];
+      state.c_oflag = modes[1];
+      state.c_cflag = modes[2];
+      state.c_lflag = modes[3];
+      bcopy (ccs, state.c_cc, NCCS);
+      state.__ispeed = speeds[0];
+      state.__ospeed = speeds[1];
 
       if (external_processing)
-       termstate.c_lflag |= EXTPROC;
+       state.c_lflag |= EXTPROC;
       else
-       termstate.c_lflag &= ~EXTPROC;
+       state.c_lflag &= ~EXTPROC;
 
-      (*bottom->set_bits) ();
+      err = (*bottom->set_bits) (&state);
+      if (err)
+       goto leave;
+
+      oldlflag = termstate.c_lflag;
+      termstate = state;
 
       if (oldlflag & ICANON)
        {
@@ -1152,17 +1166,15 @@
          if (termstate.c_lflag & ICANON)
            rescan_inputq ();
        }
-      err = 0;
     }
 
+ leave:
   mutex_unlock (&global_lock);
-
   ports_port_deref (cred);
   return err;
 }
 
 
-
 /* TIOCSETA -- Set termios state */
 kern_return_t
 S_tioctl_tiocseta (io_t port,
@@ -1395,10 +1407,7 @@
   if (!(cred->po->openmodes & (O_READ|O_WRITE)))
     err = EBADF;
   else
-    {
-      (*bottom->mdmctl) (MDMCTL_SET, bits);
-      err = 0;
-    }
+    err = (*bottom->mdmctl) (MDMCTL_SET, bits);
 
   mutex_unlock (&global_lock);
   ports_port_deref (cred);
@@ -1427,10 +1436,7 @@
   if (!(cred->po->openmodes & (O_READ|O_WRITE)))
     err = EBADF;
   else
-    {
-      (*bottom->mdmctl) (MDMCTL_BIC, bits);
-      err = 0;
-    }
+    err = (*bottom->mdmctl) (MDMCTL_BIC, bits);
   mutex_unlock (&global_lock);
 
   ports_port_deref (cred);
@@ -1460,10 +1466,7 @@
   if (!(cred->po->openmodes & (O_READ|O_WRITE)))
     err = EBADF;
   else
-    {
-      (*bottom->mdmctl) (MDMCTL_BIS, bits);
-      err = 0;
-    }
+    err = (*bottom->mdmctl) (MDMCTL_BIS, bits);
   mutex_unlock (&global_lock);
   ports_port_deref (cred);
   return err;
@@ -1492,9 +1495,12 @@
     err = EBADF;
   else
     {
+      int old_termflags = termflags;
+
       termflags &= ~USER_OUTPUT_SUSP;
-      (*bottom->start_output) ();
-      err = 0;
+      err = (*bottom->start_output) ();
+      if (err)
+       termflags = old_termflags;
     }
   mutex_unlock (&global_lock);
 
@@ -1524,9 +1530,11 @@
     err = EBADF;
   else
     {
+      int old_termflags = termflags;
       termflags |= USER_OUTPUT_SUSP;
-      (*bottom->suspend_physical_output) ();
-      err = 0;
+      err = (*bottom->suspend_physical_output) ();
+      if (err)
+       termflags = old_termflags;
     }
   mutex_unlock (&global_lock);
 
@@ -1690,10 +1698,7 @@
   if (!(cred->po->openmodes & (O_READ|O_WRITE)))
     err = EBADF;
   else
-    {
-      (*bottom->mdmctl) (MDMCTL_BIC, TIOCM_DTR);
-      err = 0;
-    }
+    err = (*bottom->mdmctl) (MDMCTL_BIC, TIOCM_DTR);
   mutex_unlock (&global_lock);
 
   ports_port_deref (cred);
@@ -1721,10 +1726,7 @@
   if (!(cred->po->openmodes & (O_READ|O_WRITE)))
     err = EBADF;
   else
-    {
-      (*bottom->mdmctl) (MDMCTL_BIS, TIOCM_DTR);
-      err = 0;
-    }
+    err = (*bottom->mdmctl) (MDMCTL_BIS, TIOCM_DTR);
   mutex_unlock (&global_lock);
 
   ports_port_deref (cred);
@@ -1752,10 +1754,7 @@
   if (!(cred->po->openmodes & (O_READ|O_WRITE)))
     err = EBADF;
   else
-    {
-      (*bottom->clear_break) ();
-      err = 0;
-    }
+    err = (*bottom->clear_break) ();
   mutex_unlock (&global_lock);
 
   ports_port_deref (cred);
@@ -1783,10 +1782,7 @@
   if (!(cred->po->openmodes & (O_READ|O_WRITE)))
     err = EBADF;
   else
-    {
-      (*bottom->set_break) ();
-      err = 0;
-    }
+    err = (*bottom->set_break) ();
   mutex_unlock (&global_lock);
 
   ports_port_deref (cred);
@@ -2239,6 +2235,8 @@
   ports_port_deref (cred);
   if (bottom == &devio_bottom)
     *ttype = TERM_ON_MACHDEV;
+  else if (bottom = &hurdio_bottom)
+    *ttype = TERM_ON_HURDIO;
   else
     *ttype = TERM_ON_MASTERPTY;
   return 0;
--- /dev/null   Wed Jan  9 18:31:40 2002
+++ hurdio.c    Thu Feb  7 03:12:48 2002
@@ -0,0 +1,591 @@
+/*
+   Copyright (C) 1995,96,98,99,2000,01,02 Free Software Foundation, Inc.
+   Written by Michael I. Bushnell, p/BSG and Marcus Brinkmann.
+
+   This file is part of the GNU Hurd.
+
+   The GNU Hurd is free software; you can redistribute it and/or
+   modify it under the terms of the GNU General Public License as
+   published by the Free Software Foundation; either version 2, or (at
+   your option) any later version.
+
+   The GNU Hurd is distributed in the hope that it will be useful, but
+   WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program; if not, write to the Free Software
+   Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111, USA. */
+
+/* Handle carrier dropped (at least EIO errors in read, write) correctly.  */
+
+#include <termios.h>
+
+#include <assert.h>
+#include <errno.h>
+#include <error.h>
+#include <string.h>
+
+#include <cthreads.h>
+
+#include <hurd.h>
+#include <hurd/ports.h>
+#include <hurd/io.h>
+#include <hurd/tioctl.h>
+
+#include "term.h"
+
+
+/* The thread asserting the DTR and performing all reads.  Only
+   different from MACH_PORT_NULL if thread is live and blocked.  */
+thread_t reader_thread = MACH_PORT_NULL;
+
+/* The Hurd file_t representing the terminal.  If this is not
+   MACH_PORT_NULL, it has the additional meaning that the DTR is
+   asserted.  */
+static file_t ioport = MACH_PORT_NULL;
+
+/* Each bit represents a supported tioctl call in the underlying node.
+   If we detect that a tioctl is not supported, we clear the bit in
+   tioc_caps (which is initialized at every open).  */
+#define TIOC_CAP_OUTQ  0x001
+#define TIOC_CAP_START 0x002
+#define TIOC_CAP_STOP  0x004
+#define TIOC_CAP_FLUSH 0x008
+#define TIOC_CAP_CBRK  0x010
+#define TIOC_CAP_SBRK  0x020
+#define TIOC_CAP_MODG  0x040
+#define TIOC_CAP_MODS  0x080
+#define TIOC_CAP_GETA  0x100
+#define TIOC_CAP_SETA  0x200
+int tioc_caps;
+
+/* The thread performing all writes.  Only different from
+   MACH_PORT_NULL if thread is live and blocked.  */
+thread_t writer_thread = MACH_PORT_NULL;
+
+/* This flag is set if the output was suspended.  */
+static int output_stopped;
+static struct condition hurdio_writer_condition;
+
+/* Hold the amount of bytes that are currently in the progress of
+   being written.  May be set to zero while you hold the global lock
+   to drain the pending output buffer.  */
+size_t npending_output;
+
+/* True if we should assert the dtr.  */
+int assert_dtr;
+static struct condition hurdio_assert_dtr_condition;
+
+
+/* Forward */
+static error_t hurdio_desert_dtr ();
+static any_t hurdio_reader_loop (any_t arg);
+static any_t hurdio_writer_loop (any_t arg);
+static error_t hurdio_set_bits (struct termios *state);
+
+
+static void init_hurdio (void) __attribute__ ((constructor));
+static void
+init_hurdio ()
+{
+  condition_init (&hurdio_writer_condition);
+  condition_init (&hurdio_assert_dtr_condition);
+
+  cthread_detach (cthread_fork (hurdio_reader_loop, 0));
+  cthread_detach (cthread_fork (hurdio_writer_loop, 0));
+}
+
+
+/* Assert the DTR if necessary.  Must be called with global lock held.  */
+static void
+wait_for_dtr (void)
+{
+  while (!assert_dtr)
+    hurd_condition_wait (&hurdio_assert_dtr_condition, &global_lock);
+  assert_dtr = 0;
+
+  /* Open the file in blocking mode, so that the carrier is
+     established as well.  */
+  ioport = file_name_lookup (pterm_name, O_READ|O_WRITE, 0);
+  if (ioport == MACH_PORT_NULL)
+    report_carrier_error (errno);
+  else
+    {
+      error_t err;
+      struct termios state = termstate;
+
+      /* Assume that we have a full blown terminal initially.  */
+      tioc_caps = ~0;
+
+      /* Set terminal in raw mode etc.  */
+      err = hurdio_set_bits (&state);
+      if (err)
+       report_carrier_error (err);
+      else
+       {
+         termstate = state;
+
+         /* Signal that we have a carrier.  */
+         report_carrier_on ();
+
+         /* Signal that the writer thread should resume its work.  */
+         condition_broadcast (&hurdio_writer_condition);
+       }
+    }
+}
+
+
+/* Read and enqueue input characters.  Is also responsible to assert
+   the DTR if necessary.  */
+static any_t
+hurdio_reader_loop (any_t arg)
+{
+  /* XXX The input buffer has 256 bytes.  */
+#define BUFFER_SIZE 256
+  char buffer[BUFFER_SIZE];
+  char *data;
+  size_t datalen;
+  error_t err;
+
+  mutex_lock (&global_lock);
+  reader_thread = mach_thread_self ();
+
+  while (1)
+    {
+      /* We can only start when the DTR has been asserted.  */
+      while (!ioport)
+       wait_for_dtr ();
+      mutex_unlock (&global_lock);
+
+      data = buffer;
+      datalen = BUFFER_SIZE;
+
+      err = io_read (ioport, &data, &datalen, -1, BUFFER_SIZE);
+
+      mutex_lock (&global_lock);
+      /* EIO or EOF can mean the carrier has been dropped.  */
+      if (err == EIO || !datalen)
+       hurdio_desert_dtr ();
+      else if (!err)
+       {
+         if (termstate.c_cflag & CREAD)
+           {
+             int i;
+
+             for (i = 0; i < datalen; i++)
+               {
+                 /* XXX Munge high bits etc.  */
+                 if (input_character (data[i]))
+                   break;
+               }
+           }
+
+         if (data != buffer)
+           vm_deallocate (mach_task_self(), (vm_address_t) data, datalen);
+       }
+    }
+#undef BUFFER_SIZE
+}
+
+
+/* Output characters.  */
+static any_t
+hurdio_writer_loop (any_t arg)
+{
+  /* XXX The output buffer has 256 bytes.  */
+#define BUFFER_SIZE 256
+  char *bufp;
+  char pending_output[BUFFER_SIZE];
+  size_t amount;
+  error_t err;
+  int size;
+  int npending_output_copy;
+  mach_port_t ioport_copy;
+
+  mutex_lock (&global_lock);
+  writer_thread = mach_thread_self ();
+
+  while (1)
+    {
+      while (!ioport || !qsize (outputq)
+            || (termflags & USER_OUTPUT_SUSP))
+       hurd_condition_wait (&hurdio_writer_condition, &global_lock);
+
+      /* If the output was suspended earlier, we have to tell the
+        underlying port to resume it.  */
+      if (output_stopped)
+       {
+         if (tioc_caps & TIOC_CAP_START)
+           {
+             err = tioctl_tiocstart (ioport);
+             if (err && (err == EMIG_BAD_ID || err == EOPNOTSUPP))
+               tioc_caps &= ~TIOC_CAP_START;
+             /* XXX Handle the error.  */
+             err = 0;
+           }
+         output_stopped = 0;
+       }
+
+      /* Copy characters onto PENDING_OUTPUT, not bothering
+        those already there. */
+      size = qsize (outputq);
+
+      if (size + npending_output > BUFFER_SIZE)
+       size = BUFFER_SIZE - npending_output;
+      
+      bufp = pending_output + npending_output;
+      npending_output += size;
+      /* We need to save these values, as otherwise there are races
+        with hurdio_abandon_physical_output or hurdio_desert_dtr,
+        which might overwrite the static variables.  */
+      npending_output_copy = npending_output;
+      ioport_copy = ioport;
+      mach_port_mod_refs (mach_task_self (), ioport_copy,
+                         MACH_PORT_RIGHT_SEND, 1);
+
+      while (size--)
+       *bufp++ = dequeue (outputq);
+
+      /* Submit all the outstanding characters to the I/O port.  */
+      mutex_unlock (&global_lock);
+      err = io_write (ioport_copy, pending_output, npending_output_copy,
+                     -1, &amount);
+      mutex_lock (&global_lock);
+
+      mach_port_mod_refs (mach_task_self (), ioport_copy,
+                         MACH_PORT_RIGHT_SEND, -1);
+      /* XXX Handle errors correctly.  */
+      if (err == EIO)
+       hurdio_desert_dtr ();
+      else if (!err)
+       {
+         /* Note that npending_output might be set to null in the
+            meantime by hurdio_abandon_physical_output.  */
+         if (amount >= npending_output)
+           {
+             npending_output = 0;
+             condition_broadcast (outputq->wait);
+           }
+         else
+           {
+             /* Copy the characters that didn't get output
+                to the front of the array.  */
+             npending_output -= amount;
+             memmove (pending_output, pending_output + amount,
+                      npending_output);
+           }
+       }
+    }
+#undef BUFFER_SIZE
+}
+
+
+/* If there are characters on the output queue, then send them.  Is
+   called with global lock held.  */
+static error_t
+hurdio_start_output ()
+{
+  condition_broadcast (&hurdio_writer_condition);
+  return 0;
+}
+
+
+/* Stop carrier on the line.  Is called with global lock held.  */
+static error_t
+hurdio_set_break ()
+{
+  if (tioc_caps & TIOC_CAP_SBRK)
+    {
+      error_t err = tioctl_tiocsbrk (ioport);
+      if (err && (err == EMIG_BAD_ID || err == EOPNOTSUPP))
+       tioc_caps &= ~TIOC_CAP_SBRK;
+      else if (err)
+       return err;
+    }
+  return 0;
+}
+
+
+/* Reassert carrier on the line.  Is called with global lock held.  */
+static error_t
+hurdio_clear_break ()
+{
+  if (tioc_caps & TIOC_CAP_CBRK)
+    {
+      error_t err = tioctl_tioccbrk (ioport);
+      if (err && (err == EMIG_BAD_ID || err == EOPNOTSUPP))
+       tioc_caps &= ~TIOC_CAP_CBRK;
+      else if (err)
+       return err;
+    }
+  return 0;
+}
+
+
+/* This is called when output queues are being flushed.  But there may
+   be pending output which is sitting in a device buffer or other
+   place lower down than the terminal's output queue; so this is
+   called to flush whatever other such things may be going on.  Is
+   called with global lock held.  */
+static error_t
+hurdio_abandon_physical_output ()
+{
+  if (tioc_caps & TIOC_CAP_FLUSH)
+    {
+      error_t err = tioctl_tiocflush (ioport, O_WRITE);
+      if (err && (err == EMIG_BAD_ID || err == EOPNOTSUPP))
+       tioc_caps &= ~TIOC_CAP_FLUSH;
+      else if (err)
+       return err;
+    }
+
+  /* Make sure that an incomplete write will not be finished.
+     hurdio_writer_loop must take care that meddling with
+     npending_output here does not introduce any races.  */
+  npending_output = 0;
+  return 0;
+}
+
+
+/* Tell the underlying port to suspend all pending output, and stop
+   output in the bottom handler as well.  Is called with the global
+   lock held.  */
+static error_t
+hurdio_suspend_physical_output ()
+{
+  if (!output_stopped)
+    {
+      if (tioc_caps & TIOC_CAP_STOP)
+       {
+         error_t err = tioctl_tiocstop (ioport);
+         if (err && (err == EMIG_BAD_ID || err == EOPNOTSUPP))
+           tioc_caps &= ~TIOC_CAP_STOP;
+         else if (err)
+           return err;
+       }
+      output_stopped = 1;
+    }
+  return 0;
+}
+
+/* This is called to notify the bottom half when an input flush has
+   occurred.  It is necessary to support pty packet mode.  */
+static error_t
+hurdio_notice_input_flushed ()
+{
+  if (tioc_caps & TIOC_CAP_FLUSH)
+    {
+      error_t err = tioctl_tiocflush (ioport, O_READ);
+      if (err && (err == EMIG_BAD_ID || err == EOPNOTSUPP))
+       tioc_caps &= ~TIOC_CAP_FLUSH;
+      else if (err)
+       return err;
+    }
+  return 0;
+}
+
+
+/* Determine the number of bytes of output pending.  */
+static int
+hurdio_pending_output_size ()
+{
+  int queue_size = 0;
+
+  if (tioc_caps & TIOC_CAP_OUTQ)
+    {
+      error_t err = tioctl_tiocoutq (ioport, &queue_size);
+      if (err && (err == EMIG_BAD_ID || err == EOPNOTSUPP))
+       tioc_caps &= ~TIOC_CAP_OUTQ;
+      else if (err)
+       queue_size = 0;
+    }
+  /* We can not get the correct number, so let's try a guess.  */
+  return queue_size + npending_output;
+}
+
+
+/* Desert the DTR.  Is called with global lock held.  */
+static error_t
+hurdio_desert_dtr ()
+{
+  if (ioport)
+    {
+      mach_port_deallocate (mach_task_self (), ioport);
+      ioport = MACH_PORT_NULL;
+      if (writer_thread != MACH_PORT_NULL)
+       hurd_thread_cancel (writer_thread);
+      if (reader_thread != MACH_PORT_NULL)
+       hurd_thread_cancel (reader_thread);
+    }
+  /* If we are called after hurdio_assert_dtr before the reader thread
+     had a chance to wake up and open the port, we can prevent it from
+     doing so by clearing this flag.  */
+  assert_dtr = 0;
+  report_carrier_off ();
+  return 0;
+}
+
+
+static error_t
+hurdio_assert_dtr ()
+{
+  if (ioport == MACH_PORT_NULL)
+    {
+      assert_dtr = 1;
+      condition_signal (&hurdio_assert_dtr_condition);
+    }
+
+  return 0;
+}
+
+
+/* Adjust physical state on the basis of the terminal state.
+   Where it isn't possible, mutate terminal state to match
+   reality. */
+static error_t
+hurdio_set_bits (struct termios *state)
+{
+  error_t err;
+  struct termios ttystat;
+  /* This structure equals how the Hurd tioctl_tiocgeta/seta split up
+     a termios structure into RPC arguments.  */
+  struct hurd_termios
+  {
+    modes_t modes;
+    ccs_t ccs;
+    speeds_t speeds;
+  } *hurd_ttystat = (struct hurd_termios *) &ttystat;
+
+  if (!(state->c_cflag & CIGNORE) && ioport != MACH_PORT_NULL)
+    {
+
+      /* If we can not get the terminal state, it doesn't make sense
+        to attempt to change it.  Even if we could change it we
+        wouldn't know what changes took effect.  */
+      if (!(tioc_caps & TIOC_CAP_GETA))
+       /* XXX Maybe return an error here, but then we must do the
+          right thing in users.c.  */
+       return 0;
+
+      err = tioctl_tiocgeta (ioport, hurd_ttystat->modes,
+                            hurd_ttystat->ccs, hurd_ttystat->speeds);
+      if (err && (err == EMIG_BAD_ID || err == EOPNOTSUPP))
+       {
+         tioc_caps &= ~TIOC_CAP_GETA;
+         /* XXX Maybe return an error here, but then we must do the
+            right thing in users.c.  */
+         return 0;
+       }
+      else if (err)
+       return err;
+
+      /* If possible, change the state.  Otherwise we will just make
+        termstate match reality below.  */
+      if (tioc_caps & TIOC_CAP_SETA)
+       {
+         if (state->__ispeed)
+           hurd_ttystat->speeds[0] = state->__ispeed;
+         if (state->__ospeed)
+           hurd_ttystat->speeds[1] = state->__ospeed;
+         cfmakeraw (&ttystat);
+         ttystat.c_cflag = state->c_cflag &~ HUPCL;
+
+         err = tioctl_tiocseta (ioport, hurd_ttystat->modes,
+                                hurd_ttystat->ccs, hurd_ttystat->speeds);
+         if (err && (err == EMIG_BAD_ID || err == EOPNOTSUPP))
+           tioc_caps &= ~TIOC_CAP_SETA;
+         else if (err)
+           return err;
+
+         /* Refetch the terminal state.  */
+         err = tioctl_tiocgeta (ioport, hurd_ttystat->modes,
+                                hurd_ttystat->ccs, hurd_ttystat->speeds);
+         if (err && (err == EMIG_BAD_ID || err == EOPNOTSUPP))
+           tioc_caps &= ~TIOC_CAP_GETA;
+         else if (err)
+           return err;
+       }
+
+      /* And now make termstate match reality.  */
+      *state = ttystat;
+    }
+
+  return 0;
+}
+
+/* Diddle the modem control bits.  If HOW is MDMCTL_BIC, the bits set
+   in BITS should be cleared.  If HOW is MDMCTL_BIS, the bits in BITS
+   should be set.  Otherwise, bits that are set in BITS should be set,
+   and the others cleared.  */
+static error_t
+hurdio_mdmctl (int how, int bits)
+{
+  error_t err;
+  int oldbits, newbits;
+  
+  if (tioc_caps & TIOC_CAP_MODS)
+    {
+      if ((how == MDMCTL_BIS) || (how == MDMCTL_BIC))
+       {
+         if (tioc_caps & TIOC_CAP_MODG)
+           {
+             error_t err = tioctl_tiocmodg (ioport, &oldbits);
+             if (err && (err == EMIG_BAD_ID || err == EOPNOTSUPP))
+               tioc_caps &= ~TIOC_CAP_MODG;
+             else if (err)
+               return err;
+           }
+       }
+
+      if (how == MDMCTL_BIS)
+       newbits = (oldbits | bits);
+      else if (how == MDMCTL_BIC)
+       newbits = (oldbits &= ~bits);
+      else
+       newbits = bits;
+
+      err = tioctl_tiocmods (ioport, oldbits);
+      if (err && (err == EMIG_BAD_ID || err == EOPNOTSUPP))
+       tioc_caps &= ~TIOC_CAP_MODS;
+      else if (err)
+       return err;
+    }
+  return 0;
+}
+
+
+static int
+hurdio_mdmstate ()
+{
+  int oldbits;
+  
+  if (tioc_caps & TIOC_CAP_MODG)
+    {
+      error_t err = tioctl_tiocmodg (ioport, &oldbits);
+      if (err && (err == EMIG_BAD_ID || err == EOPNOTSUPP))
+       tioc_caps &= ~TIOC_CAP_MODG;
+      else if (err)
+       return 0;  /* XXX What else can we do?  */
+    }
+  return 0;
+}
+
+
+
+struct bottomhalf hurdio_bottom =
+{
+  hurdio_start_output,
+  hurdio_set_break,
+  hurdio_clear_break,
+  hurdio_abandon_physical_output,
+  hurdio_suspend_physical_output,
+  hurdio_pending_output_size,
+  hurdio_notice_input_flushed,
+  hurdio_assert_dtr,
+  hurdio_desert_dtr,
+  hurdio_set_bits,
+  hurdio_mdmctl,
+  hurdio_mdmstate,
+};

-- 
`Rhubarb is no Egyptian god.' Debian http://www.debian.org brinkmd@debian.org
Marcus Brinkmann              GNU    http://www.gnu.org    marcus@gnu.org
Marcus.Brinkmann@ruhr-uni-bochum.de
http://www.marcus-brinkmann.de



reply via email to

[Prev in Thread] Current Thread [Next in Thread]