Message ID | alpine.DEB.2.11.1412041913060.2232@idea |
---|---|
State | New, archived |
Headers |
Received: (qmail 20443 invoked by alias); 5 Dec 2014 00:19:36 -0000 Mailing-List: contact gdb-patches-help@sourceware.org; run by ezmlm Precedence: bulk List-Id: <gdb-patches.sourceware.org> List-Unsubscribe: <mailto:gdb-patches-unsubscribe-##L=##H@sourceware.org> List-Subscribe: <mailto:gdb-patches-subscribe@sourceware.org> List-Archive: <http://sourceware.org/ml/gdb-patches/> List-Post: <mailto:gdb-patches@sourceware.org> List-Help: <mailto:gdb-patches-help@sourceware.org>, <http://sourceware.org/ml/#faqs> Sender: gdb-patches-owner@sourceware.org Delivered-To: mailing list gdb-patches@sourceware.org Received: (qmail 20425 invoked by uid 89); 5 Dec 2014 00:19:35 -0000 Authentication-Results: sourceware.org; auth=none X-Virus-Found: No X-Spam-SWARE-Status: No, score=-2.4 required=5.0 tests=AWL, BAYES_00, RCVD_IN_DNSWL_LOW autolearn=ham version=3.3.2 X-HELO: mail-qg0-f48.google.com Received: from mail-qg0-f48.google.com (HELO mail-qg0-f48.google.com) (209.85.192.48) by sourceware.org (qpsmtpd/0.93/v0.84-503-g423c35a) with (AES128-SHA encrypted) ESMTPS; Fri, 05 Dec 2014 00:19:34 +0000 Received: by mail-qg0-f48.google.com with SMTP id q107so13602988qgd.35 for <gdb-patches@sourceware.org>; Thu, 04 Dec 2014 16:19:32 -0800 (PST) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20130820; h=x-gm-message-state:from:date:to:cc:subject:in-reply-to:message-id :references:user-agent:mime-version:content-type; bh=hm+1y6pJtR+K2bHvtQ/hjC8ag7rAcdfQiqg+lFutDvc=; b=KfVVjbCpUo0OVLOiaeJqfVIUToA6bSvbtI9vJPva3RyugLwXiMDZQVzMLUmO6P3sdT 3rrxvYzluawsAihnDg5P/40rfJBPpiz2kO9labwqTwLGFgT8+0oOf4t40DSLzYVz3bNl HfcHbNJN5O23/50ZG7Q19MKIVnDqC44F1DjM36yutblyVP1cNdbyDx81bs5keTwpx8Qh VM03nXqyusRVbOhbzbDklm+kFTFqCqYamkrE08QnZ0pQjDEorwhaYgo5kgg7uoDmx1MK msdeN0BR7Sm+KozBn0Wv6qxLcV/B8XAnJmkqE4+6cXGLquZWSXoDuZ/97BxtqehlEdFS OKpA== X-Gm-Message-State: ALoCoQkYdpcqc/cyfEPs+G0DnQoZOxgxsg17CU4S7VIkZc3Is0y9yJoiPP23KyTLje5viqmcmqY+ X-Received: by 10.224.38.71 with SMTP id a7mr21284879qae.24.1417738772356; Thu, 04 Dec 2014 16:19:32 -0800 (PST) Received: from [192.168.1.130] (ool-4353af5c.dyn.optonline.net. [67.83.175.92]) by mx.google.com with ESMTPSA id s3sm28232966qat.4.2014.12.04.16.19.30 for <multiple recipients> (version=TLSv1 cipher=ECDHE-RSA-RC4-SHA bits=128/128); Thu, 04 Dec 2014 16:19:31 -0800 (PST) From: Patrick Palka <patrick@parcs.ath.cx> X-Google-Original-From: Patrick Palka <patrick@idea> Date: Thu, 4 Dec 2014 19:19:18 -0500 (EST) To: Pedro Alves <palves@redhat.com> cc: gdb-patches@sourceware.org Subject: Re: [PATCH] Append to input history file instead of overwriting it In-Reply-To: <54808956.9070507@redhat.com> Message-ID: <alpine.DEB.2.11.1412041913060.2232@idea> References: <1417226462-11254-1-git-send-email-patrick@parcs.ath.cx> <54808956.9070507@redhat.com> User-Agent: Alpine 2.11 (DEB 23 2013-08-11) MIME-Version: 1.0 Content-Type: TEXT/PLAIN; charset=US-ASCII; format=flowed X-IsSubscribed: yes |
Commit Message
Patrick Palka
Dec. 5, 2014, 12:19 a.m. UTC
On Thu, 4 Dec 2014, Pedro Alves wrote: > On 11/29/2014 02:01 AM, Patrick Palka wrote: >> 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. It is particularly helpful when debugging GDB with GDB. >> >> Does this look OK to commit? Tested on x86_64-unknown-linux-gnu. > > Does this mean the history file will keep growing forever, rather than > be trimmed by the history size? That it does... my .gdb_history is up to 2200 lines already! Looks like we have to explicitly truncate the history file on exit after appending to it. Here's v2 of the patch that initializes the static variable command_count, and calls history_truncate_file() appropriately. Does it look OK? > > Thanks, > Pedro Alves > > -- >8 -- 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. It is particularly helpful when debugging GDB with GDB. gdb/ChangeLog: * top.h (gdb_add_history): Declare. * top.c (command_count): New variable. (gdb_add_history): New function. (quit_force): Append to history file instead of overwriting it. Truncate the history file afterwards. (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 | 20 +++++++++++++++++--- gdb/top.h | 2 ++ 3 files changed, 20 insertions(+), 4 deletions(-)
Comments
On 12/05/2014 12:19 AM, Patrick Palka wrote: > On Thu, 4 Dec 2014, Pedro Alves wrote: > >> On 11/29/2014 02:01 AM, Patrick Palka wrote: >>> 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. It is particularly helpful when debugging GDB with GDB. >>> >>> Does this look OK to commit? Tested on x86_64-unknown-linux-gnu. >> >> Does this mean the history file will keep growing forever, rather than >> be trimmed by the history size? > > That it does... my .gdb_history is up to 2200 lines already! > > Looks like we have to explicitly truncate the history file on exit after > appending to it. Here's v2 of the patch that initializes the static > variable command_count, and calls history_truncate_file() appropriately. > Does it look OK? I'd like to hear how does bash (the canonical readline/history user) handle this scenario, if at all. It seems like we're opening ourselves up for more chances of history file corruption, considering that e.g., you may be quitting several gdb's simultaneously (e.g., when SIGTERM is sent to all processes). A single write call with O_APPEND should be atomic, but history_do_write uses mmap if available. And then seems like the truncation operation could end up with a broken hist file as well. ISTM that if we go this path, we should be doing an atomic update: create a new file under a parallel name, and then move to final destination. > 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. > It is particularly helpful when debugging GDB with GDB. I'd like to have the description of how this helps that use case expanded. I mean, why would you want the history of the top level gdb mixed with the inferior gdb's history? Like, in: $ ./gdb ./gdb (top-gdb) b foo; whatever (top-gdb) run (gdb) whatever commands to trigger bug (gdb) quit // appends "whatever commands to trigger bug" to history (top-gdb) quit // appends commands to history $ ./gdb ./gdb (top-gdb) show commands // history contains top gdb's commands. (top-gdb) run (gdb) most recent history is the top-gdb's history I'd suggest that a better way to handle that use case is to start the inferior gdb with a different history file, like, e.g.: $ export g="./gdb -data-directory=data-directory" $ gdb --args $g -ex "set history file /tmp/hist" (I have that $g export in my .bashrc, since I use it so often.) > > gdb/ChangeLog: > > * top.h (gdb_add_history): Declare. > * top.c (command_count): New variable. > (gdb_add_history): New function. > (quit_force): Append to history file instead of overwriting it. > Truncate the history file afterwards. > (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 | 20 +++++++++++++++++--- > gdb/top.h | 2 ++ > 3 files changed, 20 insertions(+), 4 deletions(-) > > diff --git a/gdb/event-top.c b/gdb/event-top.c > index cb438ac..490bca6 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 c4b5c2c..9a5ed1e 100644 > --- a/gdb/top.c > +++ b/gdb/top.c > @@ -895,7 +895,20 @@ gdb_rl_operate_and_get_next (int count, int key) > > return rl_newline (1, key); > } > - > + > +/* 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++; > +} > + > /* Read one line from the command input stream `instream' > into the local static buffer `linebuffer' (whose current length > is `linelength'). > @@ -1090,7 +1103,7 @@ command_line_input (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) > @@ -1441,7 +1454,8 @@ quit_force (char *args, int from_tty) > { > if (write_history_p && history_filename > && input_from_terminal_p ()) > - write_history (history_filename); > + append_history (command_count, history_filename); > + history_truncate_file (history_filename, history_max_entries); > } > DO_PRINT_EX; > > diff --git a/gdb/top.h b/gdb/top.h > index 94f6c48..d8baea8 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); > Thanks, Pedro Alves
On Fri, Dec 5, 2014 at 5:45 AM, Pedro Alves <palves@redhat.com> wrote: > On 12/05/2014 12:19 AM, Patrick Palka wrote: >> On Thu, 4 Dec 2014, Pedro Alves wrote: >> >>> On 11/29/2014 02:01 AM, Patrick Palka wrote: >>>> 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. It is particularly helpful when debugging GDB with GDB. >>>> >>>> Does this look OK to commit? Tested on x86_64-unknown-linux-gnu. >>> >>> Does this mean the history file will keep growing forever, rather than >>> be trimmed by the history size? >> >> That it does... my .gdb_history is up to 2200 lines already! >> >> Looks like we have to explicitly truncate the history file on exit after >> appending to it. Here's v2 of the patch that initializes the static >> variable command_count, and calls history_truncate_file() appropriately. >> Does it look OK? > > I'd like to hear how does bash (the canonical readline/history user) > handle this scenario, if at all. It looks like bash truncates the history file size whenever the $HISTFILESIZE variable is changed (which is usually at startup when it reads ~/.bashrc), not on exit like this patch does. It doesn't do any kind of file-level locking for the truncation operation or for write_history() or append_history(). It writes directly to $HISTFILE. > It seems like we're opening ourselves > up for more chances of history file corruption, considering that e.g., > you may be quitting several gdb's simultaneously (e.g., when SIGTERM > is sent to all processes). A single write call with O_APPEND should > be atomic, but history_do_write uses mmap if available. And then > seems like the truncation operation could end up with a broken hist > file as well. > ISTM that if we go this path, we should be doing an atomic update: > create a new file under a parallel name, and then move to final destination. history_truncate_file() is definitely not atomic and does not look obviously thread-safe, but if bash gets away with not doing any kind of file-level locking, then can't we? :) > >> 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. > >> It is particularly helpful when debugging GDB with GDB. > > I'd like to have the description of how this helps that use case > expanded. I mean, why would you want the history of the top > level gdb mixed with the inferior gdb's history? Like, in: I don't necessarily want to, but I think such behavior is more useful than not retaining the inferior gdb's history at all. Besides I don't debug GDB that way. In one shell I open "gdb", in another I open "gdb -p $(pidof gdb)" and I execute commands in both processes from time to time. In such a scenario, the contents of the history file depends on which gdb process I close first. I would rather like to have the history file retain the commands of both processes. This problem is not peculiar to debugging GDB with GDB, rather it's encountered whenever there are multiple GDB processes running simultaneously. So I would rather remove that remark from the commit message ("It is particularly helpful when debugging GDB with GDB.") because it's not really true. > > $ ./gdb ./gdb > (top-gdb) b foo; whatever > (top-gdb) run > (gdb) whatever commands to trigger bug > (gdb) quit // appends "whatever commands to trigger bug" to history > (top-gdb) quit // appends commands to history > $ ./gdb ./gdb > (top-gdb) show commands // history contains top gdb's commands. > (top-gdb) run > (gdb) most recent history is the top-gdb's history > > > I'd suggest that a better way to handle that use case is to start > the inferior gdb with a different history file, like, e.g.: > > $ export g="./gdb -data-directory=data-directory" > $ gdb --args $g -ex "set history file /tmp/hist" > > (I have that $g export in my .bashrc, since I use it so often.) > >> >> gdb/ChangeLog: >> >> * top.h (gdb_add_history): Declare. >> * top.c (command_count): New variable. >> (gdb_add_history): New function. >> (quit_force): Append to history file instead of overwriting it. >> Truncate the history file afterwards. >> (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 | 20 +++++++++++++++++--- >> gdb/top.h | 2 ++ >> 3 files changed, 20 insertions(+), 4 deletions(-) >> >> diff --git a/gdb/event-top.c b/gdb/event-top.c >> index cb438ac..490bca6 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 c4b5c2c..9a5ed1e 100644 >> --- a/gdb/top.c >> +++ b/gdb/top.c >> @@ -895,7 +895,20 @@ gdb_rl_operate_and_get_next (int count, int key) >> >> return rl_newline (1, key); >> } >> - >> + >> +/* 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++; >> +} >> + >> /* Read one line from the command input stream `instream' >> into the local static buffer `linebuffer' (whose current length >> is `linelength'). >> @@ -1090,7 +1103,7 @@ command_line_input (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) >> @@ -1441,7 +1454,8 @@ quit_force (char *args, int from_tty) >> { >> if (write_history_p && history_filename >> && input_from_terminal_p ()) >> - write_history (history_filename); >> + append_history (command_count, history_filename); >> + history_truncate_file (history_filename, history_max_entries); >> } >> DO_PRINT_EX; >> >> diff --git a/gdb/top.h b/gdb/top.h >> index 94f6c48..d8baea8 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); >> > > > Thanks, > Pedro Alves
On 12/05/2014 02:11 PM, Patrick Palka wrote: > On Fri, Dec 5, 2014 at 5:45 AM, Pedro Alves <palves@redhat.com> wrote: >> On 12/05/2014 12:19 AM, Patrick Palka wrote: >>> On Thu, 4 Dec 2014, Pedro Alves wrote: >>> >>>> On 11/29/2014 02:01 AM, Patrick Palka wrote: >>>>> 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. It is particularly helpful when debugging GDB with GDB. >>>>> >>>>> Does this look OK to commit? Tested on x86_64-unknown-linux-gnu. >>>> >>>> Does this mean the history file will keep growing forever, rather than >>>> be trimmed by the history size? >>> >>> That it does... my .gdb_history is up to 2200 lines already! >>> >>> Looks like we have to explicitly truncate the history file on exit after >>> appending to it. Here's v2 of the patch that initializes the static >>> variable command_count, and calls history_truncate_file() appropriately. >>> Does it look OK? >> >> I'd like to hear how does bash (the canonical readline/history user) >> handle this scenario, if at all. > > It looks like bash truncates the history file size whenever the > $HISTFILESIZE variable is changed (which is usually at startup when it > reads ~/.bashrc), not on exit like this patch does. It doesn't do any > kind of file-level locking for the truncation operation or for > write_history() or append_history(). It writes directly to $HISTFILE. Bah. Is it that hard to do though? How about temporarily renaming the history file to something that includes gdb's PID (and would not a file name a user would use in practice) while we append to it, and then (atomically) rename it back? Something like: #1 - move $HISTFILE -> $HISTFILE-gdb$PID~ #2 - write/append history to $HISTFILE-gdb$PID~ #3 - move $HISTFILE-gdb$PID~ -> $HISTFILE We can then use non-atomic file access at will in #2, as no other process will be writing to that file (unless the user does evil thinks with "set history filename2, but then he deserves what he gets). This way, if two GDB's race writing to the file, then we'll lose the history of one of them, but that's better than ending up with a corrupted file, IMO. > >> It seems like we're opening ourselves >> up for more chances of history file corruption, considering that e.g., >> you may be quitting several gdb's simultaneously (e.g., when SIGTERM >> is sent to all processes). A single write call with O_APPEND should >> be atomic, but history_do_write uses mmap if available. And then >> seems like the truncation operation could end up with a broken hist >> file as well. >> ISTM that if we go this path, we should be doing an atomic update: >> create a new file under a parallel name, and then move to final destination. > > history_truncate_file() is definitely not atomic and does not look > obviously thread-safe, but if bash gets away with not doing any kind > of file-level locking, then can't we? :) > >> >>> 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. >> >>> It is particularly helpful when debugging GDB with GDB. >> >> I'd like to have the description of how this helps that use case >> expanded. I mean, why would you want the history of the top >> level gdb mixed with the inferior gdb's history? Like, in: > > I don't necessarily want to, but I think such behavior is more useful > than not retaining the inferior gdb's history at all. Besides I don't > debug GDB that way. > > In one shell I open "gdb", in another I open "gdb -p $(pidof gdb)" and > I execute commands in both processes from time to time. In such a > scenario, the contents of the history file depends on which gdb > process I close first. I would rather like to have the history file > retain the commands of both processes. That still sounds odd to me -- the commands issued in the inferior gdb should be of no use to the other gdb, IMO. > This problem is not peculiar > to debugging GDB with GDB, rather it's encountered whenever there are > multiple GDB processes running simultaneously. Yes, that makes more sense. > So I would rather > remove that remark from the commit message ("It is particularly > helpful when debugging GDB with GDB.") because it's not really true. Alright. Thanks, Pedro Alves
> Date: Wed, 10 Dec 2014 16:54:13 +0000 > From: Pedro Alves <palves@redhat.com> > CC: gdb-patches@sourceware.org > > Is it that hard to do though? How about temporarily renaming the > history file to something that includes gdb's PID (and would not a > file name a user would use in practice) while we append > to it, and then (atomically) rename it back? Something like: > > #1 - move $HISTFILE -> $HISTFILE-gdb$PID~ > #2 - write/append history to $HISTFILE-gdb$PID~ > #3 - move $HISTFILE-gdb$PID~ -> $HISTFILE You cannot portably rename a file someone writes to, unless you are willing to limit this to Posix filesystems.
On 12/10/2014 05:12 PM, Eli Zaretskii wrote: >> Date: Wed, 10 Dec 2014 16:54:13 +0000 >> From: Pedro Alves <palves@redhat.com> >> CC: gdb-patches@sourceware.org >> >> Is it that hard to do though? How about temporarily renaming the >> history file to something that includes gdb's PID (and would not a >> file name a user would use in practice) while we append >> to it, and then (atomically) rename it back? Something like: >> >> #1 - move $HISTFILE -> $HISTFILE-gdb$PID~ >> #2 - write/append history to $HISTFILE-gdb$PID~ >> #3 - move $HISTFILE-gdb$PID~ -> $HISTFILE > > You cannot portably rename a file someone writes to, unless you are > willing to limit this to Posix filesystems. The way I've proposed, no gdb would be actually writing directly to $HISTFILE, only reading. Is it a problem still? Not considering someone manually opening the file for writing, but in that case the system that would fail the rename would fail the write-in-place too. Thanks, Pedro Alves
On Wed, Dec 10, 2014 at 11:54 AM, Pedro Alves <palves@redhat.com> wrote: > On 12/05/2014 02:11 PM, Patrick Palka wrote: >> On Fri, Dec 5, 2014 at 5:45 AM, Pedro Alves <palves@redhat.com> wrote: >>> On 12/05/2014 12:19 AM, Patrick Palka wrote: >>>> On Thu, 4 Dec 2014, Pedro Alves wrote: >>>> >>>>> On 11/29/2014 02:01 AM, Patrick Palka wrote: >>>>>> 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. It is particularly helpful when debugging GDB with GDB. >>>>>> >>>>>> Does this look OK to commit? Tested on x86_64-unknown-linux-gnu. >>>>> >>>>> Does this mean the history file will keep growing forever, rather than >>>>> be trimmed by the history size? >>>> >>>> That it does... my .gdb_history is up to 2200 lines already! >>>> >>>> Looks like we have to explicitly truncate the history file on exit after >>>> appending to it. Here's v2 of the patch that initializes the static >>>> variable command_count, and calls history_truncate_file() appropriately. >>>> Does it look OK? >>> >>> I'd like to hear how does bash (the canonical readline/history user) >>> handle this scenario, if at all. >> >> It looks like bash truncates the history file size whenever the >> $HISTFILESIZE variable is changed (which is usually at startup when it >> reads ~/.bashrc), not on exit like this patch does. It doesn't do any >> kind of file-level locking for the truncation operation or for >> write_history() or append_history(). It writes directly to $HISTFILE. > > Bah. > > Is it that hard to do though? How about temporarily renaming the > history file to something that includes gdb's PID (and would not a > file name a user would use in practice) while we append > to it, and then (atomically) rename it back? Something like: > > #1 - move $HISTFILE -> $HISTFILE-gdb$PID~ > #2 - write/append history to $HISTFILE-gdb$PID~ > #3 - move $HISTFILE-gdb$PID~ -> $HISTFILE > > We can then use non-atomic file access at will in #2, as no > other process will be writing to that file (unless the user > does evil thinks with "set history filename2, but then he deserves > what he gets). > > This way, if two GDB's race writing to the file, then we'll lose the > history of one of them, but that's better than ending up with a > corrupted file, IMO. With your renaming method, what to do if the user has no .gdb_history file to begin with? How would you tell the difference between the case of having no .gdb_history and the case of another process in the middle of writing to the history file (and thus having temporarily renamed it)? In either case it looks like the .gdb_history file doesn't exist. But in the first case we want to write a history file anyway, and in the second case we want to give up on writing to the history file. But it doesn't seem possible to tell the difference between these two cases with your proposed method. > >> >>> It seems like we're opening ourselves >>> up for more chances of history file corruption, considering that e.g., >>> you may be quitting several gdb's simultaneously (e.g., when SIGTERM >>> is sent to all processes). A single write call with O_APPEND should >>> be atomic, but history_do_write uses mmap if available. And then >>> seems like the truncation operation could end up with a broken hist >>> file as well. >>> ISTM that if we go this path, we should be doing an atomic update: >>> create a new file under a parallel name, and then move to final destination. >> >> history_truncate_file() is definitely not atomic and does not look >> obviously thread-safe, but if bash gets away with not doing any kind >> of file-level locking, then can't we? :) >> >>> >>>> 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. >>> >>>> It is particularly helpful when debugging GDB with GDB. >>> >>> I'd like to have the description of how this helps that use case >>> expanded. I mean, why would you want the history of the top >>> level gdb mixed with the inferior gdb's history? Like, in: >> >> I don't necessarily want to, but I think such behavior is more useful >> than not retaining the inferior gdb's history at all. Besides I don't >> debug GDB that way. >> >> In one shell I open "gdb", in another I open "gdb -p $(pidof gdb)" and >> I execute commands in both processes from time to time. In such a >> scenario, the contents of the history file depends on which gdb >> process I close first. I would rather like to have the history file >> retain the commands of both processes. > > That still sounds odd to me -- the commands issued in the inferior gdb > should be of no use to the other gdb, IMO. > >> This problem is not peculiar >> to debugging GDB with GDB, rather it's encountered whenever there are >> multiple GDB processes running simultaneously. > > Yes, that makes more sense. > >> So I would rather >> remove that remark from the commit message ("It is particularly >> helpful when debugging GDB with GDB.") because it's not really true. > > Alright. > > Thanks, > Pedro Alves
On Sat, Jan 10, 2015 at 9:09 AM, Patrick Palka <patrick@parcs.ath.cx> wrote: > On Wed, Dec 10, 2014 at 11:54 AM, Pedro Alves <palves@redhat.com> wrote: >> On 12/05/2014 02:11 PM, Patrick Palka wrote: >>> On Fri, Dec 5, 2014 at 5:45 AM, Pedro Alves <palves@redhat.com> wrote: >>>> On 12/05/2014 12:19 AM, Patrick Palka wrote: >>>>> On Thu, 4 Dec 2014, Pedro Alves wrote: >>>>> >>>>>> On 11/29/2014 02:01 AM, Patrick Palka wrote: >>>>>>> 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. It is particularly helpful when debugging GDB with GDB. >>>>>>> >>>>>>> Does this look OK to commit? Tested on x86_64-unknown-linux-gnu. >>>>>> >>>>>> Does this mean the history file will keep growing forever, rather than >>>>>> be trimmed by the history size? >>>>> >>>>> That it does... my .gdb_history is up to 2200 lines already! >>>>> >>>>> Looks like we have to explicitly truncate the history file on exit after >>>>> appending to it. Here's v2 of the patch that initializes the static >>>>> variable command_count, and calls history_truncate_file() appropriately. >>>>> Does it look OK? >>>> >>>> I'd like to hear how does bash (the canonical readline/history user) >>>> handle this scenario, if at all. >>> >>> It looks like bash truncates the history file size whenever the >>> $HISTFILESIZE variable is changed (which is usually at startup when it >>> reads ~/.bashrc), not on exit like this patch does. It doesn't do any >>> kind of file-level locking for the truncation operation or for >>> write_history() or append_history(). It writes directly to $HISTFILE. >> >> Bah. >> >> Is it that hard to do though? How about temporarily renaming the >> history file to something that includes gdb's PID (and would not a >> file name a user would use in practice) while we append >> to it, and then (atomically) rename it back? Something like: >> >> #1 - move $HISTFILE -> $HISTFILE-gdb$PID~ >> #2 - write/append history to $HISTFILE-gdb$PID~ >> #3 - move $HISTFILE-gdb$PID~ -> $HISTFILE >> >> We can then use non-atomic file access at will in #2, as no >> other process will be writing to that file (unless the user >> does evil thinks with "set history filename2, but then he deserves >> what he gets). >> >> This way, if two GDB's race writing to the file, then we'll lose the >> history of one of them, but that's better than ending up with a >> corrupted file, IMO. > > With your renaming method, what to do if the user has no .gdb_history > file to begin with? How would you tell the difference between the > case of having no .gdb_history and the case of another process in the > middle of writing to the history file (and thus having temporarily > renamed it)? In either case it looks like the .gdb_history file > doesn't exist. But in the first case we want to write a history file > anyway, and in the second case we want to give up on writing to the > history file. But it doesn't seem possible to tell the difference > between these two cases with your proposed method. .... therefore we must conservatively assume case #1, that the history file does not exist, and to write (not append) the process's known history to the local history file and try to rename it back anyway. > >> >>> >>>> It seems like we're opening ourselves >>>> up for more chances of history file corruption, considering that e.g., >>>> you may be quitting several gdb's simultaneously (e.g., when SIGTERM >>>> is sent to all processes). A single write call with O_APPEND should >>>> be atomic, but history_do_write uses mmap if available. And then >>>> seems like the truncation operation could end up with a broken hist >>>> file as well. >>>> ISTM that if we go this path, we should be doing an atomic update: >>>> create a new file under a parallel name, and then move to final destination. >>> >>> history_truncate_file() is definitely not atomic and does not look >>> obviously thread-safe, but if bash gets away with not doing any kind >>> of file-level locking, then can't we? :) >>> >>>> >>>>> 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. >>>> >>>>> It is particularly helpful when debugging GDB with GDB. >>>> >>>> I'd like to have the description of how this helps that use case >>>> expanded. I mean, why would you want the history of the top >>>> level gdb mixed with the inferior gdb's history? Like, in: >>> >>> I don't necessarily want to, but I think such behavior is more useful >>> than not retaining the inferior gdb's history at all. Besides I don't >>> debug GDB that way. >>> >>> In one shell I open "gdb", in another I open "gdb -p $(pidof gdb)" and >>> I execute commands in both processes from time to time. In such a >>> scenario, the contents of the history file depends on which gdb >>> process I close first. I would rather like to have the history file >>> retain the commands of both processes. >> >> That still sounds odd to me -- the commands issued in the inferior gdb >> should be of no use to the other gdb, IMO. >> >>> This problem is not peculiar >>> to debugging GDB with GDB, rather it's encountered whenever there are >>> multiple GDB processes running simultaneously. >> >> Yes, that makes more sense. >> >>> So I would rather >>> remove that remark from the commit message ("It is particularly >>> helpful when debugging GDB with GDB.") because it's not really true. >> >> Alright. >> >> Thanks, >> Pedro Alves
diff --git a/gdb/event-top.c b/gdb/event-top.c index cb438ac..490bca6 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 c4b5c2c..9a5ed1e 100644 --- a/gdb/top.c +++ b/gdb/top.c @@ -895,7 +895,20 @@ gdb_rl_operate_and_get_next (int count, int key) return rl_newline (1, key); } - + +/* 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++; +} + /* Read one line from the command input stream `instream' into the local static buffer `linebuffer' (whose current length is `linelength'). @@ -1090,7 +1103,7 @@ command_line_input (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) @@ -1441,7 +1454,8 @@ quit_force (char *args, int from_tty) { if (write_history_p && history_filename && input_from_terminal_p ()) - write_history (history_filename); + append_history (command_count, history_filename); + history_truncate_file (history_filename, history_max_entries); } DO_PRINT_EX; diff --git a/gdb/top.h b/gdb/top.h index 94f6c48..d8baea8 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);