PR record/18691: Fix fails in solib-precsave.exp
[deliverable/binutils-gdb.git] / gdb / event-loop.c
index 221dfbc9755e302899e72d45180481e3f9c79c43..9ac49086f0c33fab4880a76c6773bb27d4c70e1c 100644 (file)
@@ -1,5 +1,5 @@
 /* Event loop machinery for GDB, the GNU debugger.
-   Copyright (C) 1999-2014 Free Software Foundation, Inc.
+   Copyright (C) 1999-2015 Free Software Foundation, Inc.
    Written by Elena Zannoni <ezannoni@cygnus.com> of Cygnus Solutions.
 
    This file is part of GDB.
 #endif
 
 #include <sys/types.h>
-#include <string.h>
-#include <errno.h>
 #include <sys/time.h>
-#include "exceptions.h"
 #include "gdb_select.h"
 #include "observer.h"
 
@@ -138,10 +135,6 @@ typedef struct async_event_handler
   }
 async_event_handler;
 
-DECLARE_QUEUE_P(gdb_event_p);
-DEFINE_QUEUE_P(gdb_event_p);
-static QUEUE(gdb_event_p) *event_queue = NULL;
-
 /* 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
@@ -172,10 +165,24 @@ static struct
     /* Ptr to head of file handler list.  */
     file_handler *first_file_handler;
 
+    /* Next file handler to handle, for the select variant.  To level
+       the fairness across event sources, we serve file handlers in a
+       round-robin-like fashion.  The number and order of the polled
+       file handlers may change between invocations, but this is good
+       enough.  */
+    file_handler *next_file_handler;
+
 #ifdef HAVE_POLL
     /* Ptr to array of pollfd structures.  */
     struct pollfd *poll_fds;
 
+    /* Next file descriptor to handle, for the poll variant.  To level
+       the fairness across event sources, we poll the file descriptors
+       in a round-robin-like fashion.  The number and order of the
+       polled file descriptors may change between invocations, but
+       this is good enough.  */
+    int next_poll_fds_index;
+
     /* Timeout in milliseconds for calls to poll().  */
     int poll_timeout;
 #endif
@@ -249,104 +256,12 @@ async_event_handler_list;
 static int invoke_async_signal_handlers (void);
 static void create_file_handler (int fd, int mask, handler_func *proc,
                                 gdb_client_data client_data);
-static void handle_file_event (event_data data);
-static void check_async_event_handlers (void);
+static int check_async_event_handlers (void);
 static int gdb_wait_for_event (int);
-static void poll_timers (void);
+static int update_wait_timeout (void);
+static int poll_timers (void);
 \f
 
