X-Git-Url: http://winboard.nl/cgi-bin?a=blobdiff_plain;f=backend.c;h=f6e75c49f0e69aa380491ecdccc2ddb9739b3116;hb=2b59fb6b9575ad038bae89a48063084c8b3243a9;hp=fcc611a1412ae90f3ba446b7fa71243c64da38a4;hpb=2ee0112d8e774b268d91c618cddab6a0cfeab4fc;p=xboard.git diff --git a/backend.c b/backend.c index fcc611a..f6e75c4 100644 --- a/backend.c +++ b/backend.c @@ -57,6 +57,9 @@ #define DoSleep( n ) if( (n) != 0 ) Sleep( (n) ); +int flock(int f, int code); +#define LOCK_EX 2 + #else #define DoSleep( n ) if( (n) >= 0) sleep(n) @@ -325,7 +328,7 @@ safeStrCpy( char *dst, const char *src, size_t count ) { dst[ count-1 ] = '\0'; // make sure incomplete copy still null-terminated if(appData.debugMode) - fprintf(debugFP, "safeStrCpy: copying %s into %s didn't work, not enough space %d\n",src,dst,count); + fprintf(debugFP, "safeStrCpy: copying %s into %s didn't work, not enough space %d\n",src,dst, (int)count); } return dst; @@ -693,6 +696,24 @@ CommonEngineInit() } void +UnloadEngine(ChessProgramState *cps) +{ + /* Kill off first chess program */ + if (cps->isr != NULL) + RemoveInputSource(cps->isr); + cps->isr = NULL; + + if (cps->pr != NoProc) { + ExitAnalyzeMode(); + DoSleep( appData.delayBeforeQuit ); + SendToProgram("quit\n", cps); + DoSleep( appData.delayAfterQuit ); + DestroyChildProcess(cps->pr, cps->useSigterm); + } + cps->pr = NoProc; +} + +void ClearOptions(ChessProgramState *cps) { int i; @@ -793,6 +814,41 @@ InitEngine(ChessProgramState *cps, int n) InitEngineUCI( installDir, cps ); // [HGM] moved here from winboard.c, to make available in xboard } +ChessProgramState *savCps; + +void +LoadEngine() +{ + int i; + if(WaitForEngine(savCps, LoadEngine)) return; + CommonEngineInit(); // recalculate time odds + if(gameInfo.variant != StringToVariant(appData.variant)) { + // we changed variant when loading the engine; this forces us to reset + Reset(TRUE, savCps != &first); + EditGameEvent(); // for consistency with other path, as Reset changes mode + } + InitChessProgram(savCps, FALSE); + SendToProgram("force\n", savCps); + DisplayMessage("", ""); + if (startedFromSetupPosition) SendBoard(savCps, backwardMostMove); + for (i = backwardMostMove; i < forwardMostMove; i++) SendMoveToProgram(i, savCps); + ThawUI(); + SetGNUMode(); +} + +void +ReplaceEngine(ChessProgramState *cps, int n) +{ + EditGameEvent(); + UnloadEngine(cps); + appData.noChessProgram = False; + appData.clockMode = True; + InitEngine(cps, n); + if(n) return; // only startup first engine immediately; second can wait + savCps = cps; // parameter to LoadEngine passed as globals, to allow scheduled calling :-( + LoadEngine(); +} + void InitBackEnd1() { @@ -1268,6 +1324,12 @@ InitBackEnd3 P((void)) DisplayMessage("", ""); if (StrCaseCmp(appData.initialMode, "") == 0) { initialMode = BeginningOfGame; + if(!appData.icsActive && appData.noChessProgram) { // [HGM] could be fall-back + gameMode = MachinePlaysBlack; // "Machine Black" might have been implicitly highlighted + ModeHighlight(); // make sure XBoard knows it is highlighted, so it will un-highlight it + gameMode = BeginningOfGame; // in case BeginningOfGame now means "Edit Position" + ModeHighlight(); + } } else if (StrCaseCmp(appData.initialMode, "TwoMachines") == 0) { initialMode = TwoMachinesPlay; } else if (StrCaseCmp(appData.initialMode, "AnalyzeFile") == 0) { @@ -2925,9 +2987,9 @@ read_from_ics(isr, closure, data, count, error) } } // [HGM] chat: end of patch + backup = i; if (appData.zippyTalk || appData.zippyPlay) { /* [DM] Backup address for color zippy lines */ - backup = i; #if ZIPPY if (loggedOn == TRUE) if (ZippyControl(buf, &backup) || ZippyConverse(buf, &backup) || @@ -3092,6 +3154,8 @@ read_from_ics(isr, closure, data, count, error) continue; } + if(i < backup) { i = backup; continue; } // [HGM] for if ZippyControl matches, but the colorie code doesn't + if (looking_at(buf, &i, "\\ ")) { if (prevColor != ColorNormal) { if (oldi > next_out) { @@ -7875,7 +7939,10 @@ if(appData.debugMode) fprintf(debugFP, "nodes = %d, %lld\n", (int) programStats. snprintf(buf1, sizeof(buf1), _("Failed to start %s chess program %s on %s: %s\n"), _(cps->which), cps->program, cps->host, message); RemoveInputSource(cps->isr); - DisplayFatalError(buf1, 0, 1); + if(appData.icsActive) DisplayFatalError(buf1, 0, 1); else { + if(cps == &first) appData.noChessProgram = TRUE; + DisplayError(buf1, 0); + } return; } @@ -12059,16 +12126,18 @@ SettingsMenuIfReady() } int -WaitForSecond(DelayedEventCallback retry) +WaitForEngine(ChessProgramState *cps, DelayedEventCallback retry) { - if (second.pr == NULL) { - StartChessProgram(&second); - if (second.protocolVersion == 1) { + char buf[MSG_SIZ]; + if (cps->pr == NULL) { + StartChessProgram(cps); + if (cps->protocolVersion == 1) { retry(); } else { /* kludge: allow timeout for initial "feature" command */ FreezeUI(); - DisplayMessage("", _("Starting second chess program")); + snprintf(buf, MSG_SIZ, _("Starting %s chess program"), cps->which); + DisplayMessage("", buf); ScheduleDelayedEvent(retry, FEATURE_TIMEOUT); } return 1; @@ -12119,7 +12188,7 @@ TwoMachinesEvent P((void)) TruncateGame(); // [HGM] vari: MachineWhite and MachineBlack do this... ResurrectChessProgram(); /* in case first program isn't running */ - if(WaitForSecond(TwoMachinesEventIfReady)) return; + if(WaitForEngine(&second, TwoMachinesEventIfReady)) return; if(first.lastPing != first.lastPong) { // [HGM] wait till we are sure first engine has set up position DisplayMessage("", _("Waiting for first chess program")); ScheduleDelayedEvent(TwoMachinesEvent, 10); @@ -13732,6 +13801,7 @@ SendToProgram(message, cps) outCount = OutputToProcess(cps->pr, message, count, &error); if (outCount < count && !exiting && !endingGame) { /* [HGM] crash: to not hang GameEnds() writing to deceased engines */ + if(!cps->initDone) return; // [HGM] should not generate fatal error during engine load snprintf(buf, MSG_SIZ, _("Error writing to %s chess program"), _(cps->which)); if(gameInfo.resultDetails==NULL) { /* [HGM] crash: if game in progress, give reason for abort */ if((signed char)boards[forwardMostMove][EP_STATUS] <= EP_DRAWS) { @@ -14113,6 +14183,7 @@ FeatureDone(cps, val) DelayedEventCallback cb = GetDelayedEvent(); if ((cb == InitBackEnd3 && cps == &first) || (cb == SettingsMenuIfReady && cps == &second) || + (cb == LoadEngine) || (cb == TwoMachinesEventIfReady && cps == &second)) { CancelDelayedEvent(); ScheduleDelayedEvent(cb, val ? 1 : 3600000);