From patchwork Thu Jun 18 14:47:30 2015 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Patrick Palka X-Patchwork-Id: 7238 Received: (qmail 116320 invoked by alias); 18 Jun 2015 14:47:56 -0000 Mailing-List: contact gdb-patches-help@sourceware.org; run by ezmlm Precedence: bulk List-Id: List-Unsubscribe: List-Subscribe: List-Archive: List-Post: List-Help: , Sender: gdb-patches-owner@sourceware.org Delivered-To: mailing list gdb-patches@sourceware.org Received: (qmail 116302 invoked by uid 89); 18 Jun 2015 14:47:55 -0000 Authentication-Results: sourceware.org; auth=none X-Virus-Found: No X-Spam-SWARE-Status: No, score=-1.7 required=5.0 tests=AWL, BAYES_00, KAM_LAZY_DOMAIN_SECURITY, RCVD_IN_DNSWL_LOW autolearn=no version=3.3.2 X-HELO: mail-oi0-f45.google.com Received: from mail-oi0-f45.google.com (HELO mail-oi0-f45.google.com) (209.85.218.45) by sourceware.org (qpsmtpd/0.93/v0.84-503-g423c35a) with (AES128-GCM-SHA256 encrypted) ESMTPS; Thu, 18 Jun 2015 14:47:53 +0000 Received: by oiax193 with SMTP id x193so59070381oia.2 for ; Thu, 18 Jun 2015 07:47:51 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20130820; h=x-gm-message-state:mime-version:in-reply-to:references:from:date :message-id:subject:to:cc:content-type; bh=mD6deGuMpzBYsb0aT4951Yd6crs+d1z50wthu8/FzwI=; b=G/Kc3adtrtIRT9HW9gKE8Zf/VGNMMap9xMnnUrRdd4btnqOKVRnOBb32QjH3IlJoVh 59mcRstXXEatxAHDSopA8vcIUxZdvdrihTwXHelZ/2IW043IVhERUSsvBzGAVEXrqoUS 663nvz9EE2n/PZUukOF+vqc0VWhI5ag0yApOAUgPfD3baOQAFwvljSttmjFWnJhcaGJ8 Qh+UVMwtfvtnbfsfhWe7qvoo5x3+WlANpAIvlBYrxwFyCUL5euGjZ0eIsWqO4apWJidE IP5Z7fNHMYygJ3GjJuchhSyOPwbguGza5HctuCDPYbEdpw2oMsH1EcvwvHp1A6cRYyBo t0oQ== X-Gm-Message-State: ALoCoQnOykd20lSwyXR1VWedsN6Rjzidd9dGYxy7NuhGfVB7WZFCMmgKz9bspMpw6EKjCwfzpXDB X-Received: by 10.182.102.129 with SMTP id fo1mr9513359obb.24.1434638871686; Thu, 18 Jun 2015 07:47:51 -0700 (PDT) MIME-Version: 1.0 Received: by 10.182.96.167 with HTTP; Thu, 18 Jun 2015 07:47:30 -0700 (PDT) In-Reply-To: References: <1434572241-16019-1-git-send-email-patrick@parcs.ath.cx> <55828A13.8030703@redhat.com> From: Patrick Palka Date: Thu, 18 Jun 2015 10:47:30 -0400 Message-ID: Subject: Re: [PATCH] Test the interaction between GDBHISTSIZE and .gdbinit To: Pedro Alves Cc: "gdb-patches@sourceware.org" On Thu, Jun 18, 2015 at 8:44 AM, Patrick Palka wrote: > On Thu, Jun 18, 2015 at 5:06 AM, Pedro Alves wrote: >> On 06/17/2015 09:17 PM, Patrick Palka wrote: >>> The value inside the GDBHISTSIZE environment variable, only if valid, >>> should override setting the history size through one's .gdbinit file. >> >> Thanks, looks good. >> >>> + unset -nocomplain env(GDBHISTSIZE) >>> array set env [array get old_env] >> >> Though this unset looks unnecessary, given that the following line >> restores the whole array. > > It turns out that > > array set env [array get old_env] > > does not completely restore the env array to its original state. What > it seems to do is to reset each pre-existing environment variable > (existing in the saved env array) to its original value. New > environment variables that were set inside the env array in the > meantime do not get unset after restoring. So e.g. after doing > > array set old_env [array get env] > set env(SOME_NEW_VAR) foo > array set env [array get old_env] > > the environment variable SOME_NEW_VAR=foo will still be in the env > array. So this "array set env" trick is insufficient. That is why > the unset of GDBHISTSIZE is necessary there. > > To make the pattern of "temporarily altering global variables, > restoring their original value afterwards" more convenient and less > error-prone, I've been thinking about introducing a new tcl proc that > acts as a wrapper for saving/restoring a specified list of variables. > Its use would look something like: > > save_vars { INTERNAL_GDBFLAGS env(GDBHISTSIZE) env(HOME) } { > append INTERNAL_GDBFLAGS " -nx" > unset -nocomplain env(GDBHISTSIZE) > unset -nocomplain env(HOME) > gdb_test .... > more_gdb_test ... > } > > which guarantees that after the body has finished executing, the given > list of variables will have their contents restored to their original > values. What do you think about this? Here is an implementation of save_vars (bad name I know) which can successfully replace the manual saving/restoring of globals done in gdbinit-history.exp, gdbhistsize-history.exp and readline.exp. (TCL sure is cool.) diff --git a/gdb/testsuite/lib/gdb.exp b/gdb/testsuite/lib/gdb.exp index b5928c3..92157a7 100644 --- a/gdb/testsuite/lib/gdb.exp +++ b/gdb/testsuite/lib/gdb.exp @@ -1830,6 +1830,71 @@ proc with_test_prefix { prefix body } { } } +# Run BODY in the context of the caller. After BODY is run, the variables +# listed in VARS will be reset to the values they had before BODY was run. +# +# This is useful for providing a scope in which it is safe to temporarily +# modify global variables, e.g. +# +# global INTERNAL_GDBFLAGS +# global env(GDBHISTSIZE) +# +# save_vars { INTERNAL_GDBFLAGS env(GDBHISTSIZE) } { +# append INTERNAL_GDBFLAGS " -nx" +# unset -nocomplain env(GDBHISTSIZE) +# gdb_start +# gdb_test ... +# } +# +# Here, although INTERNAL_GDBFLAGS and env(GDBHISTSIZE) are modified inside the +# BODY, this proc will guarantee that the modifications will be undone after +# BODY finishes executing. + +proc save_vars { vars body } { + array set saved_scalars { } + array set saved_arrays { } + set unset_vars { } + + foreach var $vars { + # First evaluate VAR in the context of the caller in case the variable + # name may be a not-yet-interpolated string like env($foo) + set var [uplevel 1 list $var] + + if [uplevel 1 [list info exists $var]] { + if [uplevel 1 [list array exists $var]] { + set saved_arrays($var) [uplevel 1 [list array get $var]] + } else { + set saved_scalars($var) [uplevel 1 [list set $var]] + } + } else { + lappend unset_vars $var + } + } + + set code [catch {uplevel 1 $body} result] + + foreach {var value} [array get saved_scalars] { + uplevel 1 [list set $var $value] + } + + foreach {var value} [array get saved_arrays] { + uplevel 1 [list unset $var] + uplevel 1 [list array set $var $value] + } + + foreach var $unset_vars { + uplevel 1 [list unset -nocomplain $var] + } + + if {$code == 1} { + global errorInfo errorCode + return -code $code -errorinfo $errorInfo -errorcode $errorCode $result + } else { + return -code $code $result + } +} + + # Run tests in BODY with GDB prompt and variable $gdb_prompt set to # PROMPT. When BODY is finished, restore GDB prompt and variable # $gdb_prompt.