-/* Create a generic event, to be enqueued in the event queue for
-   processing.  PROC is the procedure associated to the event.  DATA
-   is passed to PROC upon PROC invocation.  */
-
-static gdb_event *
-create_event (event_handler_func proc, event_data data)
-{
-  gdb_event *event;
-
-  event = xmalloc (sizeof (*event));
-  event->proc = proc;
-  event->data = data;
-
-  return event;
-}
-
-/* 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.  */
-static gdb_event *
-create_file_event (int fd)
-{
-  event_data data;
-
-  data.integer = fd;
-  return create_event (handle_file_event, data);
-}
-
-
-/* Free EVENT.  */
-
-static void
-gdb_event_xfree (struct gdb_event *event)
-{
-  xfree (event);
-}
-
-/* Initialize the event queue.  */
-
-void
-initialize_event_loop (void)
-{
-  event_queue = QUEUE_alloc (gdb_event_p, gdb_event_xfree);
-}
-
-/* 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 (void)
-{
-  /* 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 (invoke_async_signal_handlers ())
-    return 1;
-
-  /* Look in the event queue to find an event that is ready
-     to be processed.  */
-
-  if (!QUEUE_is_empty (gdb_event_p, event_queue))
-    {
-      /* 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.  */
-      gdb_event *event_ptr = QUEUE_deque (gdb_event_p, event_queue);
-      /* Call the handler for the event.  */
-      event_handler_func *proc = event_ptr->proc;
-      event_data data = event_ptr->data;
-
-      gdb_event_xfree (event_ptr);
-
-      /* Now call the procedure associated with the event.  */
-      (*proc) (data);
-      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 >0 if something was done otherwise returns <0 (this
@@ -359,40 +274,46 @@ gdb_do_one_event (void)
   const int number_of_sources = 3;
   int current = 0;
 
-  /* Any events already waiting in the queue?  */
-  if (process_event ())
+  /* First let's see if there are any asynchronous signal handlers
+     that are ready.  These would be the result of invoking any of the
+     signal handlers.  */
+  if (invoke_async_signal_handlers ())
     return 1;
 
   /* To level the fairness across event sources, we poll them in a
      round-robin fashion.  */
   for (current = 0; current < number_of_sources; current++)
     {
+      int res;
+
       switch (event_source_head)
        {
        case 0:
-         /* Are any timers that are ready? If so, put an event on the
-            queue.  */
-         poll_timers ();
+         /* Are any timers that are ready?  */
+         res = poll_timers ();
          break;
        case 1:
          /* Are there events already waiting to be collected on the
             monitored file descriptors?  */
-         gdb_wait_for_event (0);
+         res = gdb_wait_for_event (0);
          break;
        case 2:
          /* Are there any asynchronous event handlers ready?  */
-         check_async_event_handlers ();
+         res = check_async_event_handlers ();
          break;
+       default:
+         internal_error (__FILE__, __LINE__,
+                         "unexpected event_source_head %d",
+                         event_source_head);
        }
 
       event_source_head++;
       if (event_source_head == number_of_sources)
        event_source_head = 0;
-    }
 
-  /* Handle any new events collected.  */
-  if (process_event ())
-    return 1;
+      if (res > 0)
+       return 1;
+    }
 
   /* Block waiting for a new event.  If gdb_wait_for_event returns -1,
      we should get out because this means that there are no event
@@ -402,10 +323,6 @@ gdb_do_one_event (void)
   if (gdb_wait_for_event (1) < 0)
     return -1;
 
-  /* Handle any new events occurred while waiting.  */
-  if (process_event ())
-    return 1;
-
   /* If gdb_wait_for_event has returned 1, it means that one event has
      been handled.  We break out of the loop.  */
   return 1;
@@ -423,14 +340,13 @@ start_event_loop (void)
      processes it.  */
   while (1)
     {
-      volatile struct gdb_exception ex;
       int result = 0;
 
-      TRY_CATCH (ex, RETURN_MASK_ALL)
+      TRY
        {
          result = gdb_do_one_event ();
        }
-      if (ex.reason < 0)
+      CATCH (ex, RETURN_MASK_ALL)
        {
          exception_print (gdb_stderr, ex);
 
@@ -453,6 +369,8 @@ start_event_loop (void)
          /* Maybe better to set a flag to be checked somewhere as to
             whether display the prompt or not.  */
        }
+      END_CATCH
+
       if (result < 0)
        break;
     }
@@ -590,6 +508,31 @@ create_file_handler (int fd, int mask, handler_func * proc,
   file_ptr->mask = mask;
 }
 
+/* Return the next file handler to handle, and advance to the next
+   file handler, wrapping around if the end of the list is
+   reached.  */
+
+static file_handler *
+get_next_file_handler_to_handle_and_advance (void)
+{
+  file_handler *curr_next;
+
+  /* The first time around, this is still NULL.  */
+  if (gdb_notifier.next_file_handler == NULL)
+    gdb_notifier.next_file_handler = gdb_notifier.first_file_handler;
+
+  curr_next = gdb_notifier.next_file_handler;
+  gdb_assert (curr_next != NULL);
+
+  /* Advance.  */
+  gdb_notifier.next_file_handler = curr_next->next_file;
+  /* Wrap around, if necessary.  */
+  if (gdb_notifier.next_file_handler == NULL)
+    gdb_notifier.next_file_handler = gdb_notifier.first_file_handler;
+
+  return curr_next;
+}
+
 /* 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
@@ -672,6 +615,17 @@ delete_file_handler (int fd)
 
   file_ptr->mask = 0;
 
+  /* If this file handler was going to be the next one to be handled,
+     advance to the next's next, if any.  */
+  if (gdb_notifier.next_file_handler == file_ptr)
+    {
+      if (file_ptr->next_file == NULL
+         && file_ptr == gdb_notifier.first_file_handler)
+       gdb_notifier.next_file_handler = NULL;
+      else
+       get_next_file_handler_to_handle_and_advance ();
+    }
+
   /* 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;
@@ -687,25 +641,17 @@ delete_file_handler (int fd)
 }
 
 /* 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.  */
+   corresponding file handler.  */
+
 static void
-handle_file_event (event_data data)
+handle_file_event (file_handler *file_ptr, int ready_mask)
 {
-  file_handler *file_ptr;
   int mask;
 #ifdef HAVE_POLL
   int error_mask;
 #endif
-  int event_file_desc = data.integer;
 
-  /* 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
@@ -723,7 +669,7 @@ handle_file_event (event_data data)
              /* POLLHUP means EOF, but can be combined with POLLIN to
                 signal more data to read.  */
              error_mask = POLLHUP | POLLERR | POLLNVAL;
-             mask = file_ptr->ready_mask & (file_ptr->mask | error_mask);
+             mask = ready_mask & (file_ptr->mask | error_mask);
 
              if ((mask & (POLLERR | POLLNVAL)) != 0)
                {
@@ -746,7 +692,7 @@ handle_file_event (event_data data)
            }
          else
            {
-             if (file_ptr->ready_mask & GDB_EXCEPTION)
+             if (ready_mask & GDB_EXCEPTION)
                {
                  printf_unfiltered (_("Exception condition detected "
                                       "on fd %d\n"), file_ptr->fd);
@@ -754,32 +700,28 @@ handle_file_event (event_data data)
                }
              else
                file_ptr->error = 0;
-             mask = file_ptr->ready_mask & file_ptr->mask;
+             mask = ready_mask & file_ptr->mask;
            }
 
-         /* 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->error, file_ptr->client_data);
-         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 BLOCK and if there are no events, this function will
-   block in the call to poll.  Return -1 if there are no file
-   descriptors to monitor, otherwise return 0.  */
+/* Wait for new events on the monitored file descriptors.  Run the
+   event handler if the first descriptor that is detected by the poll.
+   If BLOCK and if there are no events, this function will block in
+   the call to poll.  Return 1 if an event was handled.  Return -1 if
+   there are no file descriptors to monitor.  Return 1 if an event was
+   handled, otherwise returns 0.  */
+
 static int
 gdb_wait_for_event (int block)
 {
   file_handler *file_ptr;
-  gdb_event *file_event_ptr;
   int num_found = 0;
-  int i;
 
   /* Make sure all output is done before getting another event.  */
   gdb_flush (gdb_stdout);
@@ -788,6 +730,9 @@ gdb_wait_for_event (int block)
   if (gdb_notifier.num_fds == 0)
     return -1;
 
+  if (block)
+    update_wait_timeout ();
+
   if (use_poll)
     {
 #ifdef HAVE_POLL
@@ -847,38 +792,47 @@ gdb_wait_for_event (int block)
        }
     }
 
-  /* Enqueue all detected file events.  */
+  /* Avoid looking at poll_fds[i]->revents if no event fired.  */
+  if (num_found <= 0)
+    return 0;
 
+  /* Run event handlers.  We always run just one handler and go back
+     to polling, in case a handler changes the notifier list.  Since
+     events for sources we haven't consumed yet wake poll/select
+     immediately, no event is lost.  */
+
+  /* To level the fairness across event descriptors, we handle them in
+     a round-robin-like fashion.  The number and order of descriptors
+     may change between invocations, but this is good enough.  */
   if (use_poll)
     {
 #ifdef HAVE_POLL
-      for (i = 0; (i < gdb_notifier.num_fds) && (num_found > 0); i++)
+      int i;
+      int mask;
+
+      while (1)
        {
-         if ((gdb_notifier.poll_fds + i)->revents)
-           num_found--;
-         else
-           continue;
+         if (gdb_notifier.next_poll_fds_index >= gdb_notifier.num_fds)
+           gdb_notifier.next_poll_fds_index = 0;
+         i = gdb_notifier.next_poll_fds_index++;
 
-         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;
-           }
+         gdb_assert (i < gdb_notifier.num_fds);
+         if ((gdb_notifier.poll_fds + i)->revents)
+           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 = create_file_event (file_ptr->fd);
-                 QUEUE_enque (gdb_event_p, event_queue, file_event_ptr);
-               }
-             file_ptr->ready_mask = (gdb_notifier.poll_fds + i)->revents;
-           }
+      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;
        }
