Update copyright to LGPL on all files
[dyninst.git] / dyninstAPI / tests / src / test15.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
32 #include <BPatch.h>
33 #include <BPatch_process.h>
34 #include <BPatch_thread.h>
35 #include <stdio.h>
36 #include <unistd.h>
37 #include <stdarg.h>
38 #include "test_util.h"
39
40 #define NUM_THREADS 5 // one controller, four workers
41 #define TIMEOUT 20
42
43 BPatch bpatch;
44 BPatch_process *proc;
45 unsigned error;
46 bool create_proc = true;
47 unsigned thread_count;
48 static char dyn_tids[NUM_THREADS];
49 static long pthread_ids[NUM_THREADS];
50 static char deleted_tids[NUM_THREADS];
51
52 bool debug_flag = false;
53 #define dprintf if (debug_flag) fprintf
54
55 void newthr(BPatch_process *my_proc, BPatch_thread *thr)
56 {
57    unsigned my_dyn_id = thr->getBPatchID();
58
59    if (create_proc && (my_proc != proc))
60    {
61       fprintf(stderr, "[%s:%u] - Got invalid process\n", __FILE__, __LINE__);
62       error = 1;
63    }
64
65    dprintf(stderr, "[%s] New Thread: BPatchID = %d\n", __FILE__, my_dyn_id);
66
67    //Check that BPatch id is unique
68    if (my_dyn_id >= NUM_THREADS)
69    {
70       fprintf(stderr, "[%s:%d] - WARNING: Thread ID %d out of range\n",
71               __FILE__, __LINE__, my_dyn_id);
72       return;
73    }
74    if (dyn_tids[my_dyn_id])
75    {
76       fprintf(stderr, "[%s:%d] - WARNING: Thread %d called in callback twice\n",
77               __FILE__, __LINE__, my_dyn_id);
78       return;
79    }
80    dyn_tids[my_dyn_id] = 1;
81
82    //Thread IDs should be unique
83    long mytid = thr->getTid();
84    if (mytid == -1)
85    {
86       fprintf(stderr, "[%s:%d] - WARNING: Thread %d has a tid of -1\n", 
87               __FILE__, __LINE__, my_dyn_id);
88    }
89    dprintf(stderr, "[%s]           : tid = %lu\n", 
90            __FILE__, (unsigned long)mytid);
91    for (unsigned i=0; i<NUM_THREADS; i++)
92       if (i != my_dyn_id && dyn_tids[i] && mytid == pthread_ids[i])
93       {
94          unsigned long my_stack = thr->getStackTopAddr();
95             fprintf(stderr, "[%s:%d] - WARNING: Thread %d and %d share a tid of %lu, stack is 0x%lx\n",
96                     __FILE__, __LINE__, my_dyn_id, i, (unsigned long)mytid, my_stack);
97             error = 1;
98       }
99    pthread_ids[my_dyn_id] = mytid;
100    thread_count++;
101 }
102
103 #define MAX_ARGS 32
104 char *filename = "test15.mutatee_gcc";
105 char *args[MAX_ARGS];
106 char *create_arg = "-create";
107 unsigned num_args = 0; 
108
109 static BPatch_process *getProcess()
110 {
111    args[0] = filename;
112    BPatch_process *proc;
113    if (create_proc) {
114       args[1] = create_arg;
115       proc = bpatch.processCreate(filename, (const char **) args);
116       if(proc == NULL) {
117          fprintf(stderr, "%s[%d]: processCreate(%s) failed\n", 
118                  __FILE__, __LINE__, filename);
119          return NULL;
120       }
121    }
122    else {
123       int pid = startNewProcessForAttach(filename, (const char **) args);
124       if (pid < 0)
125       {
126          fprintf(stderr, "%s ", filename);
127          perror("couldn't be started");
128          return NULL;
129       }
130       proc = bpatch.processAttach(filename, pid);
131       if(proc == NULL) {
132          fprintf(stderr, "%s[%d]: processAttach(%s, %d) failed\n", 
133                  __FILE__, __LINE__, filename, pid);
134          return NULL;
135       }
136       BPatch_image *appimg = proc->getImage();
137       signalAttached(NULL, appimg);
138    }
139    return proc;
140 }
141
142 char libRTname[256];
143 static void parse_args(unsigned argc, char *argv[])
144 {
145    unsigned i;
146    args[0] = NULL;
147    for (i=1; i<argc; i++)
148    {
149       if (strcmp(argv[i], "-attach") == 0)
150       {
151          create_proc = false;
152       }
153       else if (strcmp(argv[i], "-mutatee") == 0)
154       {
155          if (++i == argc) break;
156          filename = argv[i];
157       }
158       else if (strcmp(argv[i], "-verbose") == 0)
159       {
160          debug_flag = true;
161       }
162       else if (!strcmp(argv[i], "-V")) {
163          if (libRTname[0]) {
164             fprintf (stdout, "DYNINSTAPI_RT_LIB=%s\n", libRTname);
165             fflush(stdout);
166          }
167       }
168       else
169       {
170          fprintf(stderr, "Usage: test15 [-V] [-verbose] [-attach]|[-mutatee <file>]\n");
171          exit(-1);
172       }
173    }
174 }
175
176 unsigned failed_tests = 2;
177 void error_exit()
178 {
179    printf("**Failed** %d tests\n", failed_tests);
180    if(proc && !proc->isTerminated()) 
181       proc->terminateExecution();
182    exit(-1);
183 }
184
185 int main(int argc, char *argv[])
186 {
187    unsigned num_attempts = 0;
188    bool missing_threads = false;
189    
190    libRTname[0]='\0';
191    if (!getenv("DYNINSTAPI_RT_LIB")) {
192       fprintf(stderr,"Environment variable DYNINSTAPI_RT_LIB undefined:\n"
193 #if defined(i386_unknown_nt4_0)
194                  "    using standard search strategy for libdyninstAPI_RT.dll\n");
195 #else
196                  "    set it to the full pathname of libdyninstAPI_RT\n");
197       exit(-1);
198 #endif
199    } else
200       strcpy((char *)libRTname, (char *)getenv("DYNINSTAPI_RT_LIB"));
201
202    updateSearchPaths(argv[0]);
203
204    parse_args(argc, argv);
205
206    bpatch.registerThreadEventCallback(BPatch_threadCreateEvent, newthr);
207
208    proc = getProcess();
209    if (!proc)
210       error_exit();
211
212    BPatch_image *img = proc->getImage();
213
214    BPatch_Vector<BPatch_function *> syncfuncs;
215    img->findFunction("check_sync", syncfuncs);
216    if (syncfuncs.size() != 1) {
217       fprintf(stderr, "ERROR: Didn't find 1 'check_sync' function\n");
218       error_exit();
219    }
220    BPatch_function *check_sync = syncfuncs[0];
221
222    BPatch_Vector<BPatch_function *> asyncfuncs;
223    img->findFunction("check_async", asyncfuncs);
224    if (asyncfuncs.size() != 1) {
225       fprintf(stderr, "ERROR: Didn't find 1 'check_async' function\n");
226       error_exit();
227    }
228    BPatch_function *check_async = asyncfuncs[0];
229    
230
231    BPatch_variableExpr *sync_var, *async_var;
232    sync_var = img->findVariable("sync_test");
233    if(sync_var == NULL) {
234       fprintf(stderr, "ERROR: Didn't find 'sync_test' variable\n");
235       error_exit();
236    }
237    async_var = img->findVariable("async_test");
238    if(async_var == NULL) {
239       fprintf(stderr, "ERROR: Didn't find 'async_test' variable\n");
240       error_exit();
241    }
242
243    proc->continueExecution();
244
245    // Wait for NUM_THREADS new thread callbacks to run
246    while (thread_count < NUM_THREADS) {
247       bpatch.waitForStatusChange();
248       if (proc->isTerminated()) {
249          fprintf(stderr, "[%s:%d] - App exited early\n", __FILE__, __LINE__);
250          error_exit();
251       }
252       if (num_attempts++ == TIMEOUT) {
253          fprintf(stderr, "[%s:%d] - Timed out waiting for threads\n", 
254                  __FILE__, __LINE__);
255          fprintf(stderr, "[%s:%d] - Only have %u threads, expected %u!\n",
256                  __FILE__, __LINE__, thread_count, NUM_THREADS);
257          error_exit();
258       }
259       sleep(1);
260    }
261
262    BPatch_Vector<BPatch_thread *> thrds;
263    proc->getThreads(thrds);
264    if (thrds.size() != NUM_THREADS)
265       fprintf(stderr, "[%s:%d] - Have %u threads, expected %u!\n",
266               __FILE__, __LINE__, thrds.size(), NUM_THREADS);
267
268    for (unsigned i=0; i<NUM_THREADS; i++)
269    {
270       if (!dyn_tids[i]) {
271          fprintf(stderr, "[%s:%d] - Thread %u was never created!\n",
272                  __FILE__, __LINE__, i);
273          missing_threads = true;
274       }
275    }
276    if(missing_threads) {
277       fprintf(stderr, "ERROR: Can not run test due to missing threads\n");
278       error_exit();
279    }
280
281
282    dprintf(stderr, "%s[%d]:  done waiting for thread creations\n", 
283            __FILE__, __LINE__);
284
285    // asyncOneTimeCode each worker thread
286    for (unsigned i=1; i<NUM_THREADS; i++)
287    {
288       if (dyn_tids[i] && !deleted_tids[i])
289       {
290          long tid = pthread_ids[i];
291          BPatch_thread *thr = proc->getThread(tid);
292          if(thr == NULL) {
293             fprintf(stderr, "%s[%d]: ERROR - can't find thread with tid %lu\n",
294                     __FILE__, __LINE__, (unsigned long)tid);
295             error = 1;
296             continue;
297          }
298          BPatch_constExpr *val = new BPatch_constExpr(tid);
299          BPatch_arithExpr *set_async_test = 
300             new BPatch_arithExpr(BPatch_assign, *async_var, *val);
301          BPatch_Vector<BPatch_snippet *> args;
302          BPatch_funcCallExpr call_check_async(*check_async, args);
303          BPatch_Vector<BPatch_snippet *> async_code;
304          async_code.push_back(set_async_test);
305          async_code.push_back(&call_check_async);
306          BPatch_sequence *code = new BPatch_sequence(async_code);
307          dprintf(stderr, "%s[%d]: issuing oneTimeCodeAsync for tid %lu\n", 
308                  __FILE__, __LINE__, (unsigned long)tid);
309          thr->oneTimeCodeAsync(*code);
310       }
311    }
312    if(!error) {
313       failed_tests--;
314       printf("Passed test #1 (thread-specific oneTimeCodeAsync)\n");
315    }
316
317    sleep(10);
318
319    // OneTimeCode each worker thread to allow it to exit
320    for (unsigned i=1; i<NUM_THREADS; i++)
321    {
322       if (dyn_tids[i] && !deleted_tids[i])
323       {
324          long tid = pthread_ids[i];
325          BPatch_thread *thr = proc->getThread(tid);
326          if(thr == NULL) {
327             fprintf(stderr, "%s[%d]: ERROR - can't find thread with tid %lu\n",
328                     __FILE__, __LINE__, (unsigned long)tid);
329             error = 1;
330             continue;
331          }
332          BPatch_constExpr *val = new BPatch_constExpr(pthread_ids[i]);
333          BPatch_arithExpr *set_sync_test = 
334             new BPatch_arithExpr(BPatch_assign, *sync_var, *val);
335          BPatch_Vector<BPatch_snippet *> args;
336          BPatch_funcCallExpr call_check_sync(*check_sync, args);
337          BPatch_Vector<BPatch_snippet *> sync_code;
338          sync_code.push_back(set_sync_test);
339          sync_code.push_back(&call_check_sync);
340          BPatch_sequence *code = new BPatch_sequence(sync_code);
341          dprintf(stderr, "%s[%d]: issuing oneTimeCode for tid %lu\n", 
342                  __FILE__, __LINE__, (unsigned long)tid);
343          thr->oneTimeCode(*code);
344          dprintf(stderr, "%s[%d]: finished oneTimeCode for tid %lu\n", 
345                  __FILE__, __LINE__, (unsigned long)tid);
346       }
347    }
348    if(!error) {
349       failed_tests--;
350       printf("Passed test #2 (thread-specific oneTimeCode)\n");
351    }
352
353    dprintf(stderr, "%s[%d]:  Now waiting for application to terminate.\n", __FILE__, __LINE__);
354
355    while (!proc->isTerminated())
356       bpatch.waitForStatusChange();
357
358    if (error) 
359       error_exit();
360
361    printf("All tests passed.\n");
362    return 0;
363 }