Update copyright to LGPL on all files
[dyninst.git] / testsuite / src / dyninst / test_thread_7_mutatee.c
1 /*
2  * Copyright (c) 1996-2009 Barton P. Miller
3  * 
4  * We provide the Paradyn Parallel Performance Tools (below
5  * described as "Paradyn") on an AS IS basis, and do not warrant its
6  * validity or performance.  We reserve the right to update, modify,
7  * or discontinue this software at any time.  We shall have no
8  * obligation to supply such updates or modifications or any other
9  * form of support to you.
10  * 
11  * By your use of Paradyn, you understand and agree that we (or any
12  * other person or entity with proprietary rights in Paradyn) are
13  * under no obligation to provide either maintenance services,
14  * update services, notices of latent defects, or correction of
15  * defects for Paradyn.
16  * 
17  * This library is free software; you can redistribute it and/or
18  * modify it under the terms of the GNU Lesser General Public
19  * License as published by the Free Software Foundation; either
20  * version 2.1 of the License, or (at your option) any later version.
21  * 
22  * This library is distributed in the hope that it will be useful,
23  * but WITHOUT ANY WARRANTY; without even the implied warranty of
24  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
25  * Lesser General Public License for more details.
26  * 
27  * You should have received a copy of the GNU Lesser General Public
28  * License along with this library; if not, write to the Free Software
29  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
30  */
31 #include <stdio.h>
32 #include <stdlib.h>
33 #include <string.h>
34 #include <signal.h>
35 #include <sys/types.h>
36 #include <assert.h>
37
38 #include "mutatee_util.h"
39
40 extern thread_t spawnNewThread(void *initial_func, void *param);
41 extern void joinThread(thread_t threadid);
42 extern void initThreads();
43
44 #define NTHRD 8
45 #define TIMEOUT 10
46 #define N_INSTR 4
47
48 typedef struct thrds_t
49 {
50    thread_t tid;
51    int is_in_instr;
52    int thread_setup;
53 } thrds_t;
54
55 thrds_t thrds[NTHRD];
56 volatile int threads_running[NTHRD];
57
58 testlock_t barrier_mutex;
59 testlock_t count_mutex;
60
61 volatile int times_level1_called;
62
63 void my_barrier(volatile int *br)
64 {
65    int n_sleeps = 0;
66    testLock(&barrier_mutex);
67    (*br)++;
68    if (*br == NTHRD)
69       *br = 0;
70    testUnlock(&barrier_mutex);
71    while (*br)
72    {
73       if (n_sleeps++ == TIMEOUT)
74       {
75          logerror("[%s:%u] - Not all threads reported.  Perhaps "
76                  "tramp guards are incorrectly preventing some threads "
77                  "from running\n",
78                  __FILE__, __LINE__);
79          /* FIXME Don't call exit()! */
80          exit(1);
81       }
82       P_sleep(1);        
83    }
84 }
85
86 int test_thread_7_level3(int volatile count)
87 {
88    static volatile int prevent_optimization;
89    if (!count)
90       return 0;
91    test_thread_7_level3(count-1);
92    prevent_optimization++;
93    return prevent_optimization + count;
94 }
95
96 void test_thread_7_level2()
97 {
98    test_thread_7_level3(100);
99 }
100
101 /**
102  * Instrumentation to call this function is inserted into the following funcs:
103  *  level0
104  *  level1
105  *  level2
106  *  level3 
107  * Tramp guards should prevent all of these calls except at init_func and the
108  * second call to level2
109  **/
110 void test_thread_7_level1()
111 {
112    unsigned i;
113    static int bar, bar2;
114
115    thread_t me = threadSelf();
116    for (i=0; i<NTHRD; i++) {
117       /* dprintf("Comparing %lu to %lu\n", thread_int(thrds[i].tid), thread_int(me)); */
118       if (threads_equal(thrds[i].tid, me))
119          break;
120    }
121
122    if (i == NTHRD)
123    {
124       logerror("[%s:%d] - Error, couldn't find thread id %lu\n",
125               __FILE__, __LINE__, thread_int(me));
126       /* FIXME Don't call exit()! */
127       exit(1);
128    }
129    if (thrds[i].is_in_instr)
130    {
131       logerror("[%s:%d] - Error, thread %lu reentered instrumentation\n",
132               __FILE__, __LINE__, thread_int(me));
133       /* FIXME Don't call exit()! */
134       exit(1);
135    }
136
137    thrds[i].is_in_instr = 1;
138
139    testLock(&count_mutex);
140    times_level1_called++;
141    testUnlock(&count_mutex);
142
143    /**
144     * Now try to re-enter this function with the same thread.
145     * Dyninst should prevent this
146     **/
147    my_barrier(&bar);
148    
149    test_thread_7_level2();      
150
151    my_barrier(&bar2);
152
153    thrds[i].is_in_instr = 0;
154 }
155
156 /* This is building a call stack.  Looks like it might be trouble if we're
157  * tail-call optimized.  Yes; tail-call optimization breaks the test.
158  */
159 volatile int dont_optimize = 0;
160 void test_thread_7_level0(int count)
161 {
162    if (count)
163       test_thread_7_level0(count - 1);
164    dont_optimize++;
165 }
166
167 volatile unsigned ok_to_go = 0;
168 void *init_func(void *arg)
169 {
170    threads_running[(int) (long) arg] = 1;
171    while(! ok_to_go) P_sleep(1);
172    test_thread_7_level0(N_INSTR-1);
173    return NULL;
174 }
175
176 /* int main(int argc, char *argv[]) */
177 int test_thread_7_mutatee() {
178    unsigned i;
179    int startedall = 0;
180
181 #ifndef os_windows_test
182    char c = 'T';
183 #endif
184
185    initLock(&barrier_mutex);
186    initLock(&count_mutex);
187
188    /* parse_args(argc, argv); */
189
190    for (i=1; i<NTHRD; i++)
191    {
192       thrds[i].is_in_instr = 0;
193       thrds[i].tid = spawnNewThread((void *) init_func, (void *) i);
194    }
195    thrds[0].is_in_instr = 0;
196    thrds[0].tid = threadSelf();
197
198    while (!startedall) {
199       for (i=1; i<NTHRD; i++) {
200          startedall = 1;
201          if (!threads_running[i]) {
202             startedall = 0;
203             P_sleep(1);
204             break;
205          }
206       }
207    }
208
209    ok_to_go = 1;
210    init_func(NULL);
211    for (i=1; i<NTHRD; i++)
212    {
213       joinThread(thrds[i].tid);
214    }
215    
216    if (times_level1_called != NTHRD*N_INSTR)
217    {
218       logerror("[%s:%u] - level1 called %u times.  Expected %u\n",
219               __FILE__, __LINE__, times_level1_called, NTHRD*N_INSTR);
220       return -1;
221    }
222
223    test_passes(testname);
224    return 0; /* Return value *does* matter for this one */
225 }