From patchwork Mon Oct 10 15:54:28 2011 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Aldy Hernandez X-Patchwork-Id: 118768 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from sourceware.org (server1.sourceware.org [209.132.180.131]) by ozlabs.org (Postfix) with SMTP id B618FB70FE for ; Tue, 11 Oct 2011 02:54:57 +1100 (EST) Received: (qmail 1437 invoked by alias); 10 Oct 2011 15:54:50 -0000 Received: (qmail 1401 invoked by uid 22791); 10 Oct 2011 15:54:46 -0000 X-SWARE-Spam-Status: No, hits=-6.6 required=5.0 tests=AWL, BAYES_00, RCVD_IN_DNSWL_HI, RP_MATCHES_RCVD, SPF_HELO_PASS X-Spam-Check-By: sourceware.org Received: from mx1.redhat.com (HELO mx1.redhat.com) (209.132.183.28) by sourceware.org (qpsmtpd/0.43rc1) with ESMTP; Mon, 10 Oct 2011 15:54:30 +0000 Received: from int-mx01.intmail.prod.int.phx2.redhat.com (int-mx01.intmail.prod.int.phx2.redhat.com [10.5.11.11]) by mx1.redhat.com (8.14.4/8.14.4) with ESMTP id p9AFsTWo004612 (version=TLSv1/SSLv3 cipher=DHE-RSA-AES256-SHA bits=256 verify=OK); Mon, 10 Oct 2011 11:54:29 -0400 Received: from houston.quesejoda.com (vpn-237-42.phx2.redhat.com [10.3.237.42]) by int-mx01.intmail.prod.int.phx2.redhat.com (8.13.8/8.13.8) with ESMTP id p9AFsSBR028256; Mon, 10 Oct 2011 11:54:29 -0400 Message-ID: <4E931534.90400@redhat.com> Date: Mon, 10 Oct 2011 10:54:28 -0500 From: Aldy Hernandez User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:6.0.2) Gecko/20110906 Thunderbird/6.0.2 MIME-Version: 1.0 To: gcc-patches CC: Mike Stump , Jeff Law , Andrew MacLeod Subject: simulate-thread changes to avoid infinite loops Mailing-List: contact gcc-patches-help@gcc.gnu.org; run by ezmlm Precedence: bulk List-Id: List-Unsubscribe: List-Archive: List-Post: List-Help: Sender: gcc-patches-owner@gcc.gnu.org Delivered-To: mailing list gcc-patches@gcc.gnu.org Hi folks. This was a change Andrew had made to the simulate-thread framework to avoid infinite loops in hostile threads. I forgot to merge this in my original submission, and am doing so now. The original patch is here: http://permalink.gmane.org/gmane.comp.gcc.patches/247678 My patch is a mere sed run on Andrew's patch, plus a few fixed typos in the comments. I also kept the original simulate_thread_fini name as opposed to the __gdb_memmodel_fini name Andrew has (to keep names homogeneous throughout). Tested on x86-64 Linux by running "make check RUNTESTFLAGS=simulate-thread.exp" on the build tree I already had for the original submission. OK for trunk? * gcc.dg/simulate-thread/simulate-thread.gdb: Call wrappers for *other_threads() and *final_verify(). * gcc.dg/simulate-thread/simulate-thread.h (simulate_thread_wrapper_other_threads): New. (simulate_thread_wrapper_final_verify): New. Index: gcc.dg/simulate-thread/simulate-thread.gdb =================================================================== --- gcc.dg/simulate-thread/simulate-thread.gdb (revision 179751) +++ gcc.dg/simulate-thread/simulate-thread.gdb (working copy) @@ -5,13 +5,13 @@ run set $ret = 0 while (simulate_thread_fini != 1) && (! $ret) - call simulate_thread_other_threads() + call simulate_thread_wrapper_other_threads() stepi set $ret |= simulate_thread_step_verify() end if (! $ret) - set $ret |= simulate_thread_final_verify() + set $ret |= simulate_thread_wrapper_final_verify() end continue quit $ret Index: gcc.dg/simulate-thread/simulate-thread.h =================================================================== --- gcc.dg/simulate-thread/simulate-thread.h (revision 179751) +++ gcc.dg/simulate-thread/simulate-thread.h (working copy) @@ -5,3 +5,107 @@ simulate_thread_done () { simulate_thread_fini = 1; } + +/* A hostile thread is one which changes a memory location so quickly + that another thread may never see the same value again. This is + simulated when simulate_thread_other_thread() is defined to modify + a memory location every cycle. + + A process implementing a dependency on this value can run into + difficulties with such a hostile thread. For instance, + implementing an add with a compare_and_swap loop goes something + like: + + expected = *mem; + loop: + new = expected += value; + if (!succeed (expected = compare_and_swap (mem, expected, new))) + goto loop; + + If the content of 'mem' are changed every cycle by + simulate_thread_other_thread () this will become an infinite loop + since the value *mem will never be 'expected' by the time the + compare_and_swap is executed. + + HOSTILE_THREAD_THRESHOLD defines the number of intructions which a + program will execute before triggering the hostile thread + pause. The pause will last for HOSTILE_THREAD_PAUSE instructions, + and then the counter will reset and begin again. During the pause + period, simulate_thread_other_thread will not be called. + + This provides a chance for forward progress to be made and the + infinite loop to be avoided. + + If the testcase defines HOSTILE_PAUSE_ERROR, then it will be + considered an RUNTIME FAILURE if the hostile pause is triggered. + This will allow to test for guaranteed forward progress routines. + + If the default values for HOSTILE_THREAD_THRESHOLD or + HOSTILE_THREAD_PAUSE are insufficient, then the testcase may + override these by defining the values before including this file. + + Most testcase are intended to run for very short periods of time, + so these defaults are considered to be high enough to not trigger + on a typical case, but not drag the test time out too much if a + hostile condition is interferring. */ + + +/* Define the threshold to start pausing the hostile thread. */ +#if !defined (HOSTILE_THREAD_THRESHOLD) +#define HOSTILE_THREAD_THRESHOLD 500 +#endif + +/* Define the length of pause in cycles for the hostile thread to pause to + allow forward progress to be made. */ +#if !defined (HOSTILE_THREAD_PAUSE) +#define HOSTILE_THREAD_PAUSE 20 +#endif + +void simulate_thread_other_threads (void); +int simulate_thread_final_verify (void); + +static int simulate_thread_hostile_pause = 0; + +/* This function wraps simulate_thread_other_threads an monitors for + an infinite loop. If the threshold value HOSTILE_THREAD_THRESHOLD + is reached, the other_thread process is paused for + HOSTILE_THREAD_PAUSE cycles before resuming, and the counters start + again. */ +void +simulate_thread_wrapper_other_threads() +{ + static int count = 0; + static int pause = 0; + + if (++count >= HOSTILE_THREAD_THRESHOLD) + { + if (!simulate_thread_hostile_pause) + simulate_thread_hostile_pause = 1; + + /* Count cycles before calling the hostile thread again. */ + if (pause++ < HOSTILE_THREAD_PAUSE) + return; + + /* Reset the pause counter, as well as the thread counter. */ + pause = 0; + count = 0; + } + simulate_thread_other_threads (); +} + + +/* If the test case defines HOSTILE_PAUSE_ERROR, then the test case + will fail execution if it had a hostile pause. */ +int +simulate_thread_wrapper_final_verify () +{ + int ret = simulate_thread_final_verify (); +#if defined (HOSTILE_PAUSE_ERROR) + if (simulate_thread_hostile_pause) + { + printf ("FAIL: Forward progress made only by pausing hostile thread\n"); + ret = ret | 1; /* 0 indicates proper comnpletion. */ + } +#endif + return ret; +}