]> git.ipfire.org Git - thirdparty/binutils-gdb.git/blobdiff - gdb/event-top.c
import gdb-1999-09-08 snapshot
[thirdparty/binutils-gdb.git] / gdb / event-top.c
index ad269eb25fac6ae04327454fc71a9ce1cfc042bf..330f9034ef88e1d31b1b5a2cdb956c918b96f4c3 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 "defs.h"
-#include "event-loop.h"
 #include "top.h"
-#ifdef HAVE_POLL
-#include <sys/poll.h>
-#endif
 #include "inferior.h"
-#include "terminal.h" /* for job_control*/
+#include "terminal.h"          /* for job_control */
+#include <signal.h>
+#include "event-loop.h"
+
+/* For dont_repeat() */
+#include "gdbcmd.h"
 
 /* readline include files */
 #include <readline/readline.h>
 /* readline defines this.  */
 #undef savestring
 
-extern void _initialize_event_loop (void);
+extern void _initialize_event_loop PARAMS ((void));
 
 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 *));
+static void command_line_handler_continuation PARAMS ((struct continuation_arg *));
+void gdb_readline2 PARAMS ((void));
+void pop_prompt PARAMS ((void));
+void push_prompt PARAMS ((char *, char *, char *));
 static void change_line_handler PARAMS ((void));
 static void change_annotation_level PARAMS ((void));
 static void command_handler PARAMS ((char *));
 
 /* Signal handlers. */
-static void handle_sigint PARAMS ((int));
+void handle_sigint PARAMS ((int));
 static void handle_sigquit PARAMS ((int));
 static void handle_sighup PARAMS ((int));
 static void handle_sigfpe PARAMS ((int));
+#if defined(SIGWINCH) && defined(SIGWINCH_HANDLER)
 static void handle_sigwinch PARAMS ((int));
+#endif
 /* Signal to catch ^Z typed while reading a command: SIGTSTP or SIGCONT.  */
 #ifndef STOP_SIGNAL
 #ifdef SIGTSTP
@@ -60,18 +65,11 @@ void handle_stop_sig PARAMS ((int));
 
 /* Functions to be invoked by the event loop in response to
    signals. */
-void async_request_quit PARAMS ((gdb_client_data));
 static void async_do_nothing PARAMS ((gdb_client_data));
 static void async_disconnect PARAMS ((gdb_client_data));
 static void async_float_handler PARAMS ((gdb_client_data));
 static void async_stop_sig PARAMS ((gdb_client_data));
 
-/* 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
-
 /* 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
@@ -113,6 +111,10 @@ char *new_async_prompt;
    annotation_level is 2. */
 char *async_annotation_suffix;
 
+/* This is used to display the notification of the completion of an
+   asynchronous execution command. */
+int exec_done_display_p = 0;
+
 /* This is the file descriptor for the input stream that GDB uses to
    read commands from. */
 int input_fd;
@@ -141,8 +143,6 @@ PTR sigwinch_token;
 PTR sigtstp_token;
 #endif
 
-void mark_async_signal_handler_wrapper PARAMS ((void *));
-
 /* 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
@@ -159,40 +159,33 @@ readline_input_state;
 \f
 
 /* Initialize all the necessary variables, start the event loop,
-   register readline, and stdin. */
+   register readline, and stdin, start the loop. */
 void
-start_event_loop ()
+cli_command_loop ()
 {
   int length;
   char *a_prompt;
+  char *gdb_prompt = get_prompt ();
 
   /* If we are using readline, set things up and display the first
      prompt, otherwise just print the prompt. */
   if (async_command_editing_p)
     {
       /* Tell readline what the prompt to display is and what function it
-        will need to call after a whole line is read. This also displays
-        the first prompt.*/
-      length = strlen (PREFIX (0)) + strlen (PROMPT (0)) + strlen (SUFFIX (0)) + 1;
+         will need to call after a whole line is read. This also displays
+         the first prompt. */
+      length = strlen (PREFIX (0)) + strlen (gdb_prompt) + strlen (SUFFIX (0)) + 1;
       a_prompt = (char *) xmalloc (length);
       strcpy (a_prompt, PREFIX (0));
-      strcat (a_prompt, PROMPT (0));
+      strcat (a_prompt, gdb_prompt);
       strcat (a_prompt, SUFFIX (0));
       rl_callback_handler_install (a_prompt, input_handler);
     }
   else
     display_gdb_prompt (0);
 
-  /* 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;
+  /* Now it's time to start the event loop. */
+  start_event_loop ();
 }
 
 /* Change the function to be invoked every time there is a character
@@ -217,7 +210,7 @@ change_line_handler ()
       call_readline = gdb_readline2;
 
       /* Set up the command handler as well, in case we are called as
-        first thing from .gdbinit. */
+         first thing from .gdbinit. */
       input_handler = command_line_handler;
     }
 
