我的OSX Cocoa App是一个测试应用程序,涉及NSTimers,多线程,UART处理和UI显示。
在主UI中,运行NSTimer会显示测试完成之前的测试时间。典型测试涉及许多测试项目,这些测试项目接收和发送消息到UART,4个UART到8个UART。对于4个器件,它将涉及4个UART,而对于8个器件,它将涉及8个UART。每个UART读取都由相应的线程完成,该线程读入缓冲区并随后将消息存储在日志文件中。
我的测试应用程序基本上有一个主测试线程,它本身将根据设备数量产生4或8个单独的线程。同时,有一些NSTimers可以检查启动/中止按钮的状态,显示测试时间等。在最初的几次运行中,UI正在平滑更新。 UI显示主要涉及显示测试时间,测试状态和显示每个测试项目结果的NSTableView。说几次测试后,UI开始冻结或无响应。在冻结过程中,在测试结束时,显示测试状态的NSButton会在“运行”状态下冻结。这要求用户使用鼠标点击NSButton,以便将其更新为" PASS"或"失败"。虽然UI看起来是冻结的,但实际上正在运行测试,因为我们可以从控制台日志中看到NSLog消息。
我正在调试此问题,查看内存泄漏并优化算法无济于事。 请帮我解决一下这个问题。
测试应用程序非常庞大,因此,我会发布一些相关的代码片段,删除我们的机密详细信息以节省空间。
-(void)onIdleTimer:(NSTimer*)timer
{
BOOL checkWell1 = FALSE;
if ( ! [appWindow isVisible])
return;
if (!bTestRunning[0] && !pauseTimer1) {
checkWell1 = TRUE;
}
if (checkWell1 == TRUE) {
// UART data buffer
char *pBuff1 = fetchRdBuff(0);
char *pBuff2 = fetchRdBuff(1);
char *pBuff3 = fetchRdBuff(2);
char *pBuff4 = fetchRdBuff(3);
if (!(pBuff1 == NULL) && strlen(pBuff1) != 0) {// && [uut1Check state] == 1){ //&& (uutSelected[0] == NSOnState)) {
NSString *strBuff1 = [NSString stringWithUTF8String:pBuff1];
NSRange range1 = [strBuff1 rangeOfString:RET_TOP_FIXTURE_START options:NSCaseInsensitiveSearch];
// Left button pressed to start test
if (range1.location != NSNotFound) {
startByMCU1 = TRUE;
[self runtest:RUN_NORMAL wellIndex:0];
startByMCU1 = FALSE;
return;
}
range1 = [strBuff1 rangeOfString:RET_TOP_FIXTURE_STOP options:NSCaseInsensitiveSearch];
if (range1.location != NSNotFound) {
clearRdBuff(0);
}
}
//Same goes for pBuff2, pBuff3 and pBuff4
...
}
- (void)testThreadMainRoutine:(id)argument
{
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
//Initiasation and etc
...
for (i=0; i<lineCount; i++)
{
[NSThread sleepForTimeInterval:0.001];
if ([testThread[nWellIndex] isCancelled])
{
bTestStatus[nWellIndex] = ABORT;
goto TESTTHREAD_EXIT;
}
// Is there any UUT available?
bContinue = 0;
for (j=nStartIndex; j<nEndIndex; j++)
{
if (uutActive[j])
{
bContinue = 1;
break;
}
}
if (bContinue == 0)
{
goto TESTTHREAD_EXIT;
}
while(bPaused == 0)
{
[NSThread sleepForTimeInterval:0.1];
[self setTextResult:@"Pause" textColor:[NSColor orangeColor] wellIndex:nWellIndex];
}
[self setTextResult:@"Running" textColor:[NSColor orangeColor] wellIndex:nWellIndex];
// Per Command Line
CommandLine *cmdLine = [cmdArray objectAtIndex:i];
// Run UUT independently from this command line
if ([cmdLine independentRun] == INDEPENDENTRUN_START)
{
g_nIndependentStart = i;
g_nIndependentStop = [self independentRunStopIndex];
// Dispatch independent thread for each active UUT
for (j=nStartIndex; j<nEndIndex; j++)
{
if (uutActive[j])
{
g_itemCount[j] = itemCount;
NSNumber *uutIndex = [NSNumber numberWithInt:j];
[g_uutThread[j] release];
g_uutThread[j] = [[NSThread alloc] initWithTarget:self
selector:@selector(testThreadUUTRoutine:)
object:uutIndex];
[g_uutThread[j] start];
}
}
// Waiting till test abort or UUT thread finish
while ( 1 )
{
[NSThread sleepForTimeInterval:0.05];
// User press button to abort the test
if ([testThread[nWellIndex] isCancelled])
{
// Cancel all UUT thread
for (j=nStartIndex; j<nEndIndex; j++)
{
if ([g_uutThread[j] isExecuting])
{
[g_uutThread[j] cancel];
}
}
bTestStatus[nWellIndex] = ABORT;
}
// Wait until all thread exited, then continue remaining test
bContinue = 0;
for (j=nStartIndex; j<nEndIndex; j++)
{
if (uutSelected[j])
{
if ([g_uutThread[j] isExecuting])
{
bContinue = 1;
}
else
{
[g_uutThread[j] release];
g_uutThread[j] = nil;
}
}
}
// All UUT thread exited
if ( ! bContinue)
{
break;
}
//if (canUpdate) {
// Select current test row
if (itemCount != [self maxCurrentItemCount:nWellIndex])
{
itemCount = [self maxCurrentItemCount:nWellIndex];
NSArray *objArray = [NSArray arrayWithObjects:[NSNumber numberWithInt:nWellIndex],
[NSNumber numberWithInt:itemCount], nil];
[self performSelectorOnMainThread:@selector(selectCurrentRow:)
withObject:objArray waitUntilDone:YES];
}
if (nWellIndex == 0)
{
[testTable01 display];
}
else if(nWellIndex==1)
{
[testTable02 display];
}
else
{
[testTable03 display];
}
}
// Test abort or UUT fail and aborted
if (bTestStatus[nWellIndex] == ABORT)
{
goto TESTTHREAD_EXIT;
}
if (g_nIndependentStop >= lineCount)
{
// All test done
goto TESTTHREAD_EXIT;
}
else
{
// Continue remaining test
i = g_nIndependentStop;
cmdLine = [cmdArray objectAtIndex:i];
itemCount = [self maxCurrentItemCount:nWellIndex];
}
}
NSArray *objArray = [NSArray arrayWithObjects:[NSNumber numberWithInt:nWellIndex], [NSNumber numberWithInt:itemCount], nil];
[self performSelectorOnMainThread:@selector(selectCurrentRow:) withObject:objArray waitUntilDone:YES];
NSString *cmdName = [cmdLine valueForKey:@"cmdName"];
NSString *cmdParam = [cmdLine valueForKey:@"cmdParam"];
NSString *itemName = [cmdLine valueForKey:@"itemName"];
// Clear returnArray
for (j=nStartIndex; j<nEndIndex; j++)
{
if ([cmdLine flag] & FLAG_SKIP) {
[[cmdReturn objectAtIndex:j] setUnit:@"NA"];
[[cmdReturn objectAtIndex:j] setLowerLimit:@"NA"];
[[cmdReturn objectAtIndex:j] setUpperLimit:@"NA"];
[[cmdReturn objectAtIndex:j] setCmdResult:@"Skipped"];
[[cmdReturn objectAtIndex:j] setTestResult:@"Skipped"];
[[cmdReturn objectAtIndex:j] setCmdStatus:SKIPPED];
continue;
}
if ([cmdName characterAtIndex:0] == '_') // Per UUT command
{
// Repeat for all UUT
for (j=nStartIndex; j<nEndIndex; j++)
{
// whether UUT is selected
if (uutActive[j])
{
...
// Process test result
if (itemName != nil)
{
[self saveUutResult:[[cmdReturn objectAtIndex:j] testResult] testItem:itemName uutIndex:j uutStatus:SKIPPED];
}
continue;
}
// Before Item Test, save timestamp
if (itemName != nil)
{
NSString* timeStamp = [[NSDate date] descriptionWithCalendarFormat:@"\n%y-%m-%d %H:%M:%S: " timeZone:nil locale:nil];
[strPlog[j] appendFormat:@"%@ START %@", timeStamp, itemName];
}
// insert to UART log file
char buff[1024];
NSString *strInfo = [NSString stringWithFormat:@"%d: %@, (%@), %@", i, cmdName, cmdParam, itemName];
sprintf(buff, "\n[Host Executing Cmd]%s\n", [strInfo UTF8String]);
[self uartDataLogging:j buffer:buff pureUARTData:NO];
[self parseCommand:cmdName parameter:cmdParam lineIndex:i uutIndex:j wellIndex:nWellIndex];
[self saveCmdReading:[[cmdReturn objectAtIndex:j] cmdResult]
commandLine:i uutIndex:j lineStatus:[[cmdReturn objectAtIndex:j] cmdStatus]];
// Test Item
if (itemName != nil)
{
[self saveUutResult:[[cmdReturn objectAtIndex:j] testResult]
testItem:itemName uutIndex:j uutStatus:[[cmdReturn objectAtIndex:j] cmdStatus]];
// After Item Test, save timestamp
NSString* timeStamp = [[NSDate date] descriptionWithCalendarFormat:@"\n%y-%m-%d %H:%M:%S: " timeZone:nil locale:nil];
[strPlog[j] appendFormat:@"%@ FINISH %@", timeStamp, itemName];
}
// Fail Stop/Abort
if ([[cmdReturn objectAtIndex:j] cmdStatus] == FAIL)
{
if ([cmdLine flag] & FLAG_FAILSTOP)
{
// Stop this UUT test
uutActive[j] = 0;
if ([[uutBarcode objectAtIndex:j] length] > 0) {
[self InstantPudding_Done:j];
}
}
else if ([cmdLine flag] & FLAG_FAILABORT)
{
bTestStatus[nWellIndex] = ABORT;
goto TESTTHREAD_EXIT;
}
}
}
}
}
else // For all active UUT
{
// Before Item Test, save timestamp
for (j=nStartIndex; j<nEndIndex; j++)
{
if ([cmdLine flag] & FLAG_SKIP) {
[[cmdReturn objectAtIndex:j] setUnit:@"NA"];
[[cmdReturn objectAtIndex:j] setLowerLimit:@"NA"];
[[cmdReturn objectAtIndex:j] setUpperLimit:@"NA"];
[[cmdReturn objectAtIndex:j] setCmdResult:@"Skipped"];
[[cmdReturn objectAtIndex:j] setTestResult:@"Skipped"];
[[cmdReturn objectAtIndex:j] setCmdStatus:SKIPPED];
[self saveCmdReading:[[cmdReturn objectAtIndex:j] cmdResult] commandLine:i uutIndex:j lineStatus:SKIPPED];
// Process test result
if (itemName != nil)
{
[self saveUutResult:[[cmdReturn objectAtIndex:j] testResult]
testItem:itemName uutIndex:j uutStatus:SKIPPED];
}
continue;
}
// whether UUT is selected
if (uutActive[j])
{
if (itemName != nil)
{
NSString* timeStamp = [[NSDate date] descriptionWithCalendarFormat:@"\n%y-%m-%d %H:%M:%S: " timeZone:nil locale:nil];
[strPlog[j] appendFormat:@"%@ START %@", timeStamp, itemName];
}
// insert to UART log file
char buff[1024];
NSString *strInfo = [NSString stringWithFormat:@"%d: %@, (%@), %@", i, cmdName, cmdParam, itemName];
sprintf(buff, "\n[Host Executing Cmd]%s\n", [strInfo UTF8String]);
[self uartDataLogging:j buffer:buff pureUARTData:NO];
}
}
if ([cmdLine flag] & FLAG_SKIP) {
continue;
}
[self parseCommand:cmdName parameter:cmdParam lineIndex:i uutIndex:-1 wellIndex:nWellIndex];
// Process command return result
for (j=nStartIndex; j<nEndIndex; j++)
{
// whether UUT is selected
if (uutActive[j])
{
[self saveCmdReading:[[cmdReturn objectAtIndex:j] cmdResult] commandLine:i uutIndex:j lineStatus:[[cmdReturn objectAtIndex:j] cmdStatus]];
// Process test result
if (itemName != nil)
{
[self saveUutResult:[[cmdReturn objectAtIndex:j] testResult]
testItem:itemName uutIndex:j uutStatus:[[cmdReturn objectAtIndex:j] cmdStatus]];
// After Item Test, save timestamp
NSString* timeStamp = [[NSDate date] descriptionWithCalendarFormat:@"\n%y-%m-%d %H:%M:%S: " timeZone:nil locale:nil];
[strPlog[j] appendFormat:@"%@ FINISH %@", timeStamp, itemName];
}
// Fail Stop/Abort
if ([[cmdReturn objectAtIndex:j] cmdStatus] == FAIL)
{
if ([cmdLine flag] & FLAG_FAILSTOP)
{
// Stop this UUT test
uutActive[j] = 0;
if ([[uutBarcode objectAtIndex:j] length] > 0) {
[self InstantPudding_Done:j];
}
}
else if ([cmdLine flag] & FLAG_FAILABORT)
{
bTestStatus[nWellIndex] = ABORT;
//[loopPool drain];
goto TESTTHREAD_EXIT;
}
}
}
}
}
if (itemName != nil)
itemCount++;
}
TESTTHREAD_EXIT:
if (bTestStatus[nWellIndex] != ABORT) {
for (int i = nStartIndex; i < nEndIndex; i++) {
if (uutSelected[i] == NSOnState && IPDone[i] == FALSE) {
[self InstantPudding_DoneForAll:i];
}
}
}
[NSThread sleepForTimeInterval:0.1];
for (j=nStartIndex; j<nEndIndex; j++)
{
strTestTimeRecord[j] = [[NSString stringWithString:strPlog[j]] retain];
[strPlog[j] release];
strPlog[j] = nil;
}
[self showTestStatus:bTestStatus[nWellIndex] wellIndex:nWellIndex];
// Refresh UI to indicate test result
[self performSelectorOnMainThread:@selector(afterRun:) withObject:argument waitUntilDone:NO];
[pool release];
}
- (void)testThreadUUTRoutine:(id)argument
{
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
//Initialisation and etc
...
NSLog(@"UUT%d starts to run independently...", nUUTIndex+1);
// Run
for (int i=g_nIndependentStart; i<g_nIndependentStop; i++)
{
// Per Command Line
CommandLine *cmdLine = [cmdArray objectAtIndex:i];
NSString *cmdName = [cmdLine valueForKey:@"cmdName"];
NSString *cmdParam = [cmdLine valueForKey:@"cmdParam"];
NSString *itemName = [cmdLine valueForKey:@"itemName"];
if ([g_uutThread[nUUTIndex] isCancelled])
{
goto UUTTHREAD_EXIT;
}
if ([cmdLine flag] & FLAG_SKIP) {
...
if (itemName != nil) {
[self saveUutResult:[[cmdReturn objectAtIndex:nUUTIndex] testResult]
testItem:itemName uutIndex:nUUTIndex
uutStatus:SKIPPED];
}
continue;
}
// Before Item Test, save timestamp
if (itemName != nil) {
NSString* timeStamp = [[NSDate date] descriptionWithCalendarFormat:@"\n%y-%m-%d %H:%M:%S: " timeZone:nil locale:nil];
//timeStamp1 = [NSDate date];
[strPlog[nUUTIndex] appendFormat:@"%@ START %@", timeStamp, itemName];
}
// insert to UART log file
char buff[1024];
NSString *strInfo = [NSString stringWithFormat:@"%d: %@, (%@), %@", i, cmdName, cmdParam, itemName];
sprintf(buff, "\n[Host Executing Cmd]%s\n", [strInfo UTF8String]);
[self uartDataLogging:nUUTIndex buffer:buff pureUARTData:NO];
if ([cmdName caseInsensitiveCompare:@"_If"] != NSOrderedSame &&
[cmdName caseInsensitiveCompare:@"_Else"] != NSOrderedSame &&
[cmdName caseInsensitiveCompare:@"_EndIf"] != NSOrderedSame &&
[cmdName caseInsensitiveCompare:@"_Do..."] != NSOrderedSame &&
[cmdName caseInsensitiveCompare:@"_While"] != NSOrderedSame) {
[self parseCommand:cmdName parameter:cmdParam lineIndex:i uutIndex:nUUTIndex wellIndex:nWellIndex];
}
//_If, _ElseIf and _EndIf
if ([cmdName caseInsensitiveCompare:@"_If"] == NSOrderedSame) {
paramArray = [cmdParam componentsSeparatedByString:@","];
if ([paramArray count] != 2)
{
dispatch_sync(dispatch_get_main_queue(), ^ {
NSRunAlertPanel(@"Command Execution Error",
@"Incorrect parameter number for _If! Command Line %d Ignored!",
@"OK", nil, nil, i);
});
return;
}
int nIfLineNo = [[paramArray objectAtIndex:0]intValue];
if ((nIfLineNo < 0) || (nIfLineNo >= i))
{
NSRunAlertPanel(@"Command Execution Error", @"_If statement at line %d has wrong parameter, %d!",
@"OK", nil, nil, i, nIfLineNo);
continue;
}
int nElseLineNo = [[NSApp delegate] getElseLineNo:i];
int nEndIfLineNo = [[NSApp delegate] getEndIfLineNo:i];
int nNextStepNo = nEndIfLineNo; // By default jump to _EndIF
if (nEndIfLineNo == -1)
{
NSRunAlertPanel(@"Command Execution Error",
@"_IF statement at line %d has no corresponding _ENDIF statement!",
@"OK", nil, nil, i);
continue; // ignore this line
}
else if ((nElseLineNo != -1) && (nElseLineNo < nEndIfLineNo)) // Jump to _ELSE
{
nNextStepNo = nElseLineNo+1;
}
hasIf = TRUE;
NSString *condition = [paramArray objectAtIndex:1];
// Condition
int nIfCondition;
if ([condition rangeOfString:@"PASS" options:NSCaseInsensitiveSearch].location
!= NSNotFound)
{
nIfCondition = PASS;
}
else
{
nIfCondition = FAIL;
}
BOOL jumpToIf = FALSE;
//for (j=StartIndex; j<EndIndex; j++)
//{
// Active UUT
if (uutActive[nUUTIndex]) {
CommandLine *cmdLine = [cmdArray objectAtIndex:nIfLineNo];
if ([cmdLine lineStatus:nUUTIndex] == nIfCondition) {
bIfElseFlag[nUUTIndex] = TRUE;
jumpToIf = TRUE;
}
else {
bIfElseFlag[nUUTIndex] = FALSE;
}
}
if (!jumpToIf)
{
i = nNextStepNo-1;
}
[[cmdReturn objectAtIndex:nUUTIndex] setCmdResult:@"_If"];
[[cmdReturn objectAtIndex:nUUTIndex] setTestResult:@"_If"];
[[cmdReturn objectAtIndex:nUUTIndex] setCmdStatus:PASS];
continue;
}
if ([cmdName caseInsensitiveCompare:@"_Else"] == NSOrderedSame) {
if ( ! hasIf)
{
NSRunAlertPanel(@"Command Execution Error",
@"ElseIf statement at step %d has no corresponding _IF statement!",
@"OK", nil, nil, i);
continue;
}
BOOL bIfDone = TRUE;
bIfElseFlag[nUUTIndex] = !bIfElseFlag[nUUTIndex];
if (bIfElseFlag[nUUTIndex])
{
bIfDone = FALSE;
}
// No UUT jump to _ELSE. Jump directly to _EndIf
if (bIfDone)
{
int nEndIfLineNo = [[NSApp delegate] getEndIfLineNo:i];
if (nEndIfLineNo == -1)
{
NSRunAlertPanel(@"Command Execution Error",
@"_ElseIf statement at line %d has no corresponding _EndIf statement!",
@"OK", nil, nil, i);
break; // Stop all UUT test
}
else
{
i = nEndIfLineNo-1;
}
}
[[cmdReturn objectAtIndex:nUUTIndex] setCmdResult:@"_Else"];
[[cmdReturn objectAtIndex:nUUTIndex] setTestResult:@"_Else"];
[[cmdReturn objectAtIndex:nUUTIndex] setCmdStatus:PASS];
continue;
}
if ([cmdName caseInsensitiveCompare:@"_EndIf"] == NSOrderedSame) {
if ( ! hasIf)
{
NSRunAlertPanel(@"Command Execution Error",
@"EndIf statement at line %d has no corresponding _IF statement!",
@"OK", nil, nil, i);
continue;
}
bIfElseFlag[nUUTIndex] = FALSE;
hasIf = FALSE;
[[cmdReturn objectAtIndex:nUUTIndex] setCmdResult:@"_EndIf"];
[[cmdReturn objectAtIndex:nUUTIndex] setTestResult:@"_EndIf"];
[[cmdReturn objectAtIndex:nUUTIndex] setCmdStatus:PASS];
continue;
}
//_Do... and _While
if ([cmdName caseInsensitiveCompare:@"_Do..."] == NSOrderedSame) {
g_nDoIndex[nUUTIndex] = i;
[[cmdReturn objectAtIndex:nUUTIndex] setCmdResult:@"_Do"];
[[cmdReturn objectAtIndex:nUUTIndex] setTestResult:@"_Do"];
[[cmdReturn objectAtIndex:nUUTIndex] setCmdStatus:PASS];
continue;
}
if ([cmdName caseInsensitiveCompare:@"_While"] == NSOrderedSame) {
// Check validity
if (g_nDoIndex[nUUTIndex] == -1)
{
NSRunAlertPanel(@"Command Execution Error",
@"_While statement at line %d has no corresponding _DO... statement!",
@"OK", nil, nil, i);
continue;
}
paramArray = [cmdParam componentsSeparatedByString:@","];
if ([paramArray count] != 3)
{
dispatch_sync(dispatch_get_main_queue(), ^ {
NSRunAlertPanel(@"Command Execution Error",
@"Incorrect parameter number for _While! Command Line %d Ignored!",
@"OK", nil, nil, i);
});
return;
}
int lineNo = [[paramArray objectAtIndex:0]intValue];
if ((lineNo < 0) || (lineNo >= i))
{
NSRunAlertPanel(@"Command Execution Error", @"_While statement at line %d has wrong parameter, %d!",
@"OK", nil, nil, i, lineNo);
continue;
}
if (lineNo == -1)
{
NSRunAlertPanel(@"Command Execution Error",
@"_While statement at line %d has wrong parameter(%d)!",
@"OK", nil, nil, i, lineNo);
continue;
}
NSString *condition = [paramArray objectAtIndex:1];
// Condition
int nWhileResult;
if ([condition rangeOfString:@"PASS" options:NSCaseInsensitiveSearch].location != NSNotFound)
nWhileResult = PASS;
else if ([condition rangeOfString:@"FAIL" options:NSCaseInsensitiveSearch].location != NSNotFound)
nWhileResult = FAIL;
else
nWhileResult = UNKNOWN;
// Loop if any UUT not pass
BOOL bWhileLoop = FALSE;
// Active UUT
if (uutActive[nUUTIndex] && ! bUUTPass[nUUTIndex])
{
CommandLine *cmdLine = [cmdArray objectAtIndex:lineNo];
if ([cmdLine lineStatus:nUUTIndex] == nWhileResult) {
if (g_nLoopCount[nUUTIndex] < [[paramArray objectAtIndex:2] intValue])
{
bWhileLoop = TRUE;
}
}
else
{
bUUTPass[nUUTIndex] = TRUE; // No need to test this UUT anymore in this _DO..._While loop
}
}
if (bWhileLoop)
{
i = g_nDoIndex[nUUTIndex];
g_nLoopCount[nUUTIndex]++;
}
else
{
// Do...While loop finished
g_nDoIndex[nUUTIndex] = -1;
g_nLoopCount[nUUTIndex] = 1;
bUUTPass[nUUTIndex] = FALSE;
}
[[cmdReturn objectAtIndex:nUUTIndex] setCmdResult:@"_While"];
[[cmdReturn objectAtIndex:nUUTIndex] setTestResult:@"_While"];
[[cmdReturn objectAtIndex:nUUTIndex] setCmdStatus:PASS];
continue;
}
[self saveCmdReading:[[cmdReturn objectAtIndex:nUUTIndex] cmdResult]
commandLine:i uutIndex:nUUTIndex
lineStatus:[[cmdReturn objectAtIndex:nUUTIndex] cmdStatus]];
// Test Item
if (itemName != nil)
{
[self saveUutResult:[[cmdReturn objectAtIndex:nUUTIndex] testResult]
testItem:itemName uutIndex:nUUTIndex uutStatus:[[cmdReturn objectAtIndex:nUUTIndex] cmdStatus]];
// After Item Test, save timestamp
NSString* timeStamp = [[NSDate date] descriptionWithCalendarFormat:@"\n%y-%m-%d %H:%M:%S: " timeZone:nil locale:nil];
[strPlog[nUUTIndex] appendFormat:@"%@ FINISH %@", timeStamp, itemName];
}
// Fail Stop/Abort
if ([[cmdReturn objectAtIndex:nUUTIndex] cmdStatus] == FAIL)
{
if ([cmdLine flag] & FLAG_FAILSTOP)
{
// Stop this UUT test
uutActive[nUUTIndex] = 0;
if ([[uutBarcode objectAtIndex:nUUTIndex] length] > 0) {
[self InstantPudding_Done:nUUTIndex];
}
NSLog(@"UUT%d Fail and Stop Test!", nUUTIndex+1);
goto UUTTHREAD_EXIT;
}
else if ([cmdLine flag] & FLAG_FAILABORT)
{
bTestStatus[nWellIndex] = ABORT;
// [loopPool drain];
goto UUTTHREAD_EXIT;
}
else if ([cmdLine flag] & FLAG_APPLEPASS)
{
[[cmdReturn objectAtIndex:nUUTIndex] setCmdStatus:APPLEPASS];
[self saveUutResult:[[cmdReturn objectAtIndex:nUUTIndex] testResult] testItem:itemName
uutIndex:nUUTIndex uutStatus:[[cmdReturn objectAtIndex:nUUTIndex] cmdStatus]];
}
}
if (itemName != nil)
g_itemCount[nUUTIndex]++;
}
UUTTHREAD_EXIT:
[pool release];
}