2012-06-11 Pedro Alves <palves@redhat.com>
authorPedro Alves <palves@redhat.com>
Mon, 11 Jun 2012 20:36:53 +0000 (20:36 +0000)
committerPedro Alves <palves@redhat.com>
Mon, 11 Jun 2012 20:36:53 +0000 (20:36 +0000)
* 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'.

gdb/ChangeLog
gdb/ser-base.c
gdb/serial.c
gdb/serial.h

index 075a12a3490955ba51809034898abc2b927ba3cb..6b28932c8c00550a376d71414d4998e20d79193c 100644 (file)
@@ -1,3 +1,18 @@
+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
index b4399d0c4ba7a6e104b8cc8e8a4938a076cc0c88..2f12dfcdc172fc1a0c1e550473a12b24145fa431 100644 (file)
@@ -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,
index c1f331d769912c869e5d71d3cfacae87f24f4999..1140feb93c5e642a03fc4ff3af4f6b20c964666c 100644 (file)
@@ -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
@@ -306,6 +311,26 @@ serial_un_fdopen (struct serial *scb)
   do_serial_close (scb, 0);
 }
 
+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)
 {
index 8ba8ae6ec95917b792daf53329d13c7def1caff6..187ed031052101d5fab1efa46da10a1f9c23f96d 100644 (file)
@@ -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.