@@ -225,14 +218,13 @@ change_line_handler ()
      input file descriptor, we need to create a new event source,
      corresponding to the same fd, but with a new event handler
      function. */
+  /* NOTE: this operates on input_fd, not instream. If we are reading
+     commands from a file, instream will point to the file. However in
+     async mode, we always read commands from a file with editing
+     off. This means that the 'set editing on/off' will have effect
+     only on the interactive session. */
   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
+  add_file_handler (input_fd, call_readline, 0);
 }
 
 /* Displays the prompt. The prompt that is displayed is the current
@@ -251,19 +243,42 @@ display_gdb_prompt (new_prompt)
      char *new_prompt;
 {
   int prompt_length = 0;
+  char *gdb_prompt = get_prompt ();
+
+
+  if (target_executing && sync_execution) 
+    {
+      /* This is to trick readline into not trying to display the
+        prompt.  Even though we display the prompt using this
+        function, readline still tries to do its own display if we
+        don't call rl_callback_handler_install and
+        rl_callback_handler_remove (which readline detects because a
+        global variable is not set). If readline did that, it could
+        mess up gdb signal handlers for SIGINT.  Readline assumes
+        that between calls to rl_set_signals and rl_clear_signals gdb
+        doesn't do anything with the signal handlers. Well, that's
+        not the case, because when the target executes we change the
+        SIGINT signal handler. If we allowed readline to display the
+        prompt, the signal handler change would happen exactly
+        between the calls to the above two functions.
+        Calling rl_callback_handler_remove(), does the job. */
+
+      rl_callback_handler_remove ();
+      return;
+    }
 
   if (!new_prompt)
     {
       /* Just use the top of the prompt stack. */
       prompt_length = strlen (PREFIX (0)) +
        strlen (SUFFIX (0)) +
-       strlen (PROMPT (0)) + 1;
+       strlen (gdb_prompt) + 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));
+      strcat (new_prompt, gdb_prompt);
       /* Suffix needs to have a new line at end and \032 \032 at
          beginning. */
       strcat (new_prompt, SUFFIX (0));
@@ -274,6 +289,7 @@ display_gdb_prompt (new_prompt)
       rl_callback_handler_remove ();
       rl_callback_handler_install (new_prompt, input_handler);
     }
