]> git.ipfire.org Git - thirdparty/binutils-gdb.git/blobdiff - gdb/event-loop.c
import gdb-1999-09-13 snapshot
[thirdparty/binutils-gdb.git] / gdb / event-loop.c
index fe1d0f5bd12b5ece603475d43c9d4f002c0519e1..261c8383163889445bc5366eeeb3809a334bb721 100644 (file)
 
    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. */
+   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"
-
+#include "top.h"
+#include "event-loop.h"
 #ifdef HAVE_POLL
-#include <sys/poll.h>
+#include <poll.h>
+#else
+#include <sys/types.h>
 #endif
 #include <errno.h>
+#include <setjmp.h>
 
 /* Event queue:  
    - the first event in the queue is the head of the queue. 
@@ -39,7 +38,7 @@
    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
+   the queue will be processed in a last in first out fashion, 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. */
@@ -59,7 +58,7 @@ event_queue;
    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
+/* As of 1999-04-30 only the input file descriptor is registered with the
    event loop. */
 
 #ifdef HAVE_POLL
@@ -108,10 +107,10 @@ gdb_notifier;
 static struct
   {
     /* Pointer to first in handler list. */
-    async_signal_handler *first_handler;     
-    
+    async_signal_handler *first_handler;
+
     /* Pointer to last in handler list. */
-    async_signal_handler *last_handler;             
+    async_signal_handler *last_handler;
   }
 sighandler_list;
 
@@ -121,10 +120,12 @@ sighandler_list;
    function. */
 static int async_handler_ready = 0;
 
+static void create_file_handler PARAMS ((int, int, handler_func *, gdb_client_data));
 static void invoke_async_signal_handler PARAMS ((void));
+static void handle_file_event PARAMS ((int));
 static int gdb_wait_for_event PARAMS ((void));
+static int gdb_do_one_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 
@@ -164,6 +165,22 @@ async_queue_event (event_ptr, position)
     }
 }
 
+/* Create a file event, to be enqueued in the event queue for
+   processing. The procedure associated to this event is always
+   handle_file_event, which will in turn invoke the one that was
+   associated to FD when it was registered with the event loop. */
+gdb_event *
+create_file_event (fd)
+     int fd;
+{
+  gdb_event *file_event_ptr;
+
+  file_event_ptr = (gdb_event *) xmalloc (sizeof (gdb_event));
+  file_event_ptr->proc = handle_file_event;
+  file_event_ptr->fd = fd;
+  return (file_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
@@ -239,7 +256,7 @@ process_event ()
    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
+static int
 gdb_do_one_event ()
 {
   int result = 0;
@@ -281,6 +298,9 @@ gdb_do_one_event ()
        }                       /* end of if !set_top_level */
       else
        {
+         /* FIXME: this should really be a call to a hook that is
+            interface specific, because interfaces can display the
+            prompt in their own way. */
          display_gdb_prompt (0);
          /* Maybe better to set a flag to be checked somewhere as to
             whether display the prompt or not. */
@@ -290,6 +310,41 @@ gdb_do_one_event ()
 }
 \f
 
+/* Start up the event loop. This is the entry point to the event loop
+   from the command loop. */
+void
+start_event_loop ()
+{
+  /* 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;
+}
+\f
+
+
+/* Wrapper function for create_file_handler, so that the caller
+   doesn't have to know implementation details about the use of poll
+   vs. select. */
+void
+add_file_handler (fd, proc, client_data)
+     int fd;
+     void (*proc) (void);
+     gdb_client_data client_data;
+{
+#ifdef HAVE_POLL
+  create_file_handler (fd, POLLIN, (handler_func *) proc, client_data);
+#else
+  create_file_handler (fd, GDB_READABLE, (handler_func *) proc, client_data);
+#endif
+}
+
 /* 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.  
@@ -300,11 +355,11 @@ gdb_do_one_event ()
    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
+static void
 create_file_handler (fd, mask, proc, client_data)
      int fd;
      int mask;
-     file_handler_func *proc;
+     handler_func *proc;
      gdb_client_data client_data;
 {
   file_handler *file_ptr;
@@ -338,9 +393,13 @@ create_file_handler (fd, mask, proc, client_data)
 #ifdef HAVE_POLL
 
   gdb_notifier.num_fds++;
-  gdb_notifier.poll_fds =
-    (struct pollfd *) realloc (gdb_notifier.poll_fds,
+  if (gdb_notifier.poll_fds)
+    gdb_notifier.poll_fds =
+      (struct pollfd *) realloc (gdb_notifier.poll_fds,
                           (gdb_notifier.num_fds) * sizeof (struct pollfd));
+  else
+    gdb_notifier.poll_fds =
+      (struct pollfd *) xmalloc (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;
@@ -397,11 +456,6 @@ delete_file_handler (fd)
   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. */
@@ -458,13 +512,18 @@ delete_file_handler (fd)
     }
 #endif /* HAVE_POLL */
 
+  /* Deactivate the file descriptor, by clearing its mask, 
+     so that it will not fire again. */
+
+  file_ptr->mask = 0;
+
   /* 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->next_file != file_ptr;
           prev_ptr = prev_ptr->next_file)
        ;
       prev_ptr->next_file = file_ptr->next_file;
@@ -514,7 +573,7 @@ handle_file_event (event_file_desc)
 
          /* If there was a match, then call the handler. */
          if (mask != 0)
-           (*file_ptr->proc) (file_ptr->client_data, mask);
+           (*file_ptr->proc) (file_ptr->client_data);
          break;
        }
     }
