This is the mail archive of the
gdb-patches@sourceware.cygnus.com
mailing list for the GDB project.
FYI: Buffered ASYNC serial
- To: gdb-patches at sourceware dot cygnus dot com
- Subject: FYI: Buffered ASYNC serial
- From: Andrew Cagney <ac131313 at cygnus dot com>
- Date: Thu, 30 Sep 1999 14:06:09 +1000
- DJ-Gateway: from newsgroup cygnus.patches.gdb
- Newsgroups: cygnus.patches.gdb
- Organization: Cygnus Solutions
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 */
};