1 |
689 |
jeremybenn |
int simulate_thread_fini = 0;
|
2 |
|
|
|
3 |
|
|
void __attribute__((noinline))
|
4 |
|
|
simulate_thread_done ()
|
5 |
|
|
{
|
6 |
|
|
simulate_thread_fini = 1;
|
7 |
|
|
}
|
8 |
|
|
|
9 |
|
|
/* A hostile thread is one which changes a memory location so quickly
|
10 |
|
|
that another thread may never see the same value again. This is
|
11 |
|
|
simulated when simulate_thread_other_thread() is defined to modify
|
12 |
|
|
a memory location every cycle.
|
13 |
|
|
|
14 |
|
|
A process implementing a dependency on this value can run into
|
15 |
|
|
difficulties with such a hostile thread. For instance,
|
16 |
|
|
implementing an add with a compare_and_swap loop goes something
|
17 |
|
|
like:
|
18 |
|
|
|
19 |
|
|
expected = *mem;
|
20 |
|
|
loop:
|
21 |
|
|
new = expected += value;
|
22 |
|
|
if (!succeed (expected = compare_and_swap (mem, expected, new)))
|
23 |
|
|
goto loop;
|
24 |
|
|
|
25 |
|
|
If the content of 'mem' are changed every cycle by
|
26 |
|
|
simulate_thread_other_thread () this will become an infinite loop
|
27 |
|
|
since the value *mem will never be 'expected' by the time the
|
28 |
|
|
compare_and_swap is executed.
|
29 |
|
|
|
30 |
|
|
HOSTILE_THREAD_THRESHOLD defines the number of intructions which a
|
31 |
|
|
program will execute before triggering the hostile thread
|
32 |
|
|
pause. The pause will last for HOSTILE_THREAD_PAUSE instructions,
|
33 |
|
|
and then the counter will reset and begin again. During the pause
|
34 |
|
|
period, simulate_thread_other_thread will not be called.
|
35 |
|
|
|
36 |
|
|
This provides a chance for forward progress to be made and the
|
37 |
|
|
infinite loop to be avoided.
|
38 |
|
|
|
39 |
|
|
If the testcase defines HOSTILE_PAUSE_ERROR, then it will be
|
40 |
|
|
considered a RUNTIME FAILURE if the hostile pause is triggered.
|
41 |
|
|
This will allow to test for guaranteed forward progress routines.
|
42 |
|
|
|
43 |
|
|
If the default values for HOSTILE_THREAD_THRESHOLD or
|
44 |
|
|
HOSTILE_THREAD_PAUSE are insufficient, then the testcase may
|
45 |
|
|
override these by defining the values before including this file.
|
46 |
|
|
|
47 |
|
|
Most testcase are intended to run for very short periods of time,
|
48 |
|
|
so these defaults are considered to be high enough to not trigger
|
49 |
|
|
on a typical case, but not drag the test time out too much if a
|
50 |
|
|
hostile condition is interferring. */
|
51 |
|
|
|
52 |
|
|
|
53 |
|
|
/* Define the threshold instruction count to start pausing the hostile
|
54 |
|
|
thread. To avoid huge potential log files when things are not going well,
|
55 |
|
|
set this number very low. If a test specifically requires that the forward
|
56 |
|
|
progress guarantee is made, this number should be raised by the testcase. */
|
57 |
|
|
#if !defined (HOSTILE_THREAD_THRESHOLD)
|
58 |
|
|
#define HOSTILE_THREAD_THRESHOLD 50
|
59 |
|
|
#endif
|
60 |
|
|
|
61 |
|
|
/* Define the length of pause in cycles for the hostile thread to pause to
|
62 |
|
|
allow forward progress to be made. If this number is too low, a
|
63 |
|
|
compare_and_swap loop may not have time to finish, especially on a
|
64 |
|
|
128 bit operation. */
|
65 |
|
|
#if !defined (HOSTILE_THREAD_PAUSE)
|
66 |
|
|
#define HOSTILE_THREAD_PAUSE 20
|
67 |
|
|
#endif
|
68 |
|
|
|
69 |
|
|
/* Define the number of instructions which are allowed to be executed before
|
70 |
|
|
the testcase is deemed to fail. This is primarily to avoid huge log files
|
71 |
|
|
when a testcase goes into an infinte loop. */
|
72 |
|
|
#if !defined (INSN_COUNT_THRESHOLD)
|
73 |
|
|
#define INSN_COUNT_THRESHOLD 10000
|
74 |
|
|
#endif
|
75 |
|
|
|
76 |
|
|
void simulate_thread_other_threads (void);
|
77 |
|
|
int simulate_thread_final_verify (void);
|
78 |
|
|
|
79 |
|
|
static int simulate_thread_hostile_pause = 0;
|
80 |
|
|
|
81 |
|
|
/* This function wraps simulate_thread_other_threads an monitors for
|
82 |
|
|
an infinite loop. If the threshold value HOSTILE_THREAD_THRESHOLD
|
83 |
|
|
is reached, the other_thread process is paused for
|
84 |
|
|
HOSTILE_THREAD_PAUSE cycles before resuming, and the counters start
|
85 |
|
|
again. */
|
86 |
|
|
int
|
87 |
|
|
simulate_thread_wrapper_other_threads()
|
88 |
|
|
{
|
89 |
|
|
static int insn_count = 0;
|
90 |
|
|
static int hostile_count = 0;
|
91 |
|
|
static int hostile_pause = 0;
|
92 |
|
|
|
93 |
|
|
if (++insn_count >= INSN_COUNT_THRESHOLD)
|
94 |
|
|
{
|
95 |
|
|
printf ("FAIL: Testcase exceeded maximum instruction count threshold\n");
|
96 |
|
|
return 1;
|
97 |
|
|
}
|
98 |
|
|
|
99 |
|
|
if (++hostile_count >= HOSTILE_THREAD_THRESHOLD)
|
100 |
|
|
{
|
101 |
|
|
if (!simulate_thread_hostile_pause)
|
102 |
|
|
simulate_thread_hostile_pause = 1;
|
103 |
|
|
|
104 |
|
|
/* Count cycles before calling the hostile thread again. */
|
105 |
|
|
if (hostile_pause++ < HOSTILE_THREAD_PAUSE)
|
106 |
|
|
return 0;
|
107 |
|
|
|
108 |
|
|
/* Reset the pause counter, as well as the thread counter. */
|
109 |
|
|
hostile_pause = 0;
|
110 |
|
|
hostile_count = 0;
|
111 |
|
|
}
|
112 |
|
|
simulate_thread_other_threads ();
|
113 |
|
|
return 0;
|
114 |
|
|
}
|
115 |
|
|
|
116 |
|
|
|
117 |
|
|
/* If the test case defines HOSTILE_PAUSE_ERROR, then the test case
|
118 |
|
|
will fail execution if it had a hostile pause. */
|
119 |
|
|
int
|
120 |
|
|
simulate_thread_wrapper_final_verify ()
|
121 |
|
|
{
|
122 |
|
|
int ret = simulate_thread_final_verify ();
|
123 |
|
|
#if defined (HOSTILE_PAUSE_ERROR)
|
124 |
|
|
if (simulate_thread_hostile_pause)
|
125 |
|
|
{
|
126 |
|
|
printf ("FAIL: Forward progress made only by pausing hostile thread\n");
|
127 |
|
|
ret = ret | 1; /* 0 indicates proper comnpletion. */
|
128 |
|
|
}
|
129 |
|
|
#endif
|
130 |
|
|
return ret;
|
131 |
|
|
}
|