Remove old testsuite
[dyninst.git] / testsuite / src / dyninst / test_thread_8.C
1 /*
2  * Copyright (c) 1996-2004 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  * This license is for research uses.  For such uses, there is no
12  * charge. We define "research use" to mean you may freely use it
13  * inside your organization for whatever purposes you see fit. But you
14  * may not re-distribute Paradyn or parts of Paradyn, in any form
15  * source or binary (including derivatives), electronic or otherwise,
16  * to any other organization or entity without our permission.
17  * 
18  * (for other uses, please contact us at paradyn@cs.wisc.edu)
19  * 
20  * All warranties, including without limitation, any warranty of
21  * merchantability or fitness for a particular purpose, are hereby
22  * excluded.
23  * 
24  * By your use of Paradyn, you understand and agree that we (or any
25  * other person or entity with proprietary rights in Paradyn) are
26  * under no obligation to provide either maintenance services,
27  * update services, notices of latent defects, or correction of
28  * defects for Paradyn.
29  * 
30  * Even if advised of the possibility of such damages, under no
31  * circumstances shall we (or any other person or entity with
32  * proprietary rights in the software licensed hereunder) be liable
33  * to you or any third party for direct, indirect, or consequential
34  * damages of any character regardless of type of action, including,
35  * without limitation, loss of profits, loss of use, loss of good
36  * will, or computer failure or malfunction.  You agree to indemnify
37  * us (and any other person or entity with proprietary rights in the
38  * software licensed hereunder) for any and all liability it may
39  * incur to third parties resulting from your use of Paradyn.
40  */
41
42 #include <BPatch.h>
43 #include <BPatch_process.h>
44 #include <BPatch_thread.h>
45 #include <stdio.h>
46 #include <stdarg.h>
47 #include <string.h>
48 #include "test_lib.h"
49
50 #define MAX_ARGS 32
51
52 #include "dyninst_comp.h"
53 class test_thread_8_Mutator : public DyninstMutator {
54 protected:
55   char *filename;
56   char *args[MAX_ARGS];
57   char *logfilename;
58   BPatch *bpatch;
59   unsigned failed_tests;
60
61   BPatch_process *getProcess();
62   int error_exit();
63   int mutatorTest(BPatch *bpatch);
64
65 public:
66   test_thread_8_Mutator();
67   virtual bool hasCustomExecutionPath() { return true; }
68   virtual test_results_t setup(ParameterDict &param);
69   virtual test_results_t executeTest();
70 };
71 extern "C" DLLEXPORT TestMutator *test_thread_8_factory() {
72   return new test_thread_8_Mutator();
73 }
74
75 test_thread_8_Mutator::test_thread_8_Mutator()
76   : filename(NULL), logfilename(NULL), bpatch(NULL) {
77 }
78
79 #if defined(os_windows_test)
80 #include <windows.h>
81 #else
82 #include <unistd.h>
83 #endif
84 #define NUM_THREADS 5 // one controller, four workers
85 #define TIMEOUT 20
86
87 // static FILE *outlog = NULL;
88 // static FILE *errlog = NULL;
89 static BPatch_process *proc;
90 static unsigned thread_count;
91 static char dyn_tids[NUM_THREADS];
92 static long pthread_ids[NUM_THREADS];
93
94 static unsigned error15 = 0;
95 static bool create_proc = true;
96
97 static bool debug_flag = false;
98 #define dprintf if (debug_flag) fprintf
99
100 // Globals: create_proc, dyn_tids, error15, NUM_THREADS, pthread_ids, proc,
101 // thread_count
102 static void newthr(BPatch_process *my_proc, BPatch_thread *thr)
103 {
104    dprintf(stderr, "%s[%d]:  welcome to newthr, error15 = %d\n", __FILE__, __LINE__, error15);
105    unsigned my_dyn_id = thr->getBPatchID();
106
107    if (create_proc && (my_proc != proc))
108    {
109       logerror("[%s:%u] - Got invalid process\n", __FILE__, __LINE__);
110       error15 = 1;
111    }
112
113    dprintf(stderr, "%s[%d]:  newthr: BPatchID = %d\n", __FILE__, __LINE__, my_dyn_id);
114
115    //Check that BPatch id is unique
116    if (my_dyn_id >= NUM_THREADS)
117    {
118       logerror("[%s:%d] - WARNING: Thread ID %d out of range\n",
119               __FILE__, __LINE__, my_dyn_id);
120       return;
121    }
122    if (dyn_tids[my_dyn_id])
123    {
124       logerror("[%s:%d] - WARNING: Thread %d called in callback twice\n",
125               __FILE__, __LINE__, my_dyn_id);
126       return;
127    }
128    dyn_tids[my_dyn_id] = 1;
129
130    //Thread IDs should be unique
131    long mytid = thr->getTid();
132    if (mytid == -1)
133    {
134       logerror("[%s:%d] - WARNING: Thread %d has a tid of -1\n", 
135               __FILE__, __LINE__, my_dyn_id);
136    }
137    dprintf(stderr, "%s[%d]:  newthr: tid = %lu\n", 
138            __FILE__, __LINE__,  (unsigned long)mytid);
139    for (unsigned i=0; i<NUM_THREADS; i++)
140       if (i != my_dyn_id && dyn_tids[i] && mytid == pthread_ids[i])
141       {
142             logerror("[%s:%d] - WARNING: Thread %d and %d share a tid of %u\n",
143                     __FILE__, __LINE__, my_dyn_id, i, mytid);
144             error15 = 1;
145       }
146    pthread_ids[my_dyn_id] = mytid;
147
148    thread_count++;
149    dprintf(stderr, "%s[%d]:  leaving newthr: error15 = %d\n", __FILE__, __LINE__, error15);
150 }
151
152 BPatch_process *test_thread_8_Mutator::getProcess()
153 {
154   int n = 0;
155   args[n++] = filename;
156   if (logfilename != NULL) {
157     args[n++] = "-log";
158     args[n++] = logfilename;
159   }
160
161   args[n++] = "-run";
162   args[n++] = "test_thread_8";
163
164    args[n] = NULL;
165
166    BPatch_process *proc;
167    if (create_proc) {
168       proc = bpatch->processCreate(filename, (const char **) args);
169       if(proc == NULL) {
170          logerror("%s[%d]: processCreate(%s) failed\n", 
171                  __FILE__, __LINE__, filename);
172          return NULL;
173       }
174       registerPID(proc->getPid()); // Register for cleanup
175    }
176    else
177    {
178       dprintf(stderr, "%s[%d]: starting process for attach\n", __FILE__, __LINE__);
179       int pid = startNewProcessForAttach(filename, (const char **) args,
180                                          getOutputLog(), getErrorLog(), true);
181       if (pid < 0)
182       {
183          logerror("%s ", filename);
184          perror("couldn't be started");
185          return NULL;
186       } else if (pid > 0) {
187         registerPID(pid); // Register for cleanup
188       }
189 #if defined(os_windows_test)
190       P_sleep(1);
191 #endif
192       dprintf(stderr, "%s[%d]: started process, now attaching\n", __FILE__, __LINE__);
193       proc = bpatch->processAttach(filename, pid);  
194       if(proc == NULL) {
195          logerror("%s[%d]: processAttach(%s, %d) failed\n", 
196                  __FILE__, __LINE__, filename, pid);
197          return NULL;
198       }
199       dprintf(stderr, "%s[%d]: attached to process\n", __FILE__, __LINE__);
200       BPatch_image *appimg = proc->getImage();
201       signalAttached(NULL, appimg);    
202    }
203    return proc;
204 }
205
206 int test_thread_8_Mutator::error_exit()
207 {
208    logerror("**Failed** %d tests\n", failed_tests);
209    if(proc && !proc->isTerminated()) 
210       proc->terminateExecution();
211    return -1;
212 }
213
214 int test_thread_8_Mutator::mutatorTest(BPatch *bpatch)
215 {
216    unsigned num_attempts = 0;
217    bool missing_threads = false;
218    thread_count = 0;
219    memset(dyn_tids, 0, sizeof(dyn_tids));
220    memset(pthread_ids, 0, sizeof(pthread_ids));
221    failed_tests = 2;
222    error15 = 0;
223
224    proc = getProcess();
225    if (!proc)
226       return error_exit();
227
228    BPatch_image *img = proc->getImage();
229
230    BPatch_Vector<BPatch_function *> syncfuncs;
231    img->findFunction("check_sync", syncfuncs);
232    if (syncfuncs.size() != 1) {
233       logerror("ERROR: Didn't find 1 'check_sync' function\n");
234       return error_exit();
235    }
236    BPatch_function *check_sync = syncfuncs[0];
237
238    BPatch_Vector<BPatch_function *> asyncfuncs;
239    img->findFunction("check_async", asyncfuncs);
240    if (asyncfuncs.size() != 1) {
241       logerror("ERROR: Didn't find 1 'check_async' function\n");
242       return error_exit();
243    }
244    BPatch_function *check_async = asyncfuncs[0];   
245
246    proc->continueExecution();
247
248    // Wait for NUM_THREADS to be created
249    while (thread_count < NUM_THREADS) {
250       bpatch->waitForStatusChange();
251       if (proc->isTerminated())
252       {
253          logerror("[%s:%d] - App exited early\n", __FILE__, __LINE__);
254          return error_exit();
255       }
256       if (num_attempts++ == TIMEOUT)
257       {
258          logerror("[%s:%d] - Timed out waiting for threads\n", 
259                  __FILE__, __LINE__);
260          logerror("[%s:%d] - Only have %u threads, expected %u!\n",
261               __FILE__, __LINE__, thread_count, NUM_THREADS);
262          return error_exit();
263       }
264       P_sleep(1);
265    }
266
267    dprintf(stderr, "%s[%d]:  done waiting for thread creations\n", 
268            __FILE__, __LINE__);
269
270    BPatch_Vector<BPatch_thread *> thrds;
271    proc->getThreads(thrds);
272    if (thrds.size() != NUM_THREADS)
273       logerror("[%s:%d] - Have %u threads, expected %u!\n",
274               __FILE__, __LINE__, thrds.size(), NUM_THREADS);
275    for (unsigned i=0; i<NUM_THREADS; i++)
276    {
277       if (!dyn_tids[i]) {
278          logerror("[%s:%d] - Thread %u was never created!\n",
279                  __FILE__, __LINE__, i);
280          missing_threads = true;
281       }
282    }
283    if(missing_threads) {
284       logerror("%s[%d]: ERROR during thread create stage, can not run test\n", __FILE__, __LINE__);
285       return error_exit();
286    }
287
288    // asyncOneTimeCode each worker thread
289    for (unsigned i=1; i<NUM_THREADS; i++)
290    {
291       if (dyn_tids[i])
292       {
293          long tid = pthread_ids[i];
294          BPatch_thread *thr = proc->getThread(tid);
295          if(thr == NULL) {
296             logerror("%s[%d]: ERROR - can't find thread with tid %lu\n",
297                     __FILE__, __LINE__, (unsigned long)tid);
298             error15 = 1;
299             continue;
300          }
301          BPatch_constExpr asyncVarExpr(tid);
302          BPatch_Vector<BPatch_snippet *> args;
303          args.push_back(&asyncVarExpr);
304          BPatch_funcCallExpr call_check_async(*check_async, args);
305          BPatch_Vector<BPatch_snippet *> async_code;
306          async_code.push_back(&call_check_async);
307          BPatch_sequence *code = new BPatch_sequence(async_code);
308          dprintf(stderr, "%s[%d]: issuing oneTimeCodeAsync for tid %lu\n", __FILE__, __LINE__, tid);
309          thr->oneTimeCodeAsync(*code);
310       }
311    }
312    // FIXME We don't know if the test worked yet!  This printout is premature.
313     if(!error15) {
314        failed_tests--;
315 //       logerror("Passed test #1 (thread-specific oneTimeCodeAsync)\n");
316     }
317
318    P_sleep(10);
319
320    // OneTimeCode each worker thread to allow it to exit
321    for (unsigned i=1; i<NUM_THREADS; i++)
322    {
323       if (dyn_tids[i])
324       {
325          long tid = pthread_ids[i];
326          BPatch_thread *thr = proc->getThread(tid);
327          if(thr == NULL) {
328             logerror("%s[%d]: ERROR - can't find thread with tid %lu\n",
329                     __FILE__, __LINE__, (unsigned long)tid);
330             error15 = 1;
331             continue;
332          }
333          BPatch_constExpr syncVarExpr(pthread_ids[i]);
334          BPatch_Vector<BPatch_snippet *> args;
335          args.push_back(&syncVarExpr);
336          BPatch_funcCallExpr call_check_sync(*check_sync, args);
337          BPatch_Vector<BPatch_snippet *> sync_code;
338          sync_code.push_back(&call_check_sync);
339          BPatch_sequence *code = new BPatch_sequence(sync_code);
340          dprintf(stderr, "%s[%d]: issuing oneTimeCode for tid %lu\n", __FILE__, __LINE__, tid);
341          thr->oneTimeCode(*code);
342          dprintf(stderr, "%s[%d]: finished oneTimeCode for tid %lu\n", __FILE__, __LINE__, tid);
343       }
344    }
345    // FIXME We don't know if the test worked yet!  This printout is premature.
346     if(!error15) {
347        failed_tests--;
348 //       logerror("Passed test #2 (thread-specific oneTimeCode)\n");
349     }
350
351    dprintf(stderr, "%s[%d]:  Now waiting for threads to die.\n", __FILE__, __LINE__);
352
353    while (!proc->isTerminated())
354       bpatch->waitForStatusChange();
355
356    int exitCode = proc->getExitCode();
357    // TODO Parse the exit code value so I know what to print..
358    if ((0 == exitCode) && (0 == error15) && (0 == failed_tests)) {
359      // TODO Print success message for both sync and async one time codes
360      logerror("Passed test #1 (thread-specific asyncOneTimeCode)\n");
361      logerror("Passed test #2 (thread-specific oneTimeCode)\n");
362      logerror("Passed test_thread_8 (thread-specific one time codes)\n");
363      return 0;
364    } else {
365      // TODO Figure out what went wrong and print a relevant error message
366      logerror("**Failed test_thread_8 (thread-specific one time codes)\n");
367      return -1;
368    }
369
370 //    if (error15 || failed_tests) 
371 //       return error_exit();
372
373 //    logerror("Test completed without errors\n");
374 //    return 0;
375 }
376
377 test_results_t test_thread_8_Mutator::executeTest() {
378   memset(args, 0, sizeof (args));
379
380    if (!bpatch->registerThreadEventCallback(BPatch_threadCreateEvent, newthr))
381    {
382       logerror("%s[%d]:  failed to register thread callback\n",
383               __FILE__, __LINE__);
384       return FAILED;
385    }
386    
387    int rv = mutatorTest(bpatch);
388
389    if (!bpatch->removeThreadEventCallback(BPatch_threadCreateEvent, newthr))
390    {
391       logerror("%s[%d]:  failed to remove thread callback\n",
392               __FILE__, __LINE__);
393       return FAILED;
394    }
395
396    if (0 == rv) {
397      return PASSED;
398    } else {
399      return FAILED;
400    }
401 }
402
403 // extern "C" TEST_DLL_EXPORT int test15_1_mutatorMAIN(ParameterDict &param)
404 test_results_t test_thread_8_Mutator::setup(ParameterDict &param) {
405    /* Grab info from param */
406    bpatch = (BPatch *)(param["bpatch"]->getPtr());
407    filename = param["pathname"]->getString();
408
409    // Get log file pointers
410    logfilename = param["logfilename"]->getString();
411
412    if ( param["useAttach"]->getInt() != 0 )
413    {
414       create_proc = false;
415    } else {
416      create_proc = true;
417    }
418
419    return PASSED;
420 }