+      gdb_assert (file_ptr != NULL);
+
+      mask = (gdb_notifier.poll_fds + i)->revents;
+      handle_file_event (file_ptr, mask);
+      return 1;
 #else
       internal_error (__FILE__, __LINE__,
                      _("use_poll without HAVE_POLL"));
@@ -886,11 +840,12 @@ gdb_wait_for_event (int block)
     }
   else
     {
-      for (file_ptr = gdb_notifier.first_file_handler;
-          (file_ptr != NULL) && (num_found > 0);
-          file_ptr = file_ptr->next_file)
+      /* See comment about even source fairness above.  */
+      int mask = 0;
+
+      do
        {
-         int mask = 0;
+         file_ptr = get_next_file_handler_to_handle_and_advance ();
 
          if (FD_ISSET (file_ptr->fd, &gdb_notifier.ready_masks[0]))
            mask |= GDB_READABLE;
@@ -898,22 +853,11 @@ gdb_wait_for_event (int block)
            mask |= GDB_WRITABLE;
          if (FD_ISSET (file_ptr->fd, &gdb_notifier.ready_masks[2]))
            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 = create_file_event (file_ptr->fd);
-             QUEUE_enque (gdb_event_p, event_queue, file_event_ptr);
-           }
-         file_ptr->ready_mask = mask;
        }
