diff options
-rw-r--r-- | gdb/ChangeLog | 15 | ||||
-rw-r--r-- | gdb/ser-base.c | 30 | ||||
-rw-r--r-- | gdb/serial.c | 27 | ||||
-rw-r--r-- | gdb/serial.h | 27 |
4 files changed, 88 insertions, 11 deletions
diff --git a/gdb/ChangeLog b/gdb/ChangeLog index 075a12a3490..6b28932c8c0 100644 --- a/gdb/ChangeLog +++ b/gdb/ChangeLog @@ -1,5 +1,20 @@ 2012-06-11 Pedro Alves <palves@redhat.com> + * ser-base.c (run_async_handler_and_reschedule): New. + (fd_event, push_event): Use it. + * serial.c (serial_open, serial_fdopen_ops): Set the initial + reference count to 1. + (do_serial_close): Set the bufp field to NULL. Use serial_unref + instead of xfree. + (serial_is_open, serial_ref, serial_unref): New. + * serial.h (serial_open): Adjust comment. + (serial_is_open): Declare. + (serial_close): Adjust comment. + (serial_ref, serial_unref) Declare. + (struct serial): New field 'refcnt'. + +2012-06-11 Pedro Alves <palves@redhat.com> + Remove #if 0'd "connect" command, and unnecessary associated refcounting and serial reuse bits. diff --git a/gdb/ser-base.c b/gdb/ser-base.c index b4399d0c4ba..2f12dfcdc17 100644 --- a/gdb/ser-base.c +++ b/gdb/ser-base.c @@ -123,6 +123,29 @@ reschedule (struct serial *scb) } } +/* Run the SCB's async handle, and reschedule, if the handler doesn't + close SCB. */ + +static void +run_async_handler_and_reschedule (struct serial *scb) +{ + int is_open; + + /* Take a reference, so a serial_close call within the handler + doesn't make SCB a dangling pointer. */ + serial_ref (scb); + + /* Run the handler. */ + scb->async_handler (scb, scb->async_context); + + is_open = serial_is_open (scb); + serial_unref (scb); + + /* Get ready for more, if not already closed. */ + if (is_open) + reschedule (scb); +} + /* FD_EVENT: This is scheduled when the input FIFO is empty (and there is no pending error). As soon as data arrives, it is read into the input FIFO and the client notified. The client should then drain @@ -158,8 +181,7 @@ fd_event (int error, void *context) scb->bufcnt = SERIAL_ERROR; } } - scb->async_handler (scb, scb->async_context); - reschedule (scb); + run_async_handler_and_reschedule (scb); } /* PUSH_EVENT: The input FIFO is non-empty (or there is a pending @@ -173,9 +195,7 @@ push_event (void *context) struct serial *scb = context; scb->async_state = NOTHING_SCHEDULED; /* Timers are one-off */ - scb->async_handler (scb, scb->async_context); - /* re-schedule */ - reschedule (scb); + run_async_handler_and_reschedule (scb); } /* Wait for input on scb, with timeout seconds. Returns 0 on success, diff --git a/gdb/serial.c b/gdb/serial.c index c1f331d7699..1140feb93c5 100644 --- a/gdb/serial.c +++ b/gdb/serial.c @@ -196,6 +196,7 @@ serial_open (const char *name) scb->bufcnt = 0; scb->bufp = scb->buf; scb->error_fd = -1; + scb->refcnt = 1; /* `...->open (...)' would get expanded by the open(2) syscall macro. */ if ((*scb->ops->open) (scb, open_name)) @@ -245,6 +246,7 @@ serial_fdopen_ops (const int fd, struct serial_ops *ops) scb->bufcnt = 0; scb->bufp = scb->buf; scb->error_fd = -1; + scb->refcnt = 1; scb->name = NULL; scb->debug_p = 0; @@ -291,7 +293,10 @@ do_serial_close (struct serial *scb, int really_close) if (scb->name) xfree (scb->name); - xfree (scb); + /* For serial_is_open. */ + scb->bufp = NULL; + + serial_unref (scb); } void @@ -307,6 +312,26 @@ serial_un_fdopen (struct serial *scb) } int +serial_is_open (struct serial *scb) +{ + return scb->bufp != NULL; +} + +void +serial_ref (struct serial *scb) +{ + scb->refcnt++; +} + +void +serial_unref (struct serial *scb) +{ + --scb->refcnt; + if (scb->refcnt == 0) + xfree (scb); +} + +int serial_readchar (struct serial *scb, int timeout) { int ch; diff --git a/gdb/serial.h b/gdb/serial.h index 8ba8ae6ec95..187ed031052 100644 --- a/gdb/serial.h +++ b/gdb/serial.h @@ -37,13 +37,18 @@ typedef void *serial_ttystate; struct serial; /* Try to open NAME. Returns a new `struct serial *' on success, NULL - on failure. Note that some open calls can block and, if possible, - should be written to be non-blocking, with calls to ui_look_hook - so they can be cancelled. An async interface for open could be - added to GDB if necessary. */ + on failure. The new serial object has a reference count of 1. + Note that some open calls can block and, if possible, should be + written to be non-blocking, with calls to ui_look_hook so they can + be cancelled. An async interface for open could be added to GDB if + necessary. */ extern struct serial *serial_open (const char *name); +/* Returns true if SCB is open. */ + +extern int serial_is_open (struct serial *scb); + /* Find an already opened serial stream using a file handle. */ extern struct serial *serial_for_fd (int fd); @@ -52,10 +57,18 @@ extern struct serial *serial_for_fd (int fd); extern struct serial *serial_fdopen (const int fd); -/* Push out all buffers, close the device and destroy SCB. */ +/* Push out all buffers, close the device and unref SCB. */ extern void serial_close (struct serial *scb); +/* Increment reference count of SCB. */ + +extern void serial_ref (struct serial *scb); + +/* Decrement reference count of SCB. */ + +extern void serial_unref (struct serial *scb); + /* Create a pipe, and put the read end in files[0], and the write end in filde[1]. Returns 0 for success, negative value for error (in which case errno contains the error). */ @@ -213,6 +226,10 @@ extern int serial_debug_p (struct serial *scb); struct serial { + /* serial objects are ref counted (but not the underlying + connection, just the object's lifetime in memory). */ + int refcnt; + int fd; /* File descriptor */ /* File descriptor for a separate error stream that should be immediately forwarded to gdb_stderr. This may be -1. |