int alanRun(alanContext *actx) { char me[]="alanRun", err[BIFF_STRLEN]; int tid, hack=AIR_FALSE; alanTask task[ALAN_THREAD_MAX]; if (_alanCheck(actx)) { sprintf(err, "%s: ", me); biffAdd(ALAN, err); return 1; } if (!( actx->_nlev[0] && actx->_nlev[0] )) { sprintf(err, "%s: _nlev[0,1] not allocated: " "call alanUpdate + alanInit", me); biffAdd(ALAN, err); return 1; } if (!airThreadCapable && 1 == actx->numThreads) { hack = airThreadNoopWarning; airThreadNoopWarning = AIR_FALSE; } actx->changeMutex = airThreadMutexNew(); actx->iterBarrier = airThreadBarrierNew(actx->numThreads); actx->averageChange = 0; actx->changeCount = 0; actx->stop = alanStopNot; for (tid=0; tid<actx->numThreads; tid++) { task[tid].actx = actx; task[tid].idx = tid; task[tid].thread = airThreadNew(); airThreadStart(task[tid].thread, _alanTuringWorker, (void *)&(task[tid])); } for (tid=0; tid<actx->numThreads; tid++) { airThreadJoin(task[tid].thread, &(task[tid].me)); task[tid].thread = airThreadNix(task[tid].thread); } actx->iterBarrier = airThreadBarrierNix(actx->iterBarrier); actx->changeMutex = airThreadMutexNix(actx->changeMutex); if (!airThreadCapable && 1 == actx->numThreads) { airThreadNoopWarning = hack; } /* we assume that someone set actx->stop */ return 0; }
int pushStart(pushContext *pctx) { char me[]="pushStart", err[BIFF_STRLEN]; unsigned int tidx; if (_pushContextCheck(pctx)) { sprintf(err, "%s: trouble", me); biffAdd(PUSH, err); return 1; } airSrandMT(pctx->seed); /* the ordering of things below is important: gage and fiber contexts have to be set up before they're copied by task setup */ if (_pushTensorFieldSetup(pctx) || _pushGageSetup(pctx) || _pushFiberSetup(pctx) || _pushTaskSetup(pctx) || _pushBinSetup(pctx) || _pushThingSetup(pctx)) { sprintf(err, "%s: trouble setting up context", me); biffAdd(PUSH, err); return 1; } /* HEY: this should be done by the user */ pctx->process[0] = _pushForce; pctx->process[1] = _pushUpdate; pctx->finished = AIR_FALSE; if (pctx->numThread > 1) { pctx->binMutex = airThreadMutexNew(); pctx->stageBarrierA = airThreadBarrierNew(pctx->numThread); pctx->stageBarrierB = airThreadBarrierNew(pctx->numThread); } /* start threads 1 and up running; they'll all hit stageBarrierA */ for (tidx=1; tidx<pctx->numThread; tidx++) { if (pctx->verbose > 1) { fprintf(stderr, "%s: spawning thread %d\n", me, tidx); } airThreadStart(pctx->task[tidx]->thread, _pushWorker, (void *)(pctx->task[tidx])); } return 0; }
int pullStart(pullContext *pctx) { char me[]="pullStart", err[BIFF_STRLEN]; unsigned int tidx; fprintf(stderr, "!%s: hello %p\n", me, pctx); pctx->iter = 0; /* have to initialize this here because of seedOnly hack */ /* the ordering of steps below is important! e.g. gage context has to be set up (_pullVolumeSetup) by before its copied (_pullTaskSetup) */ if (_pullContextCheck(pctx) || _pullVolumeSetup(pctx) || _pullInfoSetup(pctx) || _pullTaskSetup(pctx) || _pullBinSetup(pctx) || _pullPointSetup(pctx)) { sprintf(err, "%s: trouble setting up context", me); biffAdd(PULL, err); return 1; } fprintf(stderr, "!%s: setup done-ish\n", me); if (pctx->threadNum > 1) { pctx->binMutex = airThreadMutexNew(); pctx->iterBarrierA = airThreadBarrierNew(pctx->threadNum); pctx->iterBarrierB = airThreadBarrierNew(pctx->threadNum); /* start threads 1 and up running; they'll all hit iterBarrierA */ for (tidx=1; tidx<pctx->threadNum; tidx++) { if (pctx->verbose > 1) { fprintf(stderr, "%s: spawning thread %d\n", me, tidx); } airThreadStart(pctx->task[tidx]->thread, _pullWorker, (void *)(pctx->task[tidx])); } } else { pctx->binMutex = NULL; pctx->iterBarrierA = NULL; pctx->iterBarrierB = NULL; } pctx->timeIteration = 0; pctx->timeRun = 0; return 0; }
airThreadBarrier * airThreadBarrierNew(unsigned int numUsers) { airThreadBarrier *barrier; barrier = (airThreadBarrier *)calloc(1, sizeof(airThreadBarrier)); if (barrier) { barrier->numUsers = numUsers; barrier->numDone = 0; if (!(barrier->doneMutex = airThreadMutexNew())) { airFree(barrier); return NULL; } if (!(barrier->doneCond = airThreadCondNew())) { barrier->doneMutex = airThreadMutexNix(barrier->doneMutex); airFree(barrier); return NULL; } } return barrier; }
/* ******** hooverRender() ** ** because of the biff usage(), only one thread can call hooverRender(), ** and no promises if the threads themselves call biff... */ int hooverRender(hooverContext *ctx, int *errCodeP, int *errThreadP) { char me[]="hooverRender", err[BIFF_STRLEN]; _hooverExtraContext *ec; _hooverThreadArg args[HOOVER_THREAD_MAX]; _hooverThreadArg *errArg; airThread *thread[HOOVER_THREAD_MAX]; _htpu u; void *render; int ret; airArray *mop; int threadIdx; if (!( errCodeP && errThreadP )) { sprintf(err, "%s: got NULL int return pointer", me); biffAdd(HOOVER, err); return hooverErrInit; } /* this calls limnCameraUpdate() */ if (hooverContextCheck(ctx)) { sprintf(err, "%s: problem detected in given context", me); biffAdd(HOOVER, err); *errCodeP = 0; *errThreadP = 0; return hooverErrInit; } if (!(ec = _hooverExtraContextNew(ctx))) { sprintf(err, "%s: problem creating thread context", me); biffAdd(HOOVER, err); *errCodeP = 0; *errThreadP = 0; return hooverErrInit; } mop = airMopNew(); airMopAdd(mop, ec, (airMopper)_hooverExtraContextNix, airMopAlways); if ( (ret = (ctx->renderBegin)(&render, ctx->user)) ) { *errCodeP = ret; *errCodeP = 0; *errThreadP = 0; airMopError(mop); return hooverErrRenderBegin; } for (threadIdx=0; threadIdx<ctx->numThreads; threadIdx++) { args[threadIdx].ctx = ctx; args[threadIdx].ec = ec; args[threadIdx].render = render; args[threadIdx].whichThread = threadIdx; args[threadIdx].whichErr = hooverErrNone; args[threadIdx].errCode = 0; thread[threadIdx] = airThreadNew(); } ctx->workIdx = 0; if (1 < ctx->numThreads) { ctx->workMutex = airThreadMutexNew(); } else { ctx->workMutex = NULL; } /* (done): call airThreadStart() once per thread, passing the address of a distinct (and appropriately intialized) _hooverThreadArg to each. If return of airThreadStart() is non-zero, put its return in *errCodeP, the number of the problematic in *errThreadP, and return hooverErrThreadCreate. Then call airThreadJoin() on all the threads, passing &errArg as "retval". On non-zero return, set *errCodeP and *errThreadP, and return hooverErrThreadJoin. If return of airThreadJoin() is zero, but the errArg is non-NULL, then assume that this errArg is actually just the passed _hooverThreadArg returned to us, and from this copy errArg->errCode into *errCodeP, and return errArg->whichErr */ if (1 < ctx->numThreads && !airThreadCapable) { fprintf(stderr, "%s: WARNING: not multi-threaded; will do %d " "\"threads\" serially !!!\n", me, ctx->numThreads); } for (threadIdx=0; threadIdx<ctx->numThreads; threadIdx++) { if ((ret = airThreadStart(thread[threadIdx], _hooverThreadBody, (void *) &args[threadIdx]))) { *errCodeP = ret; *errThreadP = threadIdx; airMopError(mop); return hooverErrThreadCreate; } } for (threadIdx=0; threadIdx<ctx->numThreads; threadIdx++) { u.h = &errArg; if ((ret = airThreadJoin(thread[threadIdx], u.v))) { *errCodeP = ret; *errThreadP = threadIdx; airMopError(mop); return hooverErrThreadJoin; } if (errArg != NULL) { *errCodeP = errArg->errCode; *errThreadP = threadIdx; return errArg->whichErr; } thread[threadIdx] = airThreadNix(thread[threadIdx]); } if (1 < ctx->numThreads) { ctx->workMutex = airThreadMutexNix(ctx->workMutex); } if ( (ret = (ctx->renderEnd)(render, ctx->user)) ) { *errCodeP = ret; *errThreadP = -1; return hooverErrRenderEnd; } render = NULL; airMopOkay(mop); *errCodeP = 0; *errThreadP = 0; return hooverErrNone; }
int coilStart(coilContext *cctx) { char me[]="coilStart", err[BIFF_STRLEN]; int valIdx, valLen; coil_t (*lup)(const void*, size_t), *val; unsigned tidx, elIdx; if (!cctx) { sprintf(err, "%s: got NULL pointer", me); biffAdd(COIL, err); return 1; } cctx->task = (coilTask **)calloc(cctx->numThreads, sizeof(coilTask *)); if (!(cctx->task)) { sprintf(err, "%s: couldn't allocate array of tasks", me); biffAdd(COIL, err); return 1; } /* we create tasks for ALL threads, including me, thread 0 */ cctx->task[0] = NULL; for (tidx=0; tidx<cctx->numThreads; tidx++) { cctx->task[tidx] = _coilTaskNew(cctx, tidx); if (!(cctx->task[tidx])) { sprintf(err, "%s: couldn't allocate task %d", me, tidx); biffAdd(COIL, err); return 1; } } cctx->finished = AIR_FALSE; if (cctx->numThreads > 1) { cctx->nextSliceMutex = airThreadMutexNew(); cctx->filterBarrier = airThreadBarrierNew(cctx->numThreads); cctx->updateBarrier = airThreadBarrierNew(cctx->numThreads); } /* initialize the values in cctx->nvol */ val = (coil_t*)(cctx->nvol->data); valLen = cctx->kind->valLen; #if COIL_TYPE_FLOAT lup = nrrdFLookup[cctx->nin->type]; #else lup = nrrdDLookup[cctx->nin->type]; #endif for (elIdx=0; elIdx<cctx->size[0]*cctx->size[1]*cctx->size[2]; elIdx++) { for (valIdx=0; valIdx<valLen; valIdx++) { val[valIdx + 0*valLen] = lup(cctx->nin->data, valIdx + valLen*elIdx); val[valIdx + 1*valLen] = 0; } val += 2*valLen; } /* start threads 1 and up running; they'll all hit filterBarrier */ if (cctx->numThreads > 1) { for (tidx=1; tidx<cctx->numThreads; tidx++) { if (cctx->verbose > 1) { fprintf(stderr, "%s: spawning thread %d\n", me, tidx); } airThreadStart(cctx->task[tidx]->thread, _coilWorker, (void *)(cctx->task[tidx])); } } /* set things as though we've just finished an update phase */ cctx->nextSlice = cctx->size[2]; cctx->todoFilter = AIR_TRUE; cctx->todoUpdate = AIR_FALSE; return 0; }