Index: trunk/psModules/src/objects/pmPSFtryFitEXT.c
===================================================================
--- trunk/psModules/src/objects/pmPSFtryFitEXT.c	(revision 35560)
+++ trunk/psModules/src/objects/pmPSFtryFitEXT.c	(revision 35768)
@@ -46,9 +46,26 @@
 #include "pmSourceVisual.h"
 
+bool pmPSFThreads (void) {
+
+    psThreadTask *task = NULL;
+
+    task = psThreadTaskAlloc("PSF_TRY_FIT_EXT", 6);
+    task->function = &pmPSFtryFitEXT_Threaded;
+    psThreadTaskAdd(task);
+    psFree(task);
+
+    task = psThreadTaskAlloc("PSF_TRY_FIT_PSF", 6);
+    task->function = &pmPSFtryFitPSF_Threaded;
+    psThreadTaskAdd(task);
+    psFree(task);
+
+    return true;
+}
+
+static int Next = 0;
+
 // Fit an EXT model to all candidates PSF sources.
 // Note: this is independent of the modeled 2D variations in the PSF.
 bool pmPSFtryFitEXT (pmPSFtry *psfTry, pmPSFOptions *options, psImageMaskType maskVal, psImageMaskType markVal) {
-
-    bool status;
 
     psTimerStart ("psf.fit");
@@ -60,52 +77,74 @@
     maskVal |= markVal;
 
-    int Next = 0;
+    Next = 0;
     for (int i = 0; i < psfTry->sources->n; i++) {
 
         pmSource *source = psfTry->sources->data[i];
-        if (!source->moments) {
-            psfTry->mask->data.PS_TYPE_VECTOR_MASK_DATA[i] = PSFTRY_MASK_EXT_FAIL;
-            psTrace ("psModules.objects", 4, "masking %d (%d,%d) : no moments\n", i, source->peak->x, source->peak->y);
-            continue;
-        }
-        if (!source->moments->nPixels) {
-            psTrace ("psModules.objects", 4, "masking %d (%d,%d) : no pixels\n", i, source->peak->x, source->peak->y);
-            psfTry->mask->data.PS_TYPE_VECTOR_MASK_DATA[i] = PSFTRY_MASK_EXT_FAIL;
-            continue;
-        }
-        // If mask object does not exist, mark the source as bad.
-        // We cannot proceed with it because psImageMaskPixels leaves an uncleared error code last which causes
-        // psphot to exit with a fault. 
-        if (source->maskObj == NULL) {
-            psTrace ("psModules.objects", 4, "source %d (%d,%d) : null maskObj\n", i, source->peak->x, source->peak->y);
-            psfTry->mask->data.PS_TYPE_VECTOR_MASK_DATA[i] = PSFTRY_MASK_EXT_FAIL;
-            continue;
-        }
 
-        source->modelEXT = pmSourceModelGuess (source, options->type, maskVal, markVal);
-        if (source->modelEXT == NULL) {
-            psTrace ("psModules.objects", 4, "masking %d (%d,%d) : failed to generate model guess\n", i, source->peak->x, source->peak->y);
-            psfTry->mask->data.PS_TYPE_VECTOR_MASK_DATA[i] = PSFTRY_MASK_EXT_FAIL;
-            continue;
-        }
+	if (!source->moments) {
+	    psfTry->mask->data.PS_TYPE_VECTOR_MASK_DATA[i] = PSFTRY_MASK_EXT_FAIL;
+	    psTrace ("psModules.objects", 4, "masking %d (%d,%d) : no moments\n", i, source->peak->x, source->peak->y);
+	    continue;
+	}
+	if (!source->moments->nPixels) {
+	    psTrace ("psModules.objects", 4, "masking %d (%d,%d) : no pixels\n", i, source->peak->x, source->peak->y);
+	    psfTry->mask->data.PS_TYPE_VECTOR_MASK_DATA[i] = PSFTRY_MASK_EXT_FAIL;
+	    continue;
+	}
+	// If mask object does not exist, mark the source as bad.
+	// We cannot proceed with it because psImageMaskPixels leaves an uncleared error code last which causes
+	// psphot to exit with a fault. 
+	if (source->maskObj == NULL) {
+	    psTrace ("psModules.objects", 4, "source %d (%d,%d) : null maskObj\n", i, source->peak->x, source->peak->y);
+	    psfTry->mask->data.PS_TYPE_VECTOR_MASK_DATA[i] = PSFTRY_MASK_EXT_FAIL;
+	    continue;
+	}
 
-        // set object mask to define valid pixels
-	// XXX 0.5 PIX: is the circle symmetric about the peak coordinate (given 0.5,0.5 center)?
-        psImageKeepCircle (source->maskObj, source->peak->x, source->peak->y, options->fitRadius, "OR", markVal);
+	source->modelEXT = pmSourceModelGuess (source, options->type, maskVal, markVal);
+	if (source->modelEXT == NULL) {
+	    psTrace ("psModules.objects", 4, "masking %d (%d,%d) : failed to generate model guess\n", i, source->peak->x, source->peak->y);
+	    psfTry->mask->data.PS_TYPE_VECTOR_MASK_DATA[i] = PSFTRY_MASK_EXT_FAIL;
+	    continue;
+	}
 
-        // fit model as EXT, not PSF
-        status = pmSourceFitModel (source, source->modelEXT, options->fitOptions, maskVal);
+	// do some actual work on this source
+	psThreadJob *job = psThreadJobAlloc ("PSF_TRY_FIT_EXT");
+	psArrayAdd(job->args, 1, source);
+	psArrayAdd(job->args, 1, psfTry);
+	psArrayAdd(job->args, 1, options);
+	
+	PS_ARRAY_ADD_SCALAR(job->args, i,        PS_TYPE_S32);
 
-        // clear object mask to define valid pixels
-        psImageMaskPixels (source->maskObj, "AND", PS_NOT_IMAGE_MASK(markVal)); // clear the circular mask
+	PS_ARRAY_ADD_SCALAR(job->args, maskVal,  PS_TYPE_IMAGE_MASK);
+	PS_ARRAY_ADD_SCALAR(job->args, markVal,  PS_TYPE_IMAGE_MASK);
 
-        // exclude the poor fits
-        if (!status) {
-            psTrace ("psModules.objects", 4, "masking %d (%d,%d) : status is poor\n", i, source->peak->x, source->peak->y);
-            psfTry->mask->data.PS_TYPE_VECTOR_MASK_DATA[i] = PSFTRY_MASK_EXT_FAIL;
-            continue;
-        }
-        Next ++;
+# if (1)
+	if (!psThreadJobAddPending(job)) {
+	    psError(PS_ERR_UNKNOWN, false, "Unable to create psf model.");
+	    return false;
+	}
+# else
+	if (!pmPSFtryFitEXT_Threaded(job)) {
+	    psError(PS_ERR_UNKNOWN, false, "Unable to create psf model.");
+	    return false;
+	}
+	psFree(job);
+# endif
     }
+
+    // wait for the threads to finish and manage results
+    if (!psThreadPoolWait (false, true)) {
+	psError(PS_ERR_UNKNOWN, false, "failure to model psf");
+	return false;
+    }
+
+    // we have only supplied one type of job, so we can assume the types here
+    psThreadJob *job = NULL;
+    while ((job = psThreadJobGetDone()) != NULL) {
+	// we have no returned data from this operation
+	if (job->args->n < 1) fprintf (stderr, "error with job\n");
+	psFree(job);
+    }
+
     psLogMsg ("psphot.psftry", PS_LOG_MINUTIA, "fit ext:   %f sec for %d of %ld sources\n", psTimerMark ("psf.fit"), Next, psfTry->sources->n);
     psTrace ("psModules.object", 3, "keeping %d of %ld PSF candidates (EXT)\n", Next, psfTry->sources->n);
@@ -118,2 +157,34 @@
     return true;
 }
