import gdb-1999-05-10
authorStan Shebs <shebs@codesourcery.com>
Tue, 11 May 1999 20:29:07 +0000 (20:29 +0000)
committerStan Shebs <shebs@codesourcery.com>
Tue, 11 May 1999 20:29:07 +0000 (20:29 +0000)
gdb/event-loop.c [new file with mode: 0644]
gdb/event-loop.h [new file with mode: 0644]
gdb/event-top.c [new file with mode: 0644]

diff --git a/gdb/event-loop.c b/gdb/event-loop.c
new file mode 100644 (file)
index 0000000..fe1d0f5
--- /dev/null
@@ -0,0 +1,741 @@
+/* Event loop machinery for GDB, the GNU debugger.
+   Copyright 1999 Free Software Foundation, Inc.
+   Written by Elena Zannoni <ezannoni@cygnus.com> of Cygnus Solutions.
+
+   This file is part of GDB.
+
+   This program 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 of the License, or
+   (at your option) any later version.
+
+   This program 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-1307, USA. */
+
+#include "event-loop.h"
+#include <readline/readline.h>
+#include <setjmp.h>
+#include "top.h"
+
+/* For config.h which may define HAVE_POLL */
+#include "defs.h"
+
+#ifdef HAVE_POLL
+#include <sys/poll.h>
+#endif
+#include <errno.h>
+
+/* Event queue:  
+   - the first event in the queue is the head of the queue. 
+   It will be the next to be serviced.
+   - the last event in the queue 
+
+   Events can be inserted at the front of the queue or at the end of
+   the queue.  Events will be extracted from the queue for processing
+   starting from the head.  Therefore, events inserted at the head of
+   the queue will be processed in a last in first out fashoin, while
+   those inserted at the tail of the queue will be processed in a first
+   in first out manner.  All the fields are NULL if the queue is
+   empty. */
+
+static struct
+  {
+    gdb_event *first_event;    /* First pending event */
+    gdb_event *last_event;     /* Last pending event */
+  }
+event_queue;
+
+/* Gdb_notifier is just a list of file descriptors gdb is interested in.
+   These are the input file descriptor, and the target file
+   descriptor. We have two flavors of the notifier, one for platforms
+   that have the POLL function, the other for those that don't, and
+   only support SELECT. Each of the elements in the gdb_notifier list is
+   basically a description of what kind of events gdb is interested
+   in, for each fd. */
+
+/* As of 4/30/99 only the input file descriptor is registered with the
+   event loop. */
+
+#ifdef HAVE_POLL
+/* Poll based implementation of the notifier. */
+
+static struct
+  {
+    /* Ptr to head of file handler list. */
+    file_handler *first_file_handler;
+
+    /* Ptr to array of pollfd structures. */
+    struct pollfd *poll_fds;
+
+    /* Number of file descriptors to monitor. */
+    int num_fds;
+
+  }
+gdb_notifier;
+
+#else /* ! HAVE_POLL */
+
+/* Select based implementation of the notifier. */
+
+static struct
+  {
+    /* Ptr to head of file handler list. */
+    file_handler *first_file_handler;
+
+    /* Masks to be used in the next call to select.
+       Bits are set in response to calls to create_file_handler. */
+    fd_mask check_masks[3 * MASK_SIZE];
+
+    /* What file descriptors were found ready by select. */
+    fd_mask ready_masks[3 * MASK_SIZE];
+
+    /* Number of valid bits (highest fd value + 1). */
+    int num_fds;
+
+  }
+gdb_notifier;
+
+#endif /* HAVE_POLL */
+
+/* All the async_signal_handlers gdb is interested in are kept onto
+   this list. */
+static struct
+  {
+    /* Pointer to first in handler list. */
+    async_signal_handler *first_handler;     
+    
+    /* Pointer to last in handler list. */
+    async_signal_handler *last_handler;             
+  }
+sighandler_list;
+
+/* Is any of the handlers ready?  Check this variable using
+   check_async_ready. This is used by process_event, to determine
+   whether or not to invoke the invoke_async_signal_handler
+   function. */
+static int async_handler_ready = 0;
+
+static void invoke_async_signal_handler PARAMS ((void));
+static int gdb_wait_for_event PARAMS ((void));
+static int check_async_ready PARAMS ((void));
+extern display_gdb_prompt PARAMS ((char *));
+\f
+
+/* Insert an event object into the gdb event queue at 
+   the specified position.
+   POSITION can be head or tail, with values TAIL, HEAD.
+   EVENT_PTR points to the event to be inserted into the queue.
+   The caller must allocate memory for the event. It is freed
+   after the event has ben handled.
+   Events in the queue will be processed head to tail, therefore,
+   events inserted at the head of the queue will be processed
+   as last in first out. Event appended at the tail of the queue
+   will be processed first in first out. */
+static void
+async_queue_event (event_ptr, position)
+     gdb_event *event_ptr;
+     queue_position position;
+{
+  if (position == TAIL)
+    {
+      /* The event will become the new last_event. */
+
+      event_ptr->next_event = NULL;
+      if (event_queue.first_event == NULL)
+       event_queue.first_event = event_ptr;
+      else
+       event_queue.last_event->next_event = event_ptr;
+      event_queue.last_event = event_ptr;
+    }
+  else if (position == HEAD)
+    {
+      /* The event becomes the new first_event. */
+
+      event_ptr->next_event = event_queue.first_event;
+      if (event_queue.first_event == NULL)
+       event_queue.last_event = event_ptr;
+      event_queue.first_event = event_ptr;
+    }
+}
+
+/* Process one event.
+   The event can be the next one to be serviced in the event queue,
+   or an asynchronous event handler can be invoked in response to
+   the reception of a signal.
+   If an event was processed (either way), 1 is returned otherwise
+   0 is returned.   
+   Scan the queue from head to tail, processing therefore the high
+   priority events first, by invoking the associated event handler
+   procedure. */
+static int
+process_event ()
+{
+  gdb_event *event_ptr, *prev_ptr;
+  event_handler_func *proc;
+  int fd;
+
+  /* First let's see if there are any asynchronous event handlers that
+     are ready. These would be the result of invoking any of the
+     signal handlers. */
+
+  if (check_async_ready ())
+    {
+      invoke_async_signal_handler ();
+      return 1;
+    }
+
+  /* Look in the event queue to find an event that is ready
+     to be processed. */
+
+  for (event_ptr = event_queue.first_event; event_ptr != NULL;
+       event_ptr = event_ptr->next_event)
+    {
+      /* Call the handler for the event. */
+
+      proc = event_ptr->proc;
+      fd = event_ptr->fd;
+
+      /* Let's get rid of the event from the event queue.  We need to
+         do this now because while processing the event, the proc
+         function could end up calling 'error' and therefore jump out
+         to the caller of this function, gdb_do_one_event. In that
+         case, we would have on the event queue an event wich has been
+         processed, but not deleted. */
+
+      if (event_queue.first_event == event_ptr)
+       {
+         event_queue.first_event = event_ptr->next_event;
+         if (event_ptr->next_event == NULL)
+           event_queue.last_event = NULL;
+       }
+      else
+       {
+         prev_ptr = event_queue.first_event;
+         while (prev_ptr->next_event != event_ptr)
+           prev_ptr = prev_ptr->next_event;
+
+         prev_ptr->next_event = event_ptr->next_event;
+         if (event_ptr->next_event == NULL)
+           event_queue.last_event = prev_ptr;
+       }
+      free ((char *) event_ptr);
+
+      /* Now call the procedure associted with the event. */
+      (*proc) (fd);
+      return 1;
+    }
+
+  /* this is the case if there are no event on the event queue. */
+  return 0;
+}
+
+/* Process one high level event.  If nothing is ready at this time,
+   wait for something to happen (via gdb_wait_for_event), then process
+   it.  Returns 1 if something was done otherwise returns 0 (this can
+   happen if there are no event sources to wait for). */
+int
+gdb_do_one_event ()
+{
+  int result = 0;
+
+  while (1)
+    {
+      if (!SET_TOP_LEVEL ())
+       {
+         /* Any events already waiting in the queue? */
+         if (process_event ())
+           {
+             result = 1;
+             break;
+           }
+
+         /* Wait for a new event.  If gdb_wait_for_event returns -1,
+            we should get out because this means that there are no
+            event sources left. This will make the event loop stop,
+            and the application exit. */
+
+         result = gdb_wait_for_event ();
+         if (result < 0)
+           {
+             result = 0;
+             break;
+           }
+
+         /* Handle any new events occurred while waiting. */
+         if (process_event ())
+           {
+             result = 1;
+             break;
+           }
+
+         /* If gdb_wait_for_event has returned 1, it means that one
+            event has been handled. We break out of the loop. */
+         if (result)
+           break;
+       }                       /* end of if !set_top_level */
+      else
+       {
+         display_gdb_prompt (0);
+         /* Maybe better to set a flag to be checked somewhere as to
+            whether display the prompt or not. */
+       }
+    }
+  return result;
+}
+\f
+
+/* Add a file handler/descriptor to the list of descriptors we are
+   interested in.  
+   FD is the file descriptor for the file/stream to be listened to.  
+   For the poll case, MASK is a combination (OR) of
+   POLLIN, POLLRDNORM, POLLRDBAND, POLLPRI, POLLOUT, POLLWRNORM,
+   POLLWRBAND: these are the events we are interested in. If any of them 
+   occurs, proc should be called.
+   For the select case, MASK is a combination of READABLE, WRITABLE, EXCEPTION.
+   PROC is the procedure that will be called when an event occurs for
+   FD.  CLIENT_DATA is the argument to pass to PROC. */
+void
+create_file_handler (fd, mask, proc, client_data)
+     int fd;
+     int mask;
+     file_handler_func *proc;
+     gdb_client_data client_data;
+{
+  file_handler *file_ptr;
+
+#ifndef HAVE_POLL
+  int index, bit;
+#endif
+
+  /* Do we already have a file handler for this file? (We may be
+     changing its associated procedure). */
+  for (file_ptr = gdb_notifier.first_file_handler; file_ptr != NULL;
+       file_ptr = file_ptr->next_file)
+    {
+      if (file_ptr->fd == fd)
+       break;
+    }
+
+  /* It is a new file descriptor. */
+  if (file_ptr == NULL)
+    {
+      file_ptr = (file_handler *) xmalloc (sizeof (file_handler));
+      file_ptr->fd = fd;
+      file_ptr->ready_mask = 0;
+      file_ptr->next_file = gdb_notifier.first_file_handler;
+      gdb_notifier.first_file_handler = file_ptr;
+    }
+  file_ptr->proc = proc;
+  file_ptr->client_data = client_data;
+  file_ptr->mask = mask;
+
+#ifdef HAVE_POLL
+
+  gdb_notifier.num_fds++;
+  gdb_notifier.poll_fds =
+    (struct pollfd *) realloc (gdb_notifier.poll_fds,
+                          (gdb_notifier.num_fds) * sizeof (struct pollfd));
+  (gdb_notifier.poll_fds + gdb_notifier.num_fds - 1)->fd = fd;
+  (gdb_notifier.poll_fds + gdb_notifier.num_fds - 1)->events = mask;
+  (gdb_notifier.poll_fds + gdb_notifier.num_fds - 1)->revents = 0;
+
+#else /* ! HAVE_POLL */
+
+  index = fd / (NBBY * sizeof (fd_mask));
+  bit = 1 << (fd % (NBBY * sizeof (fd_mask)));
+
+  if (mask & GDB_READABLE)
+    gdb_notifier.check_masks[index] |= bit;
+  else
+    gdb_notifier.check_masks[index] &= ~bit;
+
+  if (mask & GDB_WRITABLE)
+    (gdb_notifier.check_masks + MASK_SIZE)[index] |= bit;
+  else
+    (gdb_notifier.check_masks + MASK_SIZE)[index] &= ~bit;
+
+  if (mask & GDB_EXCEPTION)
+    (gdb_notifier.check_masks + 2 * (MASK_SIZE))[index] |= bit;
+  else
+    (gdb_notifier.check_masks + 2 * (MASK_SIZE))[index] &= ~bit;
+
+  if (gdb_notifier.num_fds <= fd)
+    gdb_notifier.num_fds = fd + 1;
+
+#endif /* HAVE_POLL */
+}
+
+/* Remove the file descriptor FD from the list of monitored fd's: 
+   i.e. we don't care anymore about events on the FD. */
+void
+delete_file_handler (fd)
+     int fd;
+{
+  file_handler *file_ptr, *prev_ptr = NULL;
+  int i, j;
+  struct pollfd *new_poll_fds;
+#ifndef HAVE_POLL
+  int index, bit;
+  unsigned long flags;
+#endif
+
+  /* Find the entry for the given file. */
+
+  for (file_ptr = gdb_notifier.first_file_handler; file_ptr != NULL;
+       file_ptr = file_ptr->next_file)
+    {
+      if (file_ptr->fd == fd)
+       break;
+    }
+
+  if (file_ptr == NULL)
+    return;
+
+  /* Deactivate the file descriptor, by clearing its mask, 
+     so that it will not fire again. */
+
+  file_ptr->mask = 0;
+
+#ifdef HAVE_POLL
+  /* Create a new poll_fds array by copying every fd's information but the
+     one we want to get rid of. */
+
+  new_poll_fds =
+    (struct pollfd *) xmalloc ((gdb_notifier.num_fds - 1) * sizeof (struct pollfd));
+
+  for (i = 0, j = 0; i < gdb_notifier.num_fds; i++)
+    {
+      if ((gdb_notifier.poll_fds + i)->fd != fd)
+       {
+         (new_poll_fds + j)->fd = (gdb_notifier.poll_fds + i)->fd;
+         (new_poll_fds + j)->events = (gdb_notifier.poll_fds + i)->events;
+         (new_poll_fds + j)->revents = (gdb_notifier.poll_fds + i)->revents;
+         j++;
+       }
+    }
+  free (gdb_notifier.poll_fds);
+  gdb_notifier.poll_fds = new_poll_fds;
+  gdb_notifier.num_fds--;
+
+#else /* ! HAVE_POLL */
+
+  index = fd / (NBBY * sizeof (fd_mask));
+  bit = 1 << (fd % (NBBY * sizeof (fd_mask)));
+
+  if (file_ptr->mask & GDB_READABLE)
+    gdb_notifier.check_masks[index] &= ~bit;
+  if (file_ptr->mask & GDB_WRITABLE)
+    (gdb_notifier.check_masks + MASK_SIZE)[index] &= ~bit;
+  if (file_ptr->mask & GDB_EXCEPTION)
+    (gdb_notifier.check_masks + 2 * (MASK_SIZE))[index] &= ~bit;
+
+  /* Find current max fd. */
+
+  if ((fd + 1) == gdb_notifier.num_fds)
+    {
+      for (gdb_notifier.num_fds = 0; index >= 0; index--)
+       {
+         flags = gdb_notifier.check_masks[index]
+           | (gdb_notifier.check_masks + MASK_SIZE)[index]
+           | (gdb_notifier.check_masks + 2 * (MASK_SIZE))[index];
+         if (flags)
+           {
+             for (i = (NBBY * sizeof (fd_mask)); i > 0; i--)
+               {
+                 if (flags & (((unsigned long) 1) << (i - 1)))
+                   break;
+               }
+             gdb_notifier.num_fds = index * (NBBY * sizeof (fd_mask)) + i;
+             break;
+           }
+       }
+    }
+#endif /* HAVE_POLL */
+
+  /* Get rid of the file handler in the file handler list. */
+  if (file_ptr == gdb_notifier.first_file_handler)
+    gdb_notifier.first_file_handler = file_ptr->next_file;
+  else
+    {
+      for (prev_ptr = gdb_notifier.first_file_handler;
+          prev_ptr->next_file == file_ptr;
+          prev_ptr = prev_ptr->next_file)
+       ;
+      prev_ptr->next_file = file_ptr->next_file;
+    }
+  free ((char *) file_ptr);
+}
+
+/* Handle the given event by calling the procedure associated to the
+   corresponding file handler.  Called by process_event indirectly,
+   through event_ptr->proc.  EVENT_FILE_DESC is file descriptor of the
+   event in the front of the event queue. */
+static void
+handle_file_event (event_file_desc)
+     int event_file_desc;
+{
+  file_handler *file_ptr;
+  int mask, error_mask;
+
+  /* Search the file handler list to find one that matches the fd in
+     the event. */
+  for (file_ptr = gdb_notifier.first_file_handler; file_ptr != NULL;
+       file_ptr = file_ptr->next_file)
+    {
+      if (file_ptr->fd == event_file_desc)
+       {
+         /* With poll, the ready_mask could have any of three events
+            set to 1: POLLHUP, POLLERR, POLLNVAL. These events cannot
+            be used in the requested event mask (events), but they
+            can be returned in the return mask (revents). We need to
+            check for those event too, and add them to the mask which
+            will be passed to the handler. */
+
+         /* See if the desired events (mask) match the received
+            events (ready_mask). */
+
+#ifdef HAVE_POLL
+         error_mask = POLLHUP | POLLERR | POLLNVAL;
+         mask = (file_ptr->ready_mask & file_ptr->mask) |
+           (file_ptr->ready_mask & error_mask);
+
+#else /* ! HAVE_POLL */
+         mask = file_ptr->ready_mask & file_ptr->mask;
+#endif /* HAVE_POLL */
+
+         /* Clear the received events for next time around. */
+         file_ptr->ready_mask = 0;
+
+         /* If there was a match, then call the handler. */
+         if (mask != 0)
+           (*file_ptr->proc) (file_ptr->client_data, mask);
+         break;
+       }
+    }
+}
+
+/* Called by gdb_do_one_event to wait for new events on the 
+   monitored file descriptors. Queue file events as they are 
+   detected by the poll. 
+   If there are no events, this function will block in the 
+   call to poll.
+   Return -1 if there are no files descriptors to monitor, 
+   otherwise return 0. */
+static int
+gdb_wait_for_event ()
+{
+  file_handler *file_ptr;
+  gdb_event *file_event_ptr;
+  int num_found, i;
+
+#ifndef HAVE_POLL
+  int mask, bit, index;
+#endif
+
+  if (gdb_notifier.num_fds == 0)
+    return -1;
+
+#ifdef HAVE_POLL
+  num_found =
+    poll (gdb_notifier.poll_fds, (unsigned long) gdb_notifier.num_fds, -1);
+
+#else /* ! HAVE_POLL */
+  memcpy (gdb_notifier.ready_masks,
+         gdb_notifier.check_masks,
+         3 * MASK_SIZE * sizeof (fd_mask));
+  num_found = select (gdb_notifier.num_fds,
+                     (SELECT_MASK *) & gdb_notifier.ready_masks[0],
+                     (SELECT_MASK *) & gdb_notifier.ready_masks[MASK_SIZE],
+                 (SELECT_MASK *) & gdb_notifier.ready_masks[2 * MASK_SIZE],
+                     NULL);
+
+  /* Clear the masks after an error from select. */
+  if (num_found == -1)
+    memset (gdb_notifier.ready_masks,
+           0, 3 * MASK_SIZE * sizeof (fd_mask));
+
+#endif /* HAVE_POLL */
+
+  /* Enqueue all detected file events. */
+
+#ifdef HAVE_POLL
+
+  for (i = 0; (i < gdb_notifier.num_fds) && (num_found > 0); i++)
+    {
+      if ((gdb_notifier.poll_fds + i)->revents)
+       num_found--;
+      else
+       continue;
+
+      for (file_ptr = gdb_notifier.first_file_handler;
+          file_ptr != NULL;
+          file_ptr = file_ptr->next_file)
+       {
+         if (file_ptr->fd == (gdb_notifier.poll_fds + i)->fd)
+           break;
+       }
+
+      if (file_ptr)
+       {
+         /* Enqueue an event only if this is still a new event for
+            this fd. */
+         if (file_ptr->ready_mask == 0)
+           {
+             file_event_ptr =
+               (gdb_event *) xmalloc (sizeof (gdb_event));
+             file_event_ptr->proc = handle_file_event;
+             file_event_ptr->fd = file_ptr->fd;
+             async_queue_event (file_event_ptr, TAIL);
+           }
+       }
+
+      file_ptr->ready_mask = (gdb_notifier.poll_fds + i)->revents;
+    }
+
+#else /* ! HAVE_POLL */
+  for (file_ptr = gdb_notifier.first_file_handler;
+       (file_ptr != NULL) && (num_found > 0);
+       file_ptr = file_ptr->next_file)
+    {
+      index = file_ptr->fd / (NBBY * sizeof (fd_mask));
+      bit = 1 << (file_ptr->fd % (NBBY * sizeof (fd_mask)));
+      mask = 0;
+
+      if (gdb_notifier.ready_masks[index] & bit)
+       mask |= GDB_READABLE;
+      if ((gdb_notifier.ready_masks + MASK_SIZE)[index] & bit)
+       mask |= GDB_WRITABLE;
+      if ((gdb_notifier.ready_masks + 2 * (MASK_SIZE))[index] & bit)
+       mask |= GDB_EXCEPTION;
+
+      if (!mask)
+       continue;
+      else
+       num_found--;
+
+      /* Enqueue an event only if this is still a new event for
+         this fd. */
+
+      if (file_ptr->ready_mask == 0)
+       {
+         file_event_ptr =
+           (gdb_event *) xmalloc (sizeof (gdb_event));
+         file_event_ptr->proc = handle_file_event;
+         file_event_ptr->fd = file_ptr->fd;
+         async_queue_event (file_event_ptr, TAIL);
+       }
+      file_ptr->ready_mask = mask;
+    }
+#endif /* HAVE_POLL */
+
+  return 0;
+}
+\f
+
+/* Create an asynchronous handler, allocating memory for it. 
+   Return a pointer to the newly created handler.
+   This pointer will be used to invoke the handler by 
+   invoke_async_signal_handler.
+   PROC is the function to call with CLIENT_DATA argument 
+   whenever the handler is invoked. */
+async_signal_handler *
+create_async_signal_handler (proc, client_data)
+     async_handler_func *proc;
+     gdb_client_data client_data;
+{
+  async_signal_handler *async_handler_ptr;
+
+  async_handler_ptr =
+    (async_signal_handler *) xmalloc (sizeof (async_signal_handler));
+  async_handler_ptr->ready = 0;
+  async_handler_ptr->next_handler = NULL;
+  async_handler_ptr->proc = proc;
+  async_handler_ptr->client_data = client_data;
+  if (sighandler_list.first_handler == NULL)
+    sighandler_list.first_handler = async_handler_ptr;
+  else
+    sighandler_list.last_handler->next_handler = async_handler_ptr;
+  sighandler_list.last_handler = async_handler_ptr;
+  return async_handler_ptr;
+}
+
+/* Mark the handler (ASYNC_HANDLER_PTR) as ready. This information will
+   be used when the handlers are invoked, after we have waited for
+   some event.  The caller of this function is the interrupt handler
+   associated with a signal. */
+void
+mark_async_signal_handler (async_handler_ptr)
+     async_signal_handler *async_handler_ptr;
+{
+  ((async_signal_handler *) async_handler_ptr)->ready = 1;
+  async_handler_ready = 1;
+}
+
+/* Call all the handlers that are ready. */
+static void
+invoke_async_signal_handler ()
+{
+  async_signal_handler *async_handler_ptr;
+
+  if (async_handler_ready == 0)
+    return;
+  async_handler_ready = 0;
+
+  /* Invoke ready handlers. */
+
+  while (1)
+    {
+      for (async_handler_ptr = sighandler_list.first_handler; 
+          async_handler_ptr != NULL;
+          async_handler_ptr = async_handler_ptr->next_handler)
+       {
+         if (async_handler_ptr->ready)
+           break;
+       }
+      if (async_handler_ptr == NULL)
+       break;
+      async_handler_ptr->ready = 0;
+      (*async_handler_ptr->proc) (async_handler_ptr->client_data);
+    }
+
+  return;
+}
+
+/* Delete an asynchronous handler (ASYNC_HANDLER_PTR). 
+   Free the space allocated for it.  */
+void
+delete_async_signal_handler (async_handler_ptr)
+     async_signal_handler *async_handler_ptr;
+{
+  async_signal_handler *prev_ptr;
+
+  if (sighandler_list.first_handler == async_handler_ptr)
+    {
+      sighandler_list.first_handler = async_handler_ptr->next_handler;
+      if (sighandler_list.first_handler == NULL)
+       sighandler_list.last_handler = NULL;
+    }
+  else
+    {
+      prev_ptr = sighandler_list.first_handler;
+      while (prev_ptr->next_handler != async_handler_ptr)
+       prev_ptr = prev_ptr->next_handler;
+      prev_ptr->next_handler = async_handler_ptr->next_handler;
+      if (sighandler_list.last_handler == async_handler_ptr)
+       sighandler_list.last_handler = prev_ptr;
+    }
+  free ((char *) async_handler_ptr);
+}
+
+/* Is it necessary to call invoke_async_signal_handler? */
+static int
+check_async_ready ()
+{
+  return async_handler_ready;
+}
diff --git a/gdb/event-loop.h b/gdb/event-loop.h
new file mode 100644 (file)
index 0000000..6076254
--- /dev/null
@@ -0,0 +1,241 @@
+/* Definitions used by the GDB event loop.
+   Copyright 1999 Free Software Foundation, Inc.
+   Written by Elena Zannoni <ezannoni@cygnus.com> of Cygnus Solutions.
+
+   This file is part of GDB.
+
+   This program 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 of the License, or
+   (at your option) any later version.
+
+   This program 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-1307, USA.  */
+
+#include <stdlib.h>
+#include <sys/types.h>
+#include <sys/time.h>
+#include <signal.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <sys/wait.h>
+#include "defs.h"
+
+/* An event loop listens for events from multiple event sources. When
+   an event arrives, it is queued and processed by calling the
+   appropriate event handler. The event loop then continues to listen
+   for more events. An event loop completes when there are no event
+   sources to listen on.  External event sources can be plugged into
+   the loop.
+
+   There are 3 main components: 
+   - a list of file descriptors to be monitored, GDB_NOTIFIER.  
+   - a list of events that have occurred, EVENT_QUEUE.  
+   - a list of signal handling functions, SIGHANDLER_LIST.
+
+   GDB_NOTIFIER keeps track of the event sources. Event sources for
+   gdb are currently the UI and the target.  Gdb communicates with the
+   command line user interface via the readline library and usually
+   communicates with remote targets via a serial port. Serial ports
+   are represented in GDB as file descriptors and select/poll calls.
+   For native targets instead, the communication consists of calls to
+   ptrace and waits (via signals) or calls to poll/select (via file
+   descriptors). In the current gdb, the code handling events related
+   to the target resides in the wait_for_inferior function and in
+   various target specific files (*-tdep.c).
+
+   EVENT_QUEUE keeps track of the events that have happened during the
+   last iteration of the event loop, and need to be processed.  An
+   event is represented by a procedure to be invoked in order to
+   process the event.  The queue is scanned head to tail.  If the
+   event of interest is a change of state in a file descriptor, then a
+   call to poll or select will be made to detect it.
+
+   If the events generate signals, they are also queued by special
+   functions that are invoked through traditional signal handlers.
+   The actions to be taken is response to such events will be executed
+   when the SIGHANDLER_LIST is scanned, the next time through the
+   infinite loop.  
+
+   Corollary tasks are the creation and deletion of event sources. */
+
+typedef PTR gdb_client_data;
+typedef struct gdb_event gdb_event;
+
+typedef void (file_handler_func) PARAMS ((gdb_client_data, int mask));
+typedef void (async_handler_func) PARAMS ((gdb_client_data));
+typedef void (event_handler_func) PARAMS ((int));
+
+/* Event for the GDB event system.  Events are queued by calling
+   async_queue_event and serviced later on by gdb_do_one_event. An
+   event can be, for instance, a file descriptor becoming ready to be
+   read. Servicing an event simply means that the procedure PROC will
+   be called.  We have 2 queues, one for file handlers that we listen
+   to in the event loop, and one for the file handlers+events that are
+   ready. The procedure PROC associated with each event is always the
+   same (handle_file_event).  Its duty is to invoke the handler
+   associated with the file descriptor whose state change generated
+   the event, plus doing other cleanups adn such. */
+
+struct gdb_event
+  {
+    event_handler_func *proc;  /* Procedure to call to service this event. */
+    int fd;                    /* File descriptor that is ready. */
+    struct gdb_event *next_event;      /* Next in list of events or NULL. */
+  };
+
+/* Information about each file descriptor we register with the event
+   loop. */
+
+typedef struct file_handler
+  {
+    int fd;                    /* File descriptor. */
+    int mask;                  /* Events we want to monitor: POLLIN, etc. */
+    int ready_mask;            /* Events that have been seen since
+                                  the last time. */
+    file_handler_func *proc;   /* Procedure to call when fd is ready. */
+    gdb_client_data client_data;       /* Argument to pass to proc. */
+    struct file_handler *next_file;    /* Next registered file descriptor. */
+  }
+file_handler;
+
+/* PROC is a function to be invoked when the READY flag is set. This
+   happens when there has been a signal and the corresponding signal
+   handler has 'triggered' this async_signal_handler for
+   execution. The actual work to be done in response to a signal will
+   be carried out by PROC at a later time, within process_event. This
+   provides a deferred execution of signal handlers.
+   Async_init_signals takes care of setting up such an
+   asyn_signal_handler for each interesting signal. */
+
+typedef struct async_signal_handler
+  {
+    int ready; /* If ready, call this handler from the main event loop, 
+                                  using invoke_async_handler. */
+    struct async_signal_handler *next_handler; /* Ptr to next handler */
+    async_handler_func *proc;  /* Function to call to do the work */
+    gdb_client_data client_data;       /* Argument to async_handler_func */
+  }
+async_signal_handler;
+
+/* Where to add an event onto the event queue, by queue_event. */
+typedef enum
+  {
+    /* Add at tail of queue. It will be processed in first in first
+       out order. */
+    TAIL,
+    /* Add at head of queue. It will be processed in last in first out
+       order. */
+    HEAD       
+  }
+queue_position;
+
+/* Tell create_file_handler what events we are interested in. 
+   This is used by the select version of the event loop. */
+
+#define GDB_READABLE   (1<<1)
+#define GDB_WRITABLE   (1<<2)
+#define GDB_EXCEPTION  (1<<3)
+
+/* Type of the mask arguments to select. */
+
+#ifndef NO_FD_SET
+#define SELECT_MASK fd_set
+#else
+#ifndef _AIX
+typedef long fd_mask;
+#endif
+#if defined(_IBMR2)
+#define SELECT_MASK void
+#else
+#define SELECT_MASK int
+#endif
+#endif
+
+/* Define "NBBY" (number of bits per byte) if it's not already defined. */
+
+#ifndef NBBY
+#define NBBY 8
+#endif
+
+
+/* Define the number of fd_masks in an fd_set */
+
+#ifndef FD_SETSIZE
+#ifdef OPEN_MAX
+#define FD_SETSIZE OPEN_MAX
+#else
+#define FD_SETSIZE 256
+#endif
+#endif
+#if !defined(howmany)
+#define howmany(x, y) (((x)+((y)-1))/(y))
+#endif
+#ifndef NFDBITS
+#define NFDBITS NBBY*sizeof(fd_mask)
+#endif
+#define MASK_SIZE howmany(FD_SETSIZE, NFDBITS)
+
+
+/* Stack for prompts. Each prompt is composed as a prefix, a prompt
+   and a suffix. The prompt to be displayed at any given time is the
+   one on top of the stack.  A stack is necessary because of cases in
+   which the execution of a gdb command requires further input from
+   the user, like for instance 'commands' for breakpoints and
+   'actions' for tracepoints. In these cases, the prompt is '>' and
+   gdb should process input using the asynchronous readline interface
+   and the event loop.  In order to achieve this, we need to save
+   somewhere the state of GDB, i.e. that it is processing user input
+   as part of a command and not as part of the top level command loop.
+   The prompt stack represents part of the saved state. Another part
+   would be the function that readline would invoke after a whole line
+   of input has ben entered. This second piece would be something
+   like, for instance, where to return within the code for the actions
+   commands after a line has been read.  This latter portion has not
+   beeen implemented yet.  The need for a 3-part prompt arises from
+   the annotation level. When this is set to 2, the prompt is actually
+   composed of a prefix, the prompt itself and a suffix. */
+
+/* At any particular time there will be always at least one prompt on
+   the stack, the one being currently displayed by gdb. If gdb is
+   using annotation level equal 2, there will be 2 prompts on the
+   stack: the usual one, w/o prefix and suffix (at top - 1), and the
+   'composite' one with prefix and suffix added (at top). At this
+   time, this is the only use of the prompt stack. Resetting annotate
+   to 0 or 1, pops the top of the stack, resetting its size to one
+   element. The MAXPROMPTS limit is safe, for now. Once other cases
+   are dealt with (like the different prompts used for 'commands' or
+   'actions') this array implementation of the prompt stack may have
+   to change. */
+
+#define MAXPROMPTS 10
+struct prompts
+  {
+    struct
+      {
+       char *prefix;
+       char *prompt;
+       char *suffix;
+      }
+    prompt_stack[MAXPROMPTS];
+    int top;
+  };
+
+#define PROMPT(X) the_prompts.prompt_stack[the_prompts.top + X].prompt
+#define PREFIX(X) the_prompts.prompt_stack[the_prompts.top + X].prefix
+#define SUFFIX(X) the_prompts.prompt_stack[the_prompts.top + X].suffix
+
+extern void delete_file_handler PARAMS ((int));
+extern void 
+  create_file_handler PARAMS ((int, int, file_handler_func, gdb_client_data));
+extern int gdb_do_one_event PARAMS ((void));
+extern void mark_async_signal_handler PARAMS ((async_signal_handler *));
+extern async_signal_handler *
+  create_async_signal_handler PARAMS ((async_handler_func *, gdb_client_data));
+
diff --git a/gdb/event-top.c b/gdb/event-top.c
new file mode 100644 (file)
index 0000000..5851fd2
--- /dev/null
@@ -0,0 +1,950 @@
+/* Top level stuff for GDB, the GNU debugger.
+   Copyright 1999 Free Software Foundation, Inc.
+   Written by Elena Zannoni <ezannoni@cygnus.com> of Cygnus Solutions.
+
+   This file is part of GDB.
+
+   This program 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 of the License, or
+   (at your option) any later version.
+
+   This program 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-1307, USA. */
+
+#include "defs.h"
+#include "event-loop.h"
+#ifdef HAVE_POLL
+#include <sys/poll.h>
+#endif
+#include "inferior.h"
+
+/* readline include files */
+#include <readline/readline.h>
+#include <readline/history.h>
+
+/* readline defines this.  */
+#undef savestring
+
+extern FILE *instream;
+
+static void command_line_handler PARAMS ((char *));
+static void gdb_readline2 PARAMS ((void));
+static void pop_prompt PARAMS ((void));
+static void push_prompt PARAMS ((char *, char *, char *));
+
+/* Signal handlers. */
+void handle_sigint PARAMS ((int));
+void handle_sigquit PARAMS ((int));
+void handle_sighup PARAMS ((int));
+void handle_sigfpe PARAMS ((int));
+void handle_sigwinch PARAMS ((int));
+
+/* Functions to be invoked by the event loop in response to
+   signals. */
+void async_request_quit PARAMS ((void));
+void async_do_nothing PARAMS ((void));
+void async_disconnect PARAMS ((void));
+void async_float_handler PARAMS ((void));
+
+/* Functions from top.c. */
+extern void command_loop_marker PARAMS ((int));
+extern int quit_cover PARAMS ((PTR));
+extern void quit_command PARAMS ((char *, int));
+extern void execute_command PARAMS ((char *, int));
+
+/* Variables from top.c. */
+extern int source_line_number;
+extern char *source_file_name;
+extern char *source_error;
+extern char *source_pre_error;
+extern int history_expansion_p;
+extern int server_command;
+
+/* If this definition isn't overridden by the header files, assume
+   that isatty and fileno exist on this system.  */
+#ifndef ISATTY
+#define ISATTY(FP)     (isatty (fileno (FP)))
+#endif
+
+/* Hook for alternate command interface.  */
+void (*async_hook) PARAMS ((void));
+
+/* Readline offers an alternate interface, via callback
+   functions. These are all included in the file callback.c in the
+   readline distribution.  This file provides (mainly) a function, which
+   the event loop uses as callback (i.e. event handler) whenever an event
+   is detected on the standard input file descriptor.
+   readline_callback_read_char is called (by the GDB event loop) whenever
+   there is a new character ready on the input stream. This function
+   incrementally builds a buffer internal to readline where it
+   accumulates the line read up to the point of invocation.  In the
+   special case in which the character read is newline, the function
+   invokes a GDB supplied callback routine, which does the processing of
+   a full command line.  This latter routine is the asynchronous analog
+   of the old command_line_input in gdb. Instead of invoking (and waiting
+   for) readline to read the command line and pass it back to
+   command_loop for processing, the new command_line_handler function has
+   the command line already available as its parameter.  INPUT_HANDLER is
+   to be set to the function that readline will invoke when a complete
+   line of input is ready.  CALL_READLINE is to be set to the function
+   that readline offers as callback to the event_loop. */
+
+void (*input_handler) PARAMS ((char *));
+void (*call_readline) PARAMS ((void));
+
+/* Important variables for the event loop. */
+
+/* This is used to determine if GDB is using the readline library or
+   its own simplified form of readline. It is used by the asynchronous
+   form of the set editing command. 
+   ezannoni: as of 4/29/99 I expect that this
+   variable will not be used after gdb is changed to use the event
+   loop as default engine, and event-top.c is merged into top.c. */
+int async_command_editing_p;
+
+/* This variable contains the new prompt that the user sets with the
+   set prompt command. */
+char *new_async_prompt;
+
+/* This is the annotation suffix that will be used when the
+   annotation_level is 2. */
+char *async_annotation_suffix;
+
+/* This is the file descriptor for the input stream that GDB uses to
+   read commands from. */
+int input_fd;
+
+/* This is the prompt stack. Prompts will be pushed on the stack as
+   needed by the different 'kinds' of user inputs GDB is asking
+   for. See event-loop.h. */
+struct prompts the_prompts;
+
+/* signal handling variables */
+/* Each of these is a pointer to a function that the event loop will
+   invoke if the corresponding signal has received. The real signal
+   handlers mark these functions as ready to be executed and the event
+   loop, in a later iteration, calls them. See the function
+   invoke_async_signal_handler. */
+async_signal_handler *sigint_token;
+#ifdef SIGHUP
+async_signal_handler *sighup_token;
+#endif
+async_signal_handler *sigquit_token;
+async_signal_handler *sigfpe_token;
+#if defined(SIGWINCH) && defined(SIGWINCH_HANDLER)
+async_signal_handler *sigwinch_token;
+#endif
+
+/* Structure to save a partially entered command.  This is used when
+   the user types '\' at the end of a command line. This is necessary
+   because each line of input is handled by a different call to
+   command_line_handler, and normally there is no state retained
+   between different calls. */
+int more_to_come = 0;
+
+struct readline_input_state
+  {
+    char *linebuffer;
+    char *linebuffer_ptr;
+  }
+readline_input_state;
+\f
+
+/* Initialize all the necessary variables, start the event loop,
+   register readline, and stdin. */
+void
+setup_event_loop ()
+{
+  int length = strlen (PREFIX (0)) + strlen (PROMPT (0)) + strlen (SUFFIX (0)) + 1;
+  char *a_prompt = (char *) xmalloc (length);
+
+  /* Set things up for readline to be invoked via the alternate
+     interface, i.e. via a callback function (rl_callback_read_char). */
+  call_readline = rl_callback_read_char;
+
+  /* When readline has read an end-of-line character, it passes the
+     complete line to gdb for processing. command_line_handler is the
+     function that does this. */
+  input_handler = command_line_handler;
+
+  /* Tell readline what the prompt to display is and what function it
+     will need to call after a whole line is read. */
+  strcpy (a_prompt, PREFIX (0));
+  strcat (a_prompt, PROMPT (0));
+  strcat (a_prompt, SUFFIX (0));
+  rl_callback_handler_install (a_prompt, input_handler);
+
+  /* Tell readline to use the same input stream that gdb uses. */
+  rl_instream = instream;
+  /* Get a file descriptor for the input stream, so that we can
+     register it with the event loop. */
+  input_fd = fileno (instream);
+
+  /* Now we need to create the event sources for the input file descriptor. */
+  /* At this point in time, this is the only event source that we
+     register with the even loop. Another source is going to be the
+     target program (inferior), but that must be registered only when
+     it actually exists (I.e. after we say 'run' or after we connect
+     to a remote target. */
+#ifdef HAVE_POLL
+  create_file_handler (input_fd, POLLIN,
+                      (file_handler_func *) call_readline, 0);
+#else
+  create_file_handler (input_fd, GDB_READABLE,
+                      (file_handler_func *) call_readline, 0);
+#endif
+
+  /* Loop until there is something to do. This is the entry point to
+     the event loop engine. gdb_do_one_event will process one event
+     for each invocation.  It always returns 1, unless there are no
+     more event sources registered. In this case it returns 0.  */
+  while (gdb_do_one_event () != 0)
+    ;
+
+  /* We are done with the event loop. There are no more event sources
+     to listen to.  So we exit GDB. */
+  return;
+}
+
+/* Change the function to be invoked every time there is a character
+   ready on stdin. This is used when the user sets the editing off,
+   therefore bypassing readline, and letting gdb handle the input
+   itself, via gdb_readline2. Also it is used in the opposite case in
+   which the user sets editing on again, by restoring readline
+   handling of the input. */
+void
+change_line_handler ()
+{
+  if (async_command_editing_p)
+    {
+      /* Turn on editing by using readline. */
+      call_readline = rl_callback_read_char;
+    }
+  else
+    {
+      /* Turn off editing by using gdb_readline2. */
+      rl_callback_handler_remove ();
+      call_readline = gdb_readline2;
+    }
+
+  /* To tell the event loop to change the handler associated with the
+     input file descriptor, we need to create a new event source,
+     corresponding to the same fd, but with a new event handler
+     function. */
+  delete_file_handler (input_fd);
+#ifdef HAVE_POLL
+  create_file_handler (input_fd, POLLIN,
+                      (file_handler_func *) call_readline, 0);
+#else
+  create_file_handler (input_fd, GDB_READABLE,
+                      (file_handler_func *) call_readline, 0);
+#endif
+}
+
+/* Displays the prompt. The prompt that is displayed is the current
+   top of the prompt stack, if the argument NEW_PROMPT is
+   0. Otherwise, it displays whatever NEW_PROMPT is. This is used
+   after each gdb command has completed, and in the following cases:
+   1. when the user enters a command line which is ended by '\' 
+   indicating that the command will continue on the next line. 
+   In that case the prompt that is displayed is the empty string.
+   2. When the user is entering 'commands' for a breakpoint, or 
+   actions for a tracepoint. In this case the prompt will be '>' 
+   3. Other???? 
+   FIXME: 2. & 3. not implemented yet for async. */
+void
+display_gdb_prompt (new_prompt)
+     char *new_prompt;
+{
+  int prompt_length = 0;
+
+  if (!new_prompt)
+    {
+      /* Just use the top of the prompt stack. */
+      prompt_length = strlen (PREFIX (0)) +
+       strlen (SUFFIX (0)) +
+       strlen (PROMPT (0)) + 1;
+
+      new_prompt = (char *) alloca (prompt_length);
+
+      /* Prefix needs to have new line at end. */
+      strcpy (new_prompt, PREFIX (0));
+      strcat (new_prompt, PROMPT (0));
+      /* Suffix needs to have a new line at end and \032 \032 at
+         beginning. */
+      strcat (new_prompt, SUFFIX (0));
+    }
+
+  if (async_command_editing_p)
+    {
+      rl_callback_handler_remove ();
+      rl_callback_handler_install (new_prompt, input_handler);
+    }
+  else if (new_prompt)
+    {
+      /* Don't use a _filtered function here.  It causes the assumed
+         character position to be off, since the newline we read from
+         the user is not accounted for.  */
+      fputs_unfiltered (new_prompt, gdb_stdout);
+
+#ifdef MPW
+      /* Move to a new line so the entered line doesn't have a prompt
+         on the front of it. */
+      fputs_unfiltered ("\n", gdb_stdout);
+#endif /* MPW */
+      gdb_flush (gdb_stdout);
+    }
+}
+
+/* Used when the user requests a different annotation level, with
+   'set annotate'. It pushes a new prompt (with prefix and suffix) on top
+   of the prompt stack, if the annotation level desired is 2, otherwise
+   it pops the top of the prompt stack when we want the annotation level
+   to be the normal ones (1 or 2). */
+void
+change_annotation_level ()
+{
+  char *prefix, *suffix;
+
+  if (!PREFIX (0) || !PROMPT (0) || !SUFFIX (0))
+    {
+      /* The prompt stack has not been initialized to "", we are
+         using gdb w/o the --async switch */
+      warning ("Command has same effect as set annotate");
+      return;
+    }
+
+  if (annotation_level > 1)
+    {
+      if (!strcmp (PREFIX (0), "") && !strcmp (SUFFIX (0), ""))
+       {
+         /* Push a new prompt if the previous annotation_level was not >1. */
+         prefix = (char *) alloca (strlen (async_annotation_suffix) + 10);
+         strcpy (prefix, "\n\032\032pre-");
+         strcat (prefix, async_annotation_suffix);
+         strcat (prefix, "\n");
+
+         suffix = (char *) alloca (strlen (async_annotation_suffix) + 6);
+         strcpy (suffix, "\n\032\032");
+         strcat (suffix, async_annotation_suffix);
+         strcat (suffix, "\n");
+
+         push_prompt (prefix, (char *) 0, suffix);
+       }
+    }
+  else
+    {
+      if (strcmp (PREFIX (0), "") && strcmp (SUFFIX (0), ""))
+       {
+         /* Pop the top of the stack, we are going back to annotation < 1. */
+         pop_prompt ();
+       }
+    }
+}
+
+/* Pushes a new prompt on the prompt stack. Each prompt has three
+   parts: prefix, prompt, suffix. Usually prefix and suffix are empty
+   strings, except when the annotation level is 2. Memory is allocated
+   within savestring for the new prompt. */
+static void
+push_prompt (prefix, prompt, suffix)
+     char *prefix;
+     char *prompt;
+     char *suffix;
+{
+  the_prompts.top++;
+  PREFIX (0) = savestring (prefix, strlen (prefix));
+
+  if (prompt)
+    PROMPT (0) = savestring (prompt, strlen (prompt));
+  else
+    PROMPT (0) = savestring (PROMPT (-1), strlen (PROMPT (-1)));
+
+  SUFFIX (0) = savestring (suffix, strlen (suffix));
+}
+
+/* Pops the top of the prompt stack, and frees the memory allocated for it. */
+static void
+pop_prompt ()
+{
+  if (strcmp (PROMPT (0), PROMPT (-1)))
+    {
+      free (PROMPT (-1));
+      PROMPT (-1) = savestring (PROMPT (0), strlen (PROMPT (0)));
+    }
+
+  free (PREFIX (0));
+  free (PROMPT (0));
+  free (SUFFIX (0));
+  the_prompts.top--;
+}
+\f
+/* Handles a gdb command. This function is called by
+   command_line_handler, which has processed one or more input lines
+   into COMMAND. */
+/* NOTE: 4/30/99 This is the asynchronous version of the command_loop
+   function.  The command_loop function will be obsolete when we
+   switch to use the event loop at every execution of gdb. */
+void
+command_handler (command)
+     char *command;
+{
+  struct cleanup *old_chain;
+  int stdin_is_tty = ISATTY (stdin);
+  long time_at_cmd_start;
+#ifdef HAVE_SBRK
+  long space_at_cmd_start = 0;
+#endif
+  extern int display_time;
+  extern int display_space;
+
+#if defined(TUI)
+  extern int insert_mode;
+#endif
+
+  quit_flag = 0;
+  if (instream == stdin && stdin_is_tty)
+    reinitialize_more_filter ();
+  old_chain = make_cleanup ((make_cleanup_func) command_loop_marker, 0);
+
+#if defined(TUI)
+  insert_mode = 0;
+#endif
+  /* If readline returned a NULL command, it means that the 
+     connection with the terminal is gone. This happens at the
+     end of a testsuite run, after Expect has hung up 
+     but GDB is still alive. In such a case, we just quit gdb
+     killing the inferior program too. */
+  if (command == 0)
+    quit_command ((char *) 0, stdin == instream);
+
+  time_at_cmd_start = get_run_time ();
+
+  if (display_space)
+    {
+#ifdef HAVE_SBRK
+      extern char **environ;
+      char *lim = (char *) sbrk (0);
+
+      space_at_cmd_start = (long) (lim - (char *) &environ);
+#endif
+    }
+
+  execute_command (command, instream == stdin);
+
+  /* Do any commands attached to breakpoint we stopped at.  */
+  bpstat_do_actions (&stop_bpstat);
+  do_cleanups (old_chain);
+
+  if (display_time)
+    {
+      long cmd_time = get_run_time () - time_at_cmd_start;
+
+      printf_unfiltered ("Command execution time: %ld.%06ld\n",
+                        cmd_time / 1000000, cmd_time % 1000000);
+    }
+
+  if (display_space)
+    {
+#ifdef HAVE_SBRK
+      extern char **environ;
+      char *lim = (char *) sbrk (0);
+      long space_now = lim - (char *) &environ;
+      long space_diff = space_now - space_at_cmd_start;
+
+      printf_unfiltered ("Space used: %ld (%c%ld for this command)\n",
+                        space_now,
+                        (space_diff >= 0 ? '+' : '-'),
+                        space_diff);
+#endif
+    }
+}
+
+/* Handle a complete line of input. This is called by the callback
+   mechanism within the readline library.  Deal with incomplete commands
+   as well, by saving the partial input in a global buffer.  */
+
+/* NOTE: 4/30/99 This is the asynchronous version of the
+   command_line_input function. command_line_input will become
+   obsolete once we use the event loop as the default mechanism in
+   GDB. */
+static void
+command_line_handler (rl)
+     char *rl;
+{
+  static char *linebuffer = 0;
+  static unsigned linelength = 0;
+  register char *p;
+  char *p1;
+  int change_prompt = 0;
+  extern char *line;
+  extern int linesize;
+  char *nline;
+  char got_eof = 0;
+
+
+  int repeat = (instream == stdin);
+
+  if (annotation_level > 1 && instream == stdin)
+    {
+      printf_unfiltered ("\n\032\032post-");
+      printf_unfiltered (async_annotation_suffix);
+      printf_unfiltered ("\n");
+    }
+
+  if (linebuffer == 0)
+    {
+      linelength = 80;
+      linebuffer = (char *) xmalloc (linelength);
+    }
+
+  p = linebuffer;
+
+  if (more_to_come)
+    {
+      strcpy (linebuffer, readline_input_state.linebuffer);
+      p = readline_input_state.linebuffer_ptr;
+      free (readline_input_state.linebuffer);
+      more_to_come = 0;
+      change_prompt = 1;
+    }
+
+#ifdef STOP_SIGNAL
+  if (job_control)
+    signal (STOP_SIGNAL, stop_sig);
+#endif
+
+  /* Make sure that all output has been output.  Some machines may let
+     you get away with leaving out some of the gdb_flush, but not all.  */
+  wrap_here ("");
+  gdb_flush (gdb_stdout);
+  gdb_flush (gdb_stderr);
+
+  if (source_file_name != NULL)
+    {
+      ++source_line_number;
+      sprintf (source_error,
+              "%s%s:%d: Error in sourced command file:\n",
+              source_pre_error,
+              source_file_name,
+              source_line_number);
+      error_pre_print = source_error;
+    }
+
+  /* If we are in this case, then command_handler will call quit 
+     and exit from gdb. */
+  if (!rl || rl == (char *) EOF)
+    {
+      got_eof = 1;
+      command_handler (0);
+    }
+  if (strlen (rl) + 1 + (p - linebuffer) > linelength)
+    {
+      linelength = strlen (rl) + 1 + (p - linebuffer);
+      nline = (char *) xrealloc (linebuffer, linelength);
+      p += nline - linebuffer;
+      linebuffer = nline;
+    }
+  p1 = rl;
+  /* Copy line.  Don't copy null at end.  (Leaves line alone
+     if this was just a newline)  */
+  while (*p1)
+    *p++ = *p1++;
+
+  free (rl);                   /* Allocated in readline.  */
+
+  if (p == linebuffer || *(p - 1) == '\\')
+    {
+      /* We come here also if the line entered is empty (just a 'return') */
+      p--;                     /* Put on top of '\'.  */
+
+      if (*p == '\\')
+       {
+         readline_input_state.linebuffer = savestring (linebuffer,
+                                                       strlen (linebuffer));
+         readline_input_state.linebuffer_ptr = p;
+
+         /* We will not invoke a execute_command if there is more
+            input expected to complete the command. So, we need to
+            print an empty prompt here. */
+         display_gdb_prompt ("");
+         more_to_come = 1;
+       }
+    }
+
+#ifdef STOP_SIGNAL
+  if (job_control)
+    signal (STOP_SIGNAL, SIG_DFL);
+#endif
+
+#define SERVER_COMMAND_LENGTH 7
+  server_command =
+    (p - linebuffer > SERVER_COMMAND_LENGTH)
+    && STREQN (linebuffer, "server ", SERVER_COMMAND_LENGTH);
+  if (server_command)
+    {
+      /* Note that we don't set `line'.  Between this and the check in
+         dont_repeat, this insures that repeating will still do the
+         right thing.  */
+      *p = '\0';
+      command_handler (linebuffer + SERVER_COMMAND_LENGTH);
+      display_gdb_prompt (0);
+      return;
+    }
+
+  /* Do history expansion if that is wished.  */
+  if (history_expansion_p && instream == stdin
+      && ISATTY (instream))
+    {
+      char *history_value;
+      int expanded;
+
+      *p = '\0';               /* Insert null now.  */
+      expanded = history_expand (linebuffer, &history_value);
+      if (expanded)
+       {
+         /* Print the changes.  */
+         printf_unfiltered ("%s\n", history_value);
+
+         /* If there was an error, call this function again.  */
+         if (expanded < 0)
+           {
+             free (history_value);
+             return;
+           }
+         if (strlen (history_value) > linelength)
+           {
+             linelength = strlen (history_value) + 1;
+             linebuffer = (char *) xrealloc (linebuffer, linelength);
+           }
+         strcpy (linebuffer, history_value);
+         p = linebuffer + strlen (linebuffer);
+         free (history_value);
+       }
+    }
+
+  /* If we just got an empty line, and that is supposed
+     to repeat the previous command, return the value in the
+     global buffer.  */
+  if (repeat && p == linebuffer && *p != '\\')
+    {
+      command_handler (line);
+      display_gdb_prompt (0);
+      return;
+    }
+
+  for (p1 = linebuffer; *p1 == ' ' || *p1 == '\t'; p1++);
+  if (repeat && !*p1)
+    {
+      command_handler (line);
+      display_gdb_prompt (0);
+      return;
+    }
+
+  *p = 0;
+
+  /* Add line to history if appropriate.  */
+  if (instream == stdin
+      && ISATTY (stdin) && *linebuffer)
+    add_history (linebuffer);
+
+  /* Note: lines consisting solely of comments are added to the command
+     history.  This is useful when you type a command, and then
+     realize you don't want to execute it quite yet.  You can comment
+     out the command and then later fetch it from the value history
+     and remove the '#'.  The kill ring is probably better, but some
+     people are in the habit of commenting things out.  */
+  if (*p1 == '#')
+    *p1 = '\0';                        /* Found a comment. */
+
+  /* Save into global buffer if appropriate.  */
+  if (repeat)
+    {
+      if (linelength > linesize)
+       {
+         line = xrealloc (line, linelength);
+         linesize = linelength;
+       }
+      strcpy (line, linebuffer);
+      if (!more_to_come)
+       {
+         command_handler (line);
+         display_gdb_prompt (0);
+       }
+      return;
+    }
+
+  command_handler (linebuffer);
+  display_gdb_prompt (0);
+  return;
+}
+
+/* Does reading of input from terminal w/o the editing features
+   provided by the readline library. */
+
+/* NOTE: 4/30/99 Asynchronous version of gdb_readline. gdb_readline
+   will become obsolete when the event loop is made the default
+   execution for gdb. */
+static void
+gdb_readline2 ()
+{
+  int c;
+  char *result;
+  int input_index = 0;
+  int result_size = 80;
+
+  result = (char *) xmalloc (result_size);
+
+  /* We still need the while loop here, even though it would seem
+     obvious to invoke gdb_readline2 at every character entered.  If
+     not using the readline library, the terminal is in cooked mode,
+     which sends the characters all at once. Poll will notice that the
+     input fd has changed state only after enter is pressed. At this
+     point we still need to fetch all the chars entered. */
+
+  while (1)
+    {
+      /* Read from stdin if we are executing a user defined command.
+         This is the right thing for prompt_for_continue, at least.  */
+      c = fgetc (instream ? instream : stdin);
+
+      if (c == EOF)
+       {
+         if (input_index > 0)
+           /* The last line does not end with a newline.  Return it, and
+              if we are called again fgetc will still return EOF and
+              we'll return NULL then.  */
+           break;
+         free (result);
+         command_line_handler (0);
+       }
+
+      if (c == '\n')
+#ifndef CRLF_SOURCE_FILES
+       break;
+#else
+       {
+         if (input_index > 0 && result[input_index - 1] == '\r')
+           input_index--;
+         break;
+       }
+#endif
+
+      result[input_index++] = c;
+      while (input_index >= result_size)
+       {
+         result_size *= 2;
+         result = (char *) xrealloc (result, result_size);
+       }
+    }
+
+  result[input_index++] = '\0';
+  command_line_handler (result);
+}
+\f
+
+/* Initialization of signal handlers and tokens.  There is a function
+   handle_sig* for each of the signals GDB cares about. Specifically:
+   SIGINT, SIGFPE, SIGQUIT, SIGTSTP, SIGHUP, SIGWINCH.  These
+   functions are the actual signal handlers associated to the signals
+   via calls to signal().  The only job for these functions is to
+   enqueue the appropriate event/procedure with the event loop.  Such
+   procedures are the old signal handlers. The event loop will take
+   care of invoking the queued procedures to perform the usual tasks
+   associated with the reception of the signal. */
+/* NOTE: 4/30/99 This is the asynchronous version of init_signals.
+   init_signals will become obsolete as we move to have to event loop
+   as the default for gdb. */
+void
+async_init_signals ()
+{
+  signal (SIGINT, handle_sigint);
+  sigint_token =
+    create_async_signal_handler ((async_handler_func *) async_request_quit, NULL);
+
+  /* If SIGTRAP was set to SIG_IGN, then the SIG_IGN will get passed
+     to the inferior and breakpoints will be ignored.  */
+#ifdef SIGTRAP
+  signal (SIGTRAP, SIG_DFL);
+#endif
+
+  /* If we initialize SIGQUIT to SIG_IGN, then the SIG_IGN will get
+     passed to the inferior, which we don't want.  It would be
+     possible to do a "signal (SIGQUIT, SIG_DFL)" after we fork, but
+     on BSD4.3 systems using vfork, that can affect the
+     GDB process as well as the inferior (the signal handling tables
+     might be in memory, shared between the two).  Since we establish
+     a handler for SIGQUIT, when we call exec it will set the signal
+     to SIG_DFL for us.  */
+  signal (SIGQUIT, handle_sigquit);
+  sigquit_token =
+    create_async_signal_handler ((async_handler_func *) async_do_nothing, NULL);
+#ifdef SIGHUP
+  if (signal (SIGHUP, handle_sighup) != SIG_IGN)
+    sighup_token =
+      create_async_signal_handler ((async_handler_func *) async_disconnect, NULL);
+  else
+    sighup_token =
+      create_async_signal_handler ((async_handler_func *) async_do_nothing, NULL);
+#endif
+  signal (SIGFPE, handle_sigfpe);
+  sigfpe_token =
+    create_async_signal_handler ((async_handler_func *) async_float_handler, NULL);
+
+#if defined(SIGWINCH) && defined(SIGWINCH_HANDLER)
+  signal (SIGWINCH, handle_sigwinch);
+  sigwinch_token =
+    create_async_signal_handler ((async_handler_func *) SIGWINCH_HANDLER, NULL);
+#endif
+}
+
+/* Tell the event loop what to do if SIGINT is received. 
+   See event-signal.c. */
+void 
+handle_sigint (sig)
+     int sig;
+{
+  signal (sig, handle_sigint);
+
+  /* If immediate_quit is set, we go ahead and process the SIGINT right
+     away, even if we usually would defer this to the event loop. The
+     assumption here is that it is safe to process ^C immediately if
+     immediate_quit is set. If we didn't, SIGINT would be really
+     processed only the next time through the event loop.  To get to
+     that point, though, the command that we want to interrupt needs to
+     finish first, which is unacceptable. */
+  if (immediate_quit)
+    async_request_quit ();
+  else
+    /* If immediate quit is not set, we process SIGINT the next time
+       through the loop, which is fine. */
+    mark_async_signal_handler (sigint_token);
+}
+
+/* Do the quit. All the checks have been done by the caller. */
+void 
+async_request_quit ()
+{
+  quit_flag = 1;
+#ifdef REQUEST_QUIT
+  REQUEST_QUIT;
+#else
+  quit ();
+#endif
+}
+
+/* Tell the event loop what to do if SIGQUIT is received. 
+   See event-signal.c. */
+void 
+handle_sigquit (sig)
+     int sig;
+{
+  mark_async_signal_handler (sigquit_token);
+  signal (sig, handle_sigquit);
+}
+
+/* Called by the event loop in response to a SIGQUIT. */
+void 
+async_do_nothing ()
+{
+  /* Empty function body. */
+}
+
+#ifdef SIGHUP
+/* Tell the event loop what to do if SIGHUP is received. 
+   See event-signal.c. */
+void 
+handle_sighup (sig)
+     int sig;
+{
+  mark_async_signal_handler (sighup_token);
+  signal (sig, handle_sighup);
+}
+
+/* Called by the event loop to process a SIGHUP. */
+void 
+async_disconnect ()
+{
+  catch_errors (quit_cover, NULL,
+               "Could not kill the program being debugged",
+               RETURN_MASK_ALL);
+  signal (SIGHUP, SIG_DFL);    /*FIXME: ??????????? */
+  kill (getpid (), SIGHUP);
+}
+#endif
+
+/* Tell the event loop what to do if SIGFPE is received. 
+   See event-signal.c. */
+void 
+handle_sigfpe (sig)
+     int sig;
+{
+  mark_async_signal_handler (sigfpe_token);
+  signal (sig, handle_sigfpe);
+}
+
+/* Event loop will call this functin to process a SIGFPE. */
+void 
+async_float_handler ()
+{
+  /* This message is based on ANSI C, section 4.7. Note that integer
+     divide by zero causes this, so "float" is a misnomer. */
+  error ("Erroneous arithmetic operation.");
+}
+
+/* Tell the event loop what to do if SIGWINCH is received. 
+   See event-signal.c. */
+#if defined(SIGWINCH) && defined(SIGWINCH_HANDLER)
+void 
+handle_sigwinch (sig)
+     int sig;
+{
+  mark_async_signal_handler (sigwinch_token);
+  signal (sig, handle_sigwinch);
+}
+#endif
+\f
+
+/* Called by do_setshow_command.  */
+/* ARGSUSED */
+void
+set_async_editing_command (args, from_tty, c)
+     char *args;
+     int from_tty;
+     struct cmd_list_element *c;
+{
+  change_line_handler ();
+}
+
+/* Called by do_setshow_command.  */
+/* ARGSUSED */
+void
+set_async_annotation_level (args, from_tty, c)
+     char *args;
+     int from_tty;
+     struct cmd_list_element *c;
+{
+  change_annotation_level ();
+}
+
+/* Called by do_setshow_command.  */
+/* ARGSUSED */
+void
+set_async_prompt (args, from_tty, c)
+     char *args;
+     int from_tty;
+     struct cmd_list_element *c;
+{
+  PROMPT (0) = savestring (new_async_prompt, strlen (new_async_prompt));
+}
+
+
+
+