+  /* new_prompt at this point can be the top of the stack or the one passed in */
   else if (new_prompt)
     {
       /* Don't use a _filtered function here.  It causes the assumed
@@ -294,7 +310,7 @@ display_gdb_prompt (new_prompt)
    '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). */
+   to be the normal ones (1 or 0). */
 static void
 change_annotation_level ()
 {
@@ -340,7 +356,7 @@ change_annotation_level ()
    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
+void
 push_prompt (prefix, prompt, suffix)
      char *prefix;
      char *prompt;
@@ -349,6 +365,9 @@ push_prompt (prefix, prompt, suffix)
   the_prompts.top++;
   PREFIX (0) = savestring (prefix, strlen (prefix));
 
+  /* Note that this function is used by the set annotate 2
+     command. This is why we take care of saving the old prompt
+     in case a new one is not specified. */
   if (prompt)
     PROMPT (0) = savestring (prompt, strlen (prompt));
   else
@@ -358,14 +377,21 @@ push_prompt (prefix, prompt, suffix)
 }
 
 /* Pops the top of the prompt stack, and frees the memory allocated for it. */
-static void
+void
 pop_prompt ()
 {
-  if (strcmp (PROMPT (0), PROMPT (-1)))
-    {
-      free (PROMPT (-1));
-      PROMPT (-1) = savestring (PROMPT (0), strlen (PROMPT (0)));
-    }
+  /* If we are not during a 'synchronous' execution command, in which
+     case, the top prompt would be empty. */
+  if (strcmp (PROMPT (0), ""))
+    /* This is for the case in which the prompt is set while the
+       annotation level is 2. The top prompt will be changed, but when
+       we return to annotation level < 2, we want that new prompt to be
+       in effect, until the user does another 'set prompt'. */
+    if (strcmp (PROMPT (0), PROMPT (-1)))
+      {
+       free (PROMPT (-1));
+       PROMPT (-1) = savestring (PROMPT (0), strlen (PROMPT (0)));
+      }
 
   free (PREFIX (0));
   free (PROMPT (0));
@@ -385,6 +411,8 @@ command_handler (command)
 {
   struct cleanup *old_chain;
   int stdin_is_tty = ISATTY (stdin);
+  struct continuation_arg *arg1;
+  struct continuation_arg *arg2;
   long time_at_cmd_start;
 #ifdef HAVE_SBRK
   long space_at_cmd_start = 0;
@@ -426,9 +454,70 @@ command_handler (command)
 
   execute_command (command, instream == stdin);
 
-  /* Do any commands attached to breakpoint we stopped at.  */
+  /* Set things up for this function to be compete later, once the
+     executin has completed, if we are doing an execution command,
+     otherwise, just go ahead and finish. */
+  if (target_has_async && target_executing)
+    {
+      arg1 =
+       (struct continuation_arg *) xmalloc (sizeof (struct continuation_arg));
+      arg2 =
+       (struct continuation_arg *) xmalloc (sizeof (struct continuation_arg));
+      arg1->next = arg2;
+      arg2->next = NULL;
+      arg1->data = (PTR) time_at_cmd_start;
+      arg2->data = (PTR) space_at_cmd_start;
+      add_continuation (command_line_handler_continuation, arg1);
+    }
+
+  /* Do any commands attached to breakpoint we stopped at. Only if we
+     are always running synchronously. Or if we have just executed a
+     command that doesn't start the target. */
+  if (!target_has_async || !target_executing)
+    {
+      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
+       }
+    }
+}
+
+/* Do any commands attached to breakpoint we stopped at. Only if we
+   are always running synchronously. Or if we have just executed a
+   command that doesn't start the target. */
+void
+command_line_handler_continuation (arg)
+     struct continuation_arg *arg;
+{
+  extern int display_time;
+  extern int display_space;
+
+  long time_at_cmd_start = (long) arg->data;
+  long space_at_cmd_start = (long) arg->next->data;
+
   bpstat_do_actions (&stop_bpstat);
-  do_cleanups (old_chain);
+  /*do_cleanups (old_chain); *//*?????FIXME????? */
 
   if (display_time)
     {
@@ -437,7 +526,6 @@ command_handler (command)
       printf_unfiltered ("Command execution time: %ld.%06ld\n",
                         cmd_time / 1000000, cmd_time % 1000000);
     }
-
   if (display_space)
     {
 #ifdef HAVE_SBRK
@@ -470,7 +558,6 @@ command_line_handler (rl)
   static unsigned linelength = 0;
   register char *p;
   char *p1;
-  int change_prompt = 0;
   extern char *line;
   extern int linesize;
   char *nline;
@@ -500,7 +587,7 @@ command_line_handler (rl)
       p = readline_input_state.linebuffer_ptr;
       free (readline_input_state.linebuffer);
       more_to_come = 0;
-      change_prompt = 1;
+      pop_prompt ();
     }
 
 #ifdef STOP_SIGNAL
@@ -547,9 +634,8 @@ command_line_handler (rl)
 
   free (rl);                   /* Allocated in readline.  */
 
-  if (p == linebuffer || *(p - 1) == '\\')
+  if (*(p - 1) == '\\')
     {
-      /* We come here also if the line entered is empty (just a 'return') */
       p--;                     /* Put on top of '\'.  */
 
       if (*p == '\\')
@@ -561,8 +647,10 @@ command_line_handler (rl)
          /* 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;
+         push_prompt ("", "", "");
+         display_gdb_prompt (0);
+         return;
        }
     }
 
@@ -679,13 +767,26 @@ command_line_handler (rl)
 /* NOTE: 1999-04-30 Asynchronous version of gdb_readline. gdb_readline
    will become obsolete when the event loop is made the default
    execution for gdb. */
-static void
+void
 gdb_readline2 ()
 {
   int c;
   char *result;
   int input_index = 0;
   int result_size = 80;
+  static int done_once = 0;
+
+  /* Unbuffer the input stream, so that, later on, the calls to fgetc
+     fetch only one char at the time from the stream. The fgetc's will
+     get up to the first newline, but there may be more chars in the
+     stream after '\n'. If we buffer the input and fgetc drains the
+     stream, getting stuff beyond the newline as well, a select, done
+     afterwards will not trigger. */
+  if (!done_once && !ISATTY (instream))
+    {
+      setbuf (instream, NULL);
+      done_once = 1;
+    }
 
   result = (char *) xmalloc (result_size);
 
@@ -751,7 +852,7 @@ gdb_readline2 ()
    as the default for gdb. */
 void
 async_init_signals ()
-{  
+{
   signal (SIGINT, handle_sigint);
   sigint_token =
     create_async_signal_handler (async_request_quit, NULL);
@@ -797,7 +898,7 @@ async_init_signals ()
 
 }
 
-void 
+void
 mark_async_signal_handler_wrapper (token)
      void *token;
 {
@@ -806,7 +907,7 @@ mark_async_signal_handler_wrapper (token)
 
 /* Tell the event loop what to do if SIGINT is received. 
    See event-signal.c. */
-static void 
+void
 handle_sigint (sig)
      int sig;
 {
@@ -828,7 +929,7 @@ handle_sigint (sig)
 }
 
 /* Do the quit. All the checks have been done by the caller. */
-void 
+void
 async_request_quit (arg)
      gdb_client_data arg;
 {
@@ -842,7 +943,7 @@ async_request_quit (arg)
 
 /* Tell the event loop what to do if SIGQUIT is received. 
    See event-signal.c. */
-static void 
+static void
 handle_sigquit (sig)
      int sig;
 {
@@ -851,7 +952,7 @@ handle_sigquit (sig)
 }
 
 /* Called by the event loop in response to a SIGQUIT. */
-static void 
+static void
 async_do_nothing (arg)
      gdb_client_data arg;
 {
@@ -861,7 +962,7 @@ async_do_nothing (arg)
 #ifdef SIGHUP
 /* Tell the event loop what to do if SIGHUP is received. 
    See event-signal.c. */
-static void 
+static void
 handle_sighup (sig)
      int sig;
 {
@@ -870,7 +971,7 @@ handle_sighup (sig)
 }
 
 /* Called by the event loop to process a SIGHUP */
-static void 
+static void
 async_disconnect (arg)
      gdb_client_data arg;
 {
@@ -883,18 +984,19 @@ async_disconnect (arg)
 #endif
 
 #ifdef STOP_SIGNAL
-void handle_stop_sig (sig)
+void
+handle_stop_sig (sig)
      int sig;
 {
- mark_async_signal_handler_wrapper (sigtstp_token);
- signal (sig, handle_stop_sig);
 mark_async_signal_handler_wrapper (sigtstp_token);
 signal (sig, handle_stop_sig);
 }
 
 static void
 async_stop_sig (arg)
      gdb_client_data arg;
 {
char *prompt = PROMPT (0);
 char *prompt = get_prompt ();
 #if STOP_SIGNAL == SIGTSTP
   signal (SIGTSTP, SIG_DFL);
   sigsetmask (0);
@@ -913,7 +1015,7 @@ async_stop_sig (arg)
 
 /* Tell the event loop what to do if SIGFPE is received. 
    See event-signal.c. */
-static void 
+static void
 handle_sigfpe (sig)
      int sig;
 {
@@ -922,7 +1024,7 @@ handle_sigfpe (sig)
 }
 
 /* Event loop will call this functin to process a SIGFPE. */
-static void 
+static void
 async_float_handler (arg)
      gdb_client_data arg;
 {
@@ -934,7 +1036,7 @@ async_float_handler (arg)
 /* Tell the event loop what to do if SIGWINCH is received. 
    See event-signal.c. */
 #if defined(SIGWINCH) && defined(SIGWINCH_HANDLER)
-static void 
+static void
 handle_sigwinch (sig)
      int sig;
 {
@@ -979,38 +1081,43 @@ set_async_prompt (args, from_tty, c)
 
 /* Set things up for readline to be invoked via the alternate
    interface, i.e. via a callback function (rl_callback_read_char),
-   and hook up instream to the event loop.*/
+   and hook up instream to the event loop. */
 void
 _initialize_event_loop ()
 {
-  /* When a character is detected on instream by select or poll, readline
-     will be invoked via this callback function. */
-  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 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
-}
+  if (async_p)
+    {
+      /* When a character is detected on instream by select or poll,
+         readline will be invoked via this callback function. */
+      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 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);
+
+      /* Tell gdb to use the cli_command_loop as the main loop. */
+      command_loop_hook = cli_command_loop;
+
+      /* 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. */
+      add_file_handler (input_fd, call_readline, 0);
+
+      /* Tell gdb that we will be using the readline library. This
+         could be overwritten by a command in .gdbinit like 'set
+         editing on' or 'off'. */
+      async_command_editing_p = 1;
+    }
+}