simulate-thread.gdb: Call wrappers for *other_threads() and *final_verify().
* 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. Co-Authored-By: Andrew MacLeod <amacleod@redhat.com> From-SVN: r179768
This commit is contained in:
parent
fa6963330d
commit
13d563f074
@ -1,3 +1,12 @@
|
||||
2011-10-10 Aldy Hernandez <aldyh@redhat.com>
|
||||
Andrew Macleod <amacleod@redhat.com>
|
||||
|
||||
* 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.
|
||||
|
||||
2011-10-10 Uros Bizjak <ubizjak@gmail.com>
|
||||
|
||||
* lib/gcc-gdb-test.exp (gdb-test): Delete $cmd_file before return.
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user