+      while (mask == 0);
+
+      handle_file_event (file_ptr, mask);
+      return 1;
     }
   return 0;
 }
@@ -1053,32 +997,21 @@ mark_async_event_handler (async_event_handler *async_handler_ptr)
   async_handler_ptr->ready = 1;
 }
 
-struct async_event_handler_data
-{
-  async_event_handler_func* proc;
-  gdb_client_data client_data;
-};
+/* See event-loop.h.  */
 
-static void
-invoke_async_event_handler (event_data data)
+void
+clear_async_event_handler (async_event_handler *async_handler_ptr)
 {
-  struct async_event_handler_data *hdata = data.ptr;
-  async_event_handler_func* proc = hdata->proc;
-  gdb_client_data client_data = hdata->client_data;
-
-  xfree (hdata);
-  (*proc) (client_data);
+  async_handler_ptr->ready = 0;
 }
 
-/* Check if any asynchronous event handlers are ready, and queue
-   events in the ready queue for any that are.  */
-static void
+/* Check if asynchronous event handlers are ready, and call the
+   handler function for one that is.  */
+
+static int
 check_async_event_handlers (void)
 {
   async_event_handler *async_handler_ptr;
-  struct async_event_handler_data *hdata;
-  struct gdb_event *event_ptr;
-  event_data data;
 
   for (async_handler_ptr = async_event_handler_list.first_handler;
        async_handler_ptr != NULL;
@@ -1087,18 +1020,12 @@ check_async_event_handlers (void)
       if (async_handler_ptr->ready)
        {
          async_handler_ptr->ready = 0;
-
-         hdata = xmalloc (sizeof (*hdata));
-
-         hdata->proc = async_handler_ptr->proc;
-         hdata->client_data = async_handler_ptr->client_data;
-
-         data.ptr = hdata;
-
-         event_ptr = create_event (invoke_async_event_handler, data);
-         QUEUE_enque (gdb_event_p, event_queue, event_ptr);
+         (*async_handler_ptr->proc) (async_handler_ptr->client_data);
+         return 1;
        }
     }
+
+  return 0;
 }
 
 /* Delete an asynchronous handler (ASYNC_HANDLER_PTR).
@@ -1231,49 +1158,13 @@ delete_timer (int id)
   gdb_notifier.timeout_valid = 0;
 }
 
-/* When a timer event is put on the event queue, it will be handled by
-   this function.  Just call the associated procedure and delete the
-   timer event from the event queue.  Repeat this for each timer that
-   has expired.  */
-static void
-handle_timer_event (event_data dummy)
-{
-  struct timeval time_now;
-  struct gdb_timer *timer_ptr, *saved_timer;
+/* Update the timeout for the select() or poll().  Returns true if the
+   timer has already expired, false otherwise.  */
 
-  gettimeofday (&time_now, NULL);
-  timer_ptr = timer_list.first_timer;
-
-  while (timer_ptr != NULL)
-    {
-      if ((timer_ptr->when.tv_sec > time_now.tv_sec)
-         || ((timer_ptr->when.tv_sec == time_now.tv_sec)
-             && (timer_ptr->when.tv_usec > time_now.tv_usec)))
-       break;
-
-      /* Get rid of the timer from the beginning of the list.  */
-      timer_list.first_timer = timer_ptr->next;
-      saved_timer = timer_ptr;
-      timer_ptr = timer_ptr->next;
-      /* Call the procedure associated with that timer.  */
-      (*saved_timer->proc) (saved_timer->client_data);
-      xfree (saved_timer);
-    }
-
-  gdb_notifier.timeout_valid = 0;
-}
-
-/* Check whether any timers in the timers queue are ready.  If at least
-   one timer is ready, stick an event onto the event queue.  Even in
-   case more than one timer is ready, one event is enough, because the
-   handle_timer_event() will go through the timers list and call the
-   procedures associated with all that have expired.l Update the
-   timeout for the select() or poll() as well.  */
-static void
-poll_timers (void)
+static int
+update_wait_timeout (void)
 {
   struct timeval time_now, delta;
-  gdb_event *event_ptr;
 
   if (timer_list.first_timer != NULL)
     {
@@ -1287,27 +1178,18 @@ poll_timers (void)
          delta.tv_usec += 1000000;
        }
 
-      /* Oops it expired already.  Tell select / poll to return
-         immediately.  (Cannot simply test if delta.tv_sec is negative
-         because time_t might be unsigned.)  */
+      /* Cannot simply test if delta.tv_sec is negative because time_t
+         might be unsigned.  */
       if (timer_list.first_timer->when.tv_sec < time_now.tv_sec
          || (timer_list.first_timer->when.tv_sec == time_now.tv_sec
              && timer_list.first_timer->when.tv_usec < time_now.tv_usec))
        {
+         /* It expired already.  */
          delta.tv_sec = 0;
          delta.tv_usec = 0;
        }
 
-      if (delta.tv_sec == 0 && delta.tv_usec == 0)
-       {
-         event_ptr = (gdb_event *) xmalloc (sizeof (gdb_event));
-         event_ptr->proc = handle_timer_event;
-         event_ptr->data.integer = timer_list.first_timer->timer_id;
-         QUEUE_enque (gdb_event_p, event_queue, event_ptr);
-       }
-
-      /* Now we need to update the timeout for select/ poll, because
-         we don't want to sit there while this timer is expiring.  */
+      /* Update the timeout for select/ poll.  */
       if (use_poll)
        {
 #ifdef HAVE_POLL
@@ -1323,7 +1205,43 @@ poll_timers (void)
          gdb_notifier.select_timeout.tv_usec = delta.tv_usec;
        }
       gdb_notifier.timeout_valid = 1;
+
+      if (delta.tv_sec == 0 && delta.tv_usec == 0)
+       return 1;
     }
   else
     gdb_notifier.timeout_valid = 0;
+
+  return 0;
+}
+
+/* Check whether a timer in the timers queue is ready.  If a timer is
+   ready, call its handler and return.  Update the timeout for the
+   select() or poll() as well.  Return 1 if an event was handled,
+   otherwise returns 0.*/
+
+static int
+poll_timers (void)
+{
+  if (update_wait_timeout ())
+    {
+      struct gdb_timer *timer_ptr = timer_list.first_timer;
+      timer_handler_func *proc = timer_ptr->proc;
+      gdb_client_data client_data = timer_ptr->client_data;
+
+      /* Get rid of the timer from the beginning of the list.  */
+      timer_list.first_timer = timer_ptr->next;
+
+      /* Delete the timer before calling the callback, not after, in
+        case the callback itself decides to try deleting the timer
+        too.  */
+      xfree (timer_ptr);
+
+      /* Call the procedure associated with that timer.  */
+      (proc) (client_data);
+
+      return 1;
+    }
+
+  return 0;
 }
This page took 0.048459 seconds and 4 git commands to generate.