+
+bool pmPSFtryFitEXT_Threaded (psThreadJob *job) {
+
+    pmSource *source =      job->args->data[0];
+    pmPSFtry *psfTry =      job->args->data[1];
+    pmPSFOptions *options = job->args->data[2];
+
+    int i = PS_SCALAR_VALUE(job->args->data[3], S32);
+
+    psImageMaskType maskVal = PS_SCALAR_VALUE(job->args->data[4],PS_TYPE_IMAGE_MASK_DATA);
+    psImageMaskType markVal = PS_SCALAR_VALUE(job->args->data[5],PS_TYPE_IMAGE_MASK_DATA);
+
+    // set object mask to define valid pixels
+    // XXX 0.5 PIX: is the circle symmetric about the peak coordinate (given 0.5,0.5 center)?
+    psImageKeepCircle (source->maskObj, source->peak->x, source->peak->y, options->fitRadius, "OR", markVal);
+
+    // fit model as EXT, not PSF
+    bool status = pmSourceFitModel (source, source->modelEXT, options->fitOptions, maskVal);
+
+    // clear object mask to define valid pixels
+    psImageMaskPixels (source->maskObj, "AND", PS_NOT_IMAGE_MASK(markVal)); // clear the circular mask
+
+    // exclude the poor fits
+    if (!status) {
+	psTrace ("psModules.objects", 4, "masking %d (%d,%d) : status is poor\n", i, source->peak->x, source->peak->y);
+	psfTry->mask->data.PS_TYPE_VECTOR_MASK_DATA[i] = PSFTRY_MASK_EXT_FAIL;
+	return true;
+    }
+    Next ++;
+    
+    return true;
+}