@@ -532,12 +591,17 @@ gdb_wait_for_event ()
 {
   file_handler *file_ptr;
   gdb_event *file_event_ptr;
-  int num_found, i;
+  int num_found = 0;
+  int i;
 
 #ifndef HAVE_POLL
   int mask, bit, index;
 #endif
 
+  /* Make sure all output is done before getting another event. */
+  gdb_flush (gdb_stdout);
+  gdb_flush (gdb_stderr);
+
   if (gdb_notifier.num_fds == 0)
     return -1;
 
@@ -587,10 +651,7 @@ gdb_wait_for_event ()
             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;
+             file_event_ptr = create_file_event (file_ptr->fd);
              async_queue_event (file_event_ptr, TAIL);
            }
        }
@@ -624,10 +685,7 @@ gdb_wait_for_event ()
 
       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;
+         file_event_ptr = create_file_event (file_ptr->fd);
          async_queue_event (file_event_ptr, TAIL);
        }
       file_ptr->ready_mask = mask;
@@ -646,7 +704,7 @@ gdb_wait_for_event ()
    whenever the handler is invoked. */
 async_signal_handler *
 create_async_signal_handler (proc, client_data)
-     async_handler_func *proc;
+     handler_func *proc;
      gdb_client_data client_data;
 {
   async_signal_handler *async_handler_ptr;
@@ -691,7 +749,7 @@ invoke_async_signal_handler ()
 
   while (1)
     {
-      for (async_handler_ptr = sighandler_list.first_handler; 
+      for (async_handler_ptr = sighandler_list.first_handler;
           async_handler_ptr != NULL;
           async_handler_ptr = async_handler_ptr->next_handler)
        {
@@ -711,26 +769,27 @@ invoke_async_signal_handler ()
    Free the space allocated for it.  */
 void
 delete_async_signal_handler (async_handler_ptr)
-     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)
+  if (sighandler_list.first_handler == (*async_handler_ptr))
     {
-      sighandler_list.first_handler = async_handler_ptr->next_handler;
+      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)
+      while (prev_ptr->next_handler != (*async_handler_ptr) && prev_ptr)
        prev_ptr = prev_ptr->next_handler;
-      prev_ptr->next_handler = async_handler_ptr->next_handler;
-      if (sighandler_list.last_handler == async_handler_ptr)
+      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);
+  free ((char *) (*async_handler_ptr));
+  (*async_handler_ptr) = NULL;
 }
 
 /* Is it necessary to call invoke_async_signal_handler? */