public inbox for gdb-patches@sourceware.org
 help / color / mirror / Atom feed
From: Patrick Palka <patrick@parcs.ath.cx>
To: Pedro Alves <palves@redhat.com>
Cc: gdb-patches@sourceware.org
Subject: Re: [PATCH] Append to input history file instead of overwriting it
Date: Mon, 12 Jan 2015 22:56:00 -0000	[thread overview]
Message-ID: <CA+C-WL8QqcBs+ou+U2mbMpxN-vrCHp-h44_+501nQzWSusXVhA@mail.gmail.com> (raw)
In-Reply-To: <54B41B03.5030306@redhat.com>

[-- Attachment #1: Type: text/plain, Size: 2975 bytes --]

On Mon, Jan 12, 2015 at 2:05 PM, Pedro Alves <palves@redhat.com> wrote:
> On 01/10/2015 06:46 PM, Patrick Palka wrote:
>
>> +/* Safely append new history entries to the history file in a corruption-free
>> +   way using an intermediate local history file.  */
>> +
>> +static void
>> +gdb_safe_append_history (void)
>> +{
>> +  int ret, saved_errno;
>> +  char *local_history_filename;
>> +
>> +  local_history_filename = xstrprintf ("%s.%d", history_filename, getpid ());
>
> IMO just appending a number is not sufficiently distinct
> from what a user might reasonably want to name alternate history
> files.  How about picking a more obscure name, like what
> I had originally suggested:
>
>   local_history_filename = xstrprintf ("%s-gdb%d~", history_filename, getpid ());
>
> ?
>
>> +
>> +  ret = rename (history_filename, local_history_filename);
>> +  saved_errno = errno;
>> +  if (ret < 0 && saved_errno == ENOENT)
>> +    {
>> +      /* If the rename failed with ENOENT then either the global history file
>> +      never existed in the first place or another GDB process is currently
>> +      appending to it (and has thus temporarily renamed it).  Since we can't
>> +      distinguish between these two cases, we have to conservatively assume
>> +      the first case and therefore must write out (not append) our known
>> +      history to our local history file and try to move it back anyway.
>> +      Otherwise a global history file would never get created!  */
>> +      write_history (local_history_filename);
>> +    }
>> +  else if (ret < 0)
>> +    {
>> +      warning (_("Could not rename %s to %s: %s"),
>> +            history_filename, local_history_filename, strerror (saved_errno));
>
> use safe_strerror.  Watch out for line too long.
>
>
>> +      goto out;
>
> Let's avoid gotos when simple enough.  In this case, seems to
> me that to skip the second rename call, we only need to move
> the "else if" and "else" within a parent "else" branch.
>
> Also, please use a cleanup instead of the xfree at the end:
>
>   local_history_filename = xstrprintf ("%s-gdb%d~", history_filename, getpid ());
>   old_chain = make_cleanup (xfree, local_history_filename);
>   ...
>   do_cleanups (old_chain);
>
>> +    }
>> +  else
>> +    {
>> +      append_history (command_count, local_history_filename);
>> +      history_truncate_file (local_history_filename, history_max_entries);
>> +    }
>> +
>> +  ret = rename (local_history_filename, history_filename);
>> +  saved_errno = errno;
>> +  if (ret < 0 && saved_errno != EEXIST)
>> +    warning (_("Could not rename %s to %s: %s"),
>> +          local_history_filename, history_filename, strerror (saved_errno));
>
> safe_strerror.
>
>> +
>> +out:
>> +  xfree (local_history_filename);
>> +}
>> +
>
> This is OK with these changes.

I have made the changes you requested and committed the attached
patch.  I hope I haven't made any oversights.

Thanks for reviewing!

>
> Thanks!
>
> --
> Pedro Alves
>

[-- Attachment #2: 0001-Append-to-input-history-file-instead-of-overwriting-.patch --]
[-- Type: application/octet-stream, Size: 5249 bytes --]

From 6086d5e70163c62bedf3228200c378a04af23646 Mon Sep 17 00:00:00 2001
From: Patrick Palka <patrick@parcs.ath.cx>
Date: Fri, 28 Nov 2014 20:22:45 -0500
Subject: [PATCH] Append to input history file instead of overwriting it

This patch makes readline append new history lines to the GDB history
file on exit instead of overwriting the entire history file on exit.
This change allows us to run multiple simultaneous GDB sessions without
having each session overwrite the added history of each other session on
exit.

Care must be taken to ensure that the history file doesn't get corrupted
when multiple GDB processes are trying to simultaneously append to and
then truncate it.  Safety is achieved in such a situation by using an
intermediate local history file to mutually exclude multiple processes
from simultaneously performing write operations on the global history
file.

gdb/ChangeLog:

	* top.h (gdb_add_history): Declare.
	* top.c (command_count): New variable.
	(gdb_add_history): New function.
	(gdb_safe_append_history): New static function.
	(quit_force): Call it.
	(command_line_input): Use gdb_add_history instead of
	add_history.
	* event-top.c (command_line_handler): Likewise.
---
 gdb/event-top.c |  2 +-
 gdb/top.c       | 73 ++++++++++++++++++++++++++++++++++++++++++++++++++++++---
 gdb/top.h       |  2 ++
 3 files changed, 73 insertions(+), 4 deletions(-)

diff --git a/gdb/event-top.c b/gdb/event-top.c
index 13ddee2..bbda5dc 100644
--- a/gdb/event-top.c
+++ b/gdb/event-top.c
@@ -667,7 +667,7 @@ command_line_handler (char *rl)
 
   /* Add line to history if appropriate.  */
   if (*linebuffer && input_from_terminal_p ())
-    add_history (linebuffer);
+    gdb_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
diff --git a/gdb/top.c b/gdb/top.c
index b85ea1a..a1462a0 100644
--- a/gdb/top.c
+++ b/gdb/top.c
@@ -895,7 +895,74 @@ gdb_rl_operate_and_get_next (int count, int key)
 
   return rl_newline (1, key);
 }
-\f
+
+/* Number of user commands executed during this session.  */
+
+static int command_count = 0;
+
+/* Add the user command COMMAND to the input history list.  */
+
+void
+gdb_add_history (const char *command)
+{
+  add_history (command);
+  command_count++;
+}
+
+/* Safely append new history entries to the history file in a corruption-free
+   way using an intermediate local history file.  */
+
+static void
+gdb_safe_append_history (void)
+{
+  int ret, saved_errno;
+  char *local_history_filename;
+  struct cleanup *old_chain;
+
+  local_history_filename
+    = xstrprintf ("%s-gdb%d~", history_filename, getpid ());
+  old_chain = make_cleanup (xfree, local_history_filename);
+
+  ret = rename (history_filename, local_history_filename);
+  saved_errno = errno;
+  if (ret < 0 && saved_errno != ENOENT)
+    {
+      warning (_("Could not rename %s to %s: %s"),
+	       history_filename, local_history_filename,
+	       safe_strerror (saved_errno));
+    }
+  else
+    {
+      if (ret < 0)
+	{
+	  /* If the rename failed with ENOENT then either the global history
+	     file never existed in the first place or another GDB process is
+	     currently appending to it (and has thus temporarily renamed it).
+	     Since we can't distinguish between these two cases, we have to
+	     conservatively assume the first case and therefore must write out
+	     (not append) our known history to our local history file and try
+	     to move it back anyway.  Otherwise a global history file would
+	     never get created!  */
+	   gdb_assert (saved_errno == ENOENT);
+	   write_history (local_history_filename);
+	}
+      else
+	{
+	  append_history (command_count, local_history_filename);
+	  history_truncate_file (local_history_filename, history_max_entries);
+	}
+
+      ret = rename (local_history_filename, history_filename);
+      saved_errno = errno;
+      if (ret < 0 && saved_errno != EEXIST)
+        warning (_("Could not rename %s to %s: %s"),
+		 local_history_filename, history_filename,
+		 safe_strerror (saved_errno));
+    }
+
+  do_cleanups (old_chain);
+}
+
 /* Read one line from the command input stream `instream'
    into the local static buffer `linebuffer' (whose current length
    is `linelength').
@@ -1094,7 +1161,7 @@ command_line_input (const char *prompt_arg, int repeat, char *annotation_suffix)
 
   /* Add line to history if appropriate.  */
   if (*linebuffer && input_from_terminal_p ())
-    add_history (linebuffer);
+    gdb_add_history (linebuffer);
 
   /* Save into global buffer if appropriate.  */
   if (repeat)
@@ -1445,7 +1512,7 @@ quit_force (char *args, int from_tty)
     {
       if (write_history_p && history_filename
 	  && input_from_terminal_p ())
-	write_history (history_filename);
+	gdb_safe_append_history ();
     }
   DO_PRINT_EX;
 
diff --git a/gdb/top.h b/gdb/top.h
index b68e896..987279b 100644
--- a/gdb/top.h
+++ b/gdb/top.h
@@ -79,6 +79,8 @@ extern int history_expansion_p;
 extern int server_command;
 extern char *lim_at_start;
 
+extern void gdb_add_history (const char *);
+
 extern void show_commands (char *args, int from_tty);
 
 extern void set_history (char *, int);
-- 
2.2.1.212.gc5b9256


      reply	other threads:[~2015-01-12 22:56 UTC|newest]

Thread overview: 21+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2014-11-29  2:01 Patrick Palka
2014-12-01 20:50 ` Sergio Durigan Junior
2014-12-04 16:18 ` Pedro Alves
2014-12-05  0:19   ` Patrick Palka
2014-12-05 10:45     ` Pedro Alves
2014-12-05 14:11       ` Patrick Palka
2014-12-10 16:54         ` Pedro Alves
2014-12-10 17:17           ` Eli Zaretskii
2014-12-10 17:23             ` Pedro Alves
2015-01-10 14:10           ` Patrick Palka
2015-01-10 15:16             ` Patrick Palka
2015-01-10 15:18               ` Patrick Palka
2015-01-10 15:39                 ` Eli Zaretskii
2015-01-10 15:48                   ` Patrick Palka
2015-01-10 16:03                     ` Eli Zaretskii
2015-01-10 16:18                       ` Patrick Palka
2015-01-10 16:41                         ` Eli Zaretskii
2015-01-10 18:17                           ` Patrick Palka
2015-01-10 18:46                             ` Patrick Palka
2015-01-12 19:05                               ` Pedro Alves
2015-01-12 22:56                                 ` Patrick Palka [this message]

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=CA+C-WL8QqcBs+ou+U2mbMpxN-vrCHp-h44_+501nQzWSusXVhA@mail.gmail.com \
    --to=patrick@parcs.ath.cx \
    --cc=gdb-patches@sourceware.org \
    --cc=palves@redhat.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).