This is the mail archive of the gdb-patches@sourceware.cygnus.com mailing list for the GDB project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]

FYI: Buffered ASYNC serial


Hello,

I've checked in the attached. I've not been able to get it to ``break''
(1) the old synchronous serial code but, just in case ...

It adds read-a-head support to the async targets.

	Andrew

(1) As in exibit worse behavour - bug-for-bug compatible?
Thu Sep 30 12:07:03 1999  Andrew Cagney  <cagney@b1.cygnus.com>

	* serial.h (struct _serial_t): Add field async_state.  Better
 	document field bufcnt.
	(SERIAL_ERROR): Delete comment about errno.
	* serial.c (serial_open, serial_fdopen): Initialize async_state.

	* ser-unix.c (push_event, fd_event, reschedule): New functions.
  	Handle ASYNC serial input.
	(ser_unix_async): Update.
	(generic_readchar): New function. Handle event scheduling. Make
 	EOF condition sticky.
	(do_unix_readchar): Rename ser_unix_readchar.
	(ser_unix_readchar): New function, call do_unix_readchar via
 	generic_readchar.
	(do_hardwire_readchar, hardwire_readchar): Ditto.

	* ser-unix.c (ser_unix_readchar): Delete code working around ASYNC
 	fifo bugs.
	(hardwire_readchar): Delete code working around ASYNC fifo bugs.

Index: ser-unix.c
===================================================================
RCS file: /cvs/cvsfiles/devo/gdb/ser-unix.c,v
retrieving revision 2.59
diff -p -r2.59 ser-unix.c
*** ser-unix.c	1999/09/30 00:51:54	2.59
--- ser-unix.c	1999/09/30 03:56:11
*************** static int hardwire_open (serial_t scb, 
*** 71,76 ****
--- 71,78 ----
  static void hardwire_raw (serial_t scb);
  static int wait_for (serial_t scb, int timeout);
  static int hardwire_readchar (serial_t scb, int timeout);
+ static int do_hardwire_readchar (serial_t scb, int timeout);
+ static int generic_readchar (serial_t scb, int timeout, int (*do_readchar) (serial_t scb, int timeout));
  static int rate_to_code (int rate);
  static int hardwire_setbaudrate (serial_t scb, int rate);
  static void hardwire_close (serial_t scb);
*************** static int hardwire_flush_input (serial_
*** 87,92 ****
--- 89,99 ----
  static int hardwire_send_break (serial_t);
  static int hardwire_setstopbits (serial_t, int);
  
+ static int do_unix_readchar (serial_t scb, int timeout);
+ static timer_handler_func push_event;
+ static handler_func fd_event;
+ static void reschedule (serial_t scb);
+ 
  void _initialize_ser_hardwire (void);
  
  extern int (*ui_loop_hook) (int);
*************** wait_for (serial_t scb, int timeout)
*** 544,557 ****
     that. */
  
  static int
! hardwire_readchar (serial_t scb, int timeout)
  {
    int status, delta;
    int detach = 0;
  
-   if (scb->bufcnt-- > 0)
-     return *scb->bufp++;
- 
    if (timeout > 0)
      timeout++;
  
--- 551,561 ----
     that. */
  
  static int
! do_hardwire_readchar (serial_t scb, int timeout)
  {
    int status, delta;
    int detach = 0;
  
    if (timeout > 0)
      timeout++;
  
*************** hardwire_readchar (serial_t scb, int tim
*** 583,594 ****
        if (status < 0)
  	return status;
  
!       /* NOTE: cagney/1999-09-17: See ser_unix_readchar() for reason
!          why ASYNC reads are character by character. */
  
-       scb->bufcnt = read (scb->fd, scb->buf,
- 			  (SERIAL_IS_ASYNC_P (scb) ? 1 : BUFSIZ));
- 
        if (scb->bufcnt <= 0)
  	{
  	  if (scb->bufcnt == 0)
--- 587,594 ----
        if (status < 0)
  	return status;
  
!       scb->bufcnt = read (scb->fd, scb->buf, BUFSIZ);
  
        if (scb->bufcnt <= 0)
  	{
  	  if (scb->bufcnt == 0)
*************** hardwire_readchar (serial_t scb, int tim
*** 617,622 ****
--- 617,632 ----
      }
  }
  
+ /* FIXME: cagney/1999-09-30: Need to merge this wrapping code into
+    do_hardwire_readchar. See also ser_unix_readchar. */
+ 
+ static int
+ hardwire_readchar (serial_t scb, int timeout)
+ {
+   return generic_readchar (scb, timeout, do_hardwire_readchar);
+ }
+ 
+ 
  #ifndef B19200
  #define B19200 EXTA
  #endif
*************** ser_unix_wait_for (serial_t scb, int tim
*** 889,903 ****
     char if successful.  Returns -2 if timeout expired, EOF if line dropped
     dead, or -3 for any other error (see errno in that case). */
  
! int
! ser_unix_readchar (serial_t scb, int timeout)
  {
    int status;
    int delta;
  
-   if (scb->bufcnt-- > 0)
-     return *scb->bufp++;
- 
    /* We have to be able to keep the GUI alive here, so we break the original
       timeout into steps of 1 second, running the "keep the GUI alive" hook 
       each time through the loop.
--- 899,910 ----
     char if successful.  Returns -2 if timeout expired, EOF if line dropped
     dead, or -3 for any other error (see errno in that case). */
  
! static int
! do_unix_readchar (serial_t scb, int timeout)
  {
    int status;
    int delta;
  
    /* We have to be able to keep the GUI alive here, so we break the original
       timeout into steps of 1 second, running the "keep the GUI alive" hook 
       each time through the loop.
*************** ser_unix_readchar (serial_t scb, int tim
*** 947,959 ****
  
    while (1)
      {
!       /* FIXME: cagney/1999-09-17: ASYNC: The ASYNC serial code needs
! 	 to be modified so that it agressivly tries to drain its local
! 	 input buffer.  Until this is done, the read() below can only
! 	 take in single characters.  This is to ensure that
! 	 unprocessed data doesn't end up sitting in the input fifo. */
!       scb->bufcnt = read (scb->fd, scb->buf,
! 			  (SERIAL_IS_ASYNC_P (scb) ? 1 : BUFSIZ));
        if (scb->bufcnt != -1 || errno != EINTR)
  	break;
      }
--- 954,960 ----
  
    while (1)
      {
!       scb->bufcnt = read (scb->fd, scb->buf, BUFSIZ);
        if (scb->bufcnt != -1 || errno != EINTR)
  	break;
      }
*************** ser_unix_readchar (serial_t scb, int tim
*** 973,978 ****
--- 974,1020 ----
    return *scb->bufp++;
  }
  
+ /* FIXME: cagney/1999-09-30: More common to hardwire_readchar and
+    unix_readchar needs to be identified. */
+ 
+ static int
+ generic_readchar (serial_t scb, int timeout,
+ 		  int (do_readchar) (serial_t scb, int timeout))
+ {
+   int ch;
+   if (scb->bufcnt > 0)
+     {
+       ch = *scb->bufp;
+       scb->bufcnt--;
+       scb->bufp++;
+     }
+   else if (scb->bufcnt < 0)
+     {
+       /* Some errors/eof are are sticky. */
+       ch = scb->bufcnt;
+     }
+   else
+     {
+       ch = do_readchar (scb, timeout);
+       if (ch < 0)
+ 	{
+ 	  /* Make the error/eof stick. */
+ 	  if (ch == SERIAL_EOF)
+ 	    scb->bufcnt = ch;
+ 	  else
+ 	    scb->bufcnt = 0;
+ 	}
+     }
+   reschedule (scb);
+   return ch;
+ }
+ 
+ int
+ ser_unix_readchar (serial_t scb, int timeout)
+ {
+   return generic_readchar (scb, timeout, do_unix_readchar);
+ }
+ 
  int
  ser_unix_nop_noflush_set_tty_state (serial_t scb,
  				    serial_ttystate new_ttystate,
*************** ser_unix_nop_drain_output (serial_t scb)
*** 1050,1073 ****
    return 0;
  }
  
  static void
! ser_unix_event (int error, int fd, gdb_client_data context)
  {
    serial_t scb = context;
    scb->async_handler (scb, scb->async_context);
  }
  
  void
  ser_unix_async (serial_t scb,
  		int async_p)
  {
    if (async_p)
      {
!       add_file_handler (scb->fd, ser_unix_event, scb);
      }
    else
      {
!       delete_file_handler (scb->fd);
      }
  }
  
--- 1092,1245 ----
    return 0;
  }
  
+ 
+ 
+ /* Event handling for ASYNC serial code.
+ 
+    At any time the SERIAL device either: has an empty buffer and is
+    waiting on a FD event; or has a non-empty buffer/error condition
+    and is constantly scheduling timer events.
+ 
+    ASYNC only stops pestering its client when it is de-async'ed or it
+    is told to go away. */
+ 
+ enum {
+   /* >= 0 when a timer event is pending. */
+   FD_SCHEDULED = -1,
+   NOTHING_SCHEDULED = -2
+ };
+ 
+ static void
+ reschedule (serial_t scb)
+ {
+   if (SERIAL_IS_ASYNC_P (scb))
+     {
+       int next_state;
+       switch (scb->async_state)
+ 	{
+ 	case FD_SCHEDULED:
+ 	  if (scb->bufcnt == 0)
+ 	    next_state = FD_SCHEDULED;
+ 	  else
+ 	    {
+ 	      delete_file_handler (scb->fd);
+ 	      next_state = create_timer (0, push_event, scb);
+ 	    }
+ 	  break;
+ 	case NOTHING_SCHEDULED:
+ 	  if (scb->bufcnt == 0)
+ 	    {
+ 	      add_file_handler (scb->fd, fd_event, scb);
+ 	      next_state = FD_SCHEDULED;
+ 	    }
+ 	  else
+ 	    {
+ 	      next_state = create_timer (0, push_event, scb);
+ 	    }
+ 	  break;
+ 	default: /* TIMER SCHEDULED */
+ 	  if (scb->bufcnt == 0)
+ 	    {
+ 	      delete_timer (scb->async_state);
+ 	      add_file_handler (scb->fd, fd_event, scb);
+ 	      next_state = FD_SCHEDULED;
+ 	    }
+ 	  else
+ 	    next_state = scb->async_state;
+ 	  break;
+ 	}
+       if (SERIAL_DEBUG_P (scb))
+ 	{
+ 	  switch (next_state)
+ 	    {
+ 	    case FD_SCHEDULED:
+ 	      if (scb->async_state != FD_SCHEDULED)
+ 		fprintf_unfiltered (gdb_stdlog, "[fd%d->fd-scheduled]\n",
+ 				    scb->fd);
+ 	      break;
+ 	    default: /* TIMER SCHEDULED */
+ 	      if (scb->async_state == FD_SCHEDULED)
+ 		fprintf_unfiltered (gdb_stdlog, "[fd%d->timer-scheduled]\n",
+ 				    scb->fd);
+ 	      break;
+ 	    }
+ 	}
+       scb->async_state = next_state;
+     }
+ }
+ 
  static void
! fd_event (int error, int fd, void *context)
  {
    serial_t scb = context;
+   if (error != 0)
+     {
+       scb->bufcnt = SERIAL_ERROR;
+     }
+   else if (scb->bufcnt == 0)
+     {
+       int nr;
+       do
+ 	{
+ 	  nr = read (fd, scb->buf, BUFSIZ);
+ 	}
+       while (nr == -1 && errno == EINTR);
+       if (nr == 0)
+ 	{
+ 	  scb->bufcnt = SERIAL_EOF;
+ 	}
+       else if (nr > 0)
+ 	{
+ 	  scb->bufcnt = nr;
+ 	  scb->bufp = scb->buf;
+ 	}
+       else
+ 	{
+ 	  scb->bufcnt = SERIAL_ERROR;
+ 	}
+     }
    scb->async_handler (scb, scb->async_context);
+   reschedule (scb);
  }
  
+ static void
+ push_event (void *context)
+ {
+   serial_t scb = context;
+   scb->async_state = NOTHING_SCHEDULED; /* Timers are one-off */
+   scb->async_handler (scb, scb->async_context);
+   /* re-schedule */
+   reschedule (scb);
+ }
+ 
  void
  ser_unix_async (serial_t scb,
  		int async_p)
  {
    if (async_p)
      {
!       scb->async_state = NOTHING_SCHEDULED;
!       if (SERIAL_DEBUG_P (scb))
! 	fprintf_unfiltered (gdb_stdlog, "[fd%d->asynchronous]\n",
! 			    scb->fd);
!       reschedule (scb);
      }
    else
      {
!       if (SERIAL_DEBUG_P (scb))
! 	fprintf_unfiltered (gdb_stdlog, "[fd%d->synchronous]\n",
! 			    scb->fd);
!       switch (scb->async_state)
! 	{
! 	case FD_SCHEDULED:
! 	  delete_file_handler (scb->fd);
! 	  break;
! 	NOTHING_SCHEDULED:
! 	  break;
! 	default: /* TIMER SCHEDULED */
! 	  delete_timer (scb->async_state);
! 	  break;
! 	}
      }
  }
  
Index: serial.c
===================================================================
RCS file: /cvs/cvsfiles/devo/gdb/serial.c,v
retrieving revision 2.43
diff -p -r2.43 serial.c
*** serial.c	1999/09/30 00:07:41	2.43
--- serial.c	1999/09/30 03:56:11
*************** serial_open (const char *name)
*** 217,222 ****
--- 217,223 ----
    scb->next = scb_base;
    scb->refcnt = 1;
    scb->debug_p = 0;
+   scb->async_state = 0;
    scb->async_handler = NULL;
    scb->async_context = NULL;
    scb_base = scb;
*************** serial_fdopen (const int fd)
*** 264,269 ****
--- 265,271 ----
    scb->next = scb_base;
    scb->refcnt = 1;
    scb->debug_p = 0;
+   scb->async_state = 0;
    scb->async_handler = NULL;
    scb->async_context = NULL;
    scb_base = scb;
Index: serial.h
===================================================================
RCS file: /cvs/cvsfiles/devo/gdb/serial.h,v
retrieving revision 2.43
diff -p -r2.43 serial.h
*** serial.h	1999/09/30 00:07:41	2.43
--- serial.h	1999/09/30 03:56:11
*************** extern void serial_un_fdopen (serial_t s
*** 58,64 ****
     char if ok, else one of the following codes.  Note that all error
     codes are guaranteed to be < 0.  */
  
! #define SERIAL_ERROR -1		/* General error, see errno for details */
  #define SERIAL_TIMEOUT -2
  #define SERIAL_EOF -3
  
--- 58,64 ----
     char if ok, else one of the following codes.  Note that all error
     codes are guaranteed to be < 0.  */
  
! #define SERIAL_ERROR -1		/* General error */
  #define SERIAL_TIMEOUT -2
  #define SERIAL_EOF -3
  
*************** struct _serial_t
*** 197,203 ****
      struct serial_ops *ops;	/* Function vector */
      void *state;       		/* Local context info for open FD */
      serial_ttystate ttystate;	/* Not used (yet) */
!     int bufcnt;			/* Amount of data in receive buffer */
      unsigned char *bufp;	/* Current byte */
      unsigned char buf[BUFSIZ];	/* Da buffer itself */
      int current_timeout;	/* (termio{s} only), last value of VTIME */
--- 197,204 ----
      struct serial_ops *ops;	/* Function vector */
      void *state;       		/* Local context info for open FD */
      serial_ttystate ttystate;	/* Not used (yet) */
!     int bufcnt;			/* Amount of data remaining in receive
! 				   buffer.  -ve for sticky errors. */
      unsigned char *bufp;	/* Current byte */
      unsigned char buf[BUFSIZ];	/* Da buffer itself */
      int current_timeout;	/* (termio{s} only), last value of VTIME */
*************** struct _serial_t
*** 208,213 ****
--- 209,215 ----
      struct _serial_t *next;	/* Pointer to the next serial_t */
      int refcnt;			/* Number of pointers to this block */
      int debug_p;		/* Trace this serial devices operation. */
+     int async_state;		/* Async internal state. */
      void *async_context;	/* Async event thread's context */
      serial_event_ftype *async_handler;/* Async event handler */
    };


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]