1*9880d681SAndroid Build Coastguard Worker //===-- examples/ParallelJIT/ParallelJIT.cpp - Exercise threaded-safe JIT -===//
2*9880d681SAndroid Build Coastguard Worker //
3*9880d681SAndroid Build Coastguard Worker // The LLVM Compiler Infrastructure
4*9880d681SAndroid Build Coastguard Worker //
5*9880d681SAndroid Build Coastguard Worker // This file is distributed under the University of Illinois Open Source
6*9880d681SAndroid Build Coastguard Worker // License. See LICENSE.TXT for details.
7*9880d681SAndroid Build Coastguard Worker //
8*9880d681SAndroid Build Coastguard Worker //===----------------------------------------------------------------------===//
9*9880d681SAndroid Build Coastguard Worker //
10*9880d681SAndroid Build Coastguard Worker // Parallel JIT
11*9880d681SAndroid Build Coastguard Worker //
12*9880d681SAndroid Build Coastguard Worker // This test program creates two LLVM functions then calls them from three
13*9880d681SAndroid Build Coastguard Worker // separate threads. It requires the pthreads library.
14*9880d681SAndroid Build Coastguard Worker // The three threads are created and then block waiting on a condition variable.
15*9880d681SAndroid Build Coastguard Worker // Once all threads are blocked on the conditional variable, the main thread
16*9880d681SAndroid Build Coastguard Worker // wakes them up. This complicated work is performed so that all three threads
17*9880d681SAndroid Build Coastguard Worker // call into the JIT at the same time (or the best possible approximation of the
18*9880d681SAndroid Build Coastguard Worker // same time). This test had assertion errors until I got the locking right.
19*9880d681SAndroid Build Coastguard Worker //
20*9880d681SAndroid Build Coastguard Worker //===----------------------------------------------------------------------===//
21*9880d681SAndroid Build Coastguard Worker
22*9880d681SAndroid Build Coastguard Worker #include "llvm/ADT/APInt.h"
23*9880d681SAndroid Build Coastguard Worker #include "llvm/ADT/STLExtras.h"
24*9880d681SAndroid Build Coastguard Worker #include "llvm/ExecutionEngine/ExecutionEngine.h"
25*9880d681SAndroid Build Coastguard Worker #include "llvm/ExecutionEngine/GenericValue.h"
26*9880d681SAndroid Build Coastguard Worker #include "llvm/IR/Argument.h"
27*9880d681SAndroid Build Coastguard Worker #include "llvm/IR/BasicBlock.h"
28*9880d681SAndroid Build Coastguard Worker #include "llvm/IR/Constants.h"
29*9880d681SAndroid Build Coastguard Worker #include "llvm/IR/DerivedTypes.h"
30*9880d681SAndroid Build Coastguard Worker #include "llvm/IR/Function.h"
31*9880d681SAndroid Build Coastguard Worker #include "llvm/IR/InstrTypes.h"
32*9880d681SAndroid Build Coastguard Worker #include "llvm/IR/Instruction.h"
33*9880d681SAndroid Build Coastguard Worker #include "llvm/IR/Instructions.h"
34*9880d681SAndroid Build Coastguard Worker #include "llvm/IR/LLVMContext.h"
35*9880d681SAndroid Build Coastguard Worker #include "llvm/IR/Module.h"
36*9880d681SAndroid Build Coastguard Worker #include "llvm/IR/Type.h"
37*9880d681SAndroid Build Coastguard Worker #include "llvm/Support/Casting.h"
38*9880d681SAndroid Build Coastguard Worker #include "llvm/Support/TargetSelect.h"
39*9880d681SAndroid Build Coastguard Worker #include <algorithm>
40*9880d681SAndroid Build Coastguard Worker #include <cassert>
41*9880d681SAndroid Build Coastguard Worker #include <cstddef>
42*9880d681SAndroid Build Coastguard Worker #include <cstdint>
43*9880d681SAndroid Build Coastguard Worker #include <iostream>
44*9880d681SAndroid Build Coastguard Worker #include <memory>
45*9880d681SAndroid Build Coastguard Worker #include <vector>
46*9880d681SAndroid Build Coastguard Worker #include <pthread.h>
47*9880d681SAndroid Build Coastguard Worker
48*9880d681SAndroid Build Coastguard Worker using namespace llvm;
49*9880d681SAndroid Build Coastguard Worker
createAdd1(Module * M)50*9880d681SAndroid Build Coastguard Worker static Function* createAdd1(Module *M) {
51*9880d681SAndroid Build Coastguard Worker // Create the add1 function entry and insert this entry into module M. The
52*9880d681SAndroid Build Coastguard Worker // function will have a return type of "int" and take an argument of "int".
53*9880d681SAndroid Build Coastguard Worker // The '0' terminates the list of argument types.
54*9880d681SAndroid Build Coastguard Worker Function *Add1F =
55*9880d681SAndroid Build Coastguard Worker cast<Function>(M->getOrInsertFunction("add1",
56*9880d681SAndroid Build Coastguard Worker Type::getInt32Ty(M->getContext()),
57*9880d681SAndroid Build Coastguard Worker Type::getInt32Ty(M->getContext()),
58*9880d681SAndroid Build Coastguard Worker nullptr));
59*9880d681SAndroid Build Coastguard Worker
60*9880d681SAndroid Build Coastguard Worker // Add a basic block to the function. As before, it automatically inserts
61*9880d681SAndroid Build Coastguard Worker // because of the last argument.
62*9880d681SAndroid Build Coastguard Worker BasicBlock *BB = BasicBlock::Create(M->getContext(), "EntryBlock", Add1F);
63*9880d681SAndroid Build Coastguard Worker
64*9880d681SAndroid Build Coastguard Worker // Get pointers to the constant `1'.
65*9880d681SAndroid Build Coastguard Worker Value *One = ConstantInt::get(Type::getInt32Ty(M->getContext()), 1);
66*9880d681SAndroid Build Coastguard Worker
67*9880d681SAndroid Build Coastguard Worker // Get pointers to the integer argument of the add1 function...
68*9880d681SAndroid Build Coastguard Worker assert(Add1F->arg_begin() != Add1F->arg_end()); // Make sure there's an arg
69*9880d681SAndroid Build Coastguard Worker Argument *ArgX = &*Add1F->arg_begin(); // Get the arg
70*9880d681SAndroid Build Coastguard Worker ArgX->setName("AnArg"); // Give it a nice symbolic name for fun.
71*9880d681SAndroid Build Coastguard Worker
72*9880d681SAndroid Build Coastguard Worker // Create the add instruction, inserting it into the end of BB.
73*9880d681SAndroid Build Coastguard Worker Instruction *Add = BinaryOperator::CreateAdd(One, ArgX, "addresult", BB);
74*9880d681SAndroid Build Coastguard Worker
75*9880d681SAndroid Build Coastguard Worker // Create the return instruction and add it to the basic block
76*9880d681SAndroid Build Coastguard Worker ReturnInst::Create(M->getContext(), Add, BB);
77*9880d681SAndroid Build Coastguard Worker
78*9880d681SAndroid Build Coastguard Worker // Now, function add1 is ready.
79*9880d681SAndroid Build Coastguard Worker return Add1F;
80*9880d681SAndroid Build Coastguard Worker }
81*9880d681SAndroid Build Coastguard Worker
CreateFibFunction(Module * M)82*9880d681SAndroid Build Coastguard Worker static Function *CreateFibFunction(Module *M) {
83*9880d681SAndroid Build Coastguard Worker // Create the fib function and insert it into module M. This function is said
84*9880d681SAndroid Build Coastguard Worker // to return an int and take an int parameter.
85*9880d681SAndroid Build Coastguard Worker Function *FibF =
86*9880d681SAndroid Build Coastguard Worker cast<Function>(M->getOrInsertFunction("fib",
87*9880d681SAndroid Build Coastguard Worker Type::getInt32Ty(M->getContext()),
88*9880d681SAndroid Build Coastguard Worker Type::getInt32Ty(M->getContext()),
89*9880d681SAndroid Build Coastguard Worker nullptr));
90*9880d681SAndroid Build Coastguard Worker
91*9880d681SAndroid Build Coastguard Worker // Add a basic block to the function.
92*9880d681SAndroid Build Coastguard Worker BasicBlock *BB = BasicBlock::Create(M->getContext(), "EntryBlock", FibF);
93*9880d681SAndroid Build Coastguard Worker
94*9880d681SAndroid Build Coastguard Worker // Get pointers to the constants.
95*9880d681SAndroid Build Coastguard Worker Value *One = ConstantInt::get(Type::getInt32Ty(M->getContext()), 1);
96*9880d681SAndroid Build Coastguard Worker Value *Two = ConstantInt::get(Type::getInt32Ty(M->getContext()), 2);
97*9880d681SAndroid Build Coastguard Worker
98*9880d681SAndroid Build Coastguard Worker // Get pointer to the integer argument of the add1 function...
99*9880d681SAndroid Build Coastguard Worker Argument *ArgX = &*FibF->arg_begin(); // Get the arg.
100*9880d681SAndroid Build Coastguard Worker ArgX->setName("AnArg"); // Give it a nice symbolic name for fun.
101*9880d681SAndroid Build Coastguard Worker
102*9880d681SAndroid Build Coastguard Worker // Create the true_block.
103*9880d681SAndroid Build Coastguard Worker BasicBlock *RetBB = BasicBlock::Create(M->getContext(), "return", FibF);
104*9880d681SAndroid Build Coastguard Worker // Create an exit block.
105*9880d681SAndroid Build Coastguard Worker BasicBlock* RecurseBB = BasicBlock::Create(M->getContext(), "recurse", FibF);
106*9880d681SAndroid Build Coastguard Worker
107*9880d681SAndroid Build Coastguard Worker // Create the "if (arg < 2) goto exitbb"
108*9880d681SAndroid Build Coastguard Worker Value *CondInst = new ICmpInst(*BB, ICmpInst::ICMP_SLE, ArgX, Two, "cond");
109*9880d681SAndroid Build Coastguard Worker BranchInst::Create(RetBB, RecurseBB, CondInst, BB);
110*9880d681SAndroid Build Coastguard Worker
111*9880d681SAndroid Build Coastguard Worker // Create: ret int 1
112*9880d681SAndroid Build Coastguard Worker ReturnInst::Create(M->getContext(), One, RetBB);
113*9880d681SAndroid Build Coastguard Worker
114*9880d681SAndroid Build Coastguard Worker // create fib(x-1)
115*9880d681SAndroid Build Coastguard Worker Value *Sub = BinaryOperator::CreateSub(ArgX, One, "arg", RecurseBB);
116*9880d681SAndroid Build Coastguard Worker Value *CallFibX1 = CallInst::Create(FibF, Sub, "fibx1", RecurseBB);
117*9880d681SAndroid Build Coastguard Worker
118*9880d681SAndroid Build Coastguard Worker // create fib(x-2)
119*9880d681SAndroid Build Coastguard Worker Sub = BinaryOperator::CreateSub(ArgX, Two, "arg", RecurseBB);
120*9880d681SAndroid Build Coastguard Worker Value *CallFibX2 = CallInst::Create(FibF, Sub, "fibx2", RecurseBB);
121*9880d681SAndroid Build Coastguard Worker
122*9880d681SAndroid Build Coastguard Worker // fib(x-1)+fib(x-2)
123*9880d681SAndroid Build Coastguard Worker Value *Sum =
124*9880d681SAndroid Build Coastguard Worker BinaryOperator::CreateAdd(CallFibX1, CallFibX2, "addresult", RecurseBB);
125*9880d681SAndroid Build Coastguard Worker
126*9880d681SAndroid Build Coastguard Worker // Create the return instruction and add it to the basic block
127*9880d681SAndroid Build Coastguard Worker ReturnInst::Create(M->getContext(), Sum, RecurseBB);
128*9880d681SAndroid Build Coastguard Worker
129*9880d681SAndroid Build Coastguard Worker return FibF;
130*9880d681SAndroid Build Coastguard Worker }
131*9880d681SAndroid Build Coastguard Worker
132*9880d681SAndroid Build Coastguard Worker struct threadParams {
133*9880d681SAndroid Build Coastguard Worker ExecutionEngine* EE;
134*9880d681SAndroid Build Coastguard Worker Function* F;
135*9880d681SAndroid Build Coastguard Worker int value;
136*9880d681SAndroid Build Coastguard Worker };
137*9880d681SAndroid Build Coastguard Worker
138*9880d681SAndroid Build Coastguard Worker // We block the subthreads just before they begin to execute:
139*9880d681SAndroid Build Coastguard Worker // we want all of them to call into the JIT at the same time,
140*9880d681SAndroid Build Coastguard Worker // to verify that the locking is working correctly.
141*9880d681SAndroid Build Coastguard Worker class WaitForThreads
142*9880d681SAndroid Build Coastguard Worker {
143*9880d681SAndroid Build Coastguard Worker public:
WaitForThreads()144*9880d681SAndroid Build Coastguard Worker WaitForThreads()
145*9880d681SAndroid Build Coastguard Worker {
146*9880d681SAndroid Build Coastguard Worker n = 0;
147*9880d681SAndroid Build Coastguard Worker waitFor = 0;
148*9880d681SAndroid Build Coastguard Worker
149*9880d681SAndroid Build Coastguard Worker int result = pthread_cond_init( &condition, nullptr );
150*9880d681SAndroid Build Coastguard Worker assert( result == 0 );
151*9880d681SAndroid Build Coastguard Worker
152*9880d681SAndroid Build Coastguard Worker result = pthread_mutex_init( &mutex, nullptr );
153*9880d681SAndroid Build Coastguard Worker assert( result == 0 );
154*9880d681SAndroid Build Coastguard Worker }
155*9880d681SAndroid Build Coastguard Worker
~WaitForThreads()156*9880d681SAndroid Build Coastguard Worker ~WaitForThreads()
157*9880d681SAndroid Build Coastguard Worker {
158*9880d681SAndroid Build Coastguard Worker int result = pthread_cond_destroy( &condition );
159*9880d681SAndroid Build Coastguard Worker (void)result;
160*9880d681SAndroid Build Coastguard Worker assert( result == 0 );
161*9880d681SAndroid Build Coastguard Worker
162*9880d681SAndroid Build Coastguard Worker result = pthread_mutex_destroy( &mutex );
163*9880d681SAndroid Build Coastguard Worker assert( result == 0 );
164*9880d681SAndroid Build Coastguard Worker }
165*9880d681SAndroid Build Coastguard Worker
166*9880d681SAndroid Build Coastguard Worker // All threads will stop here until another thread calls releaseThreads
block()167*9880d681SAndroid Build Coastguard Worker void block()
168*9880d681SAndroid Build Coastguard Worker {
169*9880d681SAndroid Build Coastguard Worker int result = pthread_mutex_lock( &mutex );
170*9880d681SAndroid Build Coastguard Worker (void)result;
171*9880d681SAndroid Build Coastguard Worker assert( result == 0 );
172*9880d681SAndroid Build Coastguard Worker n ++;
173*9880d681SAndroid Build Coastguard Worker //~ std::cout << "block() n " << n << " waitFor " << waitFor << std::endl;
174*9880d681SAndroid Build Coastguard Worker
175*9880d681SAndroid Build Coastguard Worker assert( waitFor == 0 || n <= waitFor );
176*9880d681SAndroid Build Coastguard Worker if ( waitFor > 0 && n == waitFor )
177*9880d681SAndroid Build Coastguard Worker {
178*9880d681SAndroid Build Coastguard Worker // There are enough threads blocked that we can release all of them
179*9880d681SAndroid Build Coastguard Worker std::cout << "Unblocking threads from block()" << std::endl;
180*9880d681SAndroid Build Coastguard Worker unblockThreads();
181*9880d681SAndroid Build Coastguard Worker }
182*9880d681SAndroid Build Coastguard Worker else
183*9880d681SAndroid Build Coastguard Worker {
184*9880d681SAndroid Build Coastguard Worker // We just need to wait until someone unblocks us
185*9880d681SAndroid Build Coastguard Worker result = pthread_cond_wait( &condition, &mutex );
186*9880d681SAndroid Build Coastguard Worker assert( result == 0 );
187*9880d681SAndroid Build Coastguard Worker }
188*9880d681SAndroid Build Coastguard Worker
189*9880d681SAndroid Build Coastguard Worker // unlock the mutex before returning
190*9880d681SAndroid Build Coastguard Worker result = pthread_mutex_unlock( &mutex );
191*9880d681SAndroid Build Coastguard Worker assert( result == 0 );
192*9880d681SAndroid Build Coastguard Worker }
193*9880d681SAndroid Build Coastguard Worker
194*9880d681SAndroid Build Coastguard Worker // If there are num or more threads blocked, it will signal them all
195*9880d681SAndroid Build Coastguard Worker // Otherwise, this thread blocks until there are enough OTHER threads
196*9880d681SAndroid Build Coastguard Worker // blocked
releaseThreads(size_t num)197*9880d681SAndroid Build Coastguard Worker void releaseThreads( size_t num )
198*9880d681SAndroid Build Coastguard Worker {
199*9880d681SAndroid Build Coastguard Worker int result = pthread_mutex_lock( &mutex );
200*9880d681SAndroid Build Coastguard Worker (void)result;
201*9880d681SAndroid Build Coastguard Worker assert( result == 0 );
202*9880d681SAndroid Build Coastguard Worker
203*9880d681SAndroid Build Coastguard Worker if ( n >= num ) {
204*9880d681SAndroid Build Coastguard Worker std::cout << "Unblocking threads from releaseThreads()" << std::endl;
205*9880d681SAndroid Build Coastguard Worker unblockThreads();
206*9880d681SAndroid Build Coastguard Worker }
207*9880d681SAndroid Build Coastguard Worker else
208*9880d681SAndroid Build Coastguard Worker {
209*9880d681SAndroid Build Coastguard Worker waitFor = num;
210*9880d681SAndroid Build Coastguard Worker pthread_cond_wait( &condition, &mutex );
211*9880d681SAndroid Build Coastguard Worker }
212*9880d681SAndroid Build Coastguard Worker
213*9880d681SAndroid Build Coastguard Worker // unlock the mutex before returning
214*9880d681SAndroid Build Coastguard Worker result = pthread_mutex_unlock( &mutex );
215*9880d681SAndroid Build Coastguard Worker assert( result == 0 );
216*9880d681SAndroid Build Coastguard Worker }
217*9880d681SAndroid Build Coastguard Worker
218*9880d681SAndroid Build Coastguard Worker private:
unblockThreads()219*9880d681SAndroid Build Coastguard Worker void unblockThreads()
220*9880d681SAndroid Build Coastguard Worker {
221*9880d681SAndroid Build Coastguard Worker // Reset the counters to zero: this way, if any new threads
222*9880d681SAndroid Build Coastguard Worker // enter while threads are exiting, they will block instead
223*9880d681SAndroid Build Coastguard Worker // of triggering a new release of threads
224*9880d681SAndroid Build Coastguard Worker n = 0;
225*9880d681SAndroid Build Coastguard Worker
226*9880d681SAndroid Build Coastguard Worker // Reset waitFor to zero: this way, if waitFor threads enter
227*9880d681SAndroid Build Coastguard Worker // while threads are exiting, they will block instead of
228*9880d681SAndroid Build Coastguard Worker // triggering a new release of threads
229*9880d681SAndroid Build Coastguard Worker waitFor = 0;
230*9880d681SAndroid Build Coastguard Worker
231*9880d681SAndroid Build Coastguard Worker int result = pthread_cond_broadcast( &condition );
232*9880d681SAndroid Build Coastguard Worker (void)result;
233*9880d681SAndroid Build Coastguard Worker assert(result == 0);
234*9880d681SAndroid Build Coastguard Worker }
235*9880d681SAndroid Build Coastguard Worker
236*9880d681SAndroid Build Coastguard Worker size_t n;
237*9880d681SAndroid Build Coastguard Worker size_t waitFor;
238*9880d681SAndroid Build Coastguard Worker pthread_cond_t condition;
239*9880d681SAndroid Build Coastguard Worker pthread_mutex_t mutex;
240*9880d681SAndroid Build Coastguard Worker };
241*9880d681SAndroid Build Coastguard Worker
242*9880d681SAndroid Build Coastguard Worker static WaitForThreads synchronize;
243*9880d681SAndroid Build Coastguard Worker
callFunc(void * param)244*9880d681SAndroid Build Coastguard Worker void* callFunc( void* param )
245*9880d681SAndroid Build Coastguard Worker {
246*9880d681SAndroid Build Coastguard Worker struct threadParams* p = (struct threadParams*) param;
247*9880d681SAndroid Build Coastguard Worker
248*9880d681SAndroid Build Coastguard Worker // Call the `foo' function with no arguments:
249*9880d681SAndroid Build Coastguard Worker std::vector<GenericValue> Args(1);
250*9880d681SAndroid Build Coastguard Worker Args[0].IntVal = APInt(32, p->value);
251*9880d681SAndroid Build Coastguard Worker
252*9880d681SAndroid Build Coastguard Worker synchronize.block(); // wait until other threads are at this point
253*9880d681SAndroid Build Coastguard Worker GenericValue gv = p->EE->runFunction(p->F, Args);
254*9880d681SAndroid Build Coastguard Worker
255*9880d681SAndroid Build Coastguard Worker return (void*)(intptr_t)gv.IntVal.getZExtValue();
256*9880d681SAndroid Build Coastguard Worker }
257*9880d681SAndroid Build Coastguard Worker
main()258*9880d681SAndroid Build Coastguard Worker int main() {
259*9880d681SAndroid Build Coastguard Worker InitializeNativeTarget();
260*9880d681SAndroid Build Coastguard Worker LLVMContext Context;
261*9880d681SAndroid Build Coastguard Worker
262*9880d681SAndroid Build Coastguard Worker // Create some module to put our function into it.
263*9880d681SAndroid Build Coastguard Worker std::unique_ptr<Module> Owner = make_unique<Module>("test", Context);
264*9880d681SAndroid Build Coastguard Worker Module *M = Owner.get();
265*9880d681SAndroid Build Coastguard Worker
266*9880d681SAndroid Build Coastguard Worker Function* add1F = createAdd1( M );
267*9880d681SAndroid Build Coastguard Worker Function* fibF = CreateFibFunction( M );
268*9880d681SAndroid Build Coastguard Worker
269*9880d681SAndroid Build Coastguard Worker // Now we create the JIT.
270*9880d681SAndroid Build Coastguard Worker ExecutionEngine* EE = EngineBuilder(std::move(Owner)).create();
271*9880d681SAndroid Build Coastguard Worker
272*9880d681SAndroid Build Coastguard Worker //~ std::cout << "We just constructed this LLVM module:\n\n" << *M;
273*9880d681SAndroid Build Coastguard Worker //~ std::cout << "\n\nRunning foo: " << std::flush;
274*9880d681SAndroid Build Coastguard Worker
275*9880d681SAndroid Build Coastguard Worker // Create one thread for add1 and two threads for fib
276*9880d681SAndroid Build Coastguard Worker struct threadParams add1 = { EE, add1F, 1000 };
277*9880d681SAndroid Build Coastguard Worker struct threadParams fib1 = { EE, fibF, 39 };
278*9880d681SAndroid Build Coastguard Worker struct threadParams fib2 = { EE, fibF, 42 };
279*9880d681SAndroid Build Coastguard Worker
280*9880d681SAndroid Build Coastguard Worker pthread_t add1Thread;
281*9880d681SAndroid Build Coastguard Worker int result = pthread_create( &add1Thread, nullptr, callFunc, &add1 );
282*9880d681SAndroid Build Coastguard Worker if ( result != 0 ) {
283*9880d681SAndroid Build Coastguard Worker std::cerr << "Could not create thread" << std::endl;
284*9880d681SAndroid Build Coastguard Worker return 1;
285*9880d681SAndroid Build Coastguard Worker }
286*9880d681SAndroid Build Coastguard Worker
287*9880d681SAndroid Build Coastguard Worker pthread_t fibThread1;
288*9880d681SAndroid Build Coastguard Worker result = pthread_create( &fibThread1, nullptr, callFunc, &fib1 );
289*9880d681SAndroid Build Coastguard Worker if ( result != 0 ) {
290*9880d681SAndroid Build Coastguard Worker std::cerr << "Could not create thread" << std::endl;
291*9880d681SAndroid Build Coastguard Worker return 1;
292*9880d681SAndroid Build Coastguard Worker }
293*9880d681SAndroid Build Coastguard Worker
294*9880d681SAndroid Build Coastguard Worker pthread_t fibThread2;
295*9880d681SAndroid Build Coastguard Worker result = pthread_create( &fibThread2, nullptr, callFunc, &fib2 );
296*9880d681SAndroid Build Coastguard Worker if ( result != 0 ) {
297*9880d681SAndroid Build Coastguard Worker std::cerr << "Could not create thread" << std::endl;
298*9880d681SAndroid Build Coastguard Worker return 1;
299*9880d681SAndroid Build Coastguard Worker }
300*9880d681SAndroid Build Coastguard Worker
301*9880d681SAndroid Build Coastguard Worker synchronize.releaseThreads(3); // wait until other threads are at this point
302*9880d681SAndroid Build Coastguard Worker
303*9880d681SAndroid Build Coastguard Worker void* returnValue;
304*9880d681SAndroid Build Coastguard Worker result = pthread_join( add1Thread, &returnValue );
305*9880d681SAndroid Build Coastguard Worker if ( result != 0 ) {
306*9880d681SAndroid Build Coastguard Worker std::cerr << "Could not join thread" << std::endl;
307*9880d681SAndroid Build Coastguard Worker return 1;
308*9880d681SAndroid Build Coastguard Worker }
309*9880d681SAndroid Build Coastguard Worker std::cout << "Add1 returned " << intptr_t(returnValue) << std::endl;
310*9880d681SAndroid Build Coastguard Worker
311*9880d681SAndroid Build Coastguard Worker result = pthread_join( fibThread1, &returnValue );
312*9880d681SAndroid Build Coastguard Worker if ( result != 0 ) {
313*9880d681SAndroid Build Coastguard Worker std::cerr << "Could not join thread" << std::endl;
314*9880d681SAndroid Build Coastguard Worker return 1;
315*9880d681SAndroid Build Coastguard Worker }
316*9880d681SAndroid Build Coastguard Worker std::cout << "Fib1 returned " << intptr_t(returnValue) << std::endl;
317*9880d681SAndroid Build Coastguard Worker
318*9880d681SAndroid Build Coastguard Worker result = pthread_join( fibThread2, &returnValue );
319*9880d681SAndroid Build Coastguard Worker if ( result != 0 ) {
320*9880d681SAndroid Build Coastguard Worker std::cerr << "Could not join thread" << std::endl;
321*9880d681SAndroid Build Coastguard Worker return 1;
322*9880d681SAndroid Build Coastguard Worker }
323*9880d681SAndroid Build Coastguard Worker std::cout << "Fib2 returned " << intptr_t(returnValue) << std::endl;
324*9880d681SAndroid Build Coastguard Worker
325*9880d681SAndroid Build Coastguard Worker return 0;
326*9880d681SAndroid Build Coastguard